]> granicus.if.org Git - vim/commitdiff
patch 9.0.1146: MS-Windows: various special keys/modifiers are not mappable v9.0.1146
authorChristopher Plewright <chris@createng.com>
Wed, 4 Jan 2023 18:06:00 +0000 (18:06 +0000)
committerBram Moolenaar <Bram@vim.org>
Wed, 4 Jan 2023 18:06:00 +0000 (18:06 +0000)
Problem:    MS-Windows: various special keys and modifiers are not mappable.
Solution:   Adjust the handling of keys with modifiers. (Christian Plewright,
            closes #11768)

.appveyor.yml
nsis/README.txt
src/os_win32.c
src/testdir/test_mswin_event.vim
src/version.c

index 1a177c8e448c5fb45896d6c073e8a5a757d6628b..c87857e4a8b89ee2af1d677dfb79798876a44e77 100644 (file)
@@ -1,5 +1,7 @@
 version: "{build}"
 
+image: Visual Studio 2015
+
 skip_tags: true
 
 environment:
index 31fa7871b990d67709f5ab9745dc83fc43f5a22b..e1abc4a95ce29e2861c2e56679cc69f974a248e5 100644 (file)
@@ -29,12 +29,12 @@ To build the installable .exe:
 
 4.  Get a "diff.exe" program.  If you skip this the built-in diff will always
     be used (which is fine for most users).  If you do have your own
-    "diff.exe" put it in the "../.." directory (above the "vim82" directory,
+    "diff.exe" put it in the "../.." directory (above the "vim90" directory,
     it's the same for all Vim versions).
     You can find one in previous Vim versions or in this archive:
                http://www.mossbayeng.com/~ron/vim/diffutils.tar.gz
 
-5   Also put winpty32.dll and winpty-agent.exe in "../.." (above the "vim82"
+5   Also put winpty32.dll and winpty-agent.exe in "../.." (above the "vim90"
     directory).  This is required for the terminal window.
 
 6.  Do "make uganda.nsis.txt" in runtime/doc.  This requires sed, you may have
index f01d3399e52b39a9e0d0788e1d2f052977da5229..3f2de6485155685fefa90fb26da9d6626039235b 100644 (file)
@@ -1042,7 +1042,8 @@ win32_kbd_patch_key(
        return 1;
     }
 
-    if (pker->uChar.UnicodeChar > 0 && pker->uChar.UnicodeChar < 0xfffd)
+    // check if it already has a valid unicode character.
+    if (pker->uChar.UnicodeChar > 0 && pker->uChar.UnicodeChar < 0xFFFD)
        return 1;
 
     CLEAR_FIELD(abKeystate);
@@ -1118,13 +1119,12 @@ decode_key_event(
     {
        if (VirtKeyMap[i].wVirtKey == pker->wVirtualKeyCode)
        {
-           if (nModifs == 0)
-               *pch = VirtKeyMap[i].chAlone;
-           else if ((nModifs & SHIFT) != 0 && (nModifs & ~SHIFT) == 0)
+           *pch = VirtKeyMap[i].chAlone;
+           if ((nModifs & SHIFT) != 0)
                *pch = VirtKeyMap[i].chShift;
            else if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0)
                *pch = VirtKeyMap[i].chCtrl;
-           else if ((nModifs & ALT) != 0 && (nModifs & ~ALT) == 0)
+           else if ((nModifs & ALT) != 0)
                *pch = VirtKeyMap[i].chAlt;
 
            if (*pch != 0)
@@ -1133,6 +1133,74 @@ decode_key_event(
                {
                    *pch2 = *pch;
                    *pch = K_NUL;
+                   if (pmodifiers)
+                   {
+                       if (pker->wVirtualKeyCode >= VK_F1
+                           && pker->wVirtualKeyCode <= VK_F12)
+                       {
+                           if ((nModifs & ALT) != 0)
+                           {
+                               *pmodifiers |= MOD_MASK_ALT;
+                               if ((nModifs & SHIFT) == 0)
+                                   *pch2 = VirtKeyMap[i].chAlone;
+                           }
+                           if ((nModifs & CTRL) != 0)
+                           {
+                               *pmodifiers |= MOD_MASK_CTRL;
+                               if ((nModifs & SHIFT) == 0)
+                                   *pch2 = VirtKeyMap[i].chAlone;
+                           }
+                       }
+                       else if (pker->wVirtualKeyCode >= VK_END
+                               && pker->wVirtualKeyCode <= VK_DOWN)
+                       {
+                           // VK_END   0x23
+                           // VK_HOME  0x24
+                           // VK_LEFT  0x25
+                           // VK_UP    0x26
+                           // VK_RIGHT 0x27
+                           // VK_DOWN  0x28
+                           *pmodifiers = 0;
+                           *pch2 = VirtKeyMap[i].chAlone;
+                           if ((nModifs & SHIFT) != 0
+                                                   && (nModifs & ~SHIFT) == 0)
+                           {
+                               *pch2 = VirtKeyMap[i].chShift;
+                           }
+                           else if ((nModifs & CTRL) != 0
+                                                    && (nModifs & ~CTRL) == 0)
+                           {
+                               *pch2 = VirtKeyMap[i].chCtrl;
+                               if (pker->wVirtualKeyCode == VK_UP
+                                   || pker->wVirtualKeyCode == VK_DOWN)
+                               {
+                                   *pmodifiers |= MOD_MASK_CTRL;
+                                   *pch2 = VirtKeyMap[i].chAlone;
+                               }
+                           }
+                           else if ((nModifs & ALT) != 0
+                                                     && (nModifs & ~ALT) == 0)
+                           {
+                               *pch2 = VirtKeyMap[i].chAlt;
+                           }
+                           else if ((nModifs & SHIFT) != 0
+                                                     && (nModifs & CTRL) != 0)
+                           {
+                               *pmodifiers |= MOD_MASK_CTRL;
+                               *pch2 = VirtKeyMap[i].chShift;
+                           }
+                       }
+                       else
+                       {
+                           *pch2 = VirtKeyMap[i].chAlone;
+                           if ((nModifs & SHIFT) != 0)
+                               *pmodifiers |= MOD_MASK_SHIFT;
+                           if ((nModifs & CTRL) != 0)
+                               *pmodifiers |= MOD_MASK_CTRL;
+                           if ((nModifs & ALT) != 0)
+                               *pmodifiers |= MOD_MASK_ALT;
+                       }
+                   }
                }
 
                return TRUE;
@@ -1178,10 +1246,11 @@ encode_key_event(dict_T *args, INPUT_RECORD *ir)
 {
     static int s_dwMods = 0;
 
-    char_u *event = dict_get_string(args, "event", TRUE);
-    if (event && (STRICMP(event, "keydown") == 0
-                                       || STRICMP(event, "keyup") == 0))
+    char_u *action = dict_get_string(args, "event", TRUE);
+    if (action && (STRICMP(action, "keydown") == 0
+                                       || STRICMP(action, "keyup") == 0))
     {
+       BOOL isKeyDown = STRICMP(action, "keydown") == 0;
        WORD vkCode = dict_get_number_def(args, "keycode", 0);
        if (vkCode <= 0 || vkCode >= 0xFF)
        {
@@ -1192,7 +1261,7 @@ encode_key_event(dict_T *args, INPUT_RECORD *ir)
        ir->EventType = KEY_EVENT;
        KEY_EVENT_RECORD ker;
        ZeroMemory(&ker, sizeof(ker));
-       ker.bKeyDown = STRICMP(event, "keydown") == 0;
+       ker.bKeyDown = isKeyDown;
        ker.wRepeatCount = 1;
        ker.wVirtualScanCode = 0;
        ker.dwControlKeyState = 0;
@@ -1215,73 +1284,55 @@ encode_key_event(dict_T *args, INPUT_RECORD *ir)
 
        if (vkCode == VK_LSHIFT || vkCode == VK_RSHIFT || vkCode == VK_SHIFT)
        {
-           if (STRICMP(event, "keydown") == 0)
+           if (isKeyDown)
                s_dwMods |= SHIFT_PRESSED;
            else
                s_dwMods &= ~SHIFT_PRESSED;
        }
        else if (vkCode == VK_LCONTROL || vkCode == VK_CONTROL)
        {
-           if (STRICMP(event, "keydown") == 0)
+           if (isKeyDown)
                s_dwMods |= LEFT_CTRL_PRESSED;
            else
                s_dwMods &= ~LEFT_CTRL_PRESSED;
        }
        else if (vkCode == VK_RCONTROL)
        {
-           if (STRICMP(event, "keydown") == 0)
+           if (isKeyDown)
                s_dwMods |= RIGHT_CTRL_PRESSED;
            else
                s_dwMods &= ~RIGHT_CTRL_PRESSED;
        }
        else if (vkCode == VK_LMENU || vkCode == VK_MENU)
        {
-           if (STRICMP(event, "keydown") == 0)
+           if (isKeyDown)
                s_dwMods |= LEFT_ALT_PRESSED;
            else
                s_dwMods &= ~LEFT_ALT_PRESSED;
        }
        else if (vkCode == VK_RMENU)
        {
-           if (STRICMP(event, "keydown") == 0)
+           if (isKeyDown)
                s_dwMods |= RIGHT_ALT_PRESSED;
            else
                s_dwMods &= ~RIGHT_ALT_PRESSED;
        }
        ker.dwControlKeyState |= s_dwMods;
        ker.wVirtualKeyCode = vkCode;
-       win32_kbd_patch_key(&ker);
-
-       for (int i = ARRAY_LENGTH(VirtKeyMap); i >= 0; --i)
-       {
-           if (VirtKeyMap[i].wVirtKey == vkCode)
-           {
-               ker.uChar.UnicodeChar = 0xfffd;  // REPLACEMENT CHARACTER
-               break;
-           }
-       }
-
-       // The following are treated specially in Vim.
-       // Ctrl-6 is Ctrl-^
-       // Ctrl-2 is Ctrl-@
-       // Ctrl-- is Ctrl-_
-       if ((vkCode == 0xBD || vkCode == '2' || vkCode == '6')
-                                            && (ker.dwControlKeyState & CTRL))
-           ker.uChar.UnicodeChar = 0xfffd;  // REPLACEMENT CHARACTER
-
+       ker.uChar.UnicodeChar = 0xFFFD;  // UNICODE REPLACEMENT CHARACTER
        ir->Event.KeyEvent = ker;
-       vim_free(event);
+       vim_free(action);
     }
     else
     {
-       if (event == NULL)
+       if (action == NULL)
        {
            semsg(_(e_missing_argument_str), "event");
        }
        else
        {
-           semsg(_(e_invalid_value_for_argument_str_str), "event", event);
-           vim_free(event);
+           semsg(_(e_invalid_value_for_argument_str_str), "event", action);
+           vim_free(action);
        }
        return FALSE;
     }
@@ -2432,6 +2483,8 @@ mch_inchar(
 
            c = tgetch(&modifiers, &ch2);
 
+           c = simplify_key(c, &modifiers);
+
            // Some chars need adjustment when the Ctrl modifier is used.
            ++no_reduce_keys;
            c = may_adjust_key_for_ctrl(modifiers, c);
index a84c21a570175c63a5be4497128740e8c53525cf..2866dd1d68100420872a783df8de8d58e76f8df1 100644 (file)
@@ -3,7 +3,6 @@
 
 source check.vim
 CheckMSWindows
-
 source mouse.vim
 
 " Helper function for sending a grouped sequence of low level key presses
@@ -54,7 +53,8 @@ func ExecuteBufferedKeys()
   endif
 endfunc
 
-
+" Refer to the following page for the virtual key codes:
+" https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
 let s:VK = {
     \ 'ENTER'      : 0x0D,
     \ 'SPACE'      : 0x20,
@@ -296,11 +296,9 @@ let s:VK = {
     \ [[s:VK.CONTROL, s:VK.OEM_4], 0x1B],
     \ [[s:VK.CONTROL, s:VK.OEM_5], 0x1C],
     \ [[s:VK.CONTROL, s:VK.OEM_6], 0x1D],
+    \ [[s:VK.CONTROL, s:VK.KEY_6], 0x1E],
+    \ [[s:VK.CONTROL, s:VK.OEM_MINUS], 0x1F],
     \ ]
-" The following non-printable ascii chars fail in the GUI, but work in the 
-" console. 0x1e [^^] Record separator (RS), and 0x1f [^_] Unit separator (US)
-"      \ [[s:VK.CONTROL, s:VK.SHIFT, s:VK.KEY_6], 0x1E],
-"      \ [[s:VK.CONTROL, s:VK.SHIFT, s:VK.OEM_MINUS], 0x1F],
 
 let s:test_extra_key_chars = [
     \ [[s:VK.ALT, s:VK.KEY_1], '±'],
@@ -342,7 +340,7 @@ let s:test_extra_key_chars = [
     \ ]
 
 func s:LoopTestKeyArray(arr)
-" flush out any garbage left in the buffer
+  " flush out anything in the typeahead buffer
   while getchar(0)
   endwhile
 
@@ -351,7 +349,7 @@ func s:LoopTestKeyArray(arr)
     call SendKeyGroup(kcodes)
     let ch = getcharstr(0)
     " need to deal a bit differently with the non-printable ascii chars < 0x20
-    if kstr < 0x20 && index([s:VK.CONTROL, s:VK.LCONTROL, s:VK.RCONTROL],  kcodes[0]) >= 0
+    if kstr < 0x20 && index([s:VK.CONTROL, s:VK.LCONTROL, s:VK.RCONTROL], kcodes[0]) >= 0
       call assert_equal(nr2char(kstr), $"{ch}")
     else
       call assert_equal(kstr, $"{ch}")
@@ -389,7 +387,7 @@ func s:LoopTestKeyArray(arr)
     call assert_equal(0, mod_mask, $"key = {kstr}")
   endfor
 
-  " flush out any garbage left in the buffer
+  " flush out anything in the typeahead buffer
   while getchar(0)
   endwhile
 
@@ -489,29 +487,23 @@ func Test_mswin_key_event()
     endfor
   endif
 
-  " Windows intercepts some of these keys in the GUI
+  " Test for Function Keys 'F1' to 'F12'
+  " VK codes 112(0x70) - 123(0x7B)
+  " Also with ALL permutatios of modifiers; Shift, Ctrl & Alt
+  " NOTE: Windows intercepts some of these keys in the GUI
   if !has("gui_running")
-    " Test for Function Keys 'F1' to 'F12'
-    for n in range(1, 12)
-      let kstr = $"F{n}"
-      let keycode = eval('"\<' .. kstr .. '>"')
-      call SendKey(111+n)
-      let ch = getcharstr(0)
-      call assert_equal(keycode, $"{ch}", $"key = <{kstr}>")
-    endfor
-    "  NOTE: mod + Fn Keys not working in CI Testing!?
-    " Test for Function Keys 'F1' to 'F12'
-    " VK codes 112(0x70) - 123(0x7B)
-    " With ALL permutatios of modifiers; Shift, Ctrl & Alt
     for [mod_str, vim_mod_mask, mod_keycodes] in s:vim_key_modifiers
       for n in range(1, 12)
         let kstr = $"{mod_str}F{n}"
         let keycode = eval('"\<' .. kstr .. '>"')
+        " flush out anything in the typeahead buffer
+        while getchar(0)
+        endwhile
         " call SendKeyGroup(mod_keycodes + [111+n])
         call SendKeyWithModifiers(111+n, vim_mod_mask)
         let ch = getcharstr(0)
         let mod_mask = getcharmod()
-        """"""  call assert_equal(keycode, $"{ch}", $"key = {kstr}")
+        call assert_equal(keycode, $"{ch}", $"key = {kstr}")
         " workaround for the virtual termcap maps changing the character instead
         " of sending Shift
         for mod_key in mod_keycodes
@@ -519,14 +511,12 @@ func Test_mswin_key_event()
             let mod_mask = mod_mask + s:vim_MOD_MASK_SHIFT
           endif
         endfor
-        """"""call assert_equal(vim_mod_mask, mod_mask, $"mod = {vim_mod_mask} for key = {kstr}")
+        call assert_equal(vim_mod_mask, mod_mask, $"mod = {vim_mod_mask} for key = {kstr}")
       endfor
     endfor
   endif
 
   " Test for the various Ctrl and Shift key combinations.
-  " Refer to the following page for the virtual key codes:
-  " https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
   let keytests = [
     \ [[s:VK.SHIFT,    s:VK.PRIOR], "S-Pageup", 2],
     \ [[s:VK.LSHIFT,   s:VK.PRIOR], "S-Pageup", 2],
@@ -586,14 +576,13 @@ func Test_mswin_key_event()
     \ [[s:VK.CONTROL,  s:VK.OEM_MINUS], "C-_", 0]
     \ ]
 
-  " Not working in CI Testing yet!?
   for [kcodes, kstr, kmod] in keytests
     call SendKeyGroup(kcodes)
     let ch = getcharstr(0)
     let mod = getcharmod()
     let keycode = eval('"\<' .. kstr .. '>"')
-"      call assert_equal(keycode, ch, $"key = {kstr}")
-"      call assert_equal(kmod, mod, $"mod = {kmod} key = {kstr}")
+    call assert_equal(keycode, ch, $"key = {kstr}")
+    call assert_equal(kmod, mod, $"mod = {kmod} key = {kstr}")
   endfor
 
   bw!
@@ -634,8 +623,6 @@ func Test_QWERTY_Ctrl_minus()
   call ExecuteBufferedKeys()
   call assert_equal('BILBO', getline('$'))
 
-
-
   imapclear
   bw!
 endfunc
@@ -953,7 +940,7 @@ func Test_mswin_event_error_handling()
 
   call assert_fails("sandbox call test_mswin_event('key', {'event': 'keydown', 'keycode': 61 })", 'E48:')
 
-  " flush out any garbage left in the buffer.
+  " flush out anything in the typeahead buffer
   while getchar(0)
   endwhile
 endfunc
index 9c38fd91cf1330ec6c892208a316b53628964ea4..44d8db9b00fd9c28e624b49ce75dc1a2386b18a4 100644 (file)
@@ -695,6 +695,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1146,
 /**/
     1145,
 /**/