neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit 4fb3b57a19cb83a99d4c5489982c22d96e28e8c2
parent e00cd1ab4060915d86b8536b082e663818268b69
Author: Gregory Anders <greg@gpanders.com>
Date:   Tue, 31 Dec 2024 08:29:14 -0600

feat(tui): handle kitty key events in libtermkey (#31727)

Enable key event reporting in the kitty keyboard protocol. This causes
supporting terminals to send key events for presses, repeats, and key
releases. For now we ignore release events, but eventually we will
support users mapping those.
Diffstat:
Msrc/nvim/tui/input.c | 9+++++++++
Msrc/nvim/tui/termkey/driver-csi.c | 18+++++++++++++++---
Msrc/nvim/tui/termkey/termkey.c | 3+++
Msrc/nvim/tui/termkey/termkey_defs.h | 8++++++++
Msrc/nvim/tui/tui.c | 7+++++--
5 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c @@ -431,6 +431,15 @@ static void tk_getkeys(TermInput *input, bool force) TermKeyResult result; while ((result = tk_getkey(input->tk, &key, force)) == TERMKEY_RES_KEY) { + // Only press and repeat events are handled for now + switch (key.event) { + case TERMKEY_EVENT_PRESS: + case TERMKEY_EVENT_REPEAT: + break; + default: + continue; + } + if (key.type == TERMKEY_TYPE_UNICODE && !key.modifiers) { forward_simple_utf8(input, &key); } else if (key.type == TERMKEY_TYPE_UNICODE diff --git a/src/nvim/tui/termkey/driver-csi.c b/src/nvim/tui/termkey/driver-csi.c @@ -177,9 +177,21 @@ static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, TermKey return TERMKEY_RES_ERROR; } - if (nsubparams > 0 && subparam != 1) { - // Not a press event. Ignore for now - return TERMKEY_RES_NONE; + if (nsubparams > 0) { + switch (subparam) { + case 1: + key->event = TERMKEY_EVENT_PRESS; + break; + case 2: + key->event = TERMKEY_EVENT_REPEAT; + break; + case 3: + key->event = TERMKEY_EVENT_RELEASE; + break; + default: + // Invalid event + return TERMKEY_RES_NONE; + } } key->modifiers = args[1] - 1; diff --git a/src/nvim/tui/termkey/termkey.c b/src/nvim/tui/termkey/termkey.c @@ -834,6 +834,9 @@ static TermKeyResult peekkey(TermKey *tk, TermKeyKey *key, int force, size_t *nb return TERMKEY_RES_ERROR; } + // Press is the default event type. + key->event = TERMKEY_EVENT_PRESS; + #ifdef DEBUG fprintf(stderr, "getkey(force=%d): buffer ", force); print_buffer(tk); diff --git a/src/nvim/tui/termkey/termkey_defs.h b/src/nvim/tui/termkey/termkey_defs.h @@ -123,6 +123,12 @@ typedef enum { TERMKEY_MOUSE_RELEASE, } TermKeyMouseEvent; +typedef enum { + TERMKEY_EVENT_PRESS, + TERMKEY_EVENT_REPEAT, + TERMKEY_EVENT_RELEASE, +} TermKeyEvent; + enum { TERMKEY_KEYMOD_SHIFT = 1 << 0, TERMKEY_KEYMOD_ALT = 1 << 1, @@ -163,6 +169,8 @@ typedef struct { int modifiers; + TermKeyEvent event; + // Any Unicode character can be UTF-8 encoded in no more than 6 bytes, plus // terminating NUL char utf8[7]; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c @@ -296,7 +296,10 @@ void tui_set_key_encoding(TUIData *tui) { switch (tui->input.key_encoding) { case kKeyEncodingKitty: - out(tui, S_LEN("\x1b[>1u")); + // Progressive enhancement flags: + // 0b01 (1) Disambiguate escape codes + // 0b10 (2) Report event types + out(tui, S_LEN("\x1b[>3u")); break; case kKeyEncodingXterm: out(tui, S_LEN("\x1b[>4;2m")); @@ -311,7 +314,7 @@ static void tui_reset_key_encoding(TUIData *tui) { switch (tui->input.key_encoding) { case kKeyEncodingKitty: - out(tui, S_LEN("\x1b[<1u")); + out(tui, S_LEN("\x1b[<u")); break; case kKeyEncodingXterm: out(tui, S_LEN("\x1b[>4;0m"));