diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index 58682f9d28..9ed2fb9aa8 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -1,5 +1,8 @@ # Keyman Desktop Version History +## 2018-10-05 11.0 alpha +* Rework keyboard input to serialize input queue to resolve modifier key stickiness (#1229) + ## 2018-06-28 10.0.1200 stable * 10.0 stable release diff --git a/windows/src/engine/keyman32/K32_DBG.CPP b/windows/src/engine/keyman32/K32_DBG.CPP index 6206a8b872..3dd35f3db1 100644 --- a/windows/src/engine/keyman32/K32_DBG.CPP +++ b/windows/src/engine/keyman32/K32_DBG.CPP @@ -407,7 +407,10 @@ void DebugMessage(LPMSG msg, WPARAM wParam) // I2908 else if(msg->message == wm_keymankeyup) wsprintf(ds, "DebugMessage(%x, wm_keymankeyup: %s lParam: %X) [message flags: %x time: %d]", msg->hwnd, Debug_VirtualKey((WORD) msg->wParam), msg->lParam, wParam, msg->time); - else if(msg->message == WM_KEYDOWN || msg->message == WM_KEYUP || msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSKEYUP) + else if (msg->message == wm_keyman_keyevent) + wsprintf(ds, "DebugMessage(%x, wm_keyman_keyevent: %s lParam: %X) [message flags: %x time: %d]", msg->hwnd, + Debug_VirtualKey((WORD)msg->wParam), msg->lParam, wParam, msg->time); + else if(msg->message == WM_KEYDOWN || msg->message == WM_KEYUP || msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSKEYUP) wsprintf(ds, "DebugMessage(%x, %s, wParam: %s, lParam: %X) [message flags: %x time: %d extra: %x]", msg->hwnd, msgnames[msg->message-WM_KEYDOWN], diff --git a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp index e296b3d7f4..b80c5cd222 100644 --- a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp +++ b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp @@ -66,6 +66,30 @@ LPARAM LLKHFFlagstoWMKeymanKeyEventFlags(PKBDLLHOOKSTRUCT hs) { ((hs->flags & LLKHF_UP) ? KEYEVENTF_KEYUP : 0); } +/* + We don't attempt to serialize input to the console windows because they + behave somewhat differently to normal windows. For now, this should be + sufficient. In the future, we may want to find a way to interrogate the + focused process to find out which window actually has focus for posting + messages, because we appear to post the messages to the wrong thread + for console windows. +*/ +BOOL IsConsoleWindow(HWND hwnd) { + static HWND last_hwnd = 0; + static BOOL last_isConsoleWindow = FALSE; + + if (last_hwnd == hwnd) { + return last_isConsoleWindow; + } + + char buf[64]; + + last_hwnd = hwnd; + last_isConsoleWindow = GetClassName(hwnd, buf, 64) && !strcmp(buf, "ConsoleWindowClass"); + + return last_isConsoleWindow; +} + LRESULT _kmnLowLevelKeyboardProc( _In_ int nCode, _In_ WPARAM wParam, @@ -162,8 +186,24 @@ LRESULT _kmnLowLevelKeyboardProc( */ if (flag_ShouldSerializeInput) { - PostThreadMessage(GetWindowThreadProcessId(GetForegroundWindow(), NULL), wm_keyman_keyevent, hs->vkCode, LLKHFFlagstoWMKeymanKeyEventFlags(hs)); - return 1; + GUITHREADINFO gui = { 0 }; + gui.cbSize = sizeof(GUITHREADINFO); + if (GetGUIThreadInfo(NULL, &gui)) { + SendDebugMessageFormat(0, sdmGlobal, 0, "LowLevelHook: Active=%x Focus=%x Key=%s flags=%x", + gui.hwndActive, gui.hwndFocus, Debug_VirtualKey((WORD)hs->vkCode), LLKHFFlagstoWMKeymanKeyEventFlags(hs)); + + HWND hwnd = gui.hwndFocus ? gui.hwndFocus : gui.hwndActive; + if (!IsConsoleWindow(hwnd)) { + PostThreadMessage(GetWindowThreadProcessId(hwnd, NULL), wm_keyman_keyevent, hs->vkCode, LLKHFFlagstoWMKeymanKeyEventFlags(hs)); + return 1; + } + else { + SendDebugMessageFormat(0, sdmGlobal, 0, "LowLevelHook: console window, not serializing"); + } + } + else { + SendDebugMessageFormat(0, sdmGlobal, 0, "LowLevelHook: Failed to get Gui thread info with error %d", GetLastError()); + } } return CallNextHookEx(Globals::get_hhookLowLevelKeyboardProc(), nCode, wParam, lParam); diff --git a/windows/src/engine/keyman32/kmhook_getmessage.cpp b/windows/src/engine/keyman32/kmhook_getmessage.cpp index 73350bc560..8f021529f7 100644 --- a/windows/src/engine/keyman32/kmhook_getmessage.cpp +++ b/windows/src/engine/keyman32/kmhook_getmessage.cpp @@ -141,7 +141,9 @@ LRESULT _kmnGetMessageProc(int nCode, WPARAM wParam, LPARAM lParam) if(!InitialiseProcess(mp->hwnd)) return CallNextHookEx(Globals::get_hhookGetMessage(), nCode, wParam, lParam); } - if (mp->message >= WM_KEYFIRST && mp->message <= WM_KEYLAST && ShouldDebug(sdmMessage)) { + if (((mp->message >= WM_KEYFIRST && mp->message <= WM_KEYLAST) || mp->message == wm_keymankeydown || mp->message == wm_keymankeyup || + mp->message == wm_keyman_keyevent) + && ShouldDebug(sdmMessage)) { DebugMessage(mp, wParam); }