macOS: Change scrolling mode from Swift

After switching to macOS completely for development purposes I was annoyed (as were many others, obviously) that you can’t change the scroll direction of the mouse and trackpad independently. Changing one option changes another. So, when I’m connected to the external monitor I want to use a mouse, otherwise, trackpad, meaning, every time the external monitor is connected/disconnected (quite often) I need to go to System Settings, find this option, and toggle it. Sounds easy but still annoying.

But, there is an app for this…

Yes, there are some applications recommended on the internet, like one, two, and three. But, I need just to flip the switch and that’s it, just one button to switch the scroll direction. Looking at the source code of those apps seems like they do more than that and somehow try to interfere with the system, to achieve the reverse scroll direction effect based on the device type (mouse or trackpad)

…Or AppleScript

There are multiple AppleScript’s on various forums, but mostly need small tweaks here and there, but the main problem is when you’re trying to run the script and it hangs for a while trying to digest all the System Settings controls, trying to find the correct tab and option, long story short - it takes time and not user friendly.

Just use defaults

defaults is a tool to manage system or application preference, it’s a sort of standardized way to store settings in property lists (plists) files. Using this is really straightforward, just pass the read or write parameter in the command line and get/set system option. What is not straightforward is to get the name of the parameter that you’re interested in.

In the case of scrolling mode the name of the property is But, here is the problem - setting up this property doesn’t work. Yes, defaults does update the property, but neither System Settings updates the Natural scrolling option nor the actual scrolling is updated. In my case on Ventura, after updating this option things get messed up, was not able to switch between Natural and Normal modes at all. The reason for this is not hard to understand, updating the property is just a fraction of the overall functionality to switch the scrolling mode.

Let’s write a tool…

Ok, so a quick search on the internet led to the setSwipeScrollDirection and the complement swipeScrollDirection function, which is exported from PreferencePanesSupport private framework, which is actually doing all the work except setting the property. Now, the hard part is done, so the next step is to put the icon in a status bar to flip the scrolling mode on a click and to show the current status: Natural vs Normal mode. The final implementation is done in Swift using SwiftUI and can be downloaded here. It contains just a couple of lines of code, but solves the problem in the easiest way.