In Shift+Up isn't recognized by Emacs in a terminal I explain how terminals translate most function keys into escape sequences, because the interface between applications and terminals transmits characters (or rather bytes), not keys. Only a few modifier+character combinations have their own character:
- Ctrl plus a letter or one of
@[\]^_
turns into bytes 0–31 (ASCII control characters).
- Often Ctrl+? turns into byte 127 and Ctrl+Space is equivalent to Ctrl+@ (byte 0).
- Some function keys are equivalent to control characters: Tab = Ctrl+I, Return = Ctrl+M, Esc = Ctrl+[.
- And Backspace = Ctrl+H or Ctrl+? depending on the configuration. Ctrl+? is more convenient for Emacs, since Ctrl+H is help.
- Meta+character is sent as Esc followed by character.
So what about other combinations such as Ctrl+; or Ctrl+Shift+letter? Since there's no corresponding character, the terminal has to either reuse a character or send an escape sequence. Many terminals ignore modifiers when there's no corresponding character, so you end up with Ctrl+; sending ;
, Ctrl+Shift+letter equivalent to Ctrl+letter, etc.
Terminal vendors kept doing the simple thing for a long time. There was no standard for escape sequences, which was self-perpetuating — terminal vendors don't implement it, applications don't support it, users don't expect it. Some terminal emulators can be configured to send arbitrary escape sequences, so if yours can, you can configure it and declare the escape sequences to Emacs (more on this later).
Lately, the situation is changing, because there have been two proposals to standardize on escape sequences. One is LeoNerd's libtermkey with the syntax ESC [ codepoint ; modifier u
. Another is Thomas Dickey's xterm with the syntax ESC [ 2 7 ; modifier ; codepoint ~
. Current versions of xterm (≥216) can be configured for either syntax by setting the formatOtherKeys
resource; the feature must be activated by setting the modifyOtherKeys
to a nonzero value.
If your terminal emulator doesn't support these syntaxes but can be configured, pick either.
Since Emacs 24.4, Emacs automatically turns on the modifyOtherKeys
feature when it detects that the terminal is xterm version ≥216. Emacs's detection of escape sequences to encode keys works through the variable local-function-key-map
. As of Emacs 24.4, not all escape sequences are supported. You can use the following code in your init file to complete the job.
;; xterm with the resource ?.VT100.modifyOtherKeys: 1
;; GNU Emacs >=24.4 sets xterm in this mode and define
;; some of the escape sequences but not all of them.
(defun character-apply-modifiers (c &rest modifiers)
"Apply modifiers to the character C.
MODIFIERS must be a list of symbols amongst (meta control shift).
Return an event vector."
(if (memq 'control modifiers) (setq c (if (or (and (<= ?@ c) (<= c ?_))
(and (<= ?a c) (<= c ?z)))
(logand c ?\x1f)
(logior (lsh 1 26) c))))
(if (memq 'meta modifiers) (setq c (logior (lsh 1 27) c)))
(if (memq 'shift modifiers) (setq c (logior (lsh 1 25) c)))
(vector c))
(defun my-eval-after-load-xterm ()
(when (and (boundp 'xterm-extra-capabilities) (boundp 'xterm-function-map))
(let ((c 32))
(while (<= c 126)
(mapc (lambda (x)
(define-key xterm-function-map (format (car x) c)
(apply 'character-apply-modifiers c (cdr x))))
'(;; with ?.VT100.formatOtherKeys: 0
("\e\[27;3;%d~" meta)
("\e\[27;5;%d~" control)
("\e\[27;6;%d~" control shift)
("\e\[27;7;%d~" control meta)
("\e\[27;8;%d~" control meta shift)
;; with ?.VT100.formatOtherKeys: 1
("\e\[%d;3u" meta)
("\e\[%d;5u" control)
("\e\[%d;6u" control shift)
("\e\[%d;7u" control meta)
("\e\[%d;8u" control meta shift)))
(setq c (1+ c))))))
(eval-after-load "xterm" '(my-eval-after-load-xterm))
If the TERM
environment variable isn't set to xterm
or a variant such as xterm-256color
, Emacs won't activate those sequences. If Emacs already has support for your value of TERM
, you can add support by defining a function similar to the one above, to be executed after loading the Lisp file whose name is the value of TERM
. If Emacs has no such support, you can add it by creating a subdirectory called term
somewhere in your load-path
, and creating a Lisp file called term/$TERM.el
where $TERM
is the value of TERM
, defining a function called terminal-init-$TERM
.
As I write, it seems that few terminal emulators other than xterm have adopted these escape sequences. On OSX, you can configure iTerm2 by selecting an escape sequence for each key combination, one by one.
C-;
combo and then useM-x view-lossage
to see if it's even getting to Emacs.gnome-terminal
, andM-x view-lossage
returns:ESC [ > 1 ; 2 8 0 2 ; 0 c ; ESC x v i e w - l o s s a g e RET
C-;
rather thanc ;
(or, at least, I getC-;
).