Fix Dock Swipe simulation on macOS 27 (Spaces & Mission Control) - #1916
Open
thiagotfroes wants to merge 1 commit into
Open
Fix Dock Swipe simulation on macOS 27 (Spaces & Mission Control)#1916thiagotfroes wants to merge 1 commit into
thiagotfroes wants to merge 1 commit into
Conversation
macOS 27 (Golden Gate) broke the "Spaces & Mission Control" action when triggered via Click & Drag (switching Spaces, opening Mission Control, App Windows). The dock swipe events were no longer being registered by the system. Root cause: The macOS 27 code path in TouchSimulator attaches an IOHIDEvent to a CGEvent via CGEventSetHIDEvent -> CGEventSetIOHIDEvent. That function is a hand-rolled reimplementation that writes the IOHIDEvent pointer into the CGEvent using hardcoded offsets (0x18 / 0xd0) into the private CGEvent/CGSEventRecord layout. macOS 27 changed that layout, so the pointer was written to the wrong address and the resulting dock swipe carried no valid HID event. Fix: Prefer Apple's own private SLEventSetIOHIDEvent (SkyLight), resolved at runtime via dlsym, and fall back to the offset-based implementation only if the symbol can't be found. This matches the working approach explored in Tests/FixDockSwipes.m. Notes: - Backwards compatible: SLEventSetIOHIDEvent is available on older macOS too, so it is used there as well; the hand-rolled method remains as a graceful fallback. No macOS-version gate is needed. - Resolved via dlsym rather than linking SkyLight.framework on purpose: linking a private framework at build time could be a problem for the Mac App Store variant, whereas dlsym creates no link-time dependency and degrades gracefully if the symbol ever disappears.
zhaoqiman
added a commit
to zhaoqiman/mac-mouse-fix
that referenced
this pull request
Jul 13, 2026
…ed CGEvent offsets CGEventSetIOHIDEvent() attaches an IOHIDEvent to a CGEvent by poking the pointer into the opaque CGEvent/CGSEventRecord struct at hardcoded offsets (0x18 / 0xd0). Those offsets were never a stable ABI, and the struct layout shifted on macOS 27, so the pointer ends up at the wrong address and Dock never sees a real IOHIDEvent - which is why every synthetic dock-swipe gesture (Spaces, Mission Control, Show Desktop, Launchpad) silently stopped doing anything. See noah-nuebling#1871 and the pile of duplicates (noah-nuebling#1873, noah-nuebling#1878, noah-nuebling#1887, noah-nuebling#1891, noah-nuebling#1892, noah-nuebling#1919, ...). SkyLight.framework is already linked into the Mac Mouse Fix and Mac Mouse Fix Helper targets, so instead of poking memory ourselves we can just resolve Apple's own SLEventSetIOHIDEvent with dlsym(RTLD_DEFAULT, ...) and call that. Using RTLD_DEFAULT instead of dlopen()'ing the framework again since it's already loaded in-process. Falls back to the old offset writer if the symbol is ever missing (now with a DDLogWarn so it's not a silent failure this time). Tested on macOS 27 - Spaces/Mission Control/Show Desktop click-and-drag work again. Same root cause as noah-nuebling#1920, noah-nuebling#1912, noah-nuebling#1916 (also switch to SLEventSetIOHIDEvent); related to noah-nuebling#1895, noah-nuebling#1918.
zhaoqiman
added a commit
to zhaoqiman/mac-mouse-fix
that referenced
this pull request
Jul 13, 2026
…ed CGEvent offsets CGEventSetIOHIDEvent() attaches an IOHIDEvent to a CGEvent by poking the pointer into the opaque CGEvent/CGSEventRecord struct at hardcoded offsets (0x18 / 0xd0). Those offsets were never a stable ABI, and the struct layout shifted on macOS 27, so the pointer ends up at the wrong address and Dock never sees a real IOHIDEvent - which is why every synthetic dock-swipe gesture (Spaces, Mission Control, Show Desktop, Launchpad) silently stopped doing anything. See noah-nuebling#1871 and the pile of duplicates (noah-nuebling#1873, noah-nuebling#1878, noah-nuebling#1887, noah-nuebling#1891, noah-nuebling#1892, noah-nuebling#1919, ...). SkyLight.framework is already linked into the Mac Mouse Fix and Mac Mouse Fix Helper targets, so instead of poking memory ourselves we can just resolve Apple's own SLEventSetIOHIDEvent with dlsym(RTLD_DEFAULT, ...) and call that. Using RTLD_DEFAULT instead of dlopen()'ing the framework again since it's already loaded in-process. Falls back to the old offset writer if the symbol is ever missing (now with a DDLogWarn so it's not a silent failure this time). Tested on macOS 27 - Spaces/Mission Control/Show Desktop click-and-drag work again. Same root cause as noah-nuebling#1920, noah-nuebling#1912, noah-nuebling#1916 (also switch to SLEventSetIOHIDEvent); related to noah-nuebling#1895, noah-nuebling#1918.
zhaoqiman
added a commit
to zhaoqiman/mac-mouse-fix
that referenced
this pull request
Jul 14, 2026
…ed CGEvent offsets CGEventSetIOHIDEvent() attaches an IOHIDEvent to a CGEvent by poking the pointer into the opaque CGEvent/CGSEventRecord struct at hardcoded offsets (0x18 / 0xd0). Those offsets were never a stable ABI, and the struct layout shifted on macOS 27, so the pointer ends up at the wrong address and Dock never sees a real IOHIDEvent - which is why every synthetic dock-swipe gesture (Spaces, Mission Control, Show Desktop, Launchpad) silently stopped doing anything. See noah-nuebling#1871 and the pile of duplicates (noah-nuebling#1873, noah-nuebling#1878, noah-nuebling#1887, noah-nuebling#1891, noah-nuebling#1892, noah-nuebling#1919, ...). Now prefers Apple's own SLEventSetIOHIDEvent, resolved once via the project's existing MFLoadSymbol_native(kMFFrameworkSkyLight, ...) helper (Shared/Utility/PrivateFunctions) instead of a hand-rolled dlsym call. Also retains the IOHIDEventRef on this path, same as the old offset-writer did, since SLEventSetIOHIDEvent's retain contract isn't documented and an extra retain is safer than an under-retain. The offset-writer is kept as a fallback only for pre-macOS-27, where it was actually validated - on 27+ it's skipped instead of executed, since those offsets are already known to be wrong there and running it would provide no real safety net, just continued exposure to writing an unvalidated address. Tested on macOS 27 - Spaces/Mission Control/Show Desktop click-and-drag all work again after this. Same root cause as noah-nuebling#1920, noah-nuebling#1912, noah-nuebling#1916 (also switch to SLEventSetIOHIDEvent); related to noah-nuebling#1895, noah-nuebling#1918.
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 27 (Golden Gate), the Spaces & Mission Control action stopped working when triggered via Click & Drag (switching Spaces, opening Mission Control / App Windows). The simulated dock swipe events were no longer registered by the system.
Root cause
The macOS 27 code path in
TouchSimulatorattaches anIOHIDEventto aCGEventviaCGEventSetHIDEvent→CGEventSetIOHIDEvent. That function is a hand-rolled reimplementation that writes theIOHIDEventpointer into theCGEventusing hardcoded offsets (0x18/0xd0) into the privateCGEvent/CGSEventRecordlayout.macOS 27 changed that layout, so the pointer was written to the wrong address and the resulting dock swipe carried no valid HID event.
Fix
Prefer Apple's own private
SLEventSetIOHIDEvent(SkyLight), resolved at runtime viadlsym, and fall back to the offset-based implementation only if the symbol can't be found. This matches the working approach explored inTests/FixDockSwipes.m.SLEventSetIOHIDEventexists on older macOS too, so it's used there as well; the hand-rolled method stays as a graceful fallback. No macOS-version gate needed.dlsyminstead of linking SkyLight.framework: linking a private framework at build time could be an issue for the Mac App Store variant, whereasdlsymcreates no link-time dependency and degrades gracefully if the symbol ever disappears.Testing
Shared/IOKit/CGEventHIDEventBridge.m.