mirror of https://github.com/vim/vim.git
patch 9.0.1146: MS-Windows: various special keys/modifiers are not mappable
Problem: MS-Windows: various special keys and modifiers are not mappable. Solution: Adjust the handling of keys with modifiers. (Christian Plewright, closes #11768)
This commit is contained in:
parent
3ac1d97a1d
commit
c8b204952f
|
@ -1,5 +1,7 @@
|
|||
version: "{build}"
|
||||
|
||||
image: Visual Studio 2015
|
||||
|
||||
skip_tags: true
|
||||
|
||||
environment:
|
||||
|
|
|
@ -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
|
||||
|
|
127
src/os_win32.c
127
src/os_win32.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -695,6 +695,8 @@ static char *(features[]) =
|
|||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1146,
|
||||
/**/
|
||||
1145,
|
||||
/**/
|
||||
|
|
Loading…
Reference in New Issue