view src/testdir/test_mswin_event.vim @ 31525:f7c82a85e88a v9.0.1095

patch 9.0.1095: using freed memory when declaration fails Commit: https://github.com/vim/vim/commit/6ef5471afa69a654888bc285a51a6035405d33a0 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Dec 25 19:31:36 2022 +0000 patch 9.0.1095: using freed memory when declaration fails Problem: Using freed memory when declaration fails. (Yegappan Lakshmanan) Solution: After unreferencing an object set the reference to NULL.
author Bram Moolenaar <Bram@vim.org>
date Sun, 25 Dec 2022 20:45:04 +0100
parents b9a4699d6a35
children a3dca61f3ba3
line wrap: on
line source

" 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
  let args.event = "keydown"
  call test_mswin_event("key", args)
  let args.event = "keyup"
  call test_mswin_event("key", args)
  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
  endfor

" Test for lowercase 'a' to 'z', VK codes 65(0x41) - 90(0x5A)
" Note: VK_A-VK_Z virtual key codes coincide with uppercase ASCII codes A-Z.
" eg VK_A is 65, and the ASCII character code for uppercase 'A' is also 65.
" Caution: these are interpreted as lowercase when Shift is NOT pressed. 
" eg, sending VK_A (65) 'A' Key code without shift modifier, will produce ASCII
" 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

  set mousemodel=extend
  call test_override('no_query_mouse', 1)
  call WaitForResponses()

  let msg = ''

  call setline(1, ['one two three', 'four five six'])

  " Test mouse movement
  " by default, no mouse move events are generated
  " this setting enables it to generate move events
  set mousemev

  if !has('gui_running')
    " console version needs a button pressed,
    " otherwise it ignores mouse movements.
    call MouseLeftClick(2, 3)
  endif
  call MSWinMouseEvent(0x700, 8, 13, 0, 0, 0)
  if has('gui_running')
    call feedkeys("\<Esc>", 'Lx!')
  endif
  let pos = getmousepos()
  call assert_equal(8, pos.screenrow)
  call assert_equal(13, pos.screencol)

  if !has('gui_running')
    call MouseLeftClick(2, 3)
    call MSWinMouseEvent(0x700, 6, 4, 1, 0, 0)
    let pos = getmousepos()
    call assert_equal(6, pos.screenrow)
    call assert_equal(4, pos.screencol)
  endif

  " test cells vs pixels
  if has('gui_running')
    let args = { }
    let args.row = 9
    let args.col = 7
    let args.move = 1
    let args.cell = 1
    call test_mswin_event("mouse", args)
    call feedkeys("\<Esc>", 'Lx!')
    let pos = getmousepos()
    call assert_equal(9, pos.screenrow)
    call assert_equal(7, pos.screencol)

    let args.cell = 0
    call test_mswin_event("mouse", args)
    call feedkeys("\<Esc>", 'Lx!')
    let pos = getmousepos()
    call assert_equal(1, pos.screenrow)
    call assert_equal(1, pos.screencol)

    unlet args
  endif

  " finish testing mouse movement
  set mousemev&

  " place the cursor using left click and release in normal mode
  call MouseLeftClick(2, 4)
  call MouseLeftRelease(2, 4)
  if has('gui_running')
    call feedkeys("\<Esc>", 'Lx!')
  endif
  call assert_equal([0, 2, 4, 0], getpos('.'))

  " select and yank a word
  let @" = ''
  call MouseLeftClick(1, 9)
  let args = #{button: 0, row: 1, col: 9, multiclick: 1, modifiers: 0}
  call test_mswin_event('mouse', args)
  call MouseLeftRelease(1, 9)
  call feedkeys("y", 'Lx!')
  call assert_equal('three', @")

  " create visual selection using right click
  let @" = ''

  call MouseLeftClick(2 ,6)
  call MouseLeftRelease(2, 6)
  call MouseRightClick(2, 13)
  call MouseRightRelease(2, 13)
  call feedkeys("y", 'Lx!')
  call assert_equal('five six', @")

  " paste using middle mouse button
  let @* = 'abc '
  call feedkeys('""', 'Lx!')
  call MouseMiddleClick(1, 9)
  call MouseMiddleRelease(1, 9)
  if has('gui_running')
    call feedkeys("\<Esc>", 'Lx!')
  endif
  call assert_equal(['one two abc three', 'four five six'], getline(1, '$'))

  " test mouse scrolling (aka touchpad scrolling.)
  %d _
  set scrolloff=0
  call setline(1, range(1, 100))

  " Scroll Down
  call MouseWheelDown(2, 1)
  call MouseWheelDown(2, 1)
  call MouseWheelDown(2, 1)
  call feedkeys("H", 'Lx!')
  call assert_equal(10, line('.'))

  " Scroll Up
  call MouseWheelUp(2, 1)
  call MouseWheelUp(2, 1)
  call feedkeys("H", 'Lx!')
  call assert_equal(4, line('.'))

  " Shift Scroll Down
  call MouseShiftWheelDown(2, 1)
  call feedkeys("H", 'Lx!')
  " should scroll from where it is (4) + visible buffer height - cmdheight
  let shift_scroll_height = line('w$') - line('w0') - &cmdheight 
  call assert_equal(4 + shift_scroll_height, line('.'))

  " Shift Scroll Up
  call MouseShiftWheelUp(2, 1)
  call feedkeys("H", 'Lx!')
  call assert_equal(4, line('.'))

  if !has('gui_running')
    " Shift Scroll Down (using MOD)
    call MSWinMouseEvent(0x100, 2, 1, 0, 0, 0x04)
    call feedkeys("H", 'Lx!')
    " should scroll from where it is (4) + visible buffer height - cmdheight
    let shift_scroll_height = line('w$') - line('w0') - &cmdheight 
    call assert_equal(4 + shift_scroll_height, line('.'))

    " Shift Scroll Up (using MOD)
    call MSWinMouseEvent(0x200, 2, 1, 0, 0, 0x04)
    call feedkeys("H", 'Lx!')
    call assert_equal(4, line('.'))
  endif

  set scrolloff&

  %d _
  set nowrap
  " make the buffer 500 wide.
  call setline(1, range(10)->join('')->repeat(50))
  " Scroll Right
  call MouseWheelRight(1, 5)
  call MouseWheelRight(1, 10)
  call MouseWheelRight(1, 15)
  call feedkeys('g0', 'Lx!')
  call assert_equal(19, col('.'))

  " Scroll Left
  call MouseWheelLeft(1, 15)
  call MouseWheelLeft(1, 10)
  call feedkeys('g0', 'Lx!')
  call assert_equal(7, col('.'))

  " Shift Scroll Right
  call MouseShiftWheelRight(1, 10)
  call feedkeys('g0', 'Lx!')
  " should scroll from where it is (7) + window width
  call assert_equal(7 + winwidth(0), col('.'))
 
  " Shift Scroll Left
  call MouseShiftWheelLeft(1, 50)
  call feedkeys('g0', 'Lx!')
  call assert_equal(7, col('.'))
  set wrap&

  %d _
  call setline(1, repeat([repeat('a', 60)], 10))

  " record various mouse events
  let mouseEventNames = [
        \ 'LeftMouse', 'LeftRelease', '2-LeftMouse', '3-LeftMouse',
        \ 'S-LeftMouse', 'A-LeftMouse', 'C-LeftMouse', 'MiddleMouse',
        \ 'MiddleRelease', '2-MiddleMouse', '3-MiddleMouse',
        \ 'S-MiddleMouse', 'A-MiddleMouse', 'C-MiddleMouse',
        \ 'RightMouse', 'RightRelease', '2-RightMouse',
        \ '3-RightMouse', 'S-RightMouse', 'A-RightMouse', 'C-RightMouse',
        \ ]
  let mouseEventCodes = map(copy(mouseEventNames), "'<' .. v:val .. '>'")
  let g:events = []
  for e in mouseEventCodes
    exe 'nnoremap ' .. e .. ' <Cmd>call add(g:events, "' ..
          \ substitute(e, '[<>]', '', 'g') .. '")<CR>'
  endfor

  " Test various mouse buttons 
  "(0 - Left, 1 - Middle, 2 - Right, 
  " 0x300 - MOUSE_X1/FROM_LEFT_3RD_BUTTON,
  " 0x400 - MOUSE_X2/FROM_LEFT_4TH_BUTTON)
  for button in [0, 1, 2, 0x300, 0x400]
    " Single click
    let args = #{button: button, row: 2, col: 5, multiclick: 0, modifiers: 0}
    call test_mswin_event('mouse', args)
    let args.button = 3
    call test_mswin_event('mouse', args)

    " Double Click
    let args.button = button
    call test_mswin_event('mouse', args)
    let args.multiclick = 1
    call test_mswin_event('mouse', args)
    let args.button = 3
    let args.multiclick = 0
    call test_mswin_event('mouse', args)

    " Triple Click
    let args.button = button
    call test_mswin_event('mouse', args)
    let args.multiclick = 1
    call test_mswin_event('mouse', args)
    call test_mswin_event('mouse', args)
    let args.button = 3
    let args.multiclick = 0
    call test_mswin_event('mouse', args)

    " Shift click
    let args = #{button: button, row: 3, col: 7, multiclick: 0, modifiers: 4}
    call test_mswin_event('mouse', args)
    let args.button = 3
    call test_mswin_event('mouse', args)

    " Alt click
    let args.button = button
    let args.modifiers = 8
    call test_mswin_event('mouse', args)
    let args.button = 3
    call test_mswin_event('mouse', args)

    " Ctrl click
    let args.button = button
    let args.modifiers = 16
    call test_mswin_event('mouse', args)
    let args.button = 3
    call test_mswin_event('mouse', args)

    call feedkeys("\<Esc>", 'Lx!')
  endfor

  if has('gui_running')
    call assert_equal(['LeftMouse', 'LeftRelease', 'LeftMouse',
	\ '2-LeftMouse', 'LeftMouse', '2-LeftMouse', '3-LeftMouse',
	\ 'S-LeftMouse', 'A-LeftMouse', 'C-LeftMouse', 'MiddleMouse',
	\ 'MiddleRelease', 'MiddleMouse', '2-MiddleMouse', 'MiddleMouse',
	\ '2-MiddleMouse', '3-MiddleMouse', 'S-MiddleMouse', 'A-MiddleMouse',
	\ 'C-MiddleMouse', 'RightMouse', 'RightRelease', 'RightMouse',
	\ '2-RightMouse', 'RightMouse', '2-RightMouse', '3-RightMouse',
	\ 'S-RightMouse', 'A-RightMouse', 'C-RightMouse'],
	\ g:events)
  else
    call assert_equal(['MiddleRelease', 'LeftMouse', '2-LeftMouse',
	\ '3-LeftMouse', 'S-LeftMouse', 'MiddleMouse', '2-MiddleMouse',
	\ '3-MiddleMouse', 'MiddleMouse', 'S-MiddleMouse', 'RightMouse',
	\ '2-RightMouse', '3-RightMouse'],
	\ g:events)
  endif

  for e in mouseEventCodes
    exe 'nunmap ' .. e
  endfor

  bw!
  call test_override('no_query_mouse', 0)
  set mousemodel&
endfunc


"  Test MS-Windows test_mswin_event error handling
func Test_mswin_event_error_handling()

  let args = #{button: 0xfff, row: 2, col: 4, move: 0, multiclick: 0, modifiers: 0}
  if !has('gui_running')
    call assert_fails("call test_mswin_event('mouse', args)",'E475:')
  endif
  let args = #{button: 0, row: 2, col: 4, move: 0, multiclick: 0, modifiers: 0}
  call assert_fails("call test_mswin_event('a1b2c3', args)", 'E475:')
  call assert_fails("call test_mswin_event(test_null_string(), {})", 'E475:')
  
  call assert_fails("call test_mswin_event([], args)", 'E1174:')
  call assert_fails("call test_mswin_event('abc', [])", 'E1206:')
  
  call assert_false(test_mswin_event('mouse', test_null_dict()))
  let args = #{row: 2, col: 4, multiclick: 0, modifiers: 0}
  call assert_false(test_mswin_event('mouse', args))
  let args = #{button: 0, col: 4, multiclick: 0, modifiers: 0}
  call assert_false(test_mswin_event('mouse', args))
  let args = #{button: 0, row: 2, multiclick: 0, modifiers: 0}
  call assert_false(test_mswin_event('mouse', args))
  let args = #{button: 0, row: 2, col: 4, modifiers: 0}
  call assert_false(test_mswin_event('mouse', args))
  let args = #{button: 0, row: 2, col: 4, multiclick: 0}
  call assert_false(test_mswin_event('mouse', args))

  call assert_false(test_mswin_event('key', test_null_dict()))
  call assert_fails("call test_mswin_event('key', [])", 'E1206:')
  call assert_fails("call test_mswin_event('key', {'event': 'keydown', 'keycode': 0x0})", 'E1291:')
  call assert_fails("call test_mswin_event('key', {'event': 'keydown', 'keycode': [15]})", 'E745:')
  call assert_fails("call test_mswin_event('key', {'event': 'keys', 'keycode': 0x41})", 'E475:')
  call assert_fails("call test_mswin_event('key', {'keycode': 0x41})", 'E417:')
  call assert_fails("call test_mswin_event('key', {'event': 'keydown'})", 'E1291:')

  call assert_fails("sandbox call test_mswin_event('key', {'event': 'keydown', 'keycode': 61 })", 'E48:')

  " flush out any garbage left in the buffer.
  while getchar(0)
  endwhile
endfunc


" vim: shiftwidth=2 sts=2 expandtab