30

Do we have a key bindings table that translates all the various ways of referring to a key press? I'm using zsh, but I presume that if there was such a table it would work for any shell.

The reason I ask is that I'd like to assign some keybindings and I have no way of knowing how to refer to them (unless I'm going to steal one that's already defined).

For example, in 'zbindkey' we have this sort of thing:

[[ "$terminfo[kend]"  == " O"* ]] && \
    bindkey -M emacs "${terminfo[kend]/O/[}"  end-of-line

... and I can guess that "kend" means that this refers to the End key.

Cross checking with bindkey I see these lines:

"^E" end-of-line
"^[OF" end-of-line
"^[[F" end-of-line

... so I trust that one of those lines refers to the End key. Which one?

We also have this in the "bindkey" file:

bindkey "\e[A" history-beginning-search-backward

Now, I happen to know that that's the Up Arrow key, but how could I find out if I didn't know?

$ bindkey (at CLI)

... gives us a different language for the same key:

"^[[A" history-beginning-search-backward

... but at least now I know that ^[[A in bindkey-at-CLI speak is the same thing as \e[A in bindkey-in-zbindkey speak. That's easy. In the old days in DOS, the Up Arrow was 0;72 -- you could find the scan code of every legal keystroke and there was only the one language.

Is there a table? Or some other way of being able to pick a keystroke and know how to refer to it in terminfo[] ... in " bindkey-in-zbindkey " ... in "bindkey-at-CLI " and/or in whatever other languages there may happen to be?

Again, in DOS there was the scancode program -- type a keystroke, and you got the scancode. It was sinfully easy.


From the answers I guess then that there is no way to print out a table of all possible bindings? Anyway 'bindkey' does almost what I want:

pts/2 HP-y5-10-Debian1 root /aWorking/Docs $ bindkey -L
bindkey "^@" set-mark-command
bindkey "^A" beginning-of-line
bindkey "^B" backward-char
bindkey "^D" delete-char-or-list
bindkey "^E" end-of-line
...

at least I can see all existing bindings, even if not all possible bindings. Now, if there was just some way of translating the key glyphs into 'regular' terms:

bindkey "Home" beginning-of-line

... then I'd be happy.

1
  • 3
    Press Ctrl+V (or whatever stty -a says lnext is) then the key.
    – Mikel
    Commented Feb 23, 2014 at 18:51

6 Answers 6

24

The interface between a terminal application and a terminal emulator (or hardware terminal) transmits bytes, not keys. Function keys such as cursor movement keys are translated into escape sequences (beginning with the escape character ESC a.k.a. \e a.k.a. \033 a.k.a. 0x1b a.k.a. ^[). The same goes for combinations of a function key or a character key with modifiers, though not all terminals send different sequences for all the different modifier combinations. A few keys are sent encoded as control characters (e.g. Tab → Ctrl-I = \t = \011).

As you can see, there are many ways to describe control characters. Some have a name, corresponding to their traditional function (e.g. Tab, Line feed); those tend to have a backslash+letter combination that you can use inside $'…' or in an argument to echo or print (as well as in sed regular expressions and in string literals in awk, C and other languages (note that different tools may have a slightly different set of escape sequences)). You can use backslash+octal (e.g. \033) in these contexts as well.

There is some variation as to which escape sequence terminals send for each key. Fortunately, there is almost no overlap: there are very few character sequences that mean different keys on different terminal. The main problem is character 127 = \177 = 0x7f which is most often Backspace nowadays but sometimes Delete.

^[OF and ^[[F (i.e. \eOF and \e[F) are the two common escape sequences sent by End. ^E (i.e. \005) is the Emacs key binding (Ctrl+E) for end-of-line.

To see what your terminal emulator sends for a particular key or key combination, press Ctrl+V and then the key in question. This inserts the first character of the escape sequence literally. Escape sequences normally consist of an escape character followed by printable characters, so the rest of the escape sequence is inserted literally too.

The Terminfo database contains the escape sequences for some keys. You'll find the list of Terminfo capabilities in the terminfo(5) man page on your system. In zsh, you can list the values in the database through the terminfo associative array. Beware when printing out values that they contain escape sequences which are also interpreted by the terminal when displayed, so print them in a quoted form.

% print -lr ${(q)terminfo[kend]}
$'\033'OF

See How do keyboard input and text output work? for a more complete overview of what happens when you press a key. It isn't necessary to understand key bindings in zsh.

0
16
    BEGINNER'S GUIDE TO ZSH KEYBOARD ASSIGNMENTS, AKA 'KEYBOARD BINDINGS'.

(comments, improvements, bitter denunciations welcome: rayandrews at eastlink dot ca)

'Available' key combinations on a '101' PC keyboard attached to a PC running 'zsh' under xfce4 under Debian Linux (I don't know who's 'in charge'). All combinations that produce duplicate codes within the 'grey' keys have been removed except for the simplest avatar which is shown. Note, some grey keys/combinations have '^letter' duplicates, like 'Enter' == '^M', these have not been removed. Other active combinations were not 'available' since used by the system, even from console, eg. 'Alt+Function' keys switch terminals. Perhaps the 'Meta' key would do more, but this is with a 101 KB. Interesting that there are far more combinations available in DOS, such as Ctrl+Function -- all available in DOS, none of them available in Linux, so it seems. None of the tripple key combinations (eg. 'Ctrl+Alt+Up') produced any unique codes within the grey keys, but they do produce codes in the white keys. Interesting anomalies: '^[[22' '^[[27' '^[[30' are 'missing', you hafta wonder why those numbers were skipped. (Which is to say that you might expect 'F11' to be '^[[22' not '^[[23'.)

The key codes shown are as they would be output by 'showkeys -a' or 'bindkey' at CLI. However, for some reason if you use 'bindkey' within a script (as in '.zshrc') ' ^[ ' must be replaced with ' \e ', thus at CLI:

bindkey -s '^[[[A' 'my-command \C-m'

... bind 'F1' to 'my-command' and execute it (the ' \C-m ' simulates the 'Enter' key).

in '.zshrc':

bindkey -s '\e[25' 'my-command1 ; my command2 \C-m'

... bind 'Shift-F1' to 'my-command1' followed by 'my-command2' and execute both of them.

COMBINATIONS USING JUST THE 'GREY' KEYS:

key[F1] = '^[[[A' key[F2] = '^[[[B' key[F3] = '^[[[C' key[F4] = '^[[[D' key[F5] = '^[[[E' key[F6] = '^[[17~' key[F7] = '^[[18~' key[F8] = '^[[19~' key[F9] = '^[[20~' key[F10] = '^[[21~' key[F11] = '^[[23~' key[F12] = '^[[24~'

key[Shift-F1] = '^[[25~' key[Shift-F2] = '^[[26~' key[Shift-F3] = '^[[28~' key[Shift-F4] = '^[[29~' key[Shift-F5] = '^[[31~' key[Shift-F6] = '^[[32~' key[Shift-F7] = '^[[33~' key[Shift-F8] = '^[[34~'

key[Insert] = '^[[2~' key[Delete] = '^[[3~' key[Home] = '^[[1~' key[End] = '^[[4~' key[PageUp] = '^[[5~' key[PageDown] = '^[[6~' key[Up] = '^[[A' key[Down] = '^[[B' key[Right] = '^[[C' key[Left] = '^[[D'

key[Bksp] = '^?' key[Bksp-Alt] = '^[^?' key[Bksp-Ctrl] = '^H' console only.

key[Esc] = '^[' key[Esc-Alt] = '^[^['

key[Enter] = '^M' key[Enter-Alt] = '^[^M'

key[Tab] = '^I' or '\t' unique form! can be bound, but does not 'showkey -a'. key[Tab-Alt] = '^[\t'

COMBINATIONS USING THE WHITE KEYS:

Anomalies: 'Ctrl+`' == 'Ctrl+2', and 'Ctrl+1' == '1' in xterm. Several 'Ctrl+number' combinations are void at console, but return codes in xterm. OTOH Ctrl+Bksp returns '^H' at console, but is identical to plain 'Bksp' in xterm. There are no doubt more of these little glitches however, in the main:

White key codes are easy to undertand, each of these 'normal' printing keys has six forms:

A = 'a' (duhhh) A-Shift = 'A' (who would have guessed?) A-Alt = '^[a'
A-Ctrl = '^A' A-Alt-Ctrl = '^[^A' A-Alt-Shift = '^[A' A-Ctrl-Shift = '^A' (Shift has no effect)

Don't forget that:

/-Shift-Ctrl = Bksp = '^?' [-Ctrl = Esc = '^[' M-Ctrl = Enter = '^M'

And, we can 'stack' keybindings:

bindkey -s '^Xm' "My mistress\' eyes are nothing like the sun."

... Bind 'Ctrl-X' followed by 'm' to a nice line of poetry.

And we can flirt with madness:

bindkey -s '^Pletmenot' 'Let me not, to the marriage of true minds'

... but you hafta start something like that with a 'modifier' character. Try it, if you like keyboard shortcuts, you can really go to town.

QUESTIONS:

Where is it written that 'Ctrl-Bksp' means one thing at console, another thing in xterm?

Are these assignments changable?

Who designed all this, and what were they thinking at the time?

Why is it 'Alt-Function' to change terminals at a terminal, but 'Alt-Ctrl-Function' to change to a terminal from GUI?

How/where is 'Alt-Ctrl-Delete' defined?

enter code here
5
  • i almost wanna send an email...
    – mikeserv
    Commented Oct 23, 2014 at 11:45
  • By all means do mike: [email protected] Commented Oct 23, 2014 at 18:38
  • it was only a joke, ray - you just don't often see a bitches, gripes, complaints? email me... by-line around here. I appreciated it, is all. anyway, as an aside, on the zsh keys topic, you might like to try the zkbd function which should get you an entire key-mapping saved in a file. I believe it is autoloadable, but, if not, look for it in /usr/share/zsh/functions/Misc. There's some other weird stuff in there, too, by the way, like tetris.
    – mikeserv
    Commented Oct 23, 2014 at 19:07
  • 1
    That's one of the tools I used to make my table, but how do you get it to barf up 'everything' at once? Commented Oct 23, 2014 at 20:04
  • interesting - I guess I didn't. I've never actually run it before now - only read its source file - and that was a couple of months ago. I guess it does do a series of input tests to generate its save file. but it does save everything to a file, right?
    – mikeserv
    Commented Oct 23, 2014 at 20:20
11

There are many tools at your disposal in Unix/Linux so it can be bit confusing and overwhelming. For starters I'd use showkey:

$ showkey -a

Press any keys - Ctrl-D will terminate this program

a    97 0141 0x61
b    98 0142 0x62
c    99 0143 0x63
d   100 0144 0x64
e   101 0145 0x65
f   102 0146 0x66
g   103 0147 0x67

From the man page regarding -a:

   When  in  `ascii' dump mode, showkey prints to the standard output the 
   decimal, octal, and hexadecimal value(s) of the key pressed,
   according to he present keymap.

You can use xmodmap to get some of the mappings:

$ xmodmap
xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Alt_R (0x6c),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3      
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

The above isn't all of the pieces to the puzzle but is some additional info that might be helpful towards you finding the ultimate map between the keybindings and the scancodes. There is more info in this U&L Q&A titled: Key mappings in Linux.

References

4
  • 1
    While this is all true, it's irrelevant to understanding key bindings in a terminal. Commented Feb 24, 2014 at 0:39
  • @Gilles - yeah I kind of figured that, I was only attempting to provide leads, now that I've read your A I understand how that interface works, thanks!
    – slm
    Commented Feb 24, 2014 at 1:01
  • 1
    "showkey -a" is not irrelevant, though.
    – skagedal
    Commented Mar 28, 2015 at 21:08
  • "The above isn't all of the pieces to the puzzle" Can you elaborate? What are the other pieces to the puzzle? Commented Sep 15, 2023 at 21:23
7

if there was just some way of translating the key glyphs into 'regular' terms:

bindkey "Home" beginning-of-line

... then I'd be happy.

There is infocmp utility for describing terminfo entries. This is especially useful with -L option aka long C variable names:

$ infocmp -cL
...
key_home= '\EOH'.
key_up= '\EOA'.
key_down= '\EOB'.
key_right= '\EOC'.
key_left= '\EOD'.
key_backspace= '^H'.
key_end= '\EOF'.
...

Comparing this to the bindkey output

"^[OH" beginning-of-line
"^[OA" up-line-or-history
"^[OB" down-line-or-history
"^[OC" forward-char
"^[OD" backward-char
"^H" backward-delete-char
"^[OE" end-of-line

one can see that they use different notation for escape, but basically it is relatively easy to write a script which connects second column of infocmp with first of bindkey.

In case there is any doubt what particular string means (as printed in infocmp output) one can always look into terminfo manual where the full description is given, for example

key_send  ->  shifted end key
key_sic   ->  shifted insert-character key
key_dc    ->  delete-character key
0

I use URxvt terminal emulator. There's a useful key binding for showing such codes: Ctrl+V. After pressing it enter key sequence you want and it will print its code. For example, my Ctrl+ has code ^[Oa.

0

I wrote a couple of scripts to simplify zsh keybindings here: https://github.com/vapniks/zsh-keybindings It includes the definition of an assoc array containing keybindings so you can do e.g:

bindkey "${keys[altend]}" some-widget

to bind the Alt+End key combo. It also detects which terminal emulator you are using, and adjusts the keycodes accordingly, but I've only got definitions for xterm, guake & gnome-terminal so far. Feel free to update with info for other terminals.

1
  • Cool. Next time I'm fiddling with bindings I think that will be a resource. Commented Sep 11, 2020 at 21:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .