4

To get the character sequences of a particular keyboard shortcut we use showkey -a or verbatim insert (Ctrl+V).

What is the opposite of it? How can I get the keyboard shortcut in human readable format from character sequences?

I used some keybindings for example

^[^?
^X^U
^[[3;5~
^[[1;2D
^[[1;2C
^[[1;5C
^[[1;5D
^[[1;6C
^[[1;6D
....

Now I do not remember which key/key-combination they used to represent.

How can I find that out?

Update 1

I am looking for something which will output Ctrl+R or Ctrl+Delete etc, I mean in human readable format.

Any reference to a table which has possible character sequences and their human readable formats will also do.

1

4 Answers 4

4

The first couple of lines

^[^?
^X^U

are codes that you can find tabulated as ASCII controls

^[  (escape)
^U  (control-U)
^X  (control-X)

That ^? is the conventional representation of ASCII DEL (the delete key).

If your terminal description (TERM) is set appropriately,

infocmp -1 -x

will print the ncurses names for the keys in terminfo format. There's other information, but you would see these lines:

kDC5=\E[3;5~,

kRIT=\E[1;2C,
kRIT3=\E[1;3C,
kRIT4=\E[1;4C,
kRIT5=\E[1;5C,
kRIT6=\E[1;6C,
kRIT7=\E[1;7C,

kLFT=\E[1;2D, 
kLFT3=\E[1;3D,
kLFT4=\E[1;4D,
kLFT5=\E[1;5D,
kLFT6=\E[1;6D,
kLFT7=\E[1;7D,

which (given that terminfo \E is ASCII escape, or ^[) you could recognize as corresponding to your example. The kLFT and kRIT names tell me that those are the (xterm-style) modified left/right cursor keys (see XTerm Control Sequences for the meaning of the digit after the names, in a table of Code/Modifiers). The terminfo names are listed in the terminal database:

# These are the extended keys defined in this file:
#
# kDC3 kDC4 kDC5 kDC6 kDC7 kDN kDN3 kDN4 kDN5 kDN6 kDN7 kEND3 kEND4 kEND5 kEND6
# kEND7 kHOM3 kHOM4 kHOM5 kHOM6 kHOM7 kIC3 kIC4 kIC5 kIC6 kIC7 kLFT3 kLFT4
# kLFT5 kLFT6 kLFT7 kNXT3 kNXT4 kNXT5 kNXT6 kNXT7 kPRV3 kPRV4 kPRV5 kPRV6 kPRV7
# kRIT3 kRIT4 kRIT5 kRIT6 kRIT7 kUP kUP3 kUP4 kUP5 kUP6 kUP7 ka2 kb1 kb3 kc2

and are described in the user_caps manual page.

Given all of that, someone could make a program or script that made a table showing the readable format (but knowing where it's documented should help).

Some terminals will send that ^[^? if you press AltDelete (but that is not in the terminal description). The ^X^U is not a sequence sent by a single key in a terminal emulator (unless you've rebound keys): more likely that's two keypresses.

2

As long as your terminal generates input control sequences in ECMA-48 form, or the DECFNK, Interix, SCO Console, or Unicode RXVT forms, you can feed it to my console-decode-ecma48 tool, with the --input command-line option to tell it that the character stream is input rather than output. This is true for most terminals and terminal emulators that you will encounter in practice nowadays.

Here is what it does with your input, with ^[ replaced by the actual character of course:

% console-decode-ecma48 --input << EOF
^[^?
^X^U
^[[3;5~
^[[1;2D
^[[1;2C
^[[1;5C
^[[1;5D
^[[1;6C
^[[1;6D
EOF
DEL
LF
U+00000015
LF
DEC Control+DELETE
LF
Level2+CUB 1
LF
Level2+CUF 1
LF
Control+CUF 1
LF
Control+CUB 1
LF
Control+Level2+CUF 1
LF
Control+Level2+CUB 1
LF
%

As noted at https://unix.stackexchange.com/a/504056/5132 , if you want to decode what some terminals do with ⎇ Alt key chords you will also need the --no-7bit option; otherwise you'll get the ECMA-48 standard decoding of the 7-bit aliases for the C1 control characters.

CUF and CUB are the standard ECMA-48 names, of course: "CUrsor Forward" and "CUrsor Backward". See the manual.

The rules for terminal control sequences may surprise you. You typed , DEL, , , and . The rules for terminal control sequences handle this as follows:

  1. The begins an escape sequence.
  2. The DEL is handled immediately as a control character, leaving the escape sequence still pending.
  3. The is handled immediately as a control character, leaving the escape sequence still pending.
  4. The cancels (it being in the name) the pending escape sequence.
  5. The is processed as a C0 control character. console-decode-ecma48 prints its Unicode code point in the case of this particular character.

Note that no shell that I know of actually contains a correct ECMA-48 decoder. Shells do pattern matching, which is significantly imperfect at handling the actual ECMA-48 encoded stuff that terminals have been sending all along. This leads to things like the problems discussed at https://unix.stackexchange.com/a/499139/5132 and https://unix.stackexchange.com/a/520429/5132 amongst many others.

console-decode-ecma48 actually has a proper ECMA-48 decoder with a control sequence state machine, with variances for the SCO Console, Interix, and so forth. It won't show you exactly what things like GNU Readline, libedit, and ZLE will make of your input, because they don't get the protocol right.

But it will show you what an ECMA-48 terminal thought that it was sending, which is what you want here.

Further reading

2

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 Long (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.

0

bash

$ bind -p | grep -F '[3;5~'
"\e[3;5~": delete-char
1
  • 1
    I am looking for something which will output Ctrl+R or Ctrl+Delete etc, I mean in human readable format. Commented Jul 28, 2020 at 17:03

You must log in to answer this question.

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