aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-07-15 15:03:01 +0800
committerGitHub <noreply@github.com>2023-07-15 15:03:01 +0800
commit622ae2f53e77873a114f86f5acaff341ef3098ac (patch)
tree49baf8beeec4302306346ef98daa4e02a3fa7661
parent33e1a8cd7042816a064c0d2bf32b6570d7e88b79 (diff)
downloadrneovim-622ae2f53e77873a114f86f5acaff341ef3098ac.tar.gz
rneovim-622ae2f53e77873a114f86f5acaff341ef3098ac.tar.bz2
rneovim-622ae2f53e77873a114f86f5acaff341ef3098ac.zip
feat(tui): support Super and Meta modifiers (#24357)
-rw-r--r--src/nvim/tui/input.c78
-rw-r--r--test/functional/terminal/tui_spec.lua22
2 files changed, 79 insertions, 21 deletions
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 30a1af68ad..a5d021943b 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -229,6 +229,44 @@ static void tinput_enqueue(TermInput *input, char *buf, size_t size)
rbuffer_write(input->key_buffer, buf, size);
}
+/// Handle TERMKEY_KEYMOD_* modifiers, i.e. Shift, Alt and Ctrl.
+///
+/// @return The number of bytes written into "buf", excluding the final NUL.
+static size_t handle_termkey_modifiers(TermKeyKey *key, char *buf, size_t buflen)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ size_t len = 0;
+ if (key->modifiers & TERMKEY_KEYMOD_SHIFT) { // Shift
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, "S-");
+ }
+ if (key->modifiers & TERMKEY_KEYMOD_ALT) { // Alt
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, "A-");
+ }
+ if (key->modifiers & TERMKEY_KEYMOD_CTRL) { // Ctrl
+ len += (size_t)snprintf(buf + len, sizeof(buf) - len, "C-");
+ }
+ assert(len < buflen);
+ return len;
+}
+
+/// Handle modifiers not handled by libtermkey.
+/// Currently only Super ("D-") and Meta ("T-") are supported in Nvim.
+///
+/// @return The number of bytes written into "buf", excluding the final NUL.
+static size_t handle_more_modifiers(TermKeyKey *key, char *buf, size_t buflen)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ size_t len = 0;
+ if (key->modifiers & 8) { // Super
+ len += (size_t)snprintf(buf + len, buflen - len, "D-");
+ }
+ if (key->modifiers & 32) { // Meta
+ len += (size_t)snprintf(buf + len, buflen - len, "T-");
+ }
+ assert(len < buflen);
+ return len;
+}
+
static void handle_kitty_key_protocol(TermInput *input, TermKeyKey *key)
{
const char *name = map_get(int, cstr_t)(&kitty_key_map, (int)key->code.codepoint);
@@ -236,16 +274,10 @@ static void handle_kitty_key_protocol(TermInput *input, TermKeyKey *key)
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 += handle_termkey_modifiers(key, buf + len, sizeof(buf) - len);
+ len += handle_more_modifiers(key, buf + len, sizeof(buf) - len);
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "%s>", name);
+ assert(len < sizeof(buf));
tinput_enqueue(input, buf, len);
}
}
@@ -270,6 +302,7 @@ static void forward_simple_utf8(TermInput *input, TermKeyKey *key)
ptr++;
}
+ assert(len < sizeof(buf));
tinput_enqueue(input, buf, len);
}
@@ -297,7 +330,7 @@ static void forward_modified_utf8(TermInput *input, TermKeyKey *key)
if ((key->modifiers & TERMKEY_KEYMOD_CTRL)
&& !(key->modifiers & TERMKEY_KEYMOD_SHIFT)
&& ASCII_ISUPPER(key->code.codepoint)) {
- assert(len <= 62);
+ assert(len + 2 < sizeof(buf));
// Make room for the S-
memmove(buf + 3, buf + 1, len - 1);
buf[1] = 'S';
@@ -306,6 +339,16 @@ static void forward_modified_utf8(TermInput *input, TermKeyKey *key)
}
}
+ char more_buf[25];
+ size_t more_len = handle_more_modifiers(key, more_buf, sizeof(more_buf));
+ if (more_len > 0) {
+ assert(len + more_len < sizeof(buf));
+ memmove(buf + 1 + more_len, buf + 1, len - 1);
+ memcpy(buf + 1, more_buf, more_len);
+ len += more_len;
+ }
+
+ assert(len < sizeof(buf));
tinput_enqueue(input, buf, len);
}
@@ -343,17 +386,9 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
row--; col--; // Termkey uses 1-based coordinates
buf[len++] = '<';
- if (key->modifiers & TERMKEY_KEYMOD_SHIFT) {
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "S-");
- }
-
- if (key->modifiers & TERMKEY_KEYMOD_CTRL) {
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "C-");
- }
-
- if (key->modifiers & TERMKEY_KEYMOD_ALT) {
- len += (size_t)snprintf(buf + len, sizeof(buf) - len, "A-");
- }
+ len += handle_termkey_modifiers(key, buf + len, sizeof(buf) - len);
+ // Doesn't actually work because there are only 3 bits (0x1c) for modifiers.
+ // len += handle_more_modifiers(key, buf + len, sizeof(buf) - len);
if (button == 1) {
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "Left");
@@ -390,6 +425,7 @@ static void forward_mouse_event(TermInput *input, TermKeyKey *key)
}
len += (size_t)snprintf(buf + len, sizeof(buf) - len, "><%d,%d>", col, row);
+ assert(len < sizeof(buf));
tinput_enqueue(input, buf, len);
}
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index 44e06a0baf..f48d0e073c 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -697,6 +697,28 @@ describe('TUI', function()
]])
end)
+ it('supports Super and Meta modifiers', function()
+ feed_data('i')
+ feed_data('\022\027[106;9u') -- Super + j
+ feed_data('\022\027[107;33u') -- Meta + k
+ feed_data('\022\027[13;41u') -- Super + Meta + Enter
+ feed_data('\022\027[127;48u') -- Shift + Alt + Ctrl + Super + Meta + Backspace
+ feed('\n')
+ feed_data('\022\027[57376;9u') -- Super + F13
+ feed_data('\022\027[57377;33u') -- Meta + F14
+ feed_data('\022\027[57378;41u') -- Super + Meta + F15
+ feed_data('\022\027[57379;48u') -- Shift + Alt + Ctrl + Super + Meta + F16
+ screen:expect([[
+ <D-j><T-k><T-D-CR><M-T-C-S-D-BS> |
+ <D-F13><T-F14><T-D-F15><M-T-C-S-D-F16>{1: } |
+ {4:~ }|
+ {4:~ }|
+ {5:[No Name] [+] }|
+ {3:-- INSERT --} |
+ {3:-- TERMINAL --} |
+ ]])
+ end)
+
it('mouse events work with right-click menu', function()
child_session:request('nvim_exec', [[
call setline(1, 'popup menu test')