What character or sequence of characters a terminal sends when you press one of its keys (or key combinations) depends on the terminal itself.
While a
is quasi-universally what all terminals send when you press their A key (for those that have such a key at least), for keys like Home, Left, F1 or Ctrl+6, etc, it varies a lot between terminals.
There is some common ground though. The ASCII control characters with values 0 to 31 are often represented as ^@
, ^A
...^Z
, ^[
, ^\
, ]
, ^^
and ^_
. You'll notice for all of those, if you toggle the 6th bit of the printable character, you get the corresponding control character (for instance A
is 0x41, ^A
is 0x1). ^?
is 0x7f, ?
is 0x3f.
And terminals do send the ^X
character when you press Ctrl+X.
^I
is the TAB control character, and that's the character that is also sent when you press the Tab key for those that have one (in addition to Ctrl+I).
Same for ^[
, aka \e
and the Esc key.
^H
aka \b
is the backspace character, but some terminals send DEL
(^?
) upon Backspace while some others send ^H
.
^M
aka \r
is sent upon Return/Enter (but can be translated to ^J
aka \n
by the terminal device driver in some modes).
^@
aka \0
can be sent upon Ctrl+@ but also sometimes upon Ctrl+Space.
Some terminals have a Meta or Alt modifier key which when combined with another key sends either the same character but with its 8th bit set (for instance Meta+A (without Shift) sends byte 0xE1 when a
is 0x61). While some others (more common these days) send the ^[
character followed by the character or sequence of characters that would have been sent without Meta (so for instance Meta+A sends ^[a
).
Most of the other function keys generally send a sequence of characters which start with ^[
(ESC). One exception is Delete which on some terminals sends DEL (^?
).
Now terminal applications that handle keyboard input, when they receive a sequence of characters from the terminal device, want to know what key press they corresponds to. If different terminals send different sequences, how can they do?
That's where the $TERM
environment variable comes into play. That variable is set either by getty
, terminal emulators or the user to tell applications what terminal they're talking to. The value is a short name that is meant to identify the type of terminal uniquely.
For instance a modern xterm
terminal emulator would set it to xterm-256color
.
Then those applications are able to query a database of terminal descriptions using that value to know about the capabilities of that terminal. Such capabilities can be for instance: what sequence of characters must be sent to the terminal to enable bold text output. And some other can be what sequence of characters the application would receive from the terminal when you press the Delete key.
Historically, there are two main databases: termcap
and terminfo
each with a set of APIs to query it. Nowadays, terminfo
(more advanced) is prevalent and ncurses
(maintained by @ThomasDickey for the past few decades) is a common library used to interface with it (also exposes the termcap interface using the same backend).
Now, the set of possible capabilities stored in that database is fixed. It is described in the terminfo(5)
man page.
On the key front, there is a limited number of keys that are covered. It's still a large list, including of keys most of us will have never heard of, but it doesn't include every function key of every possible terminal past and future. It covers some key combinations (mainly Shift+SomeFuncKeys) but not all possible combinations (like Ctrl+Shift+Up).
On a GNU system, see:
man 5 terminfo | grep -Po '^\s*\Kkey_.*'
for the list.
Now, to query the terminfo
database from a shell, there are 3 main commands in ncurses
:
toe
: lists terminals in the database
tput
: prints the capability raw (typically used to send the escape sequences, like tput bold
to start bold mode).
infocmp
: retrieves full entries from the database or compare them.
Here, it's the latter that is going to be useful to find out which of your terminal keys could have sent a given sequence: infocmp -xL1
outputs all the capabilities known for the terminal whose identifier is stored in $TERM
(so your terminal), 1
per line and with the L
ong (more descriptive) capability names. So:
$ infocmp -xL1 | grep key_
key_b2=\EOE,
key_backspace=\177,
key_btab=\E[Z,
key_dc=\E[3~,
key_down=\EOB,
key_end=\EOF,
key_enter=\EOM,
[...]
Gives you all the sequences for all the known keys¹.
On my xterm
terminal, in there, I see:
key_sright=\E[1;2C,
key_sleft=\E[1;2D,
For instance.
The zsh
shell also exposes the capabilities of the current terminal in its $terminfo
special associative array (in the zsh/terminfo
module, loaded automatically when you access that variable). So another way there to get the information is with:
$ key=$'\e[1;2D'
$ echo ${(k)terminfo[(Re)$key]}
kLFT
(That's the short terminfo names there).
The terminfo database doesn't list any key that sends ^[^?
for my terminal, but I would get that sequence if I typed Esc Ctrl+? or Ctrl+[ ? or Alt+Ctrl+? for instance.
Maybe your terminal sends ^?
upon Delete, then you'd possibly get that as well upon Meta+Delete.
^X^U
would be sent upon Ctrl+X Ctrl+U, I can't imagine terminals would have a function key sending that, though note that many terminal emulators allow binding any sequence of characters to any key or key combinations.
¹ There's an extra caveat with many terminals in that the terminal can send different sequences for some function keys when in keypad application mode and when not. The terminfo entry in that case describes the sequences of the keypad application mode. An application can put the terminal in that mode by sending the sequence corresponding to the smkx
capability.