diff --git a/docs/keyboard-protocol.rst b/docs/keyboard-protocol.rst index b5666bb48..d1ca90272 100644 --- a/docs/keyboard-protocol.rst +++ b/docs/keyboard-protocol.rst @@ -188,6 +188,8 @@ and alternate screens. If a pop request is received that empties the stack, all flags are reset. If a push request is received and the stack is full, the oldest entry from the stack must be evicted. +.. _disambiguate: + Disambiguate escape codes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -198,7 +200,9 @@ 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 ``CSI u`` sequences instead of legacy ones. Here letter is any printable -ASCII letter (from 32 (i.e. space) to 126 (i.e. ~)). +ASCII letter (from 32 (i.e. space) to 126 (i.e. ~)). Additionally, all keypad +keys will be reported as separate keys with ``CSI u`` encoding, using dedicated codes +from the :ref:`table below `. Report event types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -277,7 +281,7 @@ mode* (the ``smkx/rmkx`` terminfo capabilities). This form is used only in "F11", "kf11", "CSI 23 ~" "F12", "kf12", "CSI 24 ~" -Finally, there are a few more functional keys that have special cased legacy +There are a few more functional keys that have special cased legacy encodings: .. csv-table:: C0 controls @@ -292,6 +296,9 @@ encodings: Note that :kbd:`Backspace` and :kbd:`ctrl+backspace` are swapped in some terminals. +All keypad keys are reported as there equivalent non-keypad keys. To +distinguish these, use the :ref:`disambiguate ` flag. + Legacy text keys ~~~~~~~~~~~~~~~~~~~ diff --git a/kitty/key_encoding.c b/kitty/key_encoding.c index 87523faf9..9180ded9b 100644 --- a/kitty/key_encoding.c +++ b/kitty/key_encoding.c @@ -78,16 +78,30 @@ serialize(const EncodingData *data, char *output, const char csi_trailer) { return pos; } +static inline uint32_t +convert_kp_key_to_normal_key(uint32_t key_number) { + switch(key_number) { +#define S(x) case GLFW_FKEY_KP_##x: key_number = GLFW_FKEY_##x; break; + S(ENTER) S(HOME) S(END) S(INSERT) S(DELETE) S(PAGE_UP) S(PAGE_DOWN) + S(UP) S(DOWN) S(LEFT) S(RIGHT) +#undef S + case GLFW_FKEY_KP_0: + case GLFW_FKEY_KP_9: key_number = '0' + (key_number - GLFW_FKEY_KP_0); break; + case GLFW_FKEY_KP_DECIMAL: key_number = '.'; break; + case GLFW_FKEY_KP_DIVIDE: key_number = '/'; break; + case GLFW_FKEY_KP_MULTIPLY: key_number = '*'; break; + case GLFW_FKEY_KP_SUBTRACT: key_number = '-'; break; + case GLFW_FKEY_KP_ADD: key_number = '+'; break; + case GLFW_FKEY_KP_EQUAL: key_number = '='; break; + } + return key_number; +} + static int encode_function_key(const KeyEvent *ev, char *output) { #define SIMPLE(val) return snprintf(output, KEY_BUFFER_SIZE, "%s", val); char csi_trailer = 'u'; uint32_t key_number = ev->key; - switch(key_number) { -#define S(x) case GLFW_FKEY_KP_##x: key_number = GLFW_FKEY_##x; break; - S(ENTER) S(HOME) S(END) S(INSERT) S(DELETE) S(PAGE_UP) S(PAGE_DOWN) -#undef S - } if (ev->cursor_key_mode && !ev->disambiguate && !ev->report_all_event_types) { switch(key_number) { @@ -222,6 +236,9 @@ encode_glfw_key_event(const GLFWkeyevent *e, const bool cursor_key_mode, const u .report_alternate_key = key_encoding_flags & 4 }; ev.has_text = e->text && !is_ascii_control_char(e->text[0]); + if (!ev.disambiguate && GLFW_FKEY_KP_0 <= ev.key && ev.key <= GLFW_FKEY_KP_DELETE) { + ev.key = convert_kp_key_to_normal_key(ev.key); + } switch (e->action) { case GLFW_PRESS: ev.action = PRESS; break; case GLFW_REPEAT: ev.action = REPEAT; break; diff --git a/kitty_tests/keys.py b/kitty_tests/keys.py index 2d01d10b6..a9f7a12f4 100644 --- a/kitty_tests/keys.py +++ b/kitty_tests/keys.py @@ -46,15 +46,21 @@ class TestKeys(BaseTest): a(e(mods=defines.GLFW_MOD_SHIFT | defines.GLFW_MOD_ALT), ashift or c(defines.GLFW_MOD_ALT | defines.GLFW_MOD_SHIFT)) mods_test(defines.GLFW_FKEY_ENTER, '\x0d', alt='\033\x0d', csi_num=ord('\r')) + mods_test(defines.GLFW_FKEY_KP_ENTER, '\x0d', alt='\033\x0d', csi_num=ord('\r')) mods_test(defines.GLFW_FKEY_ESCAPE, '\x1b', alt='\033\033', csi_num=27) mods_test(defines.GLFW_FKEY_BACKSPACE, '\x7f', alt='\033\x7f', csi_num=127) mods_test(defines.GLFW_FKEY_TAB, '\t', alt='\033\t', shift='\x1b[Z', csi_num=ord('\t')) mods_test(defines.GLFW_FKEY_INSERT, csi_num=2, trailer='~') + mods_test(defines.GLFW_FKEY_KP_INSERT, csi_num=2, trailer='~') mods_test(defines.GLFW_FKEY_DELETE, csi_num=3, trailer='~') + mods_test(defines.GLFW_FKEY_KP_DELETE, csi_num=3, trailer='~') mods_test(defines.GLFW_FKEY_PAGE_UP, csi_num=5, trailer='~') - mods_test(defines.GLFW_FKEY_PAGE_DOWN, csi_num=6, trailer='~') + mods_test(defines.GLFW_FKEY_KP_PAGE_UP, csi_num=5, trailer='~') + mods_test(defines.GLFW_FKEY_KP_PAGE_DOWN, csi_num=6, trailer='~') mods_test(defines.GLFW_FKEY_HOME, csi_num=1, trailer='H') + mods_test(defines.GLFW_FKEY_KP_HOME, csi_num=1, trailer='H') mods_test(defines.GLFW_FKEY_END, csi_num=1, trailer='F') + mods_test(defines.GLFW_FKEY_KP_END, csi_num=1, trailer='F') mods_test(defines.GLFW_FKEY_F1, csi_num=1, trailer='P') mods_test(defines.GLFW_FKEY_F2, csi_num=1, trailer='Q') mods_test(defines.GLFW_FKEY_F3, csi_num=1, trailer='R') @@ -68,9 +74,13 @@ class TestKeys(BaseTest): mods_test(defines.GLFW_FKEY_F11, csi_num=23, trailer='~') mods_test(defines.GLFW_FKEY_F12, csi_num=24, trailer='~') mods_test(defines.GLFW_FKEY_UP, csi_num=1, trailer='A') + mods_test(defines.GLFW_FKEY_KP_UP, csi_num=1, trailer='A') mods_test(defines.GLFW_FKEY_DOWN, csi_num=1, trailer='B') + mods_test(defines.GLFW_FKEY_KP_DOWN, csi_num=1, trailer='B') mods_test(defines.GLFW_FKEY_RIGHT, csi_num=1, trailer='C') + mods_test(defines.GLFW_FKEY_KP_RIGHT, csi_num=1, trailer='C') mods_test(defines.GLFW_FKEY_LEFT, csi_num=1, trailer='D') + mods_test(defines.GLFW_FKEY_KP_LEFT, csi_num=1, trailer='D') q = partial(enc, key=ord('a')) ae(q(), 'a')