# HG changeset patch # User Bram Moolenaar # Date 1665746104 -7200 # Node ID 0c30130f8c94bca5bf2808fde4945c04bca148ff # Parent ddf4fc8d9c655fd17c587440b2013679a50b6737 patch 9.0.0748: Kitty may send key without modifiers with CSI u code Commit: https://github.com/vim/vim/commit/b9c09c118e951bc6ea2059941101939dc572b4ce Author: Trygve Aaberge Date: Fri Oct 14 12:08:24 2022 +0100 patch 9.0.0748: Kitty may send key without modifiers with CSI u code Problem: Kitty may send key without modifiers with CSI u code. Solution: Handle CSI u code without modifiers. (Trygve Aaberge, closes #11364) diff --git a/src/term.c b/src/term.c --- a/src/term.c +++ b/src/term.c @@ -4807,6 +4807,28 @@ handle_version_response(int first, int * } /* + * Add "key" to "buf" and return the number of bytes used. + * Handles special keys and multi-byte characters. + */ + static int +add_key_to_buf(int key, char_u *buf) +{ + int idx = 0; + + if (IS_SPECIAL(key)) + { + buf[idx++] = K_SPECIAL; + buf[idx++] = KEY2TERMCAP0(key); + buf[idx++] = KEY2TERMCAP1(key); + } + else if (has_mbyte) + idx += (*mb_char2bytes)(key, buf + idx); + else + buf[idx++] = key; + return idx; +} + +/* * Handle a sequence with key and modifier, one of: * {lead}27;{modifier};{key}~ * {lead}{key};{modifier}u @@ -4824,7 +4846,6 @@ handle_key_with_modifier( { int key; int modifiers; - int new_slen; char_u string[MAX_KEY_CODE_LEN + 1]; seenModifyOtherKeys = TRUE; @@ -4842,18 +4863,33 @@ handle_key_with_modifier( modifiers = may_remove_shift_modifier(modifiers, key); // insert modifiers with KS_MODIFIER - new_slen = modifiers2keycode(modifiers, &key, string); - - if (IS_SPECIAL(key)) - { - string[new_slen++] = K_SPECIAL; - string[new_slen++] = KEY2TERMCAP0(key); - string[new_slen++] = KEY2TERMCAP1(key); - } - else if (has_mbyte) - new_slen += (*mb_char2bytes)(key, string + new_slen); - else - string[new_slen++] = key; + int new_slen = modifiers2keycode(modifiers, &key, string); + + // add the bytes for the key + new_slen += add_key_to_buf(key, string + new_slen); + + if (put_string_in_typebuf(offset, csi_len, string, new_slen, + buf, bufsize, buflen) == FAIL) + return -1; + return new_slen - csi_len + offset; +} + +/* + * Handle a sequence with key without a modifier: + * {lead}{key}u + * Returns the difference in length. + */ + static int +handle_key_without_modifier( + int *arg, + int csi_len, + int offset, + char_u *buf, + int bufsize, + int *buflen) +{ + char_u string[MAX_KEY_CODE_LEN + 1]; + int new_slen = add_key_to_buf(arg[0], string); if (put_string_in_typebuf(offset, csi_len, string, new_slen, buf, bufsize, buflen) == FAIL) @@ -5016,6 +5052,14 @@ handle_csi( csi_len, offset, buf, bufsize, buflen); } + // Key without modifier (bad Kitty may send this): + // {lead}{key}u + else if (argc == 1 && trail == 'u') + { + return len + handle_key_without_modifier(arg, + csi_len, offset, buf, bufsize, buflen); + } + // else: Unknown CSI sequence. We could drop it, but then the // user can't create a map for it. return 0; diff --git a/src/testdir/test_termcodes.vim b/src/testdir/test_termcodes.vim --- a/src/testdir/test_termcodes.vim +++ b/src/testdir/test_termcodes.vim @@ -1992,6 +1992,11 @@ func GetEscCodeCSIu(key, modifier) return "\[" .. key .. ';' .. mod .. 'u' endfunc +func GetEscCodeCSIuWithoutModifier(key) + let key = printf("%d", char2nr(a:key)) + return "\[" .. key .. 'u' +endfunc + " This checks the CSI sequences when in modifyOtherKeys mode. " The mode doesn't need to be enabled, the codes are always detected. func RunTest_modifyOtherKeys(func) @@ -2080,6 +2085,19 @@ func Test_modifyOtherKeys_no_mapping() set timeoutlen& endfunc +func Test_CSIu_keys_without_modifiers() + " Escape sent as `CSI 27 u` should act as normal escape and not undo + call setline(1, 'a') + call feedkeys('a' .. GetEscCodeCSIuWithoutModifier("\e"), 'Lx!') + call assert_equal('n', mode()) + call assert_equal('a', getline(1)) + + " Tab sent as `CSI 9 u` should work + call setline(1, '') + call feedkeys('a' .. GetEscCodeCSIuWithoutModifier("\t") .. "\", 'Lx!') + call assert_equal("\t", getline(1)) +endfunc + " Check that when DEC mouse codes are recognized a special key is handled. func Test_ignore_dec_mouse() silent !infocmp gnome >/dev/null 2>&1 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -696,6 +696,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 748, +/**/ 747, /**/ 746,