diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index f97c49bb84..2f18411b2d 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -1043,6 +1043,6 @@ BOOL ShouldAttachToProcess() void PostDummyKeyEvent() { // I3301 - Handle I3250 regression with inadvertent menu activation with Alt keys // I3534 // I4844 - keybd_event(_VK_PREFIX, 0xFF, 0, 0); // I3250 - is this unnecessary? - keybd_event(_VK_PREFIX, 0xFF, KEYEVENTF_KEYUP, 0); // I3250 - is this unnecessary? + keybd_event(_VK_PREFIX, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); // I3250 - is this unnecessary? + keybd_event(_VK_PREFIX, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); // I3250 - is this unnecessary? } diff --git a/windows/src/engine/keyman32/appint/aiTIP.cpp b/windows/src/engine/keyman32/appint/aiTIP.cpp index 1a909e1be1..507f932950 100644 --- a/windows/src/engine/keyman32/appint/aiTIP.cpp +++ b/windows/src/engine/keyman32/appint/aiTIP.cpp @@ -125,12 +125,12 @@ extern "C" __declspec(dllexport) BOOL WINAPI TIPProcessKey(WPARAM wParam, LPARAM SendDebugMessageFormat(0, sdmAIDefault, 0, "TIPProcessKey: Enter VirtualKey=%s lParam=%x IsUp=%d Extended=%d Updateable=%d Preserved=%d", Debug_VirtualKey((WORD) wParam), lParam, isUp, extended, Updateable, Preserved); - if(_td->LastKey == wParam && (scan == 0 || scan == 0xFE)) { // I4642 + if(_td->LastKey == wParam && (scan == 0 || scan == SCAN_FLAG_SERIALIZED_USER_KEY_EVENT)) { // I4642 scan = _td->LastScanCode; - SendDebugMessageFormat(0, sdmAIDefault, 0, "TIPProcessKey: Scan code was zero so using cached scan code %x", scan); + SendDebugMessageFormat(0, sdmAIDefault, 0, "TIPProcessKey: Scan code was zero or 0xFE so using cached scan code %x", scan); } - if(scan == 0xFF) { // I4370 + if(scan == SCAN_FLAG_KEYMAN_KEY_EVENT) { // I4370 SendDebugMessageFormat(0, sdmAIDefault, 0, "TIPProcessKey: Virtual Key was generated by Keyman [Scan=0xFF]"); return FALSE; } diff --git a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp index 446b819ef9..df00b85718 100644 --- a/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp +++ b/windows/src/engine/keyman32/appint/aiWin2000Unicode.cpp @@ -215,7 +215,7 @@ BOOL AIWin2000Unicode::PostKeys() pInputs[i].type = INPUT_KEYBOARD; pInputs[i].ki.wVk = (WORD)Queue[n].dwData & 0xFF; // I3242 - noted as unclean but was not cause of the issue // I3438 // I3527 - pInputs[i].ki.wScan = 0xFF; + pInputs[i].ki.wScan = SCAN_FLAG_KEYMAN_KEY_EVENT; pInputs[i].ki.dwFlags = ((Queue[n].dwData & QVK_EXTENDED) ? KEYEVENTF_EXTENDEDKEY : 0); // I3438 pInputs[i].ki.time = 0; @@ -242,7 +242,7 @@ BOOL AIWin2000Unicode::PostKeys() { pInputs[i].type = INPUT_KEYBOARD; pInputs[i].ki.wVk = (WORD) Queue[n].dwData & 0xFF; // I3242 - noted as unclean but was not cause of the issue // I3438 // I3527 - pInputs[i].ki.wScan = 0xFF; + pInputs[i].ki.wScan = SCAN_FLAG_KEYMAN_KEY_EVENT; pInputs[i].ki.dwFlags = KEYEVENTF_KEYUP | ((Queue[n].dwData & QVK_EXTENDED) ? KEYEVENTF_EXTENDEDKEY : 0); // I3438 pInputs[i].ki.time = 0; pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378 @@ -281,14 +281,14 @@ BOOL AIWin2000Unicode::PostKeys() pInputs[i].type = INPUT_KEYBOARD; pInputs[i].ki.wVk = VK_BACK; - pInputs[i].ki.wScan = 0xFF; + pInputs[i].ki.wScan = SCAN_FLAG_KEYMAN_KEY_EVENT; pInputs[i].ki.dwFlags = ((Queue[n].dwData & 0x0100) ? KEYEVENTF_EXTENDEDKEY : 0); pInputs[i].ki.time = 0; pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378 pInputs[i].type = INPUT_KEYBOARD; pInputs[i].ki.wVk = VK_BACK; - pInputs[i].ki.wScan = 0xFF; + pInputs[i].ki.wScan = SCAN_FLAG_KEYMAN_KEY_EVENT; pInputs[i].ki.dwFlags = KEYEVENTF_KEYUP | ((Queue[n].dwData & 0x0100) ? KEYEVENTF_EXTENDEDKEY : 0); pInputs[i].ki.time = 0; pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378 diff --git a/windows/src/engine/keyman32/capsstate.cpp b/windows/src/engine/keyman32/capsstate.cpp index 2eb7b92570..645a5e5539 100644 --- a/windows/src/engine/keyman32/capsstate.cpp +++ b/windows/src/engine/keyman32/capsstate.cpp @@ -65,16 +65,16 @@ void KeyCapsLockPress(BOOL FIsUp) // I3284 - void // I3529 { if(FIsUp && !(GetKeyState(VK_CAPITAL) & 1)) // I267 - 24/11/2006 invert GetKeyState test { - keybd_event(VK_CAPITAL, 0xFF, 0, 0); - keybd_event(VK_CAPITAL, 0xFF, KEYEVENTF_KEYUP, 0); + keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); + keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); } } else if(_td->lpActiveKeyboard->Keyboard->dwFlags & KF_CAPSALWAYSOFF) { if(!FIsUp && (GetKeyState(VK_CAPITAL) & 1)) { // I267 - 24/11/2006 invert GetKeyState test - keybd_event(VK_CAPITAL, 0xFF, KEYEVENTF_KEYUP, 0); - keybd_event(VK_CAPITAL, 0xFF, 0, 0); + keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); + keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); } } } @@ -92,8 +92,8 @@ void KeyShiftPress(BOOL FIsUp) // I3284 - void // I3529 { if(!FIsUp) { - keybd_event(VK_CAPITAL, 0xFF, 0, 0); - keybd_event(VK_CAPITAL, 0xFF, KEYEVENTF_KEYUP, 0); + keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); + keybd_event(VK_CAPITAL, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); } } } diff --git a/windows/src/engine/keyman32/globals.h b/windows/src/engine/keyman32/globals.h index 484750d983..09c411fcc2 100644 --- a/windows/src/engine/keyman32/globals.h +++ b/windows/src/engine/keyman32/globals.h @@ -250,7 +250,7 @@ extern UINT wm_keymanim_close, wm_keymanim_contextchanged, wm_test_keyman_functioning, - wm_keyman_ignore; + wm_keyman_ignore; // used to mask out messages that we don't want the target app to process, e.g. key events extern BOOL flag_ShouldSerializeInput, diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index b45357312b..5edfaa5ee5 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -76,8 +76,9 @@ UINT + //TODO: consolidate these messages -- they are probably not all required now wm_keyman = 0, // user message - ignore msg // I3594 - wm_keyman_ignore = 0, + wm_keyman_ignore = 0, // used to mask out messages that we don't want the target app to process, e.g. key events wm_kmdebug = 0, // " " " " - debugging wm_kmmessage = 0, // message to Keyman window // I4412 diff --git a/windows/src/engine/keyman32/keybd_shift.cpp b/windows/src/engine/keyman32/keybd_shift.cpp index 4f7b46d0a6..7ce40c4283 100644 --- a/windows/src/engine/keyman32/keybd_shift.cpp +++ b/windows/src/engine/keyman32/keybd_shift.cpp @@ -107,31 +107,22 @@ void do_keybd_event(LPINPUT pInputs, int *n, BYTE vk, BYTE scan, DWORD flags, UL */ void keybd_sendprefix(LPINPUT pInputs, int *n) { - SendDebugMessageFormat(0, sdmAIDefault, 0, "keybd_sendshift: sending prefix down+up"); - do_keybd_event(pInputs, n, _VK_PREFIX, 0xFF, 0, 0); // I4548 // I4844 - do_keybd_event(pInputs, n, _VK_PREFIX, 0xFF, KEYEVENTF_KEYUP, 0); // I4548 // I4844 -} - -void keybd_sendshift(LPINPUT pInputs, int *n, BYTE vkey, BOOL isDown) { - SendDebugMessageFormat(0, sdmAIDefault, 0, "keybd_sendshift: sending key%s - vkey=%s", isDown ? "down" : "up", Debug_VirtualKey(vkey)); - do_keybd_event(pInputs, n, vkey, 0xFF, isDown ? 0 : KEYEVENTF_KEYUP, 0); // I4548 + SendDebugMessageFormat(0, sdmAIDefault, 0, "keybd_sendprefix: sending prefix down+up"); + do_keybd_event(pInputs, n, _VK_PREFIX, SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); // I4548 // I4844 + do_keybd_event(pInputs, n, _VK_PREFIX, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); // I4548 // I4844 } /** - keybd_shift evaluates the current keyboard modifier state and queues key events in order to - initially set modifiers to "up" and, after the output key events are queued, resets the modifiers - to their initial state. + keybd_shift_release records the current keyboard state and then releases any modifier + keys. If a modifier key must be released, it first sends a dummy prefix key to prevent + isolated modifier key actions such as Alt opening up a menu. Parameters: pInputs array of INPUT structures which we will fill with our key events. - n pointer to current index into pInput, which we increment for each key + n pointer to current index into pInput, which we increment for each key event we add - FReset are we clearing or resetting the modifier state? - kbd pointer to keyboard state (256 byte array) - - There must be enough space in pInputs to contain 6 x up + 6 x down + 2 prefix-down + 2 prefix-up event = 16 events, - to support both the clear and reset calls. + kbd pointer to keyboard state (256 byte array), in which we will store + the initial modifier state for later restoration by keybd_shift_reset */ - void keybd_shift_release(LPINPUT pInputs, int *n, LPBYTE kbd) { const BYTE modifiers[6] = { VK_LMENU, VK_RMENU, VK_LCONTROL, VK_RCONTROL, VK_LSHIFT, VK_RSHIFT }; BOOL hasSentPrefix = FALSE; @@ -144,18 +135,31 @@ void keybd_shift_release(LPINPUT pInputs, int *n, LPBYTE kbd) { keybd_sendprefix(pInputs, n); hasSentPrefix = TRUE; } - keybd_sendshift(pInputs, n, modifiers[i], FALSE); + SendDebugMessageFormat(0, sdmAIDefault, 0, "keybd_shift_release: sending keyup vkey=%s", Debug_VirtualKey(modifiers[i])); + do_keybd_event(pInputs, n, modifiers[i], SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); } } } +/** + keybd_shift_reset returns the modifiers to their original pressed state and, if any modifier + key presses are emitted, emits also a dummy 'prefix' keystroke in order to prevent default + modifier actions such as Alt opening up a menu. + + Parameters: pInputs array of INPUT structures which we will fill with our key events. + n pointer to current index into pInput, which we increment for each key + event we add + kbd pointer to keyboard state (256 byte array), previously set by + keybd_shift_release +*/ void keybd_shift_reset(LPINPUT pInputs, int *n, LPBYTE kbd) { const BYTE modifiers[6] = { VK_LMENU, VK_RMENU, VK_LCONTROL, VK_RCONTROL, VK_LSHIFT, VK_RSHIFT }; BOOL needsPrefix = FALSE; for (int i = 0; i < _countof(modifiers); i++) { if (kbd[modifiers[i]] & 0x80) { - keybd_sendshift(pInputs, n, modifiers[i], TRUE); + SendDebugMessageFormat(0, sdmAIDefault, 0, "keybd_shift_reset: sending keydown vkey=%s", Debug_VirtualKey(modifiers[i])); + do_keybd_event(pInputs, n, modifiers[i], SCAN_FLAG_KEYMAN_KEY_EVENT, 0, 0); needsPrefix = TRUE; } } @@ -165,6 +169,21 @@ void keybd_shift_reset(LPINPUT pInputs, int *n, LPBYTE kbd) { } } +/** + keybd_shift evaluates the current keyboard modifier state and queues key events in order to + initially set modifiers to "up" and, after the output key events are queued, resets the modifiers + to their initial state. + + Parameters: pInputs array of INPUT structures which we will fill with our key events. + n pointer to current index into pInput, which we increment for each key + event we add + isReset are we clearing or resetting the modifier state? + kbd pointer to keyboard state (256 byte array) that owner must maintain but + that we will fill + + There must be enough space in pInputs to contain 6 x up + 6 x down + 2 prefix-down + 2 prefix-up event = 16 events, + to support both the clear and reset calls. +*/ void keybd_shift(LPINPUT pInputs, int *n, BOOL isReset, LPBYTE kbd) { if (isReset) { keybd_shift_reset(pInputs, n, kbd); diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index cbca167e47..6c60b4d8eb 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -142,12 +142,13 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) if(!InitialiseProcess(mp->hwnd)) return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } - if(mp->message == WM_CHAR || mp->message == WM_SYSCHAR || mp->message == WM_KEYDOWN || mp->message == WM_SYSKEYDOWN || mp->message == WM_KEYUP || mp->message == WM_SYSKEYUP) - if(ShouldDebug(sdmMessage)) DebugMessage(mp, wParam); + if (mp->message >= WM_KEYFIRST && mp->message <= WM_KEYLAST && ShouldDebug(sdmMessage)) { + DebugMessage(mp, wParam); + } if ((mp->message == WM_KEYDOWN || mp->message == WM_SYSKEYDOWN || mp->message == WM_KEYUP || mp->message == WM_SYSKEYUP)) { // I4642 BYTE scan = KEYMSG_LPARAM_SCAN(mp->lParam); - if (scan != 0xFE) { + if (scan != SCAN_FLAG_SERIALIZED_USER_KEY_EVENT) { _td->LastScanCode = scan; _td->LastKey = mp->wParam; } @@ -171,15 +172,19 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) */ if (flag_ShouldSerializeInput && _td->lpActiveKeyboard && - !IsDevEnvCtrlTabSequence((wParam & PM_REMOVE) == PM_REMOVE, mp)) { - if (scan < 0xFE && mp->wParam != VK_PACKET && mp->wParam != VK_PROCESSKEY) { - if ((wParam & PM_REMOVE) == PM_REMOVE) { - // We only want to send this input once -- with PM_NOREMOVE, we will be - // processing the same message multiple times + !IsDevEnvCtrlTabSequence(wParam & PM_REMOVE, mp)) { + if (scan < SCAN_FLAG_SERIALIZED_USER_KEY_EVENT && mp->wParam != VK_PACKET && mp->wParam != VK_PROCESSKEY) { + if (wParam & PM_REMOVE) { + // We only want to send this input once -- with PM_NOREMOVE, we see the + // same message multiple times. Note: we have to bit test PM_REMOVE despite what is + // written in GetMsgProc documentation at + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms644981(v=vs.85).aspx + // because we have seen undocumented situations where other flags are passed in + // to wParam, e.g. 0x0003 INPUT input; input.type = INPUT_KEYBOARD; input.ki.wVk = (WORD)mp->wParam; - input.ki.wScan = 0xFE; + input.ki.wScan = SCAN_FLAG_SERIALIZED_USER_KEY_EVENT; input.ki.time = mp->time; input.ki.dwExtraInfo = mp->lParam; // We'll copy this back later input.ki.dwFlags = @@ -199,7 +204,7 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) case VK_MENU: case VK_CONTROL: case VK_SHIFT: - if (scan != 0xFF) { // I4793 + if (scan != SCAN_FLAG_KEYMAN_KEY_EVENT) { // I4793 ProcessModifierChange((UINT)mp->wParam, mp->message == WM_KEYUP || mp->message == WM_SYSKEYUP, KEYMSG_FLAG_EXTENDED(mp->lParam)); } break; @@ -207,10 +212,10 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) // 4 Aug 2003 - mcdurdin - Stuff any Keyman wm_key* message with the correct scancode if (mp->wParam != VK_BACK) { - if (scan == 0xFE) { + if (scan == SCAN_FLAG_SERIALIZED_USER_KEY_EVENT) { mp->lParam = GetMessageExtraInfo(); SetMessageExtraInfo(0); - } else if(scan == 0xFF) { + } else if(scan == SCAN_FLAG_KEYMAN_KEY_EVENT) { mp->lParam = (mp->lParam & 0xFF00FFFFL) | (MapVirtualKey((UINT)mp->wParam, 0) << 16); } } diff --git a/windows/src/engine/keyman32/kmhook_keyboard.cpp b/windows/src/engine/keyman32/kmhook_keyboard.cpp index db55ab5b09..def532562f 100644 --- a/windows/src/engine/keyman32/kmhook_keyboard.cpp +++ b/windows/src/engine/keyman32/kmhook_keyboard.cpp @@ -140,7 +140,7 @@ BOOL KeyLanguageSwitchPress(WPARAM wParam, BOOL extended, BOOL isUp, DWORD Shift //ReportActiveKeyboard(_td, 0); Globals::PostControllers(wm_keyman_control, MAKELONG(KMC_INTERFACEHOTKEY, hotkey->Target), 0); PostDummyKeyEvent(); // I4124 // I4844 - keybd_event(VK_SHIFT, 0xFF, KEYEVENTF_KEYUP, 0); // I4203 + keybd_event(VK_SHIFT, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); // I4203 return TRUE; } diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index 938bd5cafa..849f2f0575 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -114,6 +114,9 @@ #define KEYMSG_FLAG_REPEAT(lParam) (HIWORD(lParam) & KF_REPEAT ? 1 : 0) #define KEYMSG_FLAG_UP(lParam) (HIWORD(lParam) & KF_UP ? 1 : 0) +#define SCAN_FLAG_SERIALIZED_USER_KEY_EVENT 0xFE +#define SCAN_FLAG_KEYMAN_KEY_EVENT 0xFF + /***************************************************************************/ typedef struct tagSTORE