Docs for legacy functional encoding

This commit is contained in:
Kovid Goyal 2021-01-11 21:58:54 +05:30
parent a30ea2b7f8
commit 2b12bcc07f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 232 additions and 115 deletions

View File

@ -23,6 +23,9 @@ issues in that proposal, namely:
* No way to disambiguate :kbd:`Esc` keypresses, other than using 8-bit controls
which are undesirable for other reasons
* Incorrectly claims special keys are sometimes encoded using ``CSI letter`` encodings when it
is actually ``ESC O letter``.
* Makes no mention of cursor key mode and how it changes encodings
* Incorrectly encoding shifted keys when shift modifier is used
* No way to have non-conflicting escape codes for :kbd:`alt+letter,
ctrl+letter, ctrl+alt+letter` key presses
@ -96,6 +99,8 @@ sub-field for the shifted key, like this::
CSI unicode-key-code::base-layout-key
.. _modifiers:
Modifiers
~~~~~~~~~~~~~~
@ -144,11 +149,13 @@ Non-Unicode keys
There are many keys that don't correspond to letters from human languages, and
thus aren't represented in Unicode. Think of functional keys, such as
:kbd:`Escape, Play, Pause, F1, Home, etc`. These are encoded using Unicode code
points from the Private Use Area (``0xe000 - 0xf8ff``). The mapping of key
points from the Private Use Area (``57344 - 63743``). The mapping of key
names to code points for these keys is in the
:ref:`Functional key definition table below <functional>`.
.. _progressive_enhancement:
Progressive enhancement
--------------------------
@ -176,7 +183,7 @@ The value ``3`` means all set bits are reset, unset bits are left unchanged.
"0b1 (1)", "Disambiguate escape codes"
"0b10 (2)", "Report key event types"
"0b100 (4)", "Report alternate keys"
"0b1000 (8)", "Report all keys as CSIu escape codes"
"0b1000 (8)", "Report all keys as ``CSI u`` escape codes"
The program running in the terminal can query the terminal for the
current values of the flags by sending::
@ -208,7 +215,7 @@ the :kbd:`Esc` key generates the byte ``0x1b`` which also is used to indicate
the start of an escape code. Similarly pressing the key :kbd:`alt+[` will
generate the bytes used for CSI control codes. Turning on this flag will cause
the terminal to report the :kbd:`Esc, alt+letter, ctrl+letter, ctrl+alt+letter`
keys using CSIu sequences instead of legacy ones. Here letter is any printable
keys using ``CSI u`` sequences instead of legacy ones. Here letter is any printable
ASCII letter (from 32 (i.e. space) to 126 (i.e. ~)).
Report event types
@ -227,121 +234,206 @@ This type of progressive enhancement causes the terminal to report alternate
key values in addition to the main value, to aid in shortcut matching. See
:ref:`key_codes` for details on how these are reported.
Legacy key event encoding
--------------------------------
In the default mode, the terminal uses a legacy encoding for key events. In
this encoding, only key press and repeat events are sent and there is no
way to distinguish between them. Text is sent directly as UTF-8 bytes.
Any key events not described in this section are sent using the standard
``CSI u`` encoding. This includes keys that are not encodeable in the legacy
encoding, thereby increasing the space of useable key combinations even without
progressive enhancement.
Legacy functional keys
~~~~~~~~~~~~~~~~~~~~~~~~
These keys are encoded using three schemes::
CSI number ; modifier ~
CSI 1 ; modifier {ABCDFHPQRS}
ESC O {ABCDFHPQRS}
In the above, if there are no modifiers, the modifier parameter is omitted.
The modifier value is encoded as described in the :ref:`modifiers` section,
above. When the second form is used, the number is always ``1`` and must be
omitted if the modifiers field is also absent. The third form becomes the
second form when modifiers are present.
These sequences must match entries in the terminfo database for maximum
compatibility. The table below lists the key, its terminfo entry name and
the escape code used for it by kitty. A different terminal would use whatever
escape code is present in its terminfo database for the key.
Some keys have an alternate representation when the terminal is in *cursor key
mode* (the ``smkx/rmkx`` terminfo capabilities). This form is used only in
*cursor key mode* and only when no modifiers are present.
.. csv-table:: Legacy functional encoding
:header: "Name", "Terminfo name", "Escape code"
"INSERT", "kich1", "CSI 2 ~"
"DELETE", "kdch1", "CSI 3 ~"
"PAGE_UP", "kpp", "CSI 5 ~"
"PAGE_DOWN", "knp", "CSI 6 ~"
"UP", "cuu1,kcuu1", "CSI A, ESC O A"
"DOWN", "cud1,kcud1", "CSI B, ESC O B"
"RIGHT", "cuf1,kcuf1", "CSI C, ESC O C"
"LEFT", "cub1,kcub1", "CSI D, ESC O D"
"HOME", "home,khome", "CSI H, ESC O H"
"END", "-,kend", "CSI F, ESC O F"
"F1", "kf1", "ESC O P"
"F2", "kf2", "ESC O Q"
"F3", "kf3", "ESC O R"
"F4", "kf4", "ESC O S"
"F5", "kf5", "CSI 15 ~"
"F6", "kf6", "CSI 17 ~"
"F7", "kf7", "CSI 18 ~"
"F8", "kf8", "CSI 19 ~"
"F9", "kf9", "CSI 20 ~"
"F10", "kf10", "CSI 21 ~"
"F11", "kf11", "CSI 23 ~"
"F12", "kf12", "CSI 24 ~"
Finally, there are a few more functional keys that have special cased legacy
encodings:
.. csv-table:: C0 controls
:header: "Key", "Encodings"
"Enter", "Plain - 0xd, alt+Enter - 0x1b 0x1d"
"Escape", "Plain - 0x1b, alt+Esc - 0x1b 0x1b"
"Backspace", "Plain - 0x7f, alt+Backspace - 0x1b 0x7f, ctrl+Backspace - 0x08"
"Space", "Plain - 0x20, ctrl+space - 0x0, alt+space - 0x1b 0x20"
"Tab", "Plain - 0x09, shift+tab - CSI Z"
Note that :kbd:`Backspace` and :kbd:`ctrl+backspace` are swapped in some
terminals.
Legacy text keys
~~~~~~~~~~~~~~~~~~~
.. _functional:
Functional key definitions
----------------------------
All numbers are in the Unicode Private Use Area (``57344 - 63743``) except
for a handful of keys that use numbers under 32 (C0 control codes) for legacy
compatibility reasons.
.. {{{
.. start functional key table (auto generated by gen-key-constants.py do not edit)
.. csv-table:: Functional key codes
:header: "Name", "Codepoint (base-16)"
:header: "Name", "CSI sequence"
"ESCAPE", "E000"
"ENTER", "E001"
"TAB", "E002"
"BACKSPACE", "E003"
"INSERT", "E004"
"DELETE", "E005"
"LEFT", "E006"
"RIGHT", "E007"
"UP", "E008"
"DOWN", "E009"
"PAGE_UP", "E00A"
"PAGE_DOWN", "E00B"
"HOME", "E00C"
"END", "E00D"
"CAPS_LOCK", "E00E"
"SCROLL_LOCK", "E00F"
"NUM_LOCK", "E010"
"PRINT_SCREEN", "E011"
"PAUSE", "E012"
"MENU", "E013"
"F1", "E014"
"F2", "E015"
"F3", "E016"
"F4", "E017"
"F5", "E018"
"F6", "E019"
"F7", "E01A"
"F8", "E01B"
"F9", "E01C"
"F10", "E01D"
"F11", "E01E"
"F12", "E01F"
"F13", "E020"
"F14", "E021"
"F15", "E022"
"F16", "E023"
"F17", "E024"
"F18", "E025"
"F19", "E026"
"F20", "E027"
"F21", "E028"
"F22", "E029"
"F23", "E02A"
"F24", "E02B"
"F25", "E02C"
"F26", "E02D"
"F27", "E02E"
"F28", "E02F"
"F29", "E030"
"F30", "E031"
"F31", "E032"
"F32", "E033"
"F33", "E034"
"F34", "E035"
"F35", "E036"
"KP_0", "E037"
"KP_1", "E038"
"KP_2", "E039"
"KP_3", "E03A"
"KP_4", "E03B"
"KP_5", "E03C"
"KP_6", "E03D"
"KP_7", "E03E"
"KP_8", "E03F"
"KP_9", "E040"
"KP_DECIMAL", "E041"
"KP_DIVIDE", "E042"
"KP_MULTIPLY", "E043"
"KP_SUBTRACT", "E044"
"KP_ADD", "E045"
"KP_ENTER", "E046"
"KP_EQUAL", "E047"
"KP_SEPARATOR", "E048"
"KP_LEFT", "E049"
"KP_RIGHT", "E04A"
"KP_UP", "E04B"
"KP_DOWN", "E04C"
"KP_PAGE_UP", "E04D"
"KP_PAGE_DOWN", "E04E"
"KP_HOME", "E04F"
"KP_END", "E050"
"KP_INSERT", "E051"
"KP_DELETE", "E052"
"LEFT_SHIFT", "E053"
"LEFT_CONTROL", "E054"
"LEFT_ALT", "E055"
"LEFT_SUPER", "E056"
"RIGHT_SHIFT", "E057"
"RIGHT_CONTROL", "E058"
"RIGHT_ALT", "E059"
"RIGHT_SUPER", "E05A"
"MEDIA_PLAY", "E05B"
"MEDIA_PAUSE", "E05C"
"MEDIA_PLAY_PAUSE", "E05D"
"MEDIA_REVERSE", "E05E"
"MEDIA_STOP", "E05F"
"MEDIA_FAST_FORWARD", "E060"
"MEDIA_REWIND", "E061"
"MEDIA_TRACK_NEXT", "E062"
"MEDIA_TRACK_PREVIOUS", "E063"
"MEDIA_RECORD", "E064"
"LOWER_VOLUME", "E065"
"RAISE_VOLUME", "E066"
"MUTE_VOLUME", "E067"
"ESCAPE", "CSI 57344 ... u"
"ENTER", "CSI 57345 ... u"
"TAB", "CSI 57346 ... u"
"BACKSPACE", "CSI 57347 ... u"
"INSERT", "CSI 2 ... ~"
"DELETE", "CSI 3 ... ~"
"LEFT", "CSI 1 ... D"
"RIGHT", "CSI 1 ... C"
"UP", "CSI 1 ... A"
"DOWN", "CSI 1 ... B"
"PAGE_UP", "CSI 5 ... ~"
"PAGE_DOWN", "CSI 6 ... ~"
"HOME", "CSI 1 ... H or CSI 7 ... ~"
"END", "CSI 1 ... F or CSI 8 ... ~"
"CAPS_LOCK", "CSI 57358 ... u"
"SCROLL_LOCK", "CSI 57359 ... u"
"NUM_LOCK", "CSI 57360 ... u"
"PRINT_SCREEN", "CSI 57361 ... u"
"PAUSE", "CSI 57362 ... u"
"MENU", "CSI 57363 ... u"
"F1", "CSI 1 ... P or CSI 11 ... ~"
"F2", "CSI 1 ... Q or CSI 12 ... ~"
"F3", "CSI 1 ... R or CSI 13 ... ~"
"F4", "CSI 1 ... S or CSI 14 ... ~"
"F5", "CSI 15 ... ~"
"F6", "CSI 17 ... ~"
"F7", "CSI 18 ... ~"
"F8", "CSI 19 ... ~"
"F9", "CSI 20 ... ~"
"F10", "CSI 21 ... ~"
"F11", "CSI 23 ... ~"
"F12", "CSI 24 ... ~"
"F13", "CSI 57376 ... u"
"F14", "CSI 57377 ... u"
"F15", "CSI 57378 ... u"
"F16", "CSI 57379 ... u"
"F17", "CSI 57380 ... u"
"F18", "CSI 57381 ... u"
"F19", "CSI 57382 ... u"
"F20", "CSI 57383 ... u"
"F21", "CSI 57384 ... u"
"F22", "CSI 57385 ... u"
"F23", "CSI 57386 ... u"
"F24", "CSI 57387 ... u"
"F25", "CSI 57388 ... u"
"F26", "CSI 57389 ... u"
"F27", "CSI 57390 ... u"
"F28", "CSI 57391 ... u"
"F29", "CSI 57392 ... u"
"F30", "CSI 57393 ... u"
"F31", "CSI 57394 ... u"
"F32", "CSI 57395 ... u"
"F33", "CSI 57396 ... u"
"F34", "CSI 57397 ... u"
"F35", "CSI 57398 ... u"
"KP_0", "CSI 57399 ... u"
"KP_1", "CSI 57400 ... u"
"KP_2", "CSI 57401 ... u"
"KP_3", "CSI 57402 ... u"
"KP_4", "CSI 57403 ... u"
"KP_5", "CSI 57404 ... u"
"KP_6", "CSI 57405 ... u"
"KP_7", "CSI 57406 ... u"
"KP_8", "CSI 57407 ... u"
"KP_9", "CSI 57408 ... u"
"KP_DECIMAL", "CSI 57409 ... u"
"KP_DIVIDE", "CSI 57410 ... u"
"KP_MULTIPLY", "CSI 57411 ... u"
"KP_SUBTRACT", "CSI 57412 ... u"
"KP_ADD", "CSI 57413 ... u"
"KP_ENTER", "CSI 57414 ... u"
"KP_EQUAL", "CSI 57415 ... u"
"KP_SEPARATOR", "CSI 57416 ... u"
"KP_LEFT", "CSI 57417 ... u"
"KP_RIGHT", "CSI 57418 ... u"
"KP_UP", "CSI 57419 ... u"
"KP_DOWN", "CSI 57420 ... u"
"KP_PAGE_UP", "CSI 57421 ... u"
"KP_PAGE_DOWN", "CSI 57422 ... u"
"KP_HOME", "CSI 57423 ... u"
"KP_END", "CSI 57424 ... u"
"KP_INSERT", "CSI 57425 ... u"
"KP_DELETE", "CSI 57426 ... u"
"LEFT_SHIFT", "CSI 57427 ... u"
"LEFT_CONTROL", "CSI 57428 ... u"
"LEFT_ALT", "CSI 57429 ... u"
"LEFT_SUPER", "CSI 57430 ... u"
"RIGHT_SHIFT", "CSI 57431 ... u"
"RIGHT_CONTROL", "CSI 57432 ... u"
"RIGHT_ALT", "CSI 57433 ... u"
"RIGHT_SUPER", "CSI 57434 ... u"
"MEDIA_PLAY", "CSI 57435 ... u"
"MEDIA_PAUSE", "CSI 57436 ... u"
"MEDIA_PLAY_PAUSE", "CSI 57437 ... u"
"MEDIA_REVERSE", "CSI 57438 ... u"
"MEDIA_STOP", "CSI 57439 ... u"
"MEDIA_FAST_FORWARD", "CSI 57440 ... u"
"MEDIA_REWIND", "CSI 57441 ... u"
"MEDIA_TRACK_NEXT", "CSI 57442 ... u"
"MEDIA_TRACK_PREVIOUS", "CSI 57443 ... u"
"MEDIA_RECORD", "CSI 57444 ... u"
"LOWER_VOLUME", "CSI 57445 ... u"
"RAISE_VOLUME", "CSI 57446 ... u"
"MUTE_VOLUME", "CSI 57447 ... u"
.. end functional key table
.. }}}

View File

@ -113,6 +113,16 @@ raise_volume XF86AudioRaiseVolume -
mute_volume XF86AudioMute -
''' # }}}
functional_encoding_overrides = {
'insert': 2, 'delete': 3, 'page_up': 5, 'page_down': 6,
'home': 7, 'end': 8, 'f1': 11, 'f2': 12, 'f3': 13, 'f4': 14,
'f5': 15, 'f6': 17, 'f7': 18, 'f8': 19, 'f9': 20, 'f10': 21,
'f11': 23, 'f12': 24
}
different_trailer_functionals = {
'up': 'A', 'down': 'B', 'right': 'C', 'left': 'D', 'end': 'F', 'home': 'H',
'f1': 'P', 'f2': 'Q', 'f3': 'R', 'f4': 'S'
}
functional_key_names: List[str] = []
name_to_code: Dict[str, int] = {}
name_to_xkb: Dict[str, str] = {}
@ -175,11 +185,20 @@ def generate_functional_table() -> None:
lines = [
'',
'.. csv-table:: Functional key codes',
' :header: "Name", "Codepoint (base-16)"',
' :header: "Name", "CSI sequence"',
''
]
for name, code in name_to_code.items():
lines.append(f' "{name.upper()}", "{code:X}"')
if name in functional_encoding_overrides or name in different_trailer_functionals:
code = oc = functional_encoding_overrides.get(name, code)
trailer = different_trailer_functionals.get(name, '~')
code = code if trailer == '~' else 1
if code == 1 and name not in ('up', 'down', 'left', 'right'):
trailer += f' or CSI {oc} ... ~'
else:
trailer = 'u'
name = f'"{name.upper()}",'.ljust(25)
lines.append(f' {name} "CSI {code} ... {trailer}"')
lines.append('')
patch_file('docs/keyboard-protocol.rst', 'functional key table', '\n'.join(lines), start_marker='.. ', end_marker='')

View File

@ -61,8 +61,9 @@ static inline int
serialize(const EncodingData *data, char *output, const char csi_trailer) {
int pos = 0;
#define P(fmt, ...) pos += snprintf(output + pos, KEY_BUFFER_SIZE - 2 - pos, fmt, __VA_ARGS__)
P("\x1b[%u", data->key);
if (data->add_alternates && (data->shifted_key || data->alternate_key)) {
P("\x1b%s", "[");
if (data->key != 1 || data->add_alternates || data->has_mods || data->add_actions) P("%u", data->key);
if (data->add_alternates) {
P("%s", ":");
if (data->shifted_key) P("%u", data->shifted_key);
if (data->alternate_key) P(":%u", data->alternate_key);
@ -92,10 +93,14 @@ encode_function_key(const KeyEvent *ev, char *output) {
switch(key_number) {
case GLFW_FKEY_UP: SIMPLE("\x1bOA");
case GLFW_FKEY_DOWN: SIMPLE("\x1bOB");
case GLFW_FKEY_LEFT: SIMPLE("\x1bOD");
case GLFW_FKEY_RIGHT: SIMPLE("\x1bOC");
case GLFW_FKEY_HOME: SIMPLE("\x1bOH");
case GLFW_FKEY_LEFT: SIMPLE("\x1bOD");
case GLFW_FKEY_END: SIMPLE("\x1bOF");
case GLFW_FKEY_HOME: SIMPLE("\x1bOH");
case GLFW_FKEY_F1: SIMPLE("\x1bOP");
case GLFW_FKEY_F2: SIMPLE("\x1bOQ");
case GLFW_FKEY_F3: SIMPLE("\x1bOR");
case GLFW_FKEY_F4: SIMPLE("\x1bOS");
default: break;
}
}
@ -103,7 +108,7 @@ encode_function_key(const KeyEvent *ev, char *output) {
switch(key_number) {
case GLFW_FKEY_ENTER: SIMPLE("\r");
case GLFW_FKEY_ESCAPE: {
if (ev->disambiguate) { return encode_csi_string('u', "27u", output); }
if (ev->disambiguate) { return encode_csi_string('u', "27", output); }
SIMPLE("\x1b");
}
case GLFW_FKEY_BACKSPACE: SIMPLE("\x7f");
@ -154,6 +159,7 @@ encode_function_key(const KeyEvent *ev, char *output) {
#undef S
EncodingData ed = {0};
init_encoding_data(&ed, ev);
ed.key = key_number;
ed.add_alternates = false;
return serialize(&ed, output, csi_trailer);
}