Patch 9.0.1112
Problem:    test_mswin_event() can hang.
Solution:   Add the "execute" argument to process events right away.
            (Christopher Plewright, closes #11760)
Files:      runtime/doc/testing.txt, src/gui_w32.c, src/os_win32.c,
            src/testdir/test_gui.vim, src/testdir/test_mswin_event.vim


*** ../vim-9.0.1111/runtime/doc/testing.txt     2022-12-20 20:01:09.620090910 
+0000
--- runtime/doc/testing.txt     2022-12-30 16:40:51.789520106 +0000
***************
*** 274,280 ****
                    event:      The supported string values are:
                                    keyup   generate a keyup event
                                    keydown generate a keydown event
!                   keycode:    Keycode to use for a keyup or a keydown event.
                    modifiers:  Optional; key modifiers.
                                The supported values are:
                                    2   shift is pressed
--- 274,280 ----
                    event:      The supported string values are:
                                    keyup   generate a keyup event
                                    keydown generate a keydown event
!                   keycode:    Keycode to use for a keyup or a keydown event.
                    modifiers:  Optional; key modifiers.
                                The supported values are:
                                    2   shift is pressed
***************
*** 282,290 ****
                                    8   alt is pressed
                                Note: These values are different from the
                                mouse modifiers.
!                                                               *E1291*
!               Returns TRUE if the event is successfully added, FALSE if
!               there is a failure.
  
                Can also be used as a |method|: >
                        GetEvent()->test_mswin_event({args})
--- 282,295 ----
                                    8   alt is pressed
                                Note: These values are different from the
                                mouse modifiers.
!                   execute:    Optional. Similar to |feedkeys()| mode x.
!                               When this is included and set to true
!                               (non-zero) then Vim will process any buffered
!                               unprocessed key events.  All other {args}
!                               items are optional when this is set and true.
! 
!               Returns TRUE if the event is successfully added or executed,
!               FALSE if there is a failure.
  
                Can also be used as a |method|: >
                        GetEvent()->test_mswin_event({args})
*** ../vim-9.0.1111/src/gui_w32.c       2022-12-20 20:01:09.624090908 +0000
--- src/gui_w32.c       2022-12-30 16:39:14.741599172 +0000
***************
*** 888,893 ****
--- 888,899 ----
      modifiers = get_active_modifiers();
  
      ch = simplify_key(ch, &modifiers);
+     
+     // Some keys need adjustment when the Ctrl modifier is used.
+     ++no_reduce_keys;
+     ch = may_adjust_key_for_ctrl(modifiers, ch);
+     --no_reduce_keys;
+ 
      // remove the SHIFT modifier for keys where it's already included, e.g.,
      // '(' and '*'
      modifiers = may_remove_shift_modifier(modifiers, ch);
*** ../vim-9.0.1111/src/os_win32.c      2022-12-22 21:06:35.047328431 +0000
--- src/os_win32.c      2022-12-30 16:39:14.745599171 +0000
***************
*** 1106,1136 ****
        break;
      }
  
-     // special cases
-     if ((nModifs & CTRL) != 0 && (nModifs & ~CTRL) == 0
-                                       && (pker->uChar.UnicodeChar == NUL
-                                       || pker->uChar.UnicodeChar == 0xfffd))
-     {
-       // Ctrl-6 is Ctrl-^
-       if (pker->wVirtualKeyCode == '6')
-       {
-           *pch = Ctrl_HAT;
-           return TRUE;
-       }
-       // Ctrl-2 is Ctrl-@
-       else if (pker->wVirtualKeyCode == '2')
-       {
-           *pch = NUL;
-           return TRUE;
-       }
-       // Ctrl-- is Ctrl-_
-       else if (pker->wVirtualKeyCode == 0xBD)
-       {
-           *pch = Ctrl__;
-           return TRUE;
-       }
-     }
- 
      // Shift-TAB
      if (pker->wVirtualKeyCode == VK_TAB && (nModifs & SHIFT_PRESSED))
      {
--- 1106,1111 ----
***************
*** 1277,1289 ****
        ker.wVirtualKeyCode = vkCode;
        win32_kbd_patch_key(&ker);
  
!       for (int i = ARRAY_LENGTH(VirtKeyMap);
!            --i >= 0 && !ker.uChar.UnicodeChar; )
        {
            if (VirtKeyMap[i].wVirtKey == vkCode)
                ker.uChar.UnicodeChar = 0xfffd;  // REPLACEMENT CHARACTER
        }
  
        ir->Event.KeyEvent = ker;
        vim_free(event);
      }
--- 1252,1274 ----
        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
+ 
        ir->Event.KeyEvent = ker;
        vim_free(event);
      }
***************
*** 1919,1928 ****
  
      INPUT_RECORD ir;
      BOOL input_encoded = FALSE;
      if (STRCMP(event, "key") == 0)
!       input_encoded = encode_key_event(args, &ir);
      else if (STRCMP(event, "mouse") == 0)
        input_encoded = encode_mouse_event(args, &ir);
      else
      {
        semsg(_(e_invalid_value_for_argument_str_str), "event", event);
--- 1904,1926 ----
  
      INPUT_RECORD ir;
      BOOL input_encoded = FALSE;
+     BOOL execute = FALSE;
      if (STRCMP(event, "key") == 0)
!     {
!       execute = dict_get_bool(args, "execute", FALSE);
!       if (dict_has_key(args, "event"))
!           input_encoded = encode_key_event(args, &ir);
!       else if (!execute)
!       {
!           semsg(_(e_missing_argument_str), "event");
!           return FALSE;
!       }
!     }
      else if (STRCMP(event, "mouse") == 0)
+     {
+       execute = TRUE;
        input_encoded = encode_mouse_event(args, &ir);
+     }
      else
      {
        semsg(_(e_invalid_value_for_argument_str_str), "event", event);
***************
*** 1935,1942 ****
      if (input_encoded)
        lpEventsWritten = write_input_record_buffer(&ir, 1);
  
!     if (STRCMP(event, "mouse") == 0)
        exec_normal(TRUE, TRUE, TRUE);
  
  # endif
      return lpEventsWritten;
--- 1933,1948 ----
      if (input_encoded)
        lpEventsWritten = write_input_record_buffer(&ir, 1);
  
!     // Set flags to execute the event, ie. like feedkeys mode X.
!     if (execute)
!     {
!       int save_msg_scroll = msg_scroll;
!       // Avoid a 1 second delay when the keys start Insert mode.
!       msg_scroll = FALSE;
!       ch_log(NULL, "test_mswin_event() executing");
        exec_normal(TRUE, TRUE, TRUE);
+       msg_scroll |= save_msg_scroll;
+     }
  
  # endif
      return lpEventsWritten;
***************
*** 2426,2431 ****
--- 2432,2446 ----
  
            c = tgetch(&modifiers, &ch2);
  
+           // Some chars need adjustment when the Ctrl modifier is used.
+           ++no_reduce_keys;
+           c = may_adjust_key_for_ctrl(modifiers, c);
+           --no_reduce_keys;
+ 
+           // remove the SHIFT modifier for keys where it's already included,
+           // e.g., '(' and '*'
+           modifiers = may_remove_shift_modifier(modifiers, c);
+ 
            if (typebuf_changed(tb_change_cnt))
            {
                // "buf" may be invalid now if a client put something in the
*** ../vim-9.0.1111/src/testdir/test_gui.vim    2022-12-20 20:01:09.624090908 
+0000
--- src/testdir/test_gui.vim    2022-12-30 16:39:14.745599171 +0000
***************
*** 1694,1700 ****
      \ [[0x11, 0x10, 0x28], "C-S-Down", 4],
      \ [[0x11, 0x30], "C-0", 4],
      \ [[0x11, 0x31], "C-1", 4],
!     \ [[0x11, 0x32], "C-2", 4],
      \ [[0x11, 0x33], "C-3", 4],
      \ [[0x11, 0x34], "C-4", 4],
      \ [[0x11, 0x35], "C-5", 4],
--- 1694,1700 ----
      \ [[0x11, 0x10, 0x28], "C-S-Down", 4],
      \ [[0x11, 0x30], "C-0", 4],
      \ [[0x11, 0x31], "C-1", 4],
!     \ [[0x11, 0x32], "C-@", 0],
      \ [[0x11, 0x33], "C-3", 4],
      \ [[0x11, 0x34], "C-4", 4],
      \ [[0x11, 0x35], "C-5", 4],
***************
*** 1715,1720 ****
--- 1715,1721 ----
      \ [[0x11, 0x6A], "C-*", 4],
      \ [[0x11, 0x6B], "C-+", 4],
      \ [[0x11, 0x6D], "C--", 4],
+     \ [[0x11, 0xBD], "C-_", 0],
      \ [[0x11, 0x70], "C-F1", 4],
      \ [[0x11, 0x10, 0x70], "C-S-F1", 4],
      \ [[0x11, 0x71], "C-F2", 4],
*** ../vim-9.0.1111/src/testdir/test_mswin_event.vim    2022-12-20 
20:01:09.624090908 +0000
--- src/testdir/test_mswin_event.vim    2022-12-30 16:39:14.745599171 +0000
***************
*** 1,25 ****
! " Test MS-Windows console event handling.
  
  source check.vim
  CheckMSWindows
- " The mswin events should also work in gui
  
  source mouse.vim
  
! " Helper function for sending a sequence of low level key presses
! " The modifer key(s) can be included as normal key presses in the sequence
! func SendKeys(keylist)
!   for k in a:keylist
!     call test_mswin_event("key", #{event: "keydown", keycode: k})
    endfor
!   for k in reverse(copy(a:keylist))
!     call test_mswin_event("key", #{event: "keyup", keycode: k})
    endfor
  endfunc
  
! " Send an individual key press
  " the modifers for the key press can be specified in the modifiers arg.
! func SendKey(key, modifiers)
    let args = { }
    let args.keycode = a:key
    let args.modifiers = a:modifiers
--- 1,27 ----
! " Test MS-Windows input event handling.
! " Most of this works the same in Windows GUI as well as Windows console.
  
  source check.vim
  CheckMSWindows
  
  source mouse.vim
  
! " Helper function for sending a grouped sequence of low level key presses
! " The modifer key(s) can be included as VK Key Codes in the sequence
! " Keydown events will be sent, to to the end of the group, then keyup events
! " will be sent in reverse order to release the keys.
! func SendKeyGroup(keygroup)
!   for k in a:keygroup
!     call test_mswin_event("key", {'event': "keydown", 'keycode': k})
    endfor
!   for k in reverse(copy(a:keygroup))
!     call test_mswin_event("key", {'event': "keyup", 'keycode': k})
    endfor
  endfunc
  
! " Send individual key press and release events.
  " the modifers for the key press can be specified in the modifiers arg.
! func SendKeyWithModifiers(key, modifiers)
    let args = { }
    let args.keycode = a:key
    let args.modifiers = a:modifiers
***************
*** 30,260 ****
    unlet args
  endfunc
  
! " Test MS-Windows console key events
! func Test_mswin_key_event()
!   CheckMSWindows
!   new
  
!   " flush out any garbage left in the buffer
!   while getchar(0)
!   endwhile
  
!   let VK = #{
!       \ SPACE      : 0x20,
!       \ SHIFT      : 0x10,
!       \ LSHIFT     : 0xA0,
!       \ RSHIFT     : 0xA1,
!       \ CONTROL    : 0x11,
!       \ LCONTROL   : 0xA2,
!       \ RCONTROL   : 0xA3,
!       \ MENU       : 0x12,
!       \ ALT        : 0x12,
!       \ LMENU      : 0xA4,
!       \ LALT       : 0xA4,
!       \ RMENU      : 0xA5,
!       \ RALT       : 0xA5,
!       \ OEM_1      : 0xBA,
!       \ OEM_2      : 0xBF,
!       \ OEM_3      : 0xC0,
!       \ OEM_4      : 0xDB,
!       \ OEM_5      : 0xDC,
!       \ OEM_6      : 0xDD,
!       \ OEM_7      : 0xDE,
!       \ OEM_PLUS   : 0xBB,
!       \ OEM_COMMA  : 0xBC,
!       \ OEM_MINUS  : 0xBD,
!       \ OEM_PERIOD : 0xBE,
!       \ PRIOR      : 0x21,
!       \ NEXT       : 0x22,
!       \ END        : 0x23,
!       \ HOME       : 0x24,
!       \ LEFT       : 0x25,
!       \ UP         : 0x26,
!       \ RIGHT      : 0x27,
!       \ DOWN       : 0x28,
!       \ KEY_0      : 0x30,
!       \ KEY_1      : 0x31,
!       \ KEY_2      : 0x32,
!       \ KEY_3      : 0x33,
!       \ KEY_4      : 0x34,
!       \ KEY_5      : 0x35,
!       \ KEY_6      : 0x36,
!       \ KEY_7      : 0x37,
!       \ KEY_8      : 0x38,
!       \ KEY_9      : 0x39,
!       \ NUMPAD0    : 0x60,
!       \ NUMPAD1    : 0x61,
!       \ NUMPAD2    : 0x62,
!       \ NUMPAD3    : 0x63,
!       \ NUMPAD4    : 0x64,
!       \ NUMPAD5    : 0x65,
!       \ NUMPAD6    : 0x66,
!       \ NUMPAD7    : 0x67,
!       \ NUMPAD8    : 0x68,
!       \ NUMPAD9    : 0x69,
!       \ MULTIPLY   : 0x6A,
!       \ ADD        : 0x6B,
!       \ SUBTRACT   : 0x6D,
!       \ F1         : 0x70,
!       \ F2         : 0x71,
!       \ F3         : 0x72,
!       \ F4         : 0x73,
!       \ F5         : 0x74,
!       \ F6         : 0x75,
!       \ F7         : 0x76,
!       \ F8         : 0x77,
!       \ F9         : 0x78,
!       \ F10        : 0x79,
!       \ F11        : 0x7A,
!       \ F12        : 0x7B,
!       \ KEY_A      : 0x41,
!       \ KEY_B      : 0x42,
!       \ KEY_C      : 0x43,
!       \ KEY_D      : 0x44,
!       \ KEY_E      : 0x45,
!       \ KEY_F      : 0x46,
!       \ KEY_G      : 0x47,
!       \ KEY_H      : 0x48,
!       \ KEY_I      : 0x49,
!       \ KEY_J      : 0x4A,
!       \ KEY_K      : 0x4B,
!       \ KEY_L      : 0x4C,
!       \ KEY_M      : 0x4D,
!       \ KEY_N      : 0x4E,
!       \ KEY_O      : 0x4F,
!       \ KEY_P      : 0x50,
!       \ KEY_Q      : 0x51,
!       \ KEY_R      : 0x52,
!       \ KEY_S      : 0x53,
!       \ KEY_T      : 0x54,
!       \ KEY_U      : 0x55,
!       \ KEY_V      : 0x56,
!       \ KEY_W      : 0x57,
!       \ KEY_X      : 0x58,
!       \ KEY_Y      : 0x59,
!       \ KEY_Z      : 0x5A     
!       \ }
! 
!   let vim_MOD_MASK_SHIFT = 0x02
!   let vim_MOD_MASK_CTRL  = 0x04
!   let vim_MOD_MASK_ALT   = 0x08
    
!   let vim_key_modifiers = [
      \ ["",       0,   []],
!     \ ["S-",     2,   [VK.SHIFT]],
!     \ ["C-",     4,   [VK.CONTROL]],
!     \ ["C-S-",   6,   [VK.CONTROL, VK.SHIFT]],
!     \ ["A-",     8,   [VK.MENU]],
!     \ ["A-S-",   10,  [VK.MENU, VK.SHIFT]],
!     \ ["A-C-",   12,  [VK.MENU, VK.CONTROL]],
!     \ ["A-C-S-", 14,  [VK.MENU, VK.CONTROL, VK.SHIFT]],
      \]
  
-   " Some punctuation characters
    " Assuming Standard US PC Keyboard layout
!   let test_punctuation_keys = [
!       \ [[VK.SPACE], ' '],
!       \ [[VK.OEM_1], ';'],
!       \ [[VK.OEM_2], '/'],
!       \ [[VK.OEM_3], '`'],
!       \ [[VK.OEM_4], '['],
!       \ [[VK.OEM_5], '\'],
!       \ [[VK.OEM_6], ']'],
!       \ [[VK.OEM_7], ''''],
!       \ [[VK.OEM_PLUS], '='],
!       \ [[VK.OEM_COMMA], ','],
!       \ [[VK.OEM_MINUS], '-'],
!       \ [[VK.OEM_PERIOD], '.'],
!       \ [[VK.SHIFT, VK.OEM_1], ':'],
!       \ [[VK.SHIFT, VK.OEM_2], '?'],
!       \ [[VK.SHIFT, VK.OEM_3], '~'],
!       \ [[VK.SHIFT, VK.OEM_4], '{'],
!       \ [[VK.SHIFT, VK.OEM_5], '|'],
!       \ [[VK.SHIFT, VK.OEM_6], '}'],
!       \ [[VK.SHIFT, VK.OEM_7], '"'],
!       \ [[VK.SHIFT, VK.OEM_PLUS], '+'],
!       \ [[VK.SHIFT, VK.OEM_COMMA], '<'],
!       \ [[VK.SHIFT, VK.OEM_MINUS], '_'],
!       \ [[VK.SHIFT, VK.OEM_PERIOD], '>'],
!       \ [[VK.SHIFT, VK.KEY_1], '!'],
!       \ [[VK.SHIFT, VK.KEY_2], '@'],
!       \ [[VK.SHIFT, VK.KEY_3], '#'],
!       \ [[VK.SHIFT, VK.KEY_4], '$'],
!       \ [[VK.SHIFT, VK.KEY_5], '%'],
!       \ [[VK.SHIFT, VK.KEY_6], '^'],
!       \ [[VK.SHIFT, VK.KEY_7], '&'],
!       \ [[VK.SHIFT, VK.KEY_8], '*'],
!       \ [[VK.SHIFT, VK.KEY_9], '('],
!       \ [[VK.SHIFT, VK.KEY_0], ')'],
!       \ [[VK.LSHIFT, VK.KEY_9], '('],
!       \ [[VK.RSHIFT, VK.KEY_0], ')']
!       \ ]
  
!   for [kcodes, kstr] in test_punctuation_keys
!     call SendKeys(kcodes)
      let ch = getcharstr(0)
!     call assert_equal($"{kstr}", $"{ch}")
      let mod_mask = getcharmod()
      " the mod_mask is zero when no modifiers are used
!     " and when the virtual termcap maps shift the character
      call assert_equal(0, mod_mask, $"key = {kstr}")
-   endfor
-   
-   " flush out any garbage left in the buffer
-   while getchar(0)
-   endwhile
  
!   for [kcodes, kstr] in test_punctuation_keys
      let modifiers = 0
      let key = kcodes[0]
- 
      for key in kcodes
!       if index([VK.SHIFT, VK.LSHIFT, VK.RSHIFT], key) >= 0
!         let modifiers = modifiers + vim_MOD_MASK_SHIFT
        endif
!       if index([VK.CONTROL, VK.LCONTROL, VK.RCONTROL], key) >= 0
!         let modifiers = modifiers + vim_MOD_MASK_CTRL
        endif
!       if index([VK.ALT, VK.LALT, VK.RALT], key) >= 0
!         let modifiers = modifiers + vim_MOD_MASK_ALT
        endif
      endfor
! 
!     call SendKey(key, modifiers)
      let ch = getcharstr(0)
!     call assert_equal($"{kstr}", $"{ch}")
!     let mod_mask = getcharmod()
!     " workaround for the virtual termcap maps changing the character instead
!     " of sending Shift
!     if index([VK.SHIFT, VK.LSHIFT, VK.RSHIFT], kcodes[0]) >= 0
!       let modifiers = modifiers - vim_MOD_MASK_SHIFT
      endif
!     call assert_equal(modifiers, mod_mask, $"key = {kstr}")
    endfor
  
    " flush out any garbage left in the buffer
    while getchar(0)
    endwhile
  
  " Test keyboard codes for digits
  " (0x30 - 0x39) : VK_0 - VK_9 are the same as ASCII '0' - '9'
    for kc in range(48, 57)
!     call SendKeys([kc])
      let ch = getcharstr(0)
      call assert_equal(nr2char(kc), ch)
!     call SendKey(kc, 0)
      let ch = getcharstr(0)
      call assert_equal(nr2char(kc), ch)
    endfor
  
  " Test keyboard codes for Alt-0 to Alt-9
  " Expect +128 from the digit char codes
!   for modkey in [VK.ALT, VK.LALT, VK.RALT]
      for kc in range(48, 57)
!       call SendKeys([modkey, kc])
        let ch = getchar(0)
        call assert_equal(kc+128, ch)
!       call SendKey(kc, vim_MOD_MASK_ALT)
        let ch = getchar(0)
        call assert_equal(kc+128, ch)
      endfor
--- 32,430 ----
    unlet args
  endfunc
  
! " Send an individual key press, without modifiers.
! func SendKey(key)
!   call SendKeyWithModifiers(a:key, 0)
! endfunc
  
! " Send a string of individual key-press events, without modifiers.
! func SendKeyStr(keystring)
!   for k in a:keystring
!     call SendKey(k)
!   endfor
! endfunc
! 
! " This tells Vim to execute the buffered keys as user commands, 
! " ie. same as feekdeys with mode X would do.
! func ExecuteBufferedKeys()
!   if has('gui_running')
!     call feedkeys("\<Esc>", 'Lx!')
!   else
!     call test_mswin_event("key", {'execute': v:true})
!   endif
! endfunc
  
! 
! let s:VK = {
!     \ 'ENTER'      : 0x0D,
!     \ 'SPACE'      : 0x20,
!     \ 'SHIFT'      : 0x10,
!     \ 'LSHIFT'     : 0xA0,
!     \ 'RSHIFT'     : 0xA1,
!     \ 'CONTROL'    : 0x11,
!     \ 'LCONTROL'   : 0xA2,
!     \ 'RCONTROL'   : 0xA3,
!     \ 'MENU'       : 0x12,
!     \ 'ALT'        : 0x12,
!     \ 'LMENU'      : 0xA4,
!     \ 'LALT'       : 0xA4,
!     \ 'RMENU'      : 0xA5,
!     \ 'RALT'       : 0xA5,
!     \ 'OEM_1'      : 0xBA,
!     \ 'OEM_2'      : 0xBF,
!     \ 'OEM_3'      : 0xC0,
!     \ 'OEM_4'      : 0xDB,
!     \ 'OEM_5'      : 0xDC,
!     \ 'OEM_6'      : 0xDD,
!     \ 'OEM_7'      : 0xDE,
!     \ 'OEM_PLUS'   : 0xBB,
!     \ 'OEM_COMMA'  : 0xBC,
!     \ 'OEM_MINUS'  : 0xBD,
!     \ 'OEM_PERIOD' : 0xBE,
!     \ 'PRIOR'      : 0x21,
!     \ 'NEXT'       : 0x22,
!     \ 'END'        : 0x23,
!     \ 'HOME'       : 0x24,
!     \ 'LEFT'       : 0x25,
!     \ 'UP'         : 0x26,
!     \ 'RIGHT'      : 0x27,
!     \ 'DOWN'       : 0x28,
!     \ 'KEY_0'      : 0x30,
!     \ 'KEY_1'      : 0x31,
!     \ 'KEY_2'      : 0x32,
!     \ 'KEY_3'      : 0x33,
!     \ 'KEY_4'      : 0x34,
!     \ 'KEY_5'      : 0x35,
!     \ 'KEY_6'      : 0x36,
!     \ 'KEY_7'      : 0x37,
!     \ 'KEY_8'      : 0x38,
!     \ 'KEY_9'      : 0x39,
!     \ 'KEY_A'      : 0x41,
!     \ 'KEY_B'      : 0x42,
!     \ 'KEY_C'      : 0x43,
!     \ 'KEY_D'      : 0x44,
!     \ 'KEY_E'      : 0x45,
!     \ 'KEY_F'      : 0x46,
!     \ 'KEY_G'      : 0x47,
!     \ 'KEY_H'      : 0x48,
!     \ 'KEY_I'      : 0x49,
!     \ 'KEY_J'      : 0x4A,
!     \ 'KEY_K'      : 0x4B,
!     \ 'KEY_L'      : 0x4C,
!     \ 'KEY_M'      : 0x4D,
!     \ 'KEY_N'      : 0x4E,
!     \ 'KEY_O'      : 0x4F,
!     \ 'KEY_P'      : 0x50,
!     \ 'KEY_Q'      : 0x51,
!     \ 'KEY_R'      : 0x52,
!     \ 'KEY_S'      : 0x53,
!     \ 'KEY_T'      : 0x54,
!     \ 'KEY_U'      : 0x55,
!     \ 'KEY_V'      : 0x56,
!     \ 'KEY_W'      : 0x57,
!     \ 'KEY_X'      : 0x58,
!     \ 'KEY_Y'      : 0x59,
!     \ 'KEY_Z'      : 0x5A,
!     \ 'NUMPAD0'    : 0x60,
!     \ 'NUMPAD1'    : 0x61,
!     \ 'NUMPAD2'    : 0x62,
!     \ 'NUMPAD3'    : 0x63,
!     \ 'NUMPAD4'    : 0x64,
!     \ 'NUMPAD5'    : 0x65,
!     \ 'NUMPAD6'    : 0x66,
!     \ 'NUMPAD7'    : 0x67,
!     \ 'NUMPAD8'    : 0x68,
!     \ 'NUMPAD9'    : 0x69,
!     \ 'MULTIPLY'   : 0x6A,
!     \ 'ADD'        : 0x6B,
!     \ 'SUBTRACT'   : 0x6D,
!     \ 'F1'         : 0x70,
!     \ 'F2'         : 0x71,
!     \ 'F3'         : 0x72,
!     \ 'F4'         : 0x73,
!     \ 'F5'         : 0x74,
!     \ 'F6'         : 0x75,
!     \ 'F7'         : 0x76,
!     \ 'F8'         : 0x77,
!     \ 'F9'         : 0x78,
!     \ 'F10'        : 0x79,
!     \ 'F11'        : 0x7A,
!     \ 'F12'        : 0x7B,
!     \ 'DELETE'     : 0x2E,
!     \ 'BACK'       : 0x08,
!     \ 'ESCAPE'     : 0x1B
!     \ }
! 
!   let s:vim_MOD_MASK_SHIFT = 0x02
!   let s:vim_MOD_MASK_CTRL  = 0x04
!   let s:vim_MOD_MASK_ALT   = 0x08
    
!   let s:vim_key_modifiers = [
      \ ["",       0,   []],
!     \ ["S-",     2,   [s:VK.SHIFT]],
!     \ ["C-",     4,   [s:VK.CONTROL]],
!     \ ["C-S-",   6,   [s:VK.CONTROL, s:VK.SHIFT]],
!     \ ["A-",     8,   [s:VK.MENU]],
!     \ ["A-S-",   10,  [s:VK.MENU, s:VK.SHIFT]],
!     \ ["A-C-",   12,  [s:VK.MENU, s:VK.CONTROL]],
!     \ ["A-C-S-", 14,  [s:VK.MENU, s:VK.CONTROL, s:VK.SHIFT]],
      \]
  
    " Assuming Standard US PC Keyboard layout
!   let s:test_ascii_key_chars = [
!     \ [[s:VK.SPACE], ' '],
!     \ [[s:VK.OEM_1], ';'],
!     \ [[s:VK.OEM_2], '/'],
!     \ [[s:VK.OEM_3], '`'],
!     \ [[s:VK.OEM_4], '['],
!     \ [[s:VK.OEM_5], '\'],
!     \ [[s:VK.OEM_6], ']'],
!     \ [[s:VK.OEM_7], ''''],
!     \ [[s:VK.OEM_PLUS], '='],
!     \ [[s:VK.OEM_COMMA], ','],
!     \ [[s:VK.OEM_MINUS], '-'],
!     \ [[s:VK.OEM_PERIOD], '.'],
!     \ [[s:VK.SHIFT, s:VK.OEM_1], ':'],
!     \ [[s:VK.SHIFT, s:VK.OEM_2], '?'],
!     \ [[s:VK.SHIFT, s:VK.OEM_3], '~'],
!     \ [[s:VK.SHIFT, s:VK.OEM_4], '{'],
!     \ [[s:VK.SHIFT, s:VK.OEM_5], '|'],
!     \ [[s:VK.SHIFT, s:VK.OEM_6], '}'],
!     \ [[s:VK.SHIFT, s:VK.OEM_7], '"'],
!     \ [[s:VK.SHIFT, s:VK.OEM_PLUS], '+'],
!     \ [[s:VK.SHIFT, s:VK.OEM_COMMA], '<'],
!     \ [[s:VK.SHIFT, s:VK.OEM_MINUS], '_'],
!     \ [[s:VK.SHIFT, s:VK.OEM_PERIOD], '>'],
!     \ [[s:VK.KEY_1], '1'],
!     \ [[s:VK.KEY_2], '2'],
!     \ [[s:VK.KEY_3], '3'],
!     \ [[s:VK.KEY_4], '4'],
!     \ [[s:VK.KEY_5], '5'],
!     \ [[s:VK.KEY_6], '6'],
!     \ [[s:VK.KEY_7], '7'],
!     \ [[s:VK.KEY_8], '8'],
!     \ [[s:VK.KEY_9], '9'],
!     \ [[s:VK.KEY_0], '0'],
!     \ [[s:VK.SHIFT, s:VK.KEY_1], '!'],
!     \ [[s:VK.SHIFT, s:VK.KEY_2], '@'],
!     \ [[s:VK.SHIFT, s:VK.KEY_3], '#'],
!     \ [[s:VK.SHIFT, s:VK.KEY_4], '$'],
!     \ [[s:VK.SHIFT, s:VK.KEY_5], '%'],
!     \ [[s:VK.SHIFT, s:VK.KEY_6], '^'],
!     \ [[s:VK.SHIFT, s:VK.KEY_7], '&'],
!     \ [[s:VK.SHIFT, s:VK.KEY_8], '*'],
!     \ [[s:VK.SHIFT, s:VK.KEY_9], '('],
!     \ [[s:VK.SHIFT, s:VK.KEY_0], ')'],
!     \ [[s:VK.KEY_A], 'a'],
!     \ [[s:VK.KEY_B], 'b'],
!     \ [[s:VK.KEY_C], 'c'],
!     \ [[s:VK.KEY_D], 'd'],
!     \ [[s:VK.KEY_E], 'e'],
!     \ [[s:VK.KEY_F], 'f'],
!     \ [[s:VK.KEY_G], 'g'],
!     \ [[s:VK.KEY_H], 'h'],
!     \ [[s:VK.KEY_I], 'i'],
!     \ [[s:VK.KEY_J], 'j'],
!     \ [[s:VK.KEY_K], 'k'],
!     \ [[s:VK.KEY_L], 'l'],
!     \ [[s:VK.KEY_M], 'm'],
!     \ [[s:VK.KEY_N], 'n'],
!     \ [[s:VK.KEY_O], 'o'],
!     \ [[s:VK.KEY_P], 'p'],
!     \ [[s:VK.KEY_Q], 'q'],
!     \ [[s:VK.KEY_R], 'r'],
!     \ [[s:VK.KEY_S], 's'],
!     \ [[s:VK.KEY_T], 't'],
!     \ [[s:VK.KEY_U], 'u'],
!     \ [[s:VK.KEY_V], 'v'],
!     \ [[s:VK.KEY_W], 'w'],
!     \ [[s:VK.KEY_X], 'x'],
!     \ [[s:VK.KEY_Y], 'y'],
!     \ [[s:VK.KEY_Z], 'z'],
!     \ [[s:VK.SHIFT, s:VK.KEY_A], 'A'],
!     \ [[s:VK.SHIFT, s:VK.KEY_B], 'B'],
!     \ [[s:VK.SHIFT, s:VK.KEY_C], 'C'],
!     \ [[s:VK.SHIFT, s:VK.KEY_D], 'D'],
!     \ [[s:VK.SHIFT, s:VK.KEY_E], 'E'],
!     \ [[s:VK.SHIFT, s:VK.KEY_F], 'F'],
!     \ [[s:VK.SHIFT, s:VK.KEY_G], 'G'],
!     \ [[s:VK.SHIFT, s:VK.KEY_H], 'H'],
!     \ [[s:VK.SHIFT, s:VK.KEY_I], 'I'],
!     \ [[s:VK.SHIFT, s:VK.KEY_J], 'J'],
!     \ [[s:VK.SHIFT, s:VK.KEY_K], 'K'],
!     \ [[s:VK.SHIFT, s:VK.KEY_L], 'L'],
!     \ [[s:VK.SHIFT, s:VK.KEY_M], 'M'],
!     \ [[s:VK.SHIFT, s:VK.KEY_N], 'N'],
!     \ [[s:VK.SHIFT, s:VK.KEY_O], 'O'],
!     \ [[s:VK.SHIFT, s:VK.KEY_P], 'P'],
!     \ [[s:VK.SHIFT, s:VK.KEY_Q], 'Q'],
!     \ [[s:VK.SHIFT, s:VK.KEY_R], 'R'],
!     \ [[s:VK.SHIFT, s:VK.KEY_S], 'S'],
!     \ [[s:VK.SHIFT, s:VK.KEY_T], 'T'],
!     \ [[s:VK.SHIFT, s:VK.KEY_U], 'U'],
!     \ [[s:VK.SHIFT, s:VK.KEY_V], 'V'],
!     \ [[s:VK.SHIFT, s:VK.KEY_W], 'W'],
!     \ [[s:VK.SHIFT, s:VK.KEY_X], 'X'],
!     \ [[s:VK.SHIFT, s:VK.KEY_Y], 'Y'],
!     \ [[s:VK.SHIFT, s:VK.KEY_Z], 'Z'],
!     \ [[s:VK.CONTROL, s:VK.KEY_A], 0x01],
!     \ [[s:VK.CONTROL, s:VK.KEY_B], 0x02],
!     \ [[s:VK.CONTROL, s:VK.KEY_C], 0x03],
!     \ [[s:VK.CONTROL, s:VK.KEY_D], 0x04],
!     \ [[s:VK.CONTROL, s:VK.KEY_E], 0x05],
!     \ [[s:VK.CONTROL, s:VK.KEY_F], 0x06],
!     \ [[s:VK.CONTROL, s:VK.KEY_G], 0x07],
!     \ [[s:VK.CONTROL, s:VK.KEY_H], 0x08],
!     \ [[s:VK.CONTROL, s:VK.KEY_I], 0x09],
!     \ [[s:VK.CONTROL, s:VK.KEY_J], 0x0A],
!     \ [[s:VK.CONTROL, s:VK.KEY_K], 0x0B],
!     \ [[s:VK.CONTROL, s:VK.KEY_L], 0x0C],
!     \ [[s:VK.CONTROL, s:VK.KEY_M], 0x0D],
!     \ [[s:VK.CONTROL, s:VK.KEY_N], 0x0E],
!     \ [[s:VK.CONTROL, s:VK.KEY_O], 0x0F],
!     \ [[s:VK.CONTROL, s:VK.KEY_P], 0x10],
!     \ [[s:VK.CONTROL, s:VK.KEY_Q], 0x11],
!     \ [[s:VK.CONTROL, s:VK.KEY_R], 0x12],
!     \ [[s:VK.CONTROL, s:VK.KEY_S], 0x13],
!     \ [[s:VK.CONTROL, s:VK.KEY_T], 0x14],
!     \ [[s:VK.CONTROL, s:VK.KEY_U], 0x15],
!     \ [[s:VK.CONTROL, s:VK.KEY_V], 0x16],
!     \ [[s:VK.CONTROL, s:VK.KEY_W], 0x17],
!     \ [[s:VK.CONTROL, s:VK.KEY_X], 0x18],
!     \ [[s:VK.CONTROL, s:VK.KEY_Y], 0x19],
!     \ [[s:VK.CONTROL, s:VK.KEY_Z], 0x1A],
!     \ [[s:VK.CONTROL, s:VK.OEM_4], 0x1B],
!     \ [[s:VK.CONTROL, s:VK.OEM_5], 0x1C],
!     \ [[s:VK.CONTROL, s:VK.OEM_6], 0x1D],
!     \ ]
! " 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], '±'],
!     \ [[s:VK.ALT, s:VK.KEY_2], '²'],
!     \ [[s:VK.ALT, s:VK.KEY_3], '³'],
!     \ [[s:VK.ALT, s:VK.KEY_4], '´'],
!     \ [[s:VK.ALT, s:VK.KEY_5], 'µ'],
!     \ [[s:VK.ALT, s:VK.KEY_6], '¶'],
!     \ [[s:VK.ALT, s:VK.KEY_7], '·'],
!     \ [[s:VK.ALT, s:VK.KEY_8], '¸'],
!     \ [[s:VK.ALT, s:VK.KEY_9], '¹'],
!     \ [[s:VK.ALT, s:VK.KEY_0], '°'],
!     \ [[s:VK.ALT, s:VK.KEY_A], 'á'],
!     \ [[s:VK.ALT, s:VK.KEY_B], 'â'],
!     \ [[s:VK.ALT, s:VK.KEY_C], 'ã'],
!     \ [[s:VK.ALT, s:VK.KEY_D], 'ä'],
!     \ [[s:VK.ALT, s:VK.KEY_E], 'å'],
!     \ [[s:VK.ALT, s:VK.KEY_F], 'æ'],
!     \ [[s:VK.ALT, s:VK.KEY_G], 'ç'],
!     \ [[s:VK.ALT, s:VK.KEY_H], 'è'],
!     \ [[s:VK.ALT, s:VK.KEY_I], 'é'],
!     \ [[s:VK.ALT, s:VK.KEY_J], 'ê'],
!     \ [[s:VK.ALT, s:VK.KEY_K], 'ë'],
!     \ [[s:VK.ALT, s:VK.KEY_L], 'ì'],
!     \ [[s:VK.ALT, s:VK.KEY_M], 'í'],
!     \ [[s:VK.ALT, s:VK.KEY_N], 'î'],
!     \ [[s:VK.ALT, s:VK.KEY_O], 'ï'],
!     \ [[s:VK.ALT, s:VK.KEY_P], 'ð'],
!     \ [[s:VK.ALT, s:VK.KEY_Q], 'ñ'],
!     \ [[s:VK.ALT, s:VK.KEY_R], 'ò'],
!     \ [[s:VK.ALT, s:VK.KEY_S], 'ó'],
!     \ [[s:VK.ALT, s:VK.KEY_T], 'ô'],
!     \ [[s:VK.ALT, s:VK.KEY_U], 'õ'],
!     \ [[s:VK.ALT, s:VK.KEY_V], 'ö'],
!     \ [[s:VK.ALT, s:VK.KEY_W], '÷'],
!     \ [[s:VK.ALT, s:VK.KEY_X], 'ø'],
!     \ [[s:VK.ALT, s:VK.KEY_Y], 'ù'],
!     \ [[s:VK.ALT, s:VK.KEY_Z], 'ú'],
!     \ ]
! 
! func s:LoopTestKeyArray(arr)
! " flush out any garbage left in the buffer
!   while getchar(0)
!   endwhile
  
!   for [kcodes, kstr] in a:arr
!     " Send as a sequence of key presses.
!     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
!       call assert_equal(nr2char(kstr), $"{ch}")
!     else
!       call assert_equal(kstr, $"{ch}")
!     endif
      let mod_mask = getcharmod()
      " the mod_mask is zero when no modifiers are used
!     " and when the virtual termcap maps the character
      call assert_equal(0, mod_mask, $"key = {kstr}")
  
!     " Send as a single key press with a modifers mask.
      let modifiers = 0
      let key = kcodes[0]
      for key in kcodes
!       if index([s:VK.SHIFT, s:VK.LSHIFT, s:VK.RSHIFT], key) >= 0
!         let modifiers = modifiers + s:vim_MOD_MASK_SHIFT
        endif
!       if index([s:VK.CONTROL, s:VK.LCONTROL, s:VK.RCONTROL], key) >= 0
!         let modifiers = modifiers + s:vim_MOD_MASK_CTRL
        endif
!       if index([s:VK.ALT, s:VK.LALT, s:VK.RALT], key) >= 0
!         let modifiers = modifiers + s:vim_MOD_MASK_ALT
        endif
      endfor
!     call SendKeyWithModifiers(key, modifiers)
      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
!       call assert_equal(nr2char(kstr), $"{ch}")
!     else
!       call assert_equal(kstr, $"{ch}")
      endif
!     let mod_mask = getcharmod()
!     " the mod_mask is zero when no modifiers are used
!     " and when the virtual termcap maps the character
!     call assert_equal(0, mod_mask, $"key = {kstr}")
    endfor
  
    " flush out any garbage left in the buffer
    while getchar(0)
    endwhile
  
+ endfunc
+ 
+ " Test MS-Windows key events
+ func Test_mswin_key_event()
+   CheckMSWindows
+   new
+ 
+   call s:LoopTestKeyArray(s:test_ascii_key_chars)
+ 
+   if !has('gui_running')
+     call s:LoopTestKeyArray(s:test_extra_key_chars)
+   endif
+ 
  " Test keyboard codes for digits
  " (0x30 - 0x39) : VK_0 - VK_9 are the same as ASCII '0' - '9'
    for kc in range(48, 57)
!     call SendKey(kc)
      let ch = getcharstr(0)
      call assert_equal(nr2char(kc), ch)
!     call SendKeyWithModifiers(kc, 0)
      let ch = getcharstr(0)
      call assert_equal(nr2char(kc), ch)
    endfor
  
  " Test keyboard codes for Alt-0 to Alt-9
  " Expect +128 from the digit char codes
!   for modkey in [s:VK.ALT, s:VK.LALT, s:VK.RALT]
      for kc in range(48, 57)
!       call SendKeyGroup([modkey, kc])
        let ch = getchar(0)
        call assert_equal(kc+128, ch)
!       call SendKeyWithModifiers(kc, s:vim_MOD_MASK_ALT)
        let ch = getchar(0)
        call assert_equal(kc+128, ch)
      endfor
***************
*** 268,335 ****
  " char 'a' (91) as the output.  The ASCII codes for the lowercase letters are
  " numbered 32 higher than their uppercase versions.
    for kc in range(65, 90)
!     call SendKeys([kc])
      let ch = getcharstr(0)
      call assert_equal(nr2char(kc + 32), ch)
!     call SendKey(kc, 0)
      let ch = getcharstr(0)
      call assert_equal(nr2char(kc + 32), ch)
    endfor
  
  "  Test for Uppercase 'A' - 'Z' keys
  "  ie. with VK_SHIFT, expect the keycode = character code.
!   for kc in range(65, 90)
!     call SendKeys([VK.SHIFT, kc])
!     let ch = getcharstr(0)
!     call assert_equal(nr2char(kc), ch)
!     call SendKey(kc, vim_MOD_MASK_SHIFT)
!     let ch = getcharstr(0)
!     call assert_equal(nr2char(kc), ch)
    endfor
  
    " Test for <Ctrl-A> to <Ctrl-Z> keys
-  "  Same as for lowercase, except with Ctrl Key
   "  Expect the unicode characters 0x01 to 0x1A
!    for modkey in [VK.CONTROL, VK.LCONTROL, VK.RCONTROL]
      for kc in range(65, 90)
!       call SendKeys([modkey, kc])
        let ch = getcharstr(0)
        call assert_equal(nr2char(kc - 64), ch)
!       call SendKey(kc, vim_MOD_MASK_CTRL)
        let ch = getcharstr(0)
        call assert_equal(nr2char(kc - 64), ch)
      endfor
    endfor
  
    if !has("gui_running")
!   " Test for <Alt-A> to <Alt-Z> keys
    "  Expect the unicode characters 0xE1 to 0xFA
    "  ie. 160 higher than the lowercase equivalent
!     for kc in range(65, 90)
!       call SendKeys([VK.LMENU, kc])
!       let ch = getchar(0)
!       call assert_equal(kc+160, ch)
!       call SendKey(kc, vim_MOD_MASK_ALT)
!       let ch = getchar(0)
!       call assert_equal(kc+160, ch)
      endfor
    endif
  
    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 SendKeys([111+n])
        let ch = getcharstr(0)
        call assert_equal(keycode, $"{ch}", $"key = <{kstr}>")
      endfor
    endif
  
    bw!
  endfunc
  
! "  Test MS-Windows console mouse events
  func Test_mswin_mouse_event()
    CheckMSWindows
    new
--- 438,646 ----
  " char 'a' (91) as the output.  The ASCII codes for the lowercase letters are
  " numbered 32 higher than their uppercase versions.
    for kc in range(65, 90)
!     call SendKey(kc)
      let ch = getcharstr(0)
      call assert_equal(nr2char(kc + 32), ch)
!     call SendKeyWithModifiers(kc, 0)
      let ch = getcharstr(0)
      call assert_equal(nr2char(kc + 32), ch)
    endfor
  
  "  Test for Uppercase 'A' - 'Z' keys
  "  ie. with VK_SHIFT, expect the keycode = character code.
!   for modkey in [s:VK.SHIFT, s:VK.LSHIFT, s:VK.RSHIFT]
!     for kc in range(65, 90)
!       call SendKeyGroup([modkey, kc])
!       let ch = getcharstr(0)
!       call assert_equal(nr2char(kc), ch)
!       call SendKeyWithModifiers(kc, s:vim_MOD_MASK_SHIFT)
!       let ch = getcharstr(0)
!       call assert_equal(nr2char(kc), ch)
!     endfor
    endfor
  
    " Test for <Ctrl-A> to <Ctrl-Z> keys
   "  Expect the unicode characters 0x01 to 0x1A
!    for modkey in [s:VK.CONTROL, s:VK.LCONTROL, s:VK.RCONTROL]
      for kc in range(65, 90)
!       call SendKeyGroup([modkey, kc])
        let ch = getcharstr(0)
        call assert_equal(nr2char(kc - 64), ch)
!       call SendKeyWithModifiers(kc, s:vim_MOD_MASK_CTRL)
        let ch = getcharstr(0)
        call assert_equal(nr2char(kc - 64), ch)
      endfor
    endfor
  
+   "  Windows intercepts some of these keys in the GUI.
    if !has("gui_running")
!   "  Test for <Alt-A> to <Alt-Z> keys
    "  Expect the unicode characters 0xE1 to 0xFA
    "  ie. 160 higher than the lowercase equivalent
!     for modkey in [s:VK.ALT, s:VK.LALT, s:VK.RALT]
!       for kc in range(65, 90)
!         call SendKeyGroup([modkey, kc])
!         let ch = getchar(0)
!         call assert_equal(kc+160, ch)
!         call SendKeyWithModifiers(kc, s:vim_MOD_MASK_ALT)
!         let ch = getchar(0)
!         call assert_equal(kc+160, ch)
!       endfor
      endfor
    endif
  
+   " 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 .. '>"')
+         " 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}")
+         " workaround for the virtual termcap maps changing the character 
instead
+         " of sending Shift
+         for mod_key in mod_keycodes
+           if index([s:VK.SHIFT, s:VK.LSHIFT, s:VK.RSHIFT], mod_key) >= 0
+             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}")
+       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],
+     \ [[s:VK.RSHIFT,   s:VK.PRIOR], "S-Pageup", 2],
+     \ [[s:VK.CONTROL,  s:VK.PRIOR], "C-Pageup", 4],
+     \ [[s:VK.LCONTROL, s:VK.PRIOR], "C-Pageup", 4],
+     \ [[s:VK.RCONTROL, s:VK.PRIOR], "C-Pageup", 4],
+     \ [[s:VK.CONTROL,  s:VK.SHIFT, s:VK.PRIOR], "C-S-Pageup", 6],
+     \ [[s:VK.SHIFT,    s:VK.NEXT], "S-PageDown", 2],
+     \ [[s:VK.LSHIFT,   s:VK.NEXT], "S-PageDown", 2],
+     \ [[s:VK.RSHIFT,   s:VK.NEXT], "S-PageDown", 2],
+     \ [[s:VK.CONTROL,  s:VK.NEXT], "C-PageDown", 4],
+     \ [[s:VK.LCONTROL, s:VK.NEXT], "C-PageDown", 4],
+     \ [[s:VK.RCONTROL, s:VK.NEXT], "C-PageDown", 4],
+     \ [[s:VK.CONTROL,  s:VK.SHIFT, s:VK.NEXT], "C-S-PageDown", 6],
+     \ [[s:VK.SHIFT,    s:VK.END], "S-End", 0],
+     \ [[s:VK.CONTROL,  s:VK.END], "C-End", 0],
+     \ [[s:VK.CONTROL,  s:VK.SHIFT, s:VK.END], "C-S-End", 4],
+     \ [[s:VK.SHIFT,    s:VK.HOME], "S-Home", 0],
+     \ [[s:VK.CONTROL,  s:VK.HOME], "C-Home", 0],
+     \ [[s:VK.CONTROL,  s:VK.SHIFT, s:VK.HOME], "C-S-Home", 4],
+     \ [[s:VK.SHIFT,    s:VK.LEFT], "S-Left", 0],
+     \ [[s:VK.CONTROL,  s:VK.LEFT], "C-Left", 0],
+     \ [[s:VK.CONTROL,  s:VK.SHIFT, s:VK.LEFT], "C-S-Left", 4],
+     \ [[s:VK.SHIFT,    s:VK.UP], "S-Up", 0],
+     \ [[s:VK.CONTROL,  s:VK.UP], "C-Up", 4],
+     \ [[s:VK.CONTROL,  s:VK.SHIFT, s:VK.UP], "C-S-Up", 4],
+     \ [[s:VK.SHIFT,    s:VK.RIGHT], "S-Right", 0],
+     \ [[s:VK.CONTROL,  s:VK.RIGHT], "C-Right", 0],
+     \ [[s:VK.CONTROL,  s:VK.SHIFT, s:VK.RIGHT], "C-S-Right", 4],
+     \ [[s:VK.SHIFT,    s:VK.DOWN], "S-Down", 0],
+     \ [[s:VK.CONTROL,  s:VK.DOWN], "C-Down", 4],
+     \ [[s:VK.CONTROL,  s:VK.SHIFT, s:VK.DOWN], "C-S-Down", 4],
+     \ [[s:VK.CONTROL,  s:VK.KEY_0], "C-0", 4],
+     \ [[s:VK.CONTROL,  s:VK.KEY_1], "C-1", 4],
+     \ [[s:VK.CONTROL,  s:VK.KEY_2], "C-@", 0],
+     \ [[s:VK.CONTROL,  s:VK.KEY_3], "C-3", 4],
+     \ [[s:VK.CONTROL,  s:VK.KEY_4], "C-4", 4],
+     \ [[s:VK.CONTROL,  s:VK.KEY_5], "C-5", 4],
+     \ [[s:VK.CONTROL,  s:VK.KEY_6], "C-^", 0],
+     \ [[s:VK.CONTROL,  s:VK.KEY_7], "C-7", 4],
+     \ [[s:VK.CONTROL,  s:VK.KEY_8], "C-8", 4],
+     \ [[s:VK.CONTROL,  s:VK.KEY_9], "C-9", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD0], "C-0", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD1], "C-1", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD2], "C-2", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD3], "C-3", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD4], "C-4", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD5], "C-5", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD6], "C-6", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD7], "C-7", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD8], "C-8", 4],
+     \ [[s:VK.CONTROL,  s:VK.NUMPAD9], "C-9", 4],
+     \ [[s:VK.CONTROL,  s:VK.MULTIPLY], "C-*", 4],
+     \ [[s:VK.CONTROL,  s:VK.ADD], "C-+", 4],
+     \ [[s:VK.CONTROL,  s:VK.SUBTRACT], "C--", 4],
+     \ [[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}")
+   endfor
+ 
+   bw!
+ endfunc
+ 
+ 
+ " Test for QWERTY Ctrl+- which should result in ^_
+ " issue #10817
+ func Test_QWERTY_Ctrl_minus()
+   CheckMSWindows
+   new
+ 
+   call SendKeyGroup([s:VK.CONTROL, s:VK.OEM_MINUS])
+   let ch = getcharstr(0)
+   call assert_equal(nr2char(0x1f),ch)
+ 
+   call SendKey(s:VK.KEY_I)
+   call SendKeyGroup([s:VK.CONTROL, s:VK.SUBTRACT])
+   call SendKey(s:VK.ESCAPE)
+   call ExecuteBufferedKeys()
+   call assert_equal('-', getline('$'))
+ 
+   %d _
+   imapclear
+   imap <C-_> BINGO
+   call SendKey(s:VK.KEY_I)
+   call SendKeyGroup([s:VK.CONTROL, s:VK.OEM_MINUS])
+   call SendKey(s:VK.ESCAPE)
+   call ExecuteBufferedKeys()
+   call assert_equal('BINGO', getline('$'))
+ 
+   %d _
+   imapclear
+   exec "imap \x1f BILBO"
+   call SendKey(s:VK.KEY_I)
+   call SendKeyGroup([s:VK.CONTROL, s:VK.OEM_MINUS])
+   call SendKey(s:VK.ESCAPE)
+   call ExecuteBufferedKeys()
+   call assert_equal('BILBO', getline('$'))
+ 
+ 
+ 
+   imapclear
    bw!
  endfunc
  
! "  Test MS-Windows mouse events
  func Test_mswin_mouse_event()
    CheckMSWindows
    new
*** ../vim-9.0.1111/src/version.c       2022-12-30 11:15:56.462953467 +0000
--- src/version.c       2022-12-30 16:53:28.940988632 +0000
***************
*** 697,698 ****
--- 697,700 ----
  {   /* Add new patch number below this line */
+ /**/
+     1112,
  /**/

-- 
It is illegal for anyone to try and stop a child from playfully jumping over
puddles of water.
                [real standing law in California, United States of America]

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20221230165532.A87DB1C0AA3%40moolenaar.net.

Raspunde prin e-mail lui