changeset 30827:0c30130f8c94 v9.0.0748

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 <trygveaa@gmail.com> 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)
author Bram Moolenaar <Bram@vim.org>
date Fri, 14 Oct 2022 13:15:04 +0200
parents ddf4fc8d9c65
children 0f439fcdfa1a
files src/term.c src/testdir/test_termcodes.vim src/version.c
diffstat 3 files changed, 77 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- a/src/testdir/test_termcodes.vim
+++ b/src/testdir/test_termcodes.vim
@@ -1992,6 +1992,11 @@ func GetEscCodeCSIu(key, modifier)
   return "\<Esc>[" .. key .. ';' .. mod .. 'u'
 endfunc
 
+func GetEscCodeCSIuWithoutModifier(key)
+  let key = printf("%d", char2nr(a:key))
+  return "\<Esc>[" .. 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") .. "\<Esc>", '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
--- 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,