How do I bind C-= in emacs?
Asked Answered
S

5

7

This s-expression in my .emacs file does not produce the desired result:

(define-key global-map (kbd "C-=") 'djhaskin987-untab-to-tab-stop)

Why can't I bind a command to Ctrl+=?

EDIT for clarification:

I am using emacs23-nox on the standard build of urxvt-256colors for Debian, except that I have recompiled with --disable-iso405776 (or something to that effect) it so that Ctrl+Shift doesn't do the weird 'insert character' thing. I don't know if this affects anything. For example, C-M-i sends M-TAB, which I don't understand.

EDIT II:

I apologize for not making this clear. The function djhaskin987-untab-to-tab-stop has the line (interactive) in it. This part works.

Siamang answered 18/5, 2012 at 21:38 Comment(1)
C-i is generally translated as TAB in emacs. So I dont be surprised if C-M-i is translated as M-TABHynda
I
9

In a terminal, TAB is represented by the same byte sequence as C-i. And typically the terminal has no special byte-sequence for C-=, so it will just send a =. There is nothing that Emacs can do about it. But you might be able to teach your terminal emulator to send some special byte sequence of your choice (check the documentation of your terminal emulator for that), after which you can teach Emacs to recognize it as a C-= (with something like (define-key input-decode-map "...thebytes..." [?\C-=])).

Intromit answered 20/5, 2012 at 2:9 Comment(6)
thanks Stefan.. that is very useful.. For eg..in this package some one took lot of pain to make xterm work better with emacs. dur.ac.uk/p.j.heslin/Software/Emacs/Download/xterm-extras.el (see commentary for .Xresource file)Hynda
+1 Thanks for helping me solve my problem. I can see this is the way to go.Siamang
Maybe it's better to edit in the actual solution - the linked file comes through compressed and the link could easily break. Is C-= special in terminals? The general strategy seems to be to translate X keys into unused terminal escape sequences and then define emacs keys for these and other previously-undefined terminal escapes (and then bind those keys to functions).Marikomaril
@SamBrightman: note that the link in the first comment uses key-translation-map but it should use input-decode-map instead. It is probably an artifact from the fact that input-decode-map was only introduced in Emacs-23 and before that the best you could do was use either key-translation-map or function-key-map.Intromit
@Intromit it actually breaks for me with input-decode-map in daemon mode, whilst function-key-map works in both. I've changed my answer back for now, since I don't understand what is breaking.Marikomaril
Every terminal program can support different features and use different escape sequences, so there's a different value of input-decode-map for each terminal. So in daemon mode, you need to make sure that your input-decode-map settings are applied for every terminal. E.g. by adding this binding within terminal-init-xterm-hook.Intromit
M
10

The accepted answer in combination with the link in the first comment to it is enough to get started on a complete solution. The steps are:

  1. make your terminal output escape codes for the key
  2. make Emacs recognise the escape codes as a standard keypress
  3. bind the keypress in a mode map

The first is very terminal and/or operating system dependent.

The link in the first comment shows some examples for X Window System. The key names are available in /usr/X11R6/include/X11/keysymdef.h (or try locate keysymdef.h), prefixed with XK_ (which should be removed for our purposes). I read that symbolic names are preferred over key literals.

I don't currently run X but I think it should look like this in your case:

XTerm.VT100.Translations: #override \
Ctrl ~Meta ~Shift  <Key> equal:         string(0x1b) string("[emacs-C-=")\n

The first string is the escape, the second is of your choosing.

In iTerm you can use Preferences->Keys and choose Send Escape Sequence as the Action. For example, I have:

iTerm key mappings

Emacs Wiki lists some configuration methods for other terminals.

Now you can teach Emacs to recognize it as a C-=. First define-key into input-decode-map. I have a couple of helper functions:

(defun my/global-map-and-set-key (key command &optional prefix suffix)
   "`my/map-key' KEY then `global-set-key' KEY with COMMAND.
 PREFIX or SUFFIX can wrap the key when passing to `global-set-key'."
   (my/map-key key)
   (global-set-key (kbd (concat prefix key suffix)) command))

 (defun my/map-key (key)
   "Map KEY from escape sequence \"\e[emacs-KEY\."
   (define-key function-key-map (concat "\e[emacs-" key) (kbd key)))

So then:

(my/global-map-and-set-key "C-=" 'some-function-to-bind-to)

Some keys (currently: ()\|;'`"#.,) will need escaping in the string, like C-\..

Marikomaril answered 24/10, 2016 at 15:38 Comment(0)
I
9

In a terminal, TAB is represented by the same byte sequence as C-i. And typically the terminal has no special byte-sequence for C-=, so it will just send a =. There is nothing that Emacs can do about it. But you might be able to teach your terminal emulator to send some special byte sequence of your choice (check the documentation of your terminal emulator for that), after which you can teach Emacs to recognize it as a C-= (with something like (define-key input-decode-map "...thebytes..." [?\C-=])).

Intromit answered 20/5, 2012 at 2:9 Comment(6)
thanks Stefan.. that is very useful.. For eg..in this package some one took lot of pain to make xterm work better with emacs. dur.ac.uk/p.j.heslin/Software/Emacs/Download/xterm-extras.el (see commentary for .Xresource file)Hynda
+1 Thanks for helping me solve my problem. I can see this is the way to go.Siamang
Maybe it's better to edit in the actual solution - the linked file comes through compressed and the link could easily break. Is C-= special in terminals? The general strategy seems to be to translate X keys into unused terminal escape sequences and then define emacs keys for these and other previously-undefined terminal escapes (and then bind those keys to functions).Marikomaril
@SamBrightman: note that the link in the first comment uses key-translation-map but it should use input-decode-map instead. It is probably an artifact from the fact that input-decode-map was only introduced in Emacs-23 and before that the best you could do was use either key-translation-map or function-key-map.Intromit
@Intromit it actually breaks for me with input-decode-map in daemon mode, whilst function-key-map works in both. I've changed my answer back for now, since I don't understand what is breaking.Marikomaril
Every terminal program can support different features and use different escape sequences, so there's a different value of input-decode-map for each terminal. So in daemon mode, you need to make sure that your input-decode-map settings are applied for every terminal. E.g. by adding this binding within terminal-init-xterm-hook.Intromit
C
1

The problem is that you use emacs in the terminal. The terminal does not allow "C-=". Try your function in the graphical emacs and it will work. You will have to find another keybinding for the terminal.

Contortion answered 18/5, 2012 at 23:46 Comment(1)
I realize this, but for purposes of personal preference (so that I can access emacs even through SSH, and so that all my stuff is in the terminal), I want to make C-= work even in the terminal.Siamang
F
1

You can map C-= using the default ascii codes: ^[[61;5u. Then you can bind it in Emacs either using:

(global-set-key (kbd "C-=") 'djhaskin987-untab-to-tab-stop))

or let use-package do it, e.g.:

(use-package expand-region
  :ensure t
  :bind (("C-=" . er/expand-region)))

I do want to thank Sam Brightman, for his wonderful solution. It's a very clean, albeit heavy-handed, approach that will work for any keys that cannot be sent via normal ascii codes. I've been wanting to get C-TAB working inside iterm2 for a long time. I was able to do it by deleting the builtin preferences keys for C-TAB/C-S-TAB and using his approach. With the following, I can be ssh'd into remote Linux boxes and quickly switch through lots of open buffers in projects, just like a desktop editor. enter image description here

(use-package nswbuff
  :defer 1
  :after (projectile)
  :commands (nswbuff-switch-to-previous-buffer
             nswbuff-switch-to-next-buffer)
  :config
  (progn
    (my/global-map-and-set-key "C-TAB" 'nswbuff-switch-to-previous-buffer)
    (my/global-map-and-set-key "C-S-TAB" 'nswbuff-switch-to-next-buffer))
  :init
  (setq nswbuff-display-intermediate-buffers t
        nswbuff-exclude-buffer-regexps '("^ "
                                         "^\*.*\*"
                                         "\*Treemacs.*\*"
                                         "^magit.*:.+")
        nswbuff-include-buffer-regexps '("^*Org Src")
        nswbuff-start-with-current-centered t
        nswbuff-buffer-list-function '(lambda ()
                                        (interactive)
                                        (if (projectile-project-p)
                                            (nswbuff-projectile-buffer-list)
                                          (buffer-list)))))
Filterable answered 12/10, 2019 at 10:15 Comment(0)
S
0

The function you're binding must be interactive. Try:

(define-key global-map (kbd "C-=") 
    (lambda () (interactive) (djhaskin987-untab-to-tab-stop)))
Sacchariferous answered 18/5, 2012 at 21:49 Comment(1)
I'm afraid not, but thanks for the tip. When I use this line (or mine) and hit CTRL+=, it just writes out an '=' to the buffer.Siamang

© 2022 - 2024 — McMap. All rights reserved.