diff options
Diffstat (limited to 'src/nvim/tui/input.c')
-rw-r--r-- | src/nvim/tui/input.c | 163 |
1 files changed, 144 insertions, 19 deletions
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; + } } } |