13

I like to use emacs in terminal mode (-nw), but it seems most (all?) terminals can't handle some key combinations - for example, C-<RET> or C-M-%. I know this is because most terminals emulate a VT-100, which didn't have these combinations. Are there any linux terminals (preferably KDE) which can handle these key combinations, or is this a fundamental limitation of all terminals?

Yossarian
  • 242

4 Answers4

18

When you press a key or key combination in a terminal, it is transmitted to the application running in the terminal as a sequence of one or more characters. For example, when you press a, the application receives a. When you press Enter, the application receives the character CR (a.k.a. ^M (pronounced “control-emm”), a.k.a. character number 13, a.k.a. \r or \015). Key combinations involving Alt are typically transmitted as the character ESC (a.ka. ^[ a.k.a. \e or \033) followed by the sequence for the key or key combination without Alt. Function keys and other key combinations are transmitted as escape sequences beginning with \e[ or \eO.

The escapes sequences are not fully standardized, and terminals typically ignore certain attributes for certain keys. For example, Ctrl+Shift+letter is often transmitted exactly like Ctrl+letter by default.

You can see what your terminal sends for a key combination by pressing Ctrl+V followed by that key combination in a shell prompt, or C-q or C-h c followed by the key combination in Emacs.

With some terminal emulators, you can configure the escape sequences for each key. On Xterm, this is done through X resources. Most setups read resources from ~/.Xresources when X starts, and you can load the file manually with xrdb -merge ~/.Xresources.

Term.VT100.translations:       #override \n\
    Ctrl ~Shift ~Meta <key>Return: string("\033[73;5~") \n\
    Ctrl Shift ~Meta <key>percent: string("\033[37;6~")

A common convention uses escape sequences of the form ESC [ number1 ; number2 ~ for function keys with modifiers. number1 indicates the function key (15 to 24 for F5 to F12 — for historical reasons, F1 through F4 have different escape sequences) and number2 indicates the modifier (2 for Shift, 3 for Meta, 5 for Ctrl, 7 for Ctrl+Meta, and add 1 for Shift with at least one of Ctrl or Meta).

Emacs translates escape sequences into its internal key representation through input-decode-map or local-function-key-map (or function-key-map before Emacs 23).

(define-key local-function-key-map "\033[73;5~" [(control return)])
(define-key local-function-key-map "\033[37;6~" [(control ?L)])
  • So, if I understand this correctly, I need to first define an escape sequence in my terminal which corresponds to some key combination. Then, in emacs, I need to map the escape sequence back to the key combination. Can the escape sequence be arbitrary, as long as it doesn't conflict with those defined in infocmp $TERM? – Yossarian Jun 17 '13 at 07:11
  • 2
    @Yossarian Yes. In addition to not conflicting, the escape sequences need to be unambiguous, i.e. no escape sequences should be a prefix of another one. This means in practice that the first character has to be ESC (unless you want to try some character ≥128, but that will restrict the possible input encodings) and the second character has to be something for which you want no ESC foo binding. – Gilles 'SO- stop being evil' Jun 17 '13 at 07:37
  • I've just got round to trying what you suggested. Should local-set-key actually be define-key? The former gives an error (wrong number of arguments), while the latter works, at least for C-Enter. It seems konsole still has trouble sending C-M-%. – Yossarian Jun 24 '13 at 12:25
  • @Yossarian Indeed, it should be define-key. I don't know if Konsole's escape keys can be configured, xterm is probably more customizable than any alternative. – Gilles 'SO- stop being evil' Jun 24 '13 at 14:07
  • 2
    Note that Thomas Dickey's xterm is under active development. With the XTerm*modifyOtherKeys: 2 resource it will generate unique sequences even for C-M- combinations, but with that setting you will need to provide a lot of custom mappings (XTerm*modifyOtherKeys: 1 is less capable but far more functional out of the box). For an example (albeit one which didn't work for me) see the xterm-extras.el library and the associated .Xresources and .inputrc files in the easymacs download. – phils Jun 24 '13 at 22:05
  • Cross-referencing with http://stackoverflow.com/a/17267661/324105 – phils Jun 24 '13 at 22:11
  • +1. but references to the provided facts would be quite relevant – Bleeding Fingers Sep 15 '13 at 11:09
  • In my terminal, backspace and ctrl+backspace both give ^?. Is there any possible way to distinguish between backspace and ctrl+backspace? – trusktr Oct 13 '13 at 15:54
  • @trusktr Maybe. It depends on your terminal emulator. You need to configure your terminal emulator to send different escape sequences. – Gilles 'SO- stop being evil' Oct 13 '13 at 18:57
  • Seems it's not possible with vte terminals yet (Gnome Terminal, Mate Terminal, Guake, etc) as far as I can tell. – trusktr Oct 17 '13 at 19:09
2

For a limited but significant set of keys, assuming KDE's konsole, one may do the following to have working, complex keybindings in emacs -nw:

I will use my implementation of getting S-<RET> to work as an example:

  1. Open a new konsole, go to settings -> current profile -> keyboard -> edit
  2. Hit Add and make a new entry for Return+Shift and give it a useful key sequence (I chose \E[27;3 which I think is the key sequence sent by X when I was poking around with xev, but that may be wrong -- the important thing to do is make sure that it has a proper escape and doesn't conflict with anything else).
  3. Play with it in the little test area at the bottom to make sure it is working.
  4. Restart konsole.
  5. Start up emacs -nw and in the scratch buffer evaluate:

    (read-key-sequence-vector "Type your new key:")

    then type your new key combination.

    • If you are unfamiliar with this, write the line out, leave the cursor at the end of the line, and hit C-x C-e to get emacs to run that line, it should say to you whatever you put in the quotes and wait for you to type something.
  6. It should spit out a key sequence which you may bind.
    (It returned [27 91 50 55 59 51] to me as opposed to the boring old [13] before I messed with the konsole keybinding.)

  7. Add to your emacs configuration:

    (define-key function-key-map [27 91 50 55 59 51] [(shift return)])
    
  8. I tested it with emacs -nw in a screen session using:

    (define-key ess-mode-map [(shift return)] #'ess-eval-line-and-step)
    (define-key sh-mode-map [(shift return)]  #'send-line-to-shell)
    
1

There are some efforts of extending the VT protocol in a way to allow lossless keyboard input (among other features, such as graphics).

One example is notty: https://github.com/withoutboats/notty

0

The short answer is that it is a fundamental limitation of all terminals.

The slightly longer answer is that even if someone created a terminal that does what you want, Emacs itself would require major changes to work with this hypothetical terminal.