fix(macOS): re-enable event tap after macOS disables it - #332
Open
duyhnynh wants to merge 1 commit into
Open
Conversation
initEventTap creates an active event tap, so macOS puts a deadline on OpenKeyCallback. When the callback misses that deadline (sustained CPU load) or on kCGEventTapDisabledByUserInput, the system switches the tap off and reports it back through the callback as a pseudo event type. OpenKeyCallback never checked for those two types, and CGEventTapEnable was only ever called once during setup. Once macOS turned the tap off, nothing turned it back on: the menu bar still showed the current mode and the switch key still worked, but no keystroke was converted in any app until OpenKey was relaunched. Handle both notifications in the callback and re-enable the tap. The normal event path is unchanged. Refs tuyenvm#258 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On macOS, OpenKey sometimes stops converting Vietnamese in every app at once. The menu bar icon still shows the current mode and the switch key still toggles it, but no keystroke is converted. Quitting and relaunching OpenKey is the only way back.
This matches #258, which describes the same thing ("Tất cả các ứng dụng đều không gõ được VI ... khắc phục: reboot lại OS và bật lại OpenKey").
Root cause
initEventTapcreates an active event tap:macOS puts a deadline on an active tap's callback. If
OpenKeyCallbackdoes not return in time — which happens when the machine is under sustained load — the system switches the tap off and reports it back through the same callback as the pseudo event typekCGEventTapDisabledByTimeout.kCGEventTapDisabledByUserInputis the other case.Two things then go wrong on
master:OpenKeyCallbacknever checkstypeagainst those two values, so the notification falls through the normal key-handling path and is ignored.CGEventTapEnableis called exactly once, at the end ofinitEventTap.So once macOS turns the tap off, nothing ever turns it back on. Everything else in the app keeps working — which is why the menu bar and the switch key still respond, and why it looks like OpenKey is running fine.
Fix
Handle both notifications at the top of the callback and re-enable the tap.
eventTapis file-static inOpenKeyManager.m, so re-enabling goes through a small C function there, in the same style as the existing cross-fileexterndeclarations.The normal event path is untouched — the guard returns before any existing logic runs.
Testing
xcodebuild -project Sources/OpenKey/macOS/OpenKey.xcodeproj -scheme OpenKey -configuration Release→ BUILD SUCCEEDED (Xcode 26.1.1, macOS 26.3)nmon the built binary confirms the new path is present andCGEventTapEnablenow has two call sites instead of one.Note:
MACOSX_DEPLOYMENT_TARGETin the project is10.14, which no longer builds on current Xcode (SDK does not contain 'libarclite'). I built with an override; that is a pre-existing issue unrelated to this change and I have not touched the project file.What I did not verify
I have not captured the moment the tap flips to disabled. The failure needs the callback to be mid-flight during a CPU stall, so it only happens while you are actually typing, and I could not force it on demand. The evidence here is the code path plus the symptom match with #258, not a recorded transition.
For anyone wanting to check their own machine,
CGGetEventTapList()reports anenabledflag per tap and will show OpenKey's tap as disabled while the process is still alive.Refs #258