Apple Never Fixed This Bug, so I Did It Myself

plz fix macOS bug Apple šŸ„ŗ

Richard So
Geek Culture
7 min readJun 15, 2023

--

Rewind back to August 2022. I was super hyped up for the upcoming college year, so much so that I got myself a new monitor to avoid another semester stuck working on my puny 13-inch MacBook screen.

I ended up with one of AOCā€™s low-latency monitors, given Iā€™ve never had the glorious and fabled 120Hz+ experience on any desktop OS. I didnā€™t even care that I was getting a gaming monitor for my MacBook (an M1 mac canā€™t run any real games apart from LoL or CS:GO, mind you). Man, I just wanted all my window dragging and scrolling to be smooth like butter (ā€¦ like a criminal undercover).

A week later, after a stroll to Georgia Techā€™s Amazon locker, I was in business. Oh, how breathtaking! The swift elegance of a windowā€™s movement as I dragged it round and round, the way the infamous UFO virtually flows like water across the monitor!

All went so well, until I switched Spaces.

Thatā€™s odd, the animation is taking a bit longer than usual. **Proceed to switch between spaces a few more times. Disconnect from the monitor, try switching spaces again on my laptop, and now maybe plug it back to see if it works? Okayā€¦yep.**

The animation IS longer than usual. MUCH LONGER.

Go see for yourself (thanks u/mort96):

Time to return the monitor.

(just kidding, but bruh.)

Alright, Hear Me Out

Youā€™d think Iā€™m whining nonsense. Well, 300+ other Mac users have also noticed and have been fuming over this problem for years now. Itā€™s even worse for the ones who bought one of the newer MBP models with their ProMotion displays; theyā€™re stuck with this dang problem from the get go.

Ok, maybe Iā€™m clinically insane for being this obsessed over macOS Spaces. The first part might be true, but ever since Iā€™ve switched to team Apple my workflow has solidified and revolved over the use of multiple spaces (I used to be an i3 fanboy, and i3 workspaces == macOS Spaces).

ā€œBut, can you enable ā€œReduced Motionā€ on System Settings šŸ¤“ā˜ļø?ā€

Nope. That annoying delay is still there when you switch spaces with a higher refresh-rate monitor. Not to mention that macOS with reduced motion really ruins the feel of the OS ā€” I want all my JUICY animations! (yeah, and I was an i3 user...)

Apple?

Great. This has been a bug thatā€™s been on macOS forever, and a decent number of people have caught on. No way Apple will leave this bug untouched for us avid macOS usersā€¦right? Right?

Soā€¦ Iā€™ve waited a whole year for Apple to apply a quick patch, and lo and behold, nothing. Donā€™t get it twisted, I have not the slightest clue in operating system development, but I canā€™t imagine it being harder than changing some variable to a constant. What gives?

This was becoming a real bruh moment. I went through two college semesters, wasting precious milliseconds every time I went ahead and switched spaces. I couldā€™ve contributed yet another Javascript framework to open source with all that time gone >:(

Fine, then. Iā€™ll fix it myself.

My Hack-ish Fix

READ FIRST

My ā€œhackā€ does NOT fix the delay for the gesture trigger (triple finger swipe). It only works for the keyboard shortcut (āŒƒ[Ctrl] + Left/Right arrow). However, you can look into using BetterTouchTool with yabai, though youā€™ll need to disable macOS System Integrity Protection.

Also, I canā€™t verify if this works in a multi-monitor setup ā€” I never use my external monitor and my laptop screen at the same time. You may need some changes on following instructions/code based on how your displays and spaces settings are configured.

Now, onward!

1. Stop macOS from automatically rearranging spaces

For some crazy reason, your Mac ā€” by default ā€” rearranges the order of your spaces based on when youā€™ve last used them.

Disable that by going to System Settings > Desktop & Dock > Scroll down to Mission Control > Unselect ā€œAutomatically rearrange Spaces based on most recent useā€

Disable.

If you actually use spaces with this on, youā€™re weird. Please get some help, Iā€™m rooting for you.

2. Configure keyboard shortcuts for each space

Pressing āŒƒ[Ctrl] + 1 swaps you to your first space/desktop by macOS defaults, regardless of which space you were in before. āŒƒ[Ctrl] + 2 brings you to the second space, and so on. Double check that you have these shortcuts by going to Keyboard > Keyboard Shortcuts > Mission Control.

While youā€™re at it, disable the ā€œMove left/right a spaceā€ shortcuts, and change them to something obscure (it doesnā€™t matter what the new shortcut is, as long as itā€™s not the default). Trust me, weā€™ll override these shortcuts later with another tool.

The core trick to the fix is realizing that switching spaces with these keybinds takes less animation time than using ā€œMove left/right a spaceā€. Try it yourself if you donā€™t believe me.

3. Get Hammerspoon

Hammerspoon basically lets us control or automate macOS at the system level through Lua code. Think of it as an API for almost everything macOS.

Youā€™ll want to follow the siteā€™s directions to install Hammerspoon. It doesnā€™t do anything out of the box, since you need to create a script file in the proper folder. To do this, run this following command:

$ mkdir ~/.hammerspoon && touch ~/.hammerspoon/init.lua

Youā€™ll then need to open this file using a code editor.

4. Hammerspoon code

Letā€™s lay out the blueprint. Whenever we trigger space switching to happen, we want to:

  1. Figure out which space ā€œnumberā€ we are currently on
  2. Determine if it can swap to the next/previous numbered space
  3. Send the āŒƒ[Ctrl] + <Number> shortcut to macOS

Luckily for you, Iā€™ve figured it all out with this (pretty wacky) Lua code right here, so you can copy & paste this to your init.lua file:

--- needed to auto-reload this config file after saving
function reloadConfig(files)
local doReload = false
for _,file in pairs(files) do
if file:sub(-4) == ".lua" then
doReload = true
end
end
if doReload then
hs.reload()
end
end
myWatcher = hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", reloadConfig):start()
hs.alert.show("Config loaded")

function focusedWindowSpaces()
local window = hs.window.focusedWindow()
local displayUUID = window:screen():getUUID()
local activeSpace = hs.spaces.activeSpaceOnScreen()
return window, activeSpace, hs.spaces.allSpaces()[displayUUID]
end

function getAdjacentSpace(right, currSpace, currSpaces)
if right then
adj = 1
else
adj = -1
end
for i = 1, #currSpaces do
if currSpace == currSpaces[i] then
if i + adj < 1 and i + adj > #currSpaces then
return nil
else
return currSpaces[i + adj], i + adj
end
end
end
end

hs.hotkey.bind("ctrl", "left", function()
-- get current window and space layout
window, currSpace, currSpaces = focusedWindowSpaces()

-- get current space and relative left space
newSpace, i = getAdjacentSpace(false, currSpace, currSpaces)
if newSpace == nil then return end

-- move perspective to left space
hs.eventtap.keyStroke({"ctrl"}, ""..i)
end)

hs.hotkey.bind("ctrl", "right", function()
-- get current window and space layout
window, currSpace, currSpaces = focusedWindowSpaces()

-- get current space and relative right space
newSpace, i = getAdjacentSpace(true, currSpace, currSpaces)
if newSpace == nil then return end

-- move perspective to right space
hs.eventtap.keyStroke({"ctrl"}, ""..i)
end)

Save these changes to init.lua, and youā€™ll see that your original āŒƒ[Ctrl] + Left/Right shortcuts will work again. More importantly, that darn delay is gone!

5. (Optional) A cherry on top

I swap between spaces really often, but I also find it really common that Iā€™ll want to switch to another space while bringing a window along with me. You can go to Mission Control, slowly drag that window to the neighboring space, and finally switch spacesā€¦yeah, super boring.

Or, you can bind all that to just one shortcut by adding this to init.lua:

hs.hotkey.bind({"ctrl", "shift"}, "left", function()
-- get current window and space layout
window, currSpace, currSpaces = focusedWindowSpaces()

-- get current space and relative left space
newSpace, i = getAdjacentSpace(false, currSpace, currSpaces)
if newSpace == nil then return end

-- move window and perspective to left space
hs.spaces.moveWindowToSpace(window:id(), newSpace)
hs.eventtap.keyStroke({"ctrl"}, ""..i)
end)

hs.hotkey.bind({"ctrl", "shift"}, "right", function()
-- get current window and space layout
window, currSpace, currSpaces = focusedWindowSpaces()

-- get current space and relative right space
newSpace, i = getAdjacentSpace(true, currSpace, currSpaces)
if newSpace == nil then return end

-- move window and perspective to right space
hs.spaces.moveWindowToSpace(window:id(), newSpace)
hs.eventtap.keyStroke({"ctrl"}, ""..i)
end)

Now, āŒƒ[Ctrl] + Shift + arrow keys are bound to this super powerful combination of actions. Iā€™m not sure about you, but moving windows to different spaces using shortcuts on macOS is pretty dope.

Enjoy!

With Hammerspoon and about 100 lines of Lua, I just hacked myself out of this macOS Spaces bug that has been bugging me for about a year now. Not too shabby, Iā€™ll call it a win!

Itā€™ll take a bit of getting used to the new animation and the shortcuts managed by Hammerspoon. If you ever feel like spamming these shortcuts, I actually find it faster to pause a bit between each shortcut trigger if you really want to quickly sift through your spaces.

Otherwise, I canā€™t wait for a future macOS update to make this article instantly obsolete. Iā€™m counting on you, Apple!

--

--

Richard So
Geek Culture

https://sorichard.com | BS/MS CS @ Georgia Tech, Class of ā€™25. Pursuing everything code. Always learning!