Mouser now supports macOS alongside Windows. This document covers macOS-specific setup and known differences.
arm64 Python interpreter if you want a native Apple Silicon app bundlex86_64 Python interpreter if you want a native Intel app bundlepip install -r requirements.txt
On macOS, this will also install:
- pyobjc-framework-Quartz — for CGEventTap (mouse hooking) and CGEvent (key simulation)
- pyobjc-framework-Cocoa — for NSWorkspace (app detection) and NSEvent (media keys)
Mouser uses a CGEventTap to intercept and suppress mouse button events. macOS requires Accessibility permission for this:
/usr/local/bin/python3).app bundle (if packaged)If Accessibility is not granted, Mouser will print:
[MouseHook] ERROR: Failed to create CGEventTap!
| Feature | Windows | macOS |
|---|---|---|
| Mouse hook | SetWindowsHookExW (LL hook) | CGEventTap |
| Key simulation | SendInput (VK codes) | CGEvent (CGKeyCodes) |
| Media keys | VK_MEDIA_* constants | NSEvent (NX key IDs) |
| App detection | GetForegroundWindow | NSWorkspace.frontmostApplication |
| Gesture button | HID++ + Raw Input fallback | HID++ + event-tap movement |
| Scroll inversion | Coalesced SendInput | CGEventCreateScrollWheelEvent |
| Modifier key | Ctrl | Cmd (⌘) |
| Config location | %APPDATA%\Mouser |
~/Library/Application Support/Mouser |
| Auto-reconnect | Device change notification | HID++ reconnect loop |
Actions that use Ctrl on Windows automatically use Cmd (⌘) on macOS: - Copy → Cmd+C - Paste → Cmd+V - Cut → Cmd+X - Undo → Cmd+Z - etc.
Desktop/navigation actions are also remapped to native macOS behavior: - Alt+Tab becomes Cmd+Tab - Compatibility entries like Win+D / Task View resolve to native macOS navigation shortcuts - Mouser also exposes macOS-specific actions such as Mission Control, App Expose, Previous Desktop, Next Desktop, Show Desktop, and Launchpad
On macOS, the HID gesture listener uses non-exclusive access (hid_darwin_set_open_exclusive(0))
so the mouse continues to function normally while Mouser reads HID++ reports.
Mouser ignores trackpad and Magic Mouse continuous scroll events by default so two-finger gestures and macOS natural scrolling keep working normally while mouse wheel mappings stay active.
You can change this in Point & Scroll → Scroll Direction → Ignore trackpad. Leave it enabled for built-in trackpads and most Logitech mouse setups. Disable it only if you intentionally want Mouser to handle Magic Mouse or trackpad scroll events.
The repository now includes a dedicated macOS bundle flow:
python3 -m pip install -r requirements.txt pyinstaller
./build_macos_app.sh
This produces:
dist/Mouser.app
Notes:
arm64 Python to produce an Apple Silicon app; on an Intel Mac, use an x86_64 Python to produce an Intel app.PYINSTALLER_TARGET_ARCH=arm64 or PYINSTALLER_TARGET_ARCH=x86_64 before running ./build_macos_app.sh when your macOS Python environment supports that target.images/AppIcon.icns when present; otherwise the script generates an .icns icon from images/logo_icon.png, runs PyInstaller with Mouser-mac.spec, and applies ad-hoc signing via codesign --sign -./Applications/Mouser.app and launched directly from Finder, Spotlight, or Dock.pyinstaller Mouser.spec remains available as a simpler cross-platform build path, but the dedicated macOS script is the preferred bundle flow.Mouser-macOS.zip for Apple Silicon and Mouser-macOS-intel.zip for Intel Macs.The packaged app runs as an LSUIElement, so it lives in the menu bar instead of showing a Dock icon.
python main_qml.py
python main_qml.py --start-hidden
Use --start-hidden to launch straight into the menu bar without opening the settings window.
Mouser can now manage Start at login from the app UI on macOS.
~/Library/LaunchAgents/io.github.tombadash.mouser.plist.app, but it also works in a source checkout by launching the current Python interpreter directlyIf you switch from Terminal-based startup to Mouser.app, re-grant Accessibility for the app bundle:
Send SIGUSR1 to dump all thread stack traces:
kill -USR1 $(pgrep -f main_qml.py)
$ claude mcp add Mouser \
-- python -m otcore.mcp_server <graph>