]> granicus.if.org Git - vim/commitdiff
patch 8.1.2134: modifier keys are not always recognized v8.1.2134
authorBram Moolenaar <Bram@vim.org>
Thu, 10 Oct 2019 19:14:03 +0000 (21:14 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 10 Oct 2019 19:14:03 +0000 (21:14 +0200)
Problem:    Modifier keys are not always recognized.
Solution:   Handle key codes generated by xterm with modifyOtherKeys set.
            Add this to libvterm so we can debug it.

src/getchar.c
src/globals.h
src/libvterm/include/vterm.h
src/libvterm/src/keyboard.c
src/libvterm/src/state.c
src/libvterm/src/vterm_internal.h
src/term.c
src/terminal.c
src/version.c

index 85ceddeb4cc99c69f1638fc4e12641ec9cd8c31c..ecd6bdcd044ff95faacd43a445044dd30dfe7081 100644 (file)
@@ -1733,6 +1733,25 @@ vgetc(void)
                case K_XRIGHT:  c = K_RIGHT; break;
            }
 
+           if (!no_reduce_keys)
+           {
+               // A modifier was not used for a mapping, apply it to ASCII
+               // keys.
+               if ((mod_mask & MOD_MASK_CTRL)
+                       && ((c >= '`' && c <= 0x7f)
+                           || (c >= '@' && c <= '_')))
+               {
+                   c &= 0x1f;
+                   mod_mask &= ~MOD_MASK_CTRL;
+               }
+               if ((mod_mask & (MOD_MASK_META | MOD_MASK_ALT))
+                       && c >= 0 && c <= 127)
+               {
+                   c += 0x80;
+                   mod_mask &= ~MOD_MASK_META;
+               }
+           }
+
            // For a multi-byte character get all the bytes and return the
            // converted character.
            // Note: This will loop until enough bytes are received!
index 2611266a7db498f570682d8e35ffc6cd4a3753cd..d790c82e78d7dec8bd8308fb863c57ae6c563ae5 100644 (file)
@@ -1006,6 +1006,8 @@ EXTERN int no_mapping INIT(= FALSE);      // currently no mapping allowed
 EXTERN int no_zero_mapping INIT(= 0);  // mapping zero not allowed
 EXTERN int allow_keys INIT(= FALSE);   // allow key codes when no_mapping
                                        // is set
+EXTERN int no_reduce_keys INIT(= FALSE);  // do not apply Ctrl, Shift and Alt
+                                         // to the key
 EXTERN int no_u_sync INIT(= 0);                // Don't call u_sync()
 #ifdef FEAT_EVAL
 EXTERN int u_sync_once INIT(= 0);      // Call u_sync() once when evaluating
index 02ea91cd59cbf2755bd36e74e062c20ce59dba47..28d0a10f5229d3ef7a83550e10a2ee307ab35c4a 100644 (file)
@@ -200,6 +200,7 @@ size_t vterm_output_get_buffer_remaining(const VTerm *vt);
 
 size_t vterm_output_read(VTerm *vt, char *buffer, size_t len);
 
+int vterm_is_modify_other_keys(VTerm *vt);
 void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod);
 void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod);
 
index 62338c638d828aaf97ef71e18fafa5b912ef4c0b..95b962ed6410cd985a027c49395b89d09c16532d 100644 (file)
@@ -4,10 +4,21 @@
 
 #include "utf8.h"
 
+int vterm_is_modify_other_keys(VTerm *vt)
+{
+  return vt->state->mode.modify_other_keys;
+}
+
+
 void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod)
 {
   int needs_CSIu;
 
+  if (vt->state->mode.modify_other_keys && mod != 0) {
+    vterm_push_output_sprintf_ctrl(vt, C1_CSI, "27;%d;%d~", mod+1, c);
+    return;
+  }
+
   // The shift modifier is never important for Unicode characters
   // apart from Space
   if(c != ' ')
index 1f7ac02de9e6c678f522b144081c50554886ae00..6b2583af9979b4e9fe3d1e8a9abbbb7c40080699 100644 (file)
@@ -1334,6 +1334,11 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
     vterm_state_setpen(state, args, argcount);
     break;
 
+  case LEADER('>', 0x6d): // xterm resource modifyOtherKeys
+    if (argcount == 2 && args[0] == 4)
+      state->mode.modify_other_keys = args[1] == 2;
+    break;
+
   case 0x6e: // DSR - ECMA-48 8.3.35
   case LEADER('?', 0x6e): // DECDSR
     val = CSI_ARG_OR(args[0], 0);
index 5b6198bdc00265aec5602903e569b89af25b9277..e2b8b159beb077571523003ef3a0fde6451f24d2 100644 (file)
@@ -124,6 +124,7 @@ struct VTermState
     unsigned int leftrightmargin:1;
     unsigned int bracketpaste:1;
     unsigned int report_focus:1;
+    unsigned int modify_other_keys:1;
   } mode;
 
   VTermEncodingInstance encoding[4], encoding_utf8;
index f021a17ff741e10e6b9b0d3f48194e16223f39fd..27def15c6a450566c3845bdca784cbf9cc9e4e8e 100644 (file)
@@ -4198,6 +4198,99 @@ is_mouse_topline(win_T *wp)
 }
 #endif
 
+/*
+ * Put "string[new_slen]" in typebuf, or in "buf[bufsize]" if "buf" is not NULL.
+ * Remove "slen" bytes.
+ * Returns FAIL for error.
+ */
+    static int
+put_string_in_typebuf(
+       int     offset,
+       int     slen,
+       char_u  *string,
+       int     new_slen,
+       char_u  *buf,
+       int     bufsize,
+       int     *buflen)
+{
+    int                extra = new_slen - slen;
+
+    string[new_slen] = NUL;
+    if (buf == NULL)
+    {
+       if (extra < 0)
+           // remove matched chars, taking care of noremap
+           del_typebuf(-extra, offset);
+       else if (extra > 0)
+           // insert the extra space we need
+           ins_typebuf(string + slen, REMAP_YES, offset, FALSE, FALSE);
+
+       // Careful: del_typebuf() and ins_typebuf() may have reallocated
+       // typebuf.tb_buf[]!
+       mch_memmove(typebuf.tb_buf + typebuf.tb_off + offset, string,
+                                                            (size_t)new_slen);
+    }
+    else
+    {
+       if (extra < 0)
+           // remove matched characters
+           mch_memmove(buf + offset, buf + offset - extra,
+                                          (size_t)(*buflen + offset + extra));
+       else if (extra > 0)
+       {
+           // Insert the extra space we need.  If there is insufficient
+           // space return -1.
+           if (*buflen + extra + new_slen >= bufsize)
+               return FAIL;
+           mch_memmove(buf + offset + extra, buf + offset,
+                                                  (size_t)(*buflen - offset));
+       }
+       mch_memmove(buf + offset, string, (size_t)new_slen);
+       *buflen = *buflen + extra + new_slen;
+    }
+    return OK;
+}
+
+/*
+ * Decode a modifier number as xterm provides it into MOD_MASK bits.
+ */
+    static int
+decode_modifiers(int n)
+{
+    int            code = n - 1;
+    int            modifiers = 0;
+
+    if (code & 1)
+       modifiers |= MOD_MASK_SHIFT;
+    if (code & 2)
+       modifiers |= MOD_MASK_ALT;
+    if (code & 4)
+       modifiers |= MOD_MASK_CTRL;
+    if (code & 8)
+       modifiers |= MOD_MASK_META;
+    return modifiers;
+}
+
+    static int
+modifiers2keycode(int modifiers, int *key, char_u *string)
+{
+    int new_slen = 0;
+
+    if (modifiers != 0)
+    {
+       // Some keys have the modifier included.  Need to handle that here to
+       // make mappings work.
+       *key = simplify_key(*key, &modifiers);
+       if (modifiers != 0)
+       {
+           string[new_slen++] = K_SPECIAL;
+           string[new_slen++] = (int)KS_MODIFIER;
+           string[new_slen++] = modifiers;
+       }
+    }
+    return new_slen;
+}
+
 /*
  * Check if typebuf.tb_buf[] contains a terminal key code.
  * Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off
@@ -4229,8 +4322,7 @@ check_termcode(
     int                modifiers;
     char_u     *modifiers_start = NULL;
     int                key;
-    int                new_slen;
-    int                extra;
+    int                new_slen;   // Length of what will replace the termcode
     char_u     string[MAX_KEY_CODE_LEN + 1];
     int                i, j;
     int                idx = 0;
@@ -4401,16 +4493,9 @@ check_termcode(
 
                            modifiers_start = tp + slen - 2;
 
-                           /* Match!  Convert modifier bits. */
-                           n = atoi((char *)modifiers_start) - 1;
-                           if (n & 1)
-                               modifiers |= MOD_MASK_SHIFT;
-                           if (n & 2)
-                               modifiers |= MOD_MASK_ALT;
-                           if (n & 4)
-                               modifiers |= MOD_MASK_CTRL;
-                           if (n & 8)
-                               modifiers |= MOD_MASK_META;
+                           // Match!  Convert modifier bits.
+                           n = atoi((char *)modifiers_start);
+                           modifiers |= decode_modifiers(n);
 
                            slen = j;
                        }
@@ -4751,9 +4836,32 @@ not_enough:
                        winpos_status.tr_progress = STATUS_GOT;
                }
 
-               // TODO: key with modifier:
+               // Key with modifier:
                //      {lead}27;{modifier};{key}~
                //      {lead}{key};{modifier}u
+               else if ((arg[0] == 27 && argc == 3 && trail == '~')
+                       || (argc == 2 && trail == 'u'))
+               {
+                   if (trail == 'u')
+                       key = arg[0];
+                   else
+                       key = arg[2];
+
+                   // insert modifiers with KS_MODIFIER
+                   modifiers = decode_modifiers(arg[1]);
+                   new_slen = modifiers2keycode(modifiers, &key, string);
+                   slen = csi_len;
+
+                   if (has_mbyte)
+                       new_slen += (*mb_char2bytes)(key, string + new_slen);
+                   else
+                       string[new_slen++] = key;
+
+                   if (put_string_in_typebuf(offset, slen, string, new_slen,
+                                                buf, bufsize, buflen) == FAIL)
+                       return -1;
+                   return len + new_slen - slen + offset;
+               }
 
                // else: Unknown CSI sequence.  We could drop it, but then the
                // user can't create a map for it.
@@ -5138,19 +5246,7 @@ not_enough:
        /*
         * Add any modifier codes to our string.
         */
-       new_slen = 0;           /* Length of what will replace the termcode */
-       if (modifiers != 0)
-       {
-           /* Some keys have the modifier included.  Need to handle that here
-            * to make mappings work. */
-           key = simplify_key(key, &modifiers);
-           if (modifiers != 0)
-           {
-               string[new_slen++] = K_SPECIAL;
-               string[new_slen++] = (int)KS_MODIFIER;
-               string[new_slen++] = modifiers;
-           }
-       }
+       new_slen = modifiers2keycode(modifiers, &key, string);
 
        /* Finally, add the special key code to our string */
        key_name[0] = KEY2TERMCAP0(key);
@@ -5176,43 +5272,10 @@ not_enough:
            string[new_slen++] = key_name[0];
            string[new_slen++] = key_name[1];
        }
-       string[new_slen] = NUL;
-       extra = new_slen - slen;
-       if (buf == NULL)
-       {
-           if (extra < 0)
-               /* remove matched chars, taking care of noremap */
-               del_typebuf(-extra, offset);
-           else if (extra > 0)
-               /* insert the extra space we need */
-               ins_typebuf(string + slen, REMAP_YES, offset, FALSE, FALSE);
-
-           /*
-            * Careful: del_typebuf() and ins_typebuf() may have reallocated
-            * typebuf.tb_buf[]!
-            */
-           mch_memmove(typebuf.tb_buf + typebuf.tb_off + offset, string,
-                                                           (size_t)new_slen);
-       }
-       else
-       {
-           if (extra < 0)
-               /* remove matched characters */
-               mch_memmove(buf + offset, buf + offset - extra,
-                                          (size_t)(*buflen + offset + extra));
-           else if (extra > 0)
-           {
-               /* Insert the extra space we need.  If there is insufficient
-                * space return -1. */
-               if (*buflen + extra + new_slen >= bufsize)
-                   return -1;
-               mch_memmove(buf + offset + extra, buf + offset,
-                                                  (size_t)(*buflen - offset));
-           }
-           mch_memmove(buf + offset, string, (size_t)new_slen);
-           *buflen = *buflen + extra + new_slen;
-       }
-       return retval == 0 ? (len + extra + offset) : retval;
+       if (put_string_in_typebuf(offset, slen, string, new_slen,
+                                                buf, bufsize, buflen) == FAIL)
+           return -1;
+       return retval == 0 ? (len + new_slen - slen + offset) : retval;
     }
 
 #ifdef FEAT_TERMRESPONSE
index 42a80cd7dcb29542de6e19e5f92bd806e65b38f6..a992b444dcd0f3b70882e0fa967821b14379cecd 100644 (file)
@@ -1371,11 +1371,13 @@ term_convert_key(term_T *term, int c, char *buf)
                                break;
     }
 
+    // add modifiers for the typed key
+    mod |= mod_mask;
+
     /*
      * Convert special keys to vterm keys:
      * - Write keys to vterm: vterm_keyboard_key()
      * - Write output to channel.
-     * TODO: use mod_mask
      */
     if (key != VTERM_KEY_NONE)
        /* Special key, let vterm convert it. */
@@ -1902,15 +1904,21 @@ term_vgetc()
 {
     int c;
     int save_State = State;
+    int modify_other_keys =
+                         vterm_is_modify_other_keys(curbuf->b_term->tl_vterm);
 
     State = TERMINAL;
     got_int = FALSE;
 #ifdef MSWIN
     ctrl_break_was_pressed = FALSE;
 #endif
+    if (modify_other_keys)
+       ++no_reduce_keys;
     c = vgetc();
     got_int = FALSE;
     State = save_State;
+    if (modify_other_keys)
+       --no_reduce_keys;
     return c;
 }
 
@@ -2255,6 +2263,7 @@ term_win_entered()
 terminal_loop(int blocking)
 {
     int                c;
+    int                raw_c;
     int                termwinkey = 0;
     int                ret;
 #ifdef UNIX
@@ -2307,6 +2316,13 @@ terminal_loop(int blocking)
        if (c == K_IGNORE)
            continue;
 
+       // vgetc may not include CTRL in the key when modify_other_keys is set.
+       raw_c = c;
+       if ((mod_mask & MOD_MASK_CTRL)
+               && ((c >= '`' && c <= 0x7f)
+                   || (c >= '@' && c <= '_')))
+           c &= 0x1f;
+
 #ifdef UNIX
        /*
         * The shell or another program may change the tty settings.  Getting
@@ -2417,7 +2433,7 @@ terminal_loop(int blocking)
                c = wc;
        }
 # endif
-       if (send_keys_to_term(curbuf->b_term, c, TRUE) != OK)
+       if (send_keys_to_term(curbuf->b_term, raw_c, TRUE) != OK)
        {
            if (c == K_MOUSEMOVE)
                /* We are sure to come back here, don't reset the cursor color
index acbcc2d258f0cf2710c3108ff97a88dc3a0341df..7289c9bb6daac3f5fb11d27c9e52ec19bca45077 100644 (file)
@@ -753,6 +753,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2134,
 /**/
     2133,
 /**/