fix(windows): reinstall low level keyboard hook if it gets removed#15179
fix(windows): reinstall low level keyboard hook if it gets removed#15179
Conversation
This change improves the stability of Keyman for Windows by monitoring the health of the low level keyboard hook. If keyman.exe is unresponsive at any time, Windows can silently uninstall its low level keyboard hook, which results in (at least) two problems: * Keyman's hotkeys stop working * A modifier key can become stuck, if it was pressed around the time Keyman became unresponsive. The most common scenario in which Keyman can become unresponsive is high system load, e.g. rendering graphics, videoconference calls, compiling software. Restarting Keyman always resolved both of these two issues in the past, but with this patch, I hope that this will no longer be necessary. A related 'fakefreeze' project is included for simulating a keyman.exe hang by posting a `wm_keyman_control:KMC_WATCHDOG_FAKEFREEZE` message to it, which keyman.exe responds to by `Sleep()`ing for 5 seconds. While keyman.exe is freezing, any keystroke will cause the low level hook to be uninstalled by Windows. Logging has been updated; look for "LowLevelHookWatchDog" in the log for related events. One final small change in keyman32.cpp, as I refactored the WH_KEYBOARD_LL hook installation/uninstallation, was to always clear out hook variables when uninstalling a hook, because if the hook fails to uninstall, there's really nothing we can do about it anyway, and we probably shouldn't be trying again. Fixes: #8064
User Test ResultsTest specification and instructions Test Artifacts |
| void LowLevelHookWatchDog::HookIsAlive() { | ||
| // ULONGLONG Previous = LastLowLevelEventTick; | ||
| LastLowLevelEventTick = GetTickCount64(); | ||
| // SendDebugMessageFormat("LowLevelHookWatchDog::HookIsAlive currentLL=%llu currentGM=%llu (lastLL=%llu)", LastLowLevelEventTick, LastGetMessageEventTick, Previous); |
There was a problem hiding this comment.
Leaving these debug messages in, but commented out, on purpose.
|
|
||
| #define KMC_PROFILECHANGED 18 // 9.0.426.0 // I3933 | ||
|
|
||
| #define KMC_HINTRESPONSE 19 // 14.0 HIWORD(wParam) = ModalResult, lParam = hint enum |
There was a problem hiding this comment.
This line just to match KeymanControlMessages.pas
rc-swag
left a comment
There was a problem hiding this comment.
lgtm
I was initally thinking a in memory total freeze count might be useful for anaylytics and we could post to sentry if we reached a threshold. It might help see a patern.
However, reading the stackoverflow and the frequency you see hotkeys stop working it is not really needed.
Yes, it would be a good idea to record an event on sentry in the event of a freeze. That would give us real world frequency. I will look at adding that as a follow-up to this PR. |
Test Specifications
Prerequisites
Test Results
|
This change improves the stability of Keyman for Windows by monitoring the health of the low level keyboard hook. If keyman.exe is unresponsive at any time, Windows can silently uninstall its low level keyboard hook, which results in (at least) two problems: * Keyman's hotkeys stop working * A modifier key can become stuck, if it was pressed around the time Keyman became unresponsive. The most common scenario in which Keyman can become unresponsive is high system load, e.g. rendering graphics, videoconference calls, compiling software. Restarting Keyman always resolved both of these two issues in the past, but with this patch, I hope that this will no longer be necessary. A related 'fakefreeze' project is not included in this cherry-pick; see PR #15179 for this. Logging has been updated; look for "LowLevelHookWatchDog" in the log for related events. One final small change in keyman32.cpp, as I refactored the WH_KEYBOARD_LL hook installation/uninstallation, was to always clear out hook variables when uninstalling a hook, because if the hook fails to uninstall, there's really nothing we can do about it anyway, and we probably shouldn't be trying again. Fixes: #8064 Cherry-pick-of: #15179 Test-bot: skip Build-bot: skip
This change improves the stability of Keyman for Windows by monitoring the health of the low level keyboard hook. If keyman.exe is unresponsive at any time, Windows can silently uninstall its low level keyboard hook, which results in (at least) two problems: * Keyman's hotkeys stop working * A modifier key can become stuck, if it was pressed around the time Keyman became unresponsive. The most common scenario in which Keyman can become unresponsive is high system load, e.g. rendering graphics, videoconference calls, compiling software. Restarting Keyman always resolved both of these two issues in the past, but with this patch, I hope that this will no longer be necessary. A related 'fakefreeze' project is not included in this cherry-pick; see PR #15179 for this. Logging has been updated; look for "LowLevelHookWatchDog" in the log for related events. One final small change in keyman32.cpp, as I refactored the WH_KEYBOARD_LL hook installation/uninstallation, was to always clear out hook variables when uninstalling a hook, because if the hook fails to uninstall, there's really nothing we can do about it anyway, and we probably shouldn't be trying again. Fixes: #8064 Cherry-pick-of: #15179 Test-bot: skip Build-bot: skip
This change improves the stability of Keyman for Windows by monitoring the health of the low level keyboard hook. If keyman.exe is unresponsive at any time, Windows can silently uninstall its low level keyboard hook, which results in (at least) two problems: * Keyman's hotkeys stop working * A modifier key can become stuck, if it was pressed around the time Keyman became unresponsive. The most common scenario in which Keyman can become unresponsive is high system load, e.g. rendering graphics, videoconference calls, compiling software. Restarting Keyman always resolved both of these two issues in the past, but with this patch, I hope that this will no longer be necessary. A related 'fakefreeze' project is not included in this cherry-pick; see PR #15179 for this. Logging has been updated; look for "LowLevelHookWatchDog" in the log for related events. One final small change in keyman32.cpp, as I refactored the WH_KEYBOARD_LL hook installation/uninstallation, was to always clear out hook variables when uninstalling a hook, because if the hook fails to uninstall, there's really nothing we can do about it anyway, and we probably shouldn't be trying again. Fixes: #8064 Cherry-pick-of: #15179 Test-bot: skip Build-bot: skip
|
Changes in this pull request will be available for download in Keyman version 19.0.165-alpha |
This change improves the stability of Keyman for Windows by monitoring the health of the low level keyboard hook. If keyman.exe is unresponsive at any time, Windows can silently uninstall its low level keyboard hook, which results in (at least) two problems:
The most common scenario in which Keyman can become unresponsive is high system load, e.g. rendering graphics, videoconference calls, compiling software.
Restarting Keyman always resolved both of these two issues in the past, but with this patch, I hope that this will no longer be necessary.
A related 'fakefreeze' project is included for simulating a keyman.exe hang by posting a
wm_keyman_control:KMC_WATCHDOG_FAKEFREEZEmessage to it, which keyman.exe responds to bySleep()ing for 5 seconds. While keyman.exe is freezing, any keystroke will cause the low level hook to be uninstalled by Windows.Logging has been updated; look for "LowLevelHookWatchDog" in the log for related events.
One final small change in keyman32.cpp, as I refactored the WH_KEYBOARD_LL hook installation/uninstallation, was to always clear out hook variables when uninstalling a hook, because if the hook fails to uninstall, there's really nothing we can do about it anyway, and we probably shouldn't be trying again.
Related:
Fixes: #8064
User Testing
TEST_KEYMAN: Please run through a basic test of Keyman keyboard input. Swap keyboards, type text, swap applications, verify that Keyman continues to run robustly. Confirm that modifier keys do not become 'stuck' while you are running tests. Please run this test for at least 5 minutes of normal usage.
TEST_FREEZE: Download and unzip the attached fakefreeze.zip. Setup hotkeys in Keyman (e.g. to show/hide On Screen Keyboard). Run fakefreeze.exe, and while the 5 second timer it shows is running, press any of the Keyman hotkeys. Note that the hotkey has no effect. After the timer finishes, press the hotkey again and verify that it now works again. (Note that by design, you may need to press another key before pressing the hotkey, after a freeze, as the first time you press a key, Keyman will detect that it needs to heal itself.)
fakefreeze.zip