When the Stars Align

There’s a moment in any tinkering project where the universe briefly stops working against you. The documentation exists. The API does what the blog post said it would. The code compiles on the first try. If you’ve been building software for any length of time, you know how rare this is. You also know it never lasts. But for the duration of that window — before the edge cases arrive, before the OS update breaks everything, before you discover the footnote that invalidates your entire approach — it feels like the stars have aligned and you should move fast before they drift apart again.

This is the story of one such alignment. It involves macOS Spaces, two strangers’ GitHub repositories, a fistful of undocumented event fields, and the Dock’s surprisingly trusting attitude toward synthetic trackpad gestures.

The Slow Orbit

ActiveSpace is one of my smaller utilities. It sits in the menu bar, shows which Space you’re on, and lets you switch between them with a click. That’s it. A few hundred lines of Swift. The kind of app that should be invisible.

The problem was the switching. macOS doesn’t provide a public API for moving between Spaces programmatically. The official way to switch is to simulate keyboard input — specifically, the control and control shortcuts that Mission Control responds to. ActiveSpace was doing exactly this: constructing an AppleScript that told System Events to fire key code 124 using {control down}, once per space you needed to traverse, with a 0.35-second delay between each keystroke to let the animation complete.

It worked. It was also miserable.

If you wanted to jump from Space 1 to Space 4, you got to sit through three sequential sliding animations, each one a gentle reminder that macOS thinks you enjoy watching your desktops glide past like carriages on a miniature railway. The whole thing took over a second. For a utility whose entire reason for existing was to make space switching faster, this was — let’s say — not ideal.

I’d accepted it as the cost of doing business. Apple doesn’t expose a “just go there, instantly, without the theatre” API. Private APIs exist for querying space state — CGSCopyManagedDisplaySpaces, CGSGetActiveSpace — and the community has been using those reliably for years. But for the actual switching, the conventional wisdom was that you were stuck with keyboard simulation and whatever animation Apple deemed appropriate.

Then I found ISS.

The Other ISS

Not the one in low Earth orbit. This one was in a GitHub repository belonging to Joshua Li. A tiny C program — under 300 lines — that intercepted trackpad swipe gestures and replaced them with synthetic high-velocity equivalents. The result: instant space switching. No animation. No sliding. Just there.

The key insight was beautiful in its simplicity. When you swipe between Spaces on a trackpad, the system generates gesture events that the Dock processes. The Dock looks at the velocity of the swipe to decide how to animate the transition. A gentle swipe gets a gentle slide. A fast swipe gets a faster slide. And a swipe at velocity 400? The Dock effectively says “right, no point animating that” and teleports you to the next space.

ISS didn’t fight the system. It didn’t bypass the Dock or hack the window server. It simply spoke the Dock’s language, very loudly.

I wanted that for ActiveSpace. Not the trackpad interception — ActiveSpace triggers from menu bar clicks and keyboard shortcuts, not swipe gestures — but the underlying technique of posting synthetic dock-swipe events to achieve instant transitions.

Charting the Dark Matter

The technique relies on what you might charitably call “undocumented APIs” and what you might more honestly call “things discovered by people with disassemblers and a lot of patience.” The synthetic events require setting specific integer and double fields on a CGEvent object, and those fields aren’t in any header file Apple ships.

Field 55 is the event sub-type. Field 110 is the HID event type. Field 132 is the gesture phase. Field 124 is the cumulative swipe progress. Field 129 is the velocity. These aren’t documented. They were reverse-engineered from traces of real trackpad events, and they’ve been stable across enough macOS releases that a small ecosystem of tools depends on them.

This is the dark matter of macOS development. You can’t see it in the documentation. You can’t find it in the SDK headers. But it’s holding everything together, and if you know where to look, you can use it.

A second project proved invaluable here: jurplel/InstantSpaceSwitcher by Justin Proulx. Where ISS was minimal and focused on trackpad interception, InstantSpaceSwitcher was a full macOS application that used the same synthetic gesture technique to switch spaces via configurable hotkeys. Its C implementation of the gesture posting was meticulous — and it revealed a detail that ISS’s approach had glossed over: the companion event.

Each space-switch gesture isn’t just a dock-control event. It’s a pair: a kCGSEventDockControl (type 30) followed by a kCGSEventGesture (type 29) companion. Two pairs per switch — one for the begin phase, one for the end phase. Four events to move one space. The dock-control event carries the payload (direction, velocity, progress). The gesture event is almost empty — just a type marker. But without it, the Dock’s gesture state machine doesn’t transition correctly.

I was looking at the gravitational pull of two stars, each illuminating a different part of the same dark sky.

Course Corrections

Translating this from C to Swift should have been straightforward. And in the broad strokes, it was. Swift’s CGEvent API maps cleanly to the C equivalents. CGEventSetIntegerValueField becomes event.setIntegerValueField. CGEventPost(kCGSessionEventTap, event) becomes event.post(tap: .cgSessionEventTap). The field constants, the phase values, the magic velocity of 400 — all translatable.

What I didn’t expect was macOS 16.

The first version switched spaces, but didn’t restore the desktop. The space indicator in the menu bar updated — confirming the switch had happened at the CGS layer — but the screen didn’t change. Windows from the previous space stayed visible. It was as if the window server had been told about the new space but hadn’t bothered to redraw.

A second attempt used CGSManagedDisplaySetCurrentSpace — a direct private API call that tells the window server to change the active space. Same result: the space changed internally, but the visual state didn’t follow.

This is the part where the stars start to wobble. You’ve got a technique that works in two independent open-source projects, and it’s not working in yours. The temptation is to assume you’ve made a transcription error. So you check the field numbers. You check the event types. You check the posting order. Everything matches. You build a standalone C test tool that replicates the InstantSpaceSwitcher code verbatim and run it from the terminal. Nothing happens.

That’s when you stop checking your code and start questioning your assumptions.

The Missing Gravity

The breakthrough came from a detail that both reference implementations shared but that seemed incidental: they both registered a CGEventTap at initialisation time. ISS needed one because it was intercepting real trackpad gestures. InstantSpaceSwitcher created one with an empty callback that just passed events through. I’d assumed this was a leftover from development, or perhaps a requirement for the hotkey detection that InstantSpaceSwitcher also performed.

It wasn’t a leftover. It was load-bearing.

On macOS 16, the system appears to require an active event tap registered at the session level before it will accept synthetic gesture events posted to that level. Without the tap, CGEventPost succeeds silently — no error, no crash — but the events are simply discarded. The Dock never sees them.

Adding a minimal event tap — listening for key events with a pass-through callback — was enough. The synthetic gesture events started reaching the Dock. The spaces started switching. The desktop started restoring. And because the velocity was 400, there was no animation. Just an instant cut from one space to the next.

The celestial mechanics of four undocumented event types, a registered-but-idle event tap, and a window server that only listens when it knows someone is watching. The stars had aligned.

The Full Constellation

With the core switching working, the rest came together quickly.

Wrap-around navigation. If you’re on the last space and hit “next,” you land on the first space. If you’re on the first and hit “previous,” you land on the last. This is one of those features that feels obvious the moment you use it and inexplicably absent from Mission Control’s own implementation.

Configurable keyboard shortcuts. The event tap that enabled synthetic gesture posting also enabled global hotkey detection — a pleasing bit of dual-purpose engineering. The tap callback checks incoming key events against user-configured shortcuts. If there’s a match, it consumes the event and triggers the switch. If not, it passes the event through untouched. Two birds, one gravitational field.

Multi-space jumps. Jumping from Space 1 to Space 4 means posting three gesture pairs in rapid succession. Because each switch is instant (no animation to wait for), they chain seamlessly. Three switches that each take effectively zero time still take effectively zero time in total.

The entire implementation is about 120 lines of Swift for the gesture posting, and another 80 or so for the hotkey handling. The rest of the app — the space observer, the menu bar icon, the settings view — was already there. The surgery was precise: replace the AppleScript engine with a gesture engine, keep everything else.

Credit Where Credit Orbits

I want to be explicit about the debt here. This implementation wouldn’t exist without two pieces of work by two developers I’ve never met:

Joshua Li’s ISS demonstrated that synthetic dock-swipe gestures could achieve instant space switching. The elegance of the approach — working with the Dock’s gesture processing rather than around it — is what made this entire line of investigation viable.

Justin Proulx’s InstantSpaceSwitcher provided the complete gesture event structure, including the companion gesture events and the event tap registration that proved essential on macOS 16. Without this reference implementation, I’d still be staring at a space indicator that updated without a screen that followed.

Both projects are open source. Both are small. Both solve one problem and solve it well. They’re exactly the kind of software I believe in building, and I’m grateful they exist.

Ephemeris

There’s a lesson here that I keep relearning. The hardest problems in systems programming aren’t algorithmic. They’re archaeological. The information exists, scattered across GitHub repositories and reverse-engineering notes and forum posts from 2019. The technique works. The APIs are stable. But nobody’s written it all down in one place, for your specific language, on your specific OS version, with your specific calling context. You have to triangulate from multiple sources, test each assumption independently, and be prepared for the moment when something that works everywhere else doesn’t work for you — because that’s where the actual learning happens.

This morning, the stars aligned. Two open-source projects pointed the way. A handful of undocumented event fields did what they’ve apparently been doing since at least macOS 13. An idle event tap convinced the system to listen. And a space switch that used to take over a second now takes no perceptible time at all.

Tomorrow the stars will drift. Apple will change something. The field numbers will shift, or the event tap requirement will tighten, or the Dock will stop trusting synthetic gestures entirely. That’s the nature of building on undocumented APIs — you’re navigating by stars that someone else hung in the sky, and they can rearrange the constellations whenever they like.

But today, it works. And it’s instant. And that’s enough.