Open-source project
pilotmoon/Scroll-Reverser avatar
pilotmoon/Scroll-Reverser

Scroll Reverser: per-device scroll direction for macOS, in one event tap

Per-device scrolling prefs on macOS.

3,624 stars175 forksObjective-CApache-2.0

At a glance

What is it?
A small Objective-C utility that flips scrolling for mice and trackpads independently, built on a Quartz event tap. The README calls everything except MouseTap.m user interface rigging, and the file list suggests otherwise.
Who is it for?
Scroll Reverser solves a genuine macOS inconsistency in about a page of documentation, and if you want mouse scrolling inverted while your trackpad stays native, the preferences window is where you find it. It is the wrong tool if your complaint is that an application ignores the system setting, because the utility reverses the event stream rather than changing the preference, so an app that hardcodes direction is not going to cooperate.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 20 days ago.
What is it written in?
Mainly Objective-C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 6, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One preference for trackpads and mice, kept apart

The entire promise fits in the README's first line: it reverses the direction of scrolling on macOS, with independent settings for trackpads and mice. That independence is the feature. macOS has a single system preference for natural scrolling, and the people who want it reversed usually want it reversed for one input device and not the other, because the two devices feel different when inverted. A global toggle forces a choice between a trackpad that feels wrong and a mouse that feels wrong.

This is not a utility that needs a feature list, and the README does not pretend otherwise. There is no configuration file, no launch agent, no menu bar icon documented as a feature. What exists is a menu bar presence, a preferences window, and a rule for classifying input.

The downloads are the more interesting part of the README. It points at a home page on pilotmoon.com for download links and more information, and separately notes that downloads are also available in the GitHub releases tab. So there are two distribution channels, one of them a company product site, and the repository does not state a price for the binary or describe how the two channels differ. The Apache 2.0 license in the repository covers the source you can read here; the README does not extend it to the distributed application.

How the trackpad and the mouse are told apart

The mechanism is an event tap. The README states that Scroll Reverser installs an event tap, which gives it access to the event stream including scrolling events and gesture events, and points at Quartz Event Services as the main documentation for that. This is the same interception point a screen reader or an accessibility tool uses, which is why an app like this needs a permission grant before it will do anything.

Classification works through gesture events. The README says the app examines gesture events to determine whether there are two or more fingers on the trackpad, and if so assumes scrolling is coming from the trackpad, otherwise a mouse. It adds a parenthetical that there is more to it than that, which is the right amount of honesty: the simple rule is the concept, not the implementation.

The implementation lives in one file by the README's account. It says the guts of the code are in MouseTap.m and that everything else is user interface rigging. The file list tells a longer story. Alongside `MouseTap.m` and `MouseTap.h` there are `PermissionsManager.h` and `PermissionsManager.m`, `LoginItemController.h` and `.m`, `StatusItemController.h` and `.m`, `TapLogger.h` and `.m`, `Logger.h`, `LoggerScrollView.h` and `.m`, `LinkView.h` and `.m`, and five window controllers covering preferences, debug, test, and welcome windows.

Read those two claims side by side rather than picking one. The README is right that the direction logic is one file, which is why this is a small, comprehensible program. It is understating the rest: `PermissionsManager` is the part that has to survive macOS changing its permission model, and `LoginItemController` is the part that decides whether the utility starts at login. Those are not interface concerns.

Building from a clone means replacing the code signing certificate

This is the most useful paragraph in the README and it is buried under a heading called Building. Two things have to happen before the project builds at all.

The first is the submodule. After cloning, the BuildScripts submodule has to be checked out:

bash
git submodule update --init

The second is signing. The README says a fresh build fails because you do not have the author's code signing certificate, and that the fix is to replace it with your own Developer ID certificate in the Signing and Capabilities tab of the Scroll Reverser target settings in Xcode. The `BuildScripts` entry in the tree and the `.xcodeproj/` directory confirm this is a full Xcode project with a submodule for build automation, not a Makefile or Swift package.

The debug build has documented oddities that are not bugs. Debug builds produce an application with no app icon, named Scroll Reverser (Dev), with the version string 99999. The README calls this the expected behaviour and says the build is otherwise fully functional. That is worth knowing before you assume you broke something, and it is also a small design decision you can look for later: a development build that cannot be confused with the installed one.

The configuration split is visible in the tree as `Common.xcconfig`, `Development.xcconfig`, `Production.xcconfig` and `Version.xcconfig`, which is a conventional arrangement and explains why the debug version is set from a file rather than in the build settings panel.

A custom debug window because NSLog is too slow for the tap

The performance reasoning in the README is the kind of detail that separates a utility that works from one that gets uninstalled. Scroll Reverser's main event tap does not write debug output with `NSLog`, because doing so would slow event processing too much. Instead it has custom debug code that is described as more efficient to write to.

The result is a small application with a real user interface rather than a logging facility. `DebugWindow.xib` and `DebugWindowController.h` and `.m` exist for it, alongside `TestWindow.xib` and `WelcomeWindow.xib`. To see the log, you Option-click the Scroll Reverser menu bar icon.

The supporting files explain the design. `TapLogger.h` and `TapLogger.m` are separate from `Logger.h`, `LoggerScrollView.h` and `LoggerScrollView.m`, so the tap's logging path is isolated from the general-purpose one. That separation is the file-level evidence for the README's performance claim: the author built a different logger for the hot path instead of reconfiguring the existing one.

`ScrollReverser.sdef` is in the tree, which is a scripting definition file. That means the app exposes an AppleScript interface, which is how it can be driven by a shortcut or an automation rather than only by clicking the menu bar icon. The README does not document the scripting commands, so if automation is your use case you will be reading the sdef rather than a guide.

v1.9 from 2024, with commits landing in 2026

The release history and the push history do not line up, and the gap is large enough to state in dates. The most recent named release is v1.9, published on 2024-06-21. Around it sit two build-tagged releases, b10527 and b10528, both on 2024-06-20, whose notes are cosmetic fixes to the preferences window and the application icon. The repository's last push was 2026-10-03 and it is not archived.

So the last versioned release carries a June 2024 date while the branch has been receiving commits more than two years later. Both facts come from the repository, and neither one tells you which of them reflects the current state of the application.

The v1.9 notes are themselves informative about what this project considers a release. It fixed the start-at-login setting on recent macOS versions, added an icon in the Big Sur style, changed behaviour when the app is relaunched while running, hid the step size setting unless a scroll wheel is actually in use, corrected Czech, Slovak, Spanish and Turkish translations, updated the Sparkle auto-update framework, and raised the minimum system requirement to macOS 13.5 Ventura. That last item is the one to check first, since it is a hard floor.

The presence of `Sparkle.framework/` in the tree matches the auto-update note, and `ReleaseNotes.md` at the root is the file where the project's own history lives. The `NOTICE` file sits alongside `LICENSE`, which is the Apache 2.0 convention for third-party attribution, and in this case it is the attribution for the bundled Sparkle framework rather than for the utility itself.

What this utility is not, and what to compare it against

The important limitation is the one the README does not discuss. Scroll Reverser works by intercepting and rewriting events in the stream, not by changing the system preference. That distinction decides where it works. Anything that honours the macOS scrolling preference, which is most native applications, responds to the change. Anything that hardcodes its own direction, or that runs in a context where an event tap cannot see the scroll, will not. The README says nothing about known non-cooperating applications, so you should expect to discover them yourself.

There is a second category of difference worth separating. If your problem is that macOS inverted scrolling after an update and you want the old behaviour back, the system preference solves that and this app is unnecessary. If your problem is that you want opposite behaviour per device, no system preference solves it and this app does.

Against the alternatives, the comparison is short. Mos, LinearMouse and the macOS setting itself all change behaviour globally or per device through supported means, and they do so without an accessibility permission grant. What Scroll Reverser adds is per-device independence plus scripting, and what it costs is a background process holding an event tap and the permission that requires. On a machine where an event tap is already present for accessibility reasons, adding a second one is cheap; on a locked-down corporate Mac, it may be blocked outright.

For a developer, the honest comparison is with writing it yourself. The README's central claim is that this is a small amount of real logic in one file plus interface scaffolding, and the file list broadly supports the size of that claim. Whether it is worth forty minutes of your own time depends on whether you want the menu bar integration, the login item handling and the permission flow handed to you.

Editorial conclusion

Scroll Reverser solves a genuine macOS inconsistency in about a page of documentation, and if you want mouse scrolling inverted while your trackpad stays native, the preferences window is where you find it. It is the wrong tool if your complaint is that an application ignores the system setting, because the utility reverses the event stream rather than changing the preference, so an app that hardcodes direction is not going to cooperate. Before building it yourself, read the note about the code signing certificate, because a fresh clone does not build without replacing the author's certificate with your own Developer ID, and a debug build is versioned 99999 with no icon. Option-click the menu bar icon for the runtime debug window when you need to see whether events are arriving at all, and check the releases tab against the pilotmoon.com download page since the last tagged version is v1.9 from 2024 while the repository itself has been pushed to more recently.

Frequently asked questions

Is a scroll reverser safe?

Scroll Reverser works by installing an event tap, the Quartz Event Services mechanism that gives an application access to the event stream including scroll and gesture events, which is the same interception point accessibility tools use. It therefore needs a macOS permission grant before it will function.

Can I use Scroll Reverser on my MacBook?

The application is macOS software and the v1.9 release notes set the minimum system requirement at macOS 13.5 Ventura, so a current MacBook qualifies. It is not built for other platforms, and the project ships no Windows or Linux build.

How do I turn off reverse scrolling?

The README documents independent settings for trackpads and mice rather than a single global switch, so reversing can be turned off per device class from the preferences window. It does not document an uninstall procedure, and the source tree includes a login item controller, so you also want to check the start-at-login setting.

Official sources

  1. License: Apache-2.0
  2. pilotmoon/Scroll-Reverser on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pilotmoon-scroll-reverser.svg)](https://hysenlabs.com/projects/pilotmoon-scroll-reverser)

Was this useful?