diff --git a/docs/keyboard-protocol.rst b/docs/keyboard-protocol.rst
index 3b2fc7950..a742f24db 100644
--- a/docs/keyboard-protocol.rst
+++ b/docs/keyboard-protocol.rst
@@ -19,26 +19,8 @@ To solve these issues and others, kitty has created a new keyboard protocol,
that is backward compatible but allows applications to opt-in to support more
advanced usages. The protocol is based on initial work in `fixterms
`_, however, it corrects various
-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
- * No way to specify both shifted and unshifted keys for robust shortcut
- matching (think matching :kbd:`ctrl+shift+equal` and :kbd:`ctrl+plus`)
- * No way to specify alternate layout key. This is useful for keyboard layouts
- such as Cyrillic where you want the shortcut :kbd:`ctrl+c` to work when
- pressing the :kbd:`ctrl+ц` on the keyboard.
- * No way to report repeat and release key events, only key press events
- * No way to report key events without text, useful for gaming. Think of using
- the :kbd:`WASD` keys to control movement.
- * A very small subset of all possible functional keys are specified.
-
+issues in that proposal, listed at the :ref:`bottom of this document
+`.
A basic overview
------------------
@@ -321,7 +303,7 @@ 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
+for a handful of keys that use numbers under 32 and 127 (C0 control codes) for legacy
compatibility reasons.
.. {{{
@@ -331,9 +313,9 @@ compatibility reasons.
:header: "Name", "CSI sequence"
"ESCAPE", "CSI 57344 ... u"
- "ENTER", "CSI 57345 ... u"
- "TAB", "CSI 57346 ... u"
- "BACKSPACE", "CSI 57347 ... u"
+ "ENTER", "CSI 13 ... u"
+ "TAB", "CSI 9 ... u"
+ "BACKSPACE", "CSI 127 ... u"
"INSERT", "CSI 2 ... ~"
"DELETE", "CSI 3 ... ~"
"LEFT", "CSI 1 ... D"
@@ -352,7 +334,7 @@ compatibility reasons.
"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 ... ~"
+ "F3", "CSI 1 ... R or CSI 57366 ... ~"
"F4", "CSI 1 ... S or CSI 14 ... ~"
"F5", "CSI 15 ... ~"
"F6", "CSI 17 ... ~"
@@ -437,3 +419,28 @@ compatibility reasons.
.. end functional key table
.. }}}
+
+.. _fixterms_bugs:
+
+Bugs in fixterms
+-------------------
+
+ * 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``.
+ * ``Enter`` and ``F3`` are both assigned the number 13.
+ * Makes no mention of cursor key mode and how it changes encodings
+ * Incorrectly encoding shifted keys when shift modifier is used, for
+ instance, for :kbd:`ctrl+shift+I`.
+ * No way to have non-conflicting escape codes for :kbd:`alt+letter,
+ ctrl+letter, ctrl+alt+letter` key presses
+ * No way to specify both shifted and unshifted keys for robust shortcut
+ matching (think matching :kbd:`ctrl+shift+equal` and :kbd:`ctrl+plus`)
+ * No way to specify alternate layout key. This is useful for keyboard layouts
+ such as Cyrillic where you want the shortcut :kbd:`ctrl+c` to work when
+ pressing the :kbd:`ctrl+ц` on the keyboard.
+ * No way to report repeat and release key events, only key press events
+ * No way to report key events for presses that generate text, useful for
+ gaming. Think of using the :kbd:`WASD` keys to control movement.
+ * Only a small subset of all possible functional keys are assigned numbers.
diff --git a/gen-key-constants.py b/gen-key-constants.py
index b943eff6e..feec53a3e 100644
--- a/gen-key-constants.py
+++ b/gen-key-constants.py
@@ -115,13 +115,14 @@ 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,
+ 'home': 7, 'end': 8, 'tab': 9, 'f1': 11, 'f2': 12, 'enter': 13, 'f4': 14,
'f5': 15, 'f6': 17, 'f7': 18, 'f8': 19, 'f9': 20, 'f10': 21,
- 'f11': 23, 'f12': 24
+ 'f11': 23, 'f12': 24, 'backspace': 127
}
different_trailer_functionals = {
'up': 'A', 'down': 'B', 'right': 'C', 'left': 'D', 'end': 'F', 'home': 'H',
- 'f1': 'P', 'f2': 'Q', 'f3': 'R', 'f4': 'S'
+ 'f1': 'P', 'f2': 'Q', 'f3': 'R', 'f4': 'S', 'enter': 'u', 'tab': 'u',
+ 'backspace': 'u'
}
functional_key_names: List[str] = []
name_to_code: Dict[str, int] = {}
@@ -188,11 +189,13 @@ def generate_functional_table() -> None:
' :header: "Name", "CSI sequence"',
''
]
+ enc_lines = []
for name, code in name_to_code.items():
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
+ code = code if trailer in '~u' else 1
+ enc_lines.append((' ' * 8) + f"case GLFW_FKEY_{name.upper()}: S({code}, '{trailer}');")
if code == 1 and name not in ('up', 'down', 'left', 'right'):
trailer += f' or CSI {oc} ... ~'
else:
@@ -201,6 +204,7 @@ def generate_functional_table() -> None:
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='')
+ patch_file('kitty/key_encoding.c', 'special numbers', '\n'.join(enc_lines))
def main() -> None:
diff --git a/kitty/key_encoding.c b/kitty/key_encoding.c
index 9d00e5b9c..ab29a06e1 100644
--- a/kitty/key_encoding.c
+++ b/kitty/key_encoding.c
@@ -132,20 +132,24 @@ encode_function_key(const KeyEvent *ev, char *output) {
#define S(number, trailer) key_number = number; csi_trailer = trailer; break
switch(key_number) {
+ /* start special numbers (auto generated by gen-key-constants.py do not edit) */
+ case GLFW_FKEY_ENTER: S(13, 'u');
+ case GLFW_FKEY_TAB: S(9, 'u');
+ case GLFW_FKEY_BACKSPACE: S(127, 'u');
+ case GLFW_FKEY_INSERT: S(2, '~');
+ case GLFW_FKEY_DELETE: S(3, '~');
+ case GLFW_FKEY_LEFT: S(1, 'D');
+ case GLFW_FKEY_RIGHT: S(1, 'C');
case GLFW_FKEY_UP: S(1, 'A');
case GLFW_FKEY_DOWN: S(1, 'B');
- case GLFW_FKEY_LEFT: S(1, 'C');
- case GLFW_FKEY_RIGHT: S(1, 'D');
+ case GLFW_FKEY_PAGE_UP: S(5, '~');
+ case GLFW_FKEY_PAGE_DOWN: S(6, '~');
case GLFW_FKEY_HOME: S(1, 'H');
case GLFW_FKEY_END: S(1, 'F');
case GLFW_FKEY_F1: S(1, 'P');
case GLFW_FKEY_F2: S(1, 'Q');
case GLFW_FKEY_F3: S(1, 'R');
case GLFW_FKEY_F4: S(1, 'S');
- case GLFW_FKEY_INSERT: S(2, '~');
- case GLFW_FKEY_DELETE: S(3, '~');
- case GLFW_FKEY_PAGE_UP: S(5, '~');
- case GLFW_FKEY_PAGE_DOWN: S(6, '~');
case GLFW_FKEY_F5: S(15, '~');
case GLFW_FKEY_F6: S(17, '~');
case GLFW_FKEY_F7: S(18, '~');
@@ -154,6 +158,7 @@ encode_function_key(const KeyEvent *ev, char *output) {
case GLFW_FKEY_F10: S(21, '~');
case GLFW_FKEY_F11: S(23, '~');
case GLFW_FKEY_F12: S(24, '~');
+/* end special numbers */
default: break;
}
#undef S
diff --git a/kitty_tests/keys.py b/kitty_tests/keys.py
index c0c3d24cc..bc654817e 100644
--- a/kitty_tests/keys.py
+++ b/kitty_tests/keys.py
@@ -8,6 +8,9 @@ from . import BaseTest
class TestKeys(BaseTest):
+ def test_encode_key_event(self):
+ pass
+
def test_encode_mouse_event(self):
NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL = range(4)
L, M, R = 1, 2, 3