diff options
author | erw7 <erw7.github@gmail.com> | 2021-11-24 02:05:35 +0900 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2022-07-04 21:09:33 +0800 |
commit | 33ed85a2f62d2b8dbac131cb61d03ac601808342 (patch) | |
tree | e8926b05923c8245ab0a1c3f832723c61adce91a | |
parent | ab5929e1b0f13b8750c8a97d41396ac9a0769e18 (diff) | |
download | rneovim-33ed85a2f62d2b8dbac131cb61d03ac601808342.tar.gz rneovim-33ed85a2f62d2b8dbac131cb61d03ac601808342.tar.bz2 rneovim-33ed85a2f62d2b8dbac131cb61d03ac601808342.zip |
feat(tui): recognize keypad keys when using kitty keyboard protocol
-rw-r--r-- | src/nvim/getchar.c | 4 | ||||
-rw-r--r-- | src/nvim/map.c | 5 | ||||
-rw-r--r-- | src/nvim/map.h | 4 | ||||
-rw-r--r-- | src/nvim/tui/input.c | 163 | ||||
-rw-r--r-- | src/nvim/tui/input.h | 1 | ||||
-rw-r--r-- | src/nvim/tui/input_defs.h | 118 |
6 files changed, 276 insertions, 19 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index c3dbb02dce..0f6eddef9d 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1545,12 +1545,16 @@ int vgetc(void) } break; + case K_KUP: case K_XUP: c = K_UP; break; + case K_KDOWN: case K_XDOWN: c = K_DOWN; break; + case K_KLEFT: case K_XLEFT: c = K_LEFT; break; + case K_KRIGHT: case K_XRIGHT: c = K_RIGHT; break; } diff --git a/src/nvim/map.c b/src/nvim/map.c index d27e40b4ee..d3058a5d52 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -30,6 +30,8 @@ #define int_eq kh_int_hash_equal #define handle_T_hash kh_int_hash_func #define handle_T_eq kh_int_hash_equal +#define KittyKey_hash kh_int_hash_func +#define KittyKey_eq kh_int_hash_equal #if defined(ARCH_64) # define ptr_t_hash(key) uint64_t_hash((uint64_t)(key)) @@ -162,6 +164,7 @@ static inline bool ColorKey_eq(ColorKey ae1, ColorKey ae2) } MAP_IMPL(int, int, DEFAULT_INITIALIZER) +MAP_IMPL(int, cstr_t, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER) MAP_IMPL(cstr_t, int, DEFAULT_INITIALIZER) MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER) @@ -177,6 +180,8 @@ MAP_IMPL(int, String, DEFAULT_INITIALIZER) MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER) +MAP_IMPL(KittyKey, cstr_t, DEFAULT_INITIALIZER) + /// Deletes a key:value pair from a string:pointer map, and frees the /// storage of both key and value. /// diff --git a/src/nvim/map.h b/src/nvim/map.h index 4f4aaa3552..845daac3f7 100644 --- a/src/nvim/map.h +++ b/src/nvim/map.h @@ -7,6 +7,7 @@ #include "nvim/extmark_defs.h" #include "nvim/highlight_defs.h" #include "nvim/map_defs.h" +#include "nvim/tui/input_defs.h" #include "nvim/ui_client.h" #if defined(__NetBSD__) @@ -34,6 +35,7 @@ // NOTE: Keys AND values must be allocated! khash.h does not make a copy. // MAP_DECLS(int, int) +MAP_DECLS(int, cstr_t) MAP_DECLS(cstr_t, ptr_t) MAP_DECLS(cstr_t, int) MAP_DECLS(ptr_t, ptr_t) @@ -50,6 +52,8 @@ MAP_DECLS(int, String) MAP_DECLS(ColorKey, ColorItem) +MAP_DECLS(KittyKey, cstr_t) + #define MAP_INIT { { 0, 0, 0, 0, NULL, NULL, NULL } } #define map_init(k, v, map) do { *(map) = (Map(k, v)) MAP_INIT; } while (false) diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 3e24e892b8..61a59bcf06 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -23,6 +23,91 @@ #define KEY_BUFFER_SIZE 0xfff +static const struct kitty_key_map_entry { + KittyKey key; + const char *name; +} kitty_key_map_entry[] = { + { KITTY_KEY_ESCAPE, "Esc" }, + { KITTY_KEY_ENTER, "CR" }, + { KITTY_KEY_TAB, "Tab" }, + { KITTY_KEY_BACKSPACE, "BS" }, + { KITTY_KEY_INSERT, "Insert" }, + { KITTY_KEY_DELETE, "Del" }, + { KITTY_KEY_LEFT, "Left" }, + { KITTY_KEY_RIGHT, "Right" }, + { KITTY_KEY_UP, "Up" }, + { KITTY_KEY_DOWN, "Down" }, + { KITTY_KEY_PAGE_UP, "PageUp" }, + { KITTY_KEY_PAGE_DOWN, "PageDown" }, + { KITTY_KEY_HOME, "Home" }, + { KITTY_KEY_END, "End" }, + { KITTY_KEY_F1, "F1" }, + { KITTY_KEY_F2, "F2" }, + { KITTY_KEY_F3, "F3" }, + { KITTY_KEY_F4, "F4" }, + { KITTY_KEY_F5, "F5" }, + { KITTY_KEY_F6, "F6" }, + { KITTY_KEY_F7, "F7" }, + { KITTY_KEY_F8, "F8" }, + { KITTY_KEY_F9, "F9" }, + { KITTY_KEY_F10, "F10" }, + { KITTY_KEY_F11, "F11" }, + { KITTY_KEY_F12, "F12" }, + { KITTY_KEY_F13, "F13" }, + { KITTY_KEY_F14, "F14" }, + { KITTY_KEY_F15, "F15" }, + { KITTY_KEY_F16, "F16" }, + { KITTY_KEY_F17, "F17" }, + { KITTY_KEY_F18, "F18" }, + { KITTY_KEY_F19, "F19" }, + { KITTY_KEY_F20, "F20" }, + { KITTY_KEY_F21, "F21" }, + { KITTY_KEY_F22, "F22" }, + { KITTY_KEY_F23, "F23" }, + { KITTY_KEY_F24, "F24" }, + { KITTY_KEY_F25, "F25" }, + { KITTY_KEY_F26, "F26" }, + { KITTY_KEY_F27, "F27" }, + { KITTY_KEY_F28, "F28" }, + { KITTY_KEY_F29, "F29" }, + { KITTY_KEY_F30, "F30" }, + { KITTY_KEY_F31, "F31" }, + { KITTY_KEY_F32, "F32" }, + { KITTY_KEY_F33, "F33" }, + { KITTY_KEY_F34, "F34" }, + { KITTY_KEY_F35, "F35" }, + { KITTY_KEY_KP_0, "k0" }, + { KITTY_KEY_KP_1, "k1" }, + { KITTY_KEY_KP_2, "k2" }, + { KITTY_KEY_KP_3, "k3" }, + { KITTY_KEY_KP_4, "k4" }, + { KITTY_KEY_KP_5, "k5" }, + { KITTY_KEY_KP_6, "k6" }, + { KITTY_KEY_KP_7, "k7" }, + { KITTY_KEY_KP_8, "k8" }, + { KITTY_KEY_KP_9, "k9" }, + { KITTY_KEY_KP_DECIMAL, "kPoint" }, + { KITTY_KEY_KP_DIVIDE, "kDivide" }, + { KITTY_KEY_KP_MULTIPLY, "kMultiply" }, + { KITTY_KEY_KP_SUBTRACT, "kMinus" }, + { KITTY_KEY_KP_ADD, "kPlus" }, + { KITTY_KEY_KP_ENTER, "kEnter" }, + { KITTY_KEY_KP_EQUAL, "kEqual" }, + { KITTY_KEY_KP_LEFT, "kLeft" }, + { KITTY_KEY_KP_RIGHT, "kRight" }, + { KITTY_KEY_KP_UP, "kUp" }, + { KITTY_KEY_KP_DOWN, "kDown" }, + { KITTY_KEY_KP_PAGE_UP, "kPageUp" }, + { KITTY_KEY_KP_PAGE_DOWN, "kPageDown" }, + { KITTY_KEY_KP_HOME, "kHome" }, + { KITTY_KEY_KP_END, "kEnd" }, + { KITTY_KEY_KP_INSERT, "kInsert" }, + { KITTY_KEY_KP_DELETE, "kDel" }, + { KITTY_KEY_KP_BEGIN, "kOrigin" }, +}; + +static Map(KittyKey, cstr_t) kitty_key_map = MAP_INIT; + #ifndef UNIT_TESTING typedef enum { kIncomplete = -1, @@ -50,6 +135,11 @@ void tinput_init(TermInput *input, Loop *loop) uv_mutex_init(&input->key_buffer_mutex); uv_cond_init(&input->key_buffer_cond); + for (size_t i = 0; i < ARRAY_SIZE(kitty_key_map_entry); i++) { + map_put(KittyKey, cstr_t)(&kitty_key_map, kitty_key_map_entry[i].key, + kitty_key_map_entry[i].name); + } + // If stdin is not a pty, switch to stderr. For cases like: // echo q | nvim -es // ls *.md | xargs nvim @@ -89,6 +179,7 @@ void tinput_init(TermInput *input, Loop *loop) void tinput_destroy(TermInput *input) { + map_destroy(KittyKey, cstr_t)(&kitty_key_map); rbuffer_free(input->key_buffer); uv_mutex_destroy(&input->key_buffer_mutex); uv_cond_destroy(&input->key_buffer_cond); @@ -206,19 +297,46 @@ static void tinput_enqueue(TermInput *input, char *buf, size_t size) rbuffer_write(input->key_buffer, buf, size); } +static void handle_kitty_key_protocol(TermInput *input, TermKeyKey *key) +{ + const char *name = map_get(KittyKey, cstr_t)(&kitty_key_map, (KittyKey)key->code.codepoint); + if (name) { + char buf[64]; + size_t len = 0; + buf[len++] = '<'; + if (key->modifiers & TERMKEY_KEYMOD_SHIFT) { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "S-"); + } + if (key->modifiers & TERMKEY_KEYMOD_ALT) { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "A-"); + } + if (key->modifiers & TERMKEY_KEYMOD_CTRL) { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "C-"); + } + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "%s>", name); + tinput_enqueue(input, buf, len); + } +} + static void forward_simple_utf8(TermInput *input, TermKeyKey *key) { size_t len = 0; char buf[64]; char *ptr = key->utf8; - while (*ptr) { - if (*ptr == '<') { - len += (size_t)snprintf(buf + len, sizeof(buf) - len, "<lt>"); - } else { - buf[len++] = *ptr; + if (key->code.codepoint >= 0xE000 && key->code.codepoint <= 0xF8FF + && map_has(KittyKey, cstr_t)(&kitty_key_map, (KittyKey)key->code.codepoint)) { + handle_kitty_key_protocol(input, key); + return; + } else { + while (*ptr) { + if (*ptr == '<') { + len += (size_t)snprintf(buf + len, sizeof(buf) - len, "<lt>"); + } else { + buf[len++] = *ptr; + } + ptr++; } - ptr++; } tinput_enqueue(input, buf, len); @@ -236,19 +354,26 @@ static void forward_modified_utf8(TermInput *input, TermKeyKey *key) len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM); } else { assert(key->modifiers); - // Termkey doesn't include the S- modifier for ASCII characters (e.g., - // ctrl-shift-l is <C-L> instead of <C-S-L>. Vim, on the other hand, - // treats <C-L> and <C-l> the same, requiring the S- modifier. - len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM); - if ((key->modifiers & TERMKEY_KEYMOD_CTRL) - && !(key->modifiers & TERMKEY_KEYMOD_SHIFT) - && ASCII_ISUPPER(key->code.codepoint)) { - assert(len <= 62); - // Make room for the S- - memmove(buf + 3, buf + 1, len - 1); - buf[1] = 'S'; - buf[2] = '-'; - len += 2; + if (key->code.codepoint >= 0xE000 && key->code.codepoint <= 0xF8FF + && map_has(KittyKey, cstr_t)(&kitty_key_map, + (KittyKey)key->code.codepoint)) { + handle_kitty_key_protocol(input, key); + return; + } else { + // Termkey doesn't include the S- modifier for ASCII characters (e.g., + // ctrl-shift-l is <C-L> instead of <C-S-L>. Vim, on the other hand, + // treats <C-L> and <C-l> the same, requiring the S- modifier. + len = termkey_strfkey(input->tk, buf, sizeof(buf), key, TERMKEY_FORMAT_VIM); + if ((key->modifiers & TERMKEY_KEYMOD_CTRL) + && !(key->modifiers & TERMKEY_KEYMOD_SHIFT) + && ASCII_ISUPPER(key->code.codepoint)) { + assert(len <= 62); + // Make room for the S- + memmove(buf + 3, buf + 1, len - 1); + buf[1] = 'S'; + buf[2] = '-'; + len += 2; + } } } diff --git a/src/nvim/tui/input.h b/src/nvim/tui/input.h index 84daf40744..51df57938c 100644 --- a/src/nvim/tui/input.h +++ b/src/nvim/tui/input.h @@ -6,6 +6,7 @@ #include "nvim/event/stream.h" #include "nvim/event/time.h" +#include "nvim/tui/input_defs.h" #include "nvim/tui/tui.h" typedef enum { diff --git a/src/nvim/tui/input_defs.h b/src/nvim/tui/input_defs.h new file mode 100644 index 0000000000..846cf45350 --- /dev/null +++ b/src/nvim/tui/input_defs.h @@ -0,0 +1,118 @@ +#ifndef NVIM_TUI_INPUT_DEFS_H +#define NVIM_TUI_INPUT_DEFS_H + +typedef enum { + KITTY_KEY_ESCAPE = 57344, + KITTY_KEY_ENTER = 57345, + KITTY_KEY_TAB = 57346, + KITTY_KEY_BACKSPACE = 57347, + KITTY_KEY_INSERT = 57348, + KITTY_KEY_DELETE = 57349, + KITTY_KEY_LEFT = 57350, + KITTY_KEY_RIGHT = 57351, + KITTY_KEY_UP = 57352, + KITTY_KEY_DOWN = 57353, + KITTY_KEY_PAGE_UP = 57354, + KITTY_KEY_PAGE_DOWN = 57355, + KITTY_KEY_HOME = 57356, + KITTY_KEY_END = 57357, + KITTY_KEY_CAPS_LOCK = 57358, + KITTY_KEY_SCROLL_LOCK = 57359, + KITTY_KEY_NUM_LOCK = 57360, + KITTY_KEY_PRINT_SCREEN = 57361, + KITTY_KEY_PAUSE = 57362, + KITTY_KEY_MENU = 57363, + KITTY_KEY_F1 = 57364, + KITTY_KEY_F2 = 57365, + KITTY_KEY_F3 = 57366, + KITTY_KEY_F4 = 57367, + KITTY_KEY_F5 = 57368, + KITTY_KEY_F6 = 57369, + KITTY_KEY_F7 = 57370, + KITTY_KEY_F8 = 57371, + KITTY_KEY_F9 = 57372, + KITTY_KEY_F10 = 57373, + KITTY_KEY_F11 = 57374, + KITTY_KEY_F12 = 57375, + KITTY_KEY_F13 = 57376, + KITTY_KEY_F14 = 57377, + KITTY_KEY_F15 = 57378, + KITTY_KEY_F16 = 57379, + KITTY_KEY_F17 = 57380, + KITTY_KEY_F18 = 57381, + KITTY_KEY_F19 = 57382, + KITTY_KEY_F20 = 57383, + KITTY_KEY_F21 = 57384, + KITTY_KEY_F22 = 57385, + KITTY_KEY_F23 = 57386, + KITTY_KEY_F24 = 57387, + KITTY_KEY_F25 = 57388, + KITTY_KEY_F26 = 57389, + KITTY_KEY_F27 = 57390, + KITTY_KEY_F28 = 57391, + KITTY_KEY_F29 = 57392, + KITTY_KEY_F30 = 57393, + KITTY_KEY_F31 = 57394, + KITTY_KEY_F32 = 57395, + KITTY_KEY_F33 = 57396, + KITTY_KEY_F34 = 57397, + KITTY_KEY_F35 = 57398, + KITTY_KEY_KP_0 = 57399, + KITTY_KEY_KP_1 = 57400, + KITTY_KEY_KP_2 = 57401, + KITTY_KEY_KP_3 = 57402, + KITTY_KEY_KP_4 = 57403, + KITTY_KEY_KP_5 = 57404, + KITTY_KEY_KP_6 = 57405, + KITTY_KEY_KP_7 = 57406, + KITTY_KEY_KP_8 = 57407, + KITTY_KEY_KP_9 = 57408, + KITTY_KEY_KP_DECIMAL = 57409, + KITTY_KEY_KP_DIVIDE = 57410, + KITTY_KEY_KP_MULTIPLY = 57411, + KITTY_KEY_KP_SUBTRACT = 57412, + KITTY_KEY_KP_ADD = 57413, + KITTY_KEY_KP_ENTER = 57414, + KITTY_KEY_KP_EQUAL = 57415, + KITTY_KEY_KP_SEPARATOR = 57416, + KITTY_KEY_KP_LEFT = 57417, + KITTY_KEY_KP_RIGHT = 57418, + KITTY_KEY_KP_UP = 57419, + KITTY_KEY_KP_DOWN = 57420, + KITTY_KEY_KP_PAGE_UP = 57421, + KITTY_KEY_KP_PAGE_DOWN = 57422, + KITTY_KEY_KP_HOME = 57423, + KITTY_KEY_KP_END = 57424, + KITTY_KEY_KP_INSERT = 57425, + KITTY_KEY_KP_DELETE = 57426, + KITTY_KEY_KP_BEGIN = 57427, + KITTY_KEY_MEDIA_PLAY = 57428, + KITTY_KEY_MEDIA_PAUSE = 57429, + KITTY_KEY_MEDIA_PLAY_PAUSE = 57430, + KITTY_KEY_MEDIA_REVERSE = 57431, + KITTY_KEY_MEDIA_STOP = 57432, + KITTY_KEY_MEDIA_FAST_FORWARD = 57433, + KITTY_KEY_MEDIA_REWIND = 57434, + KITTY_KEY_MEDIA_TRACK_NEXT = 57435, + KITTY_KEY_MEDIA_TRACK_PREVIOUS = 57436, + KITTY_KEY_MEDIA_RECORD = 57437, + KITTY_KEY_LOWER_VOLUME = 57438, + KITTY_KEY_RAISE_VOLUME = 57439, + KITTY_KEY_MUTE_VOLUME = 57440, + KITTY_KEY_LEFT_SHIFT = 57441, + KITTY_KEY_LEFT_CONTROL = 57442, + KITTY_KEY_LEFT_ALT = 57443, + KITTY_KEY_LEFT_SUPER = 57444, + KITTY_KEY_LEFT_HYPER = 57445, + KITTY_KEY_LEFT_META = 57446, + KITTY_KEY_RIGHT_SHIFT = 57447, + KITTY_KEY_RIGHT_CONTROL = 57448, + KITTY_KEY_RIGHT_ALT = 57449, + KITTY_KEY_RIGHT_SUPER = 57450, + KITTY_KEY_RIGHT_HYPER = 57451, + KITTY_KEY_RIGHT_META = 57452, + KITTY_KEY_ISO_LEVEL3_SHIFT = 57453, + KITTY_KEY_ISO_LEVEL5_SHIFT = 57454, +} KittyKey; + +#endif // NVIM_TUI_INPUT_DEFS_H |