fix: re-enable CGEventTap on timeout and skip trackpad scroll events#64
Open
hieshima wants to merge 1 commit intoTomBadash:masterfrom
Open
fix: re-enable CGEventTap on timeout and skip trackpad scroll events#64hieshima wants to merge 1 commit intoTomBadash:masterfrom
hieshima wants to merge 1 commit intoTomBadash:masterfrom
Conversation
Two fixes for macOS CGEventTap reliability: 1. Handle kCGEventTapDisabledByTimeout (0xFFFFFFFE) and kCGEventTapDisabledByUserInput (0xFFFFFFFF) in the event tap callback by immediately calling CGEventTapEnable to re-activate. Without this, macOS silently disables the tap when the callback runs too slowly, permanently losing all button/scroll remapping. 2. Check kCGScrollWheelEventIsContinuous (field 88) at the top of the kCGEventScrollWheel handler to pass through trackpad and Magic Mouse events untouched. Previously all scroll events were intercepted regardless of source, which broke trackpad gestures, applied scroll inversion to trackpad, and triggered hscroll actions on two-finger swipes.
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
Two macOS CGEventTap issues that affect daily use:
Button/scroll remapping silently stops working after running for a while.
macOS disables a
CGEventTapwhen the callback responds too slowly (kCGEventTapDisabledByTimeout). The existing wake observer (NSWorkspaceDidWakeNotification) only covers sleep/wake — it does not handle runtime timeout disabling. Once disabled, all remapping permanently stops until restart.Trackpad gestures and scroll direction break while Mouser is running.
The
kCGEventScrollWheelhandler intercepts all scroll events — including trackpad two-finger scrolls — without distinguishing input source. This causes:invert_vscrollapplies to trackpad, overriding the system scroll directionRelated: #35, PR #45
Fix
1. Handle
kCGEventTapDisabledByTimeout/kCGEventTapDisabledByUserInputAt the top of
_event_tap_callback, detect the two disabled signal event types (0xFFFFFFFE,0xFFFFFFFF) and immediately callCGEventTapEnable(tap, True). This is the Apple-recommended pattern for keeping an event tap alive.2. Filter trackpad events via
kCGScrollWheelEventIsContinuousAt the top of the
kCGEventScrollWheelhandler (before any dispatch/block/inversion logic), check CGEvent field 88 (kCGScrollWheelEventIsContinuous):0→ discrete mouse wheel event → process normally (dispatch, block, invert)1→ continuous trackpad/Magic Mouse event →return cg_event(pass through untouched)This is the same approach used by Scroll Reverser, Mos, and LinearMouse. Field 88 is a documented Apple API stable since macOS 10.5.
Verification
CGEventTap re-enable (manual test on macOS 15.5)
Added a temporary
time.sleep(5)inside_event_tap_callbackto force macOS to trigger the timeout mechanism. Result:The tap was automatically re-enabled each time macOS disabled it. Remapping resumed without restart.
Trackpad filtering (manual test on macOS 15.5)
invert_vscroll: inversion applies correctly ✅Automated tests
New tests added:
test_reenable_on_timeout— callback receives0xFFFFFFFE, assertsCGEventTapEnable(tap, True)is calledtest_reenable_on_user_input— same for0xFFFFFFFFtest_normal_event_does_not_reenable— normal events don't trigger re-enabletest_trackpad_scroll_passes_through_callback— continuous scroll returnscg_eventas-istest_trackpad_hscroll_not_blocked— trackpad horizontal scroll not dispatched as HSCROLL actiontest_mouse_wheel_hscroll_dispatched_and_blocked— discrete mouse wheel horizontal scroll dispatches and blocks correctly