MCPcopy Index your code
hub / github.com/TomBadash/Mouser

github.com/TomBadash/Mouser @v3.6.0 sqlite

repository ↗ · DeepWiki ↗ · release v3.6.0 ↗
982 symbols 2,629 edges 37 files 173 documented · 18%
README

macOS Support

Mouser now supports macOS alongside Windows. This document covers macOS-specific setup and known differences.

Requirements

  • macOS 12 (Monterey) or later recommended
  • Python 3.11+ (via Homebrew or python.org)
  • Apple Silicon / M1+: use an arm64 Python interpreter if you want a native Apple Silicon app bundle
  • Intel Macs: use an x86_64 Python interpreter if you want a native Intel app bundle
  • Accessibility permission — required for CGEventTap to intercept mouse events

Python Dependencies

pip 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)

Granting Accessibility Permission

Mouser uses a CGEventTap to intercept and suppress mouse button events. macOS requires Accessibility permission for this:

  1. Open System Settings → Privacy & Security → Accessibility
  2. Click the + button
  3. Add either:
  4. Terminal.app / iTerm2 (if running from terminal)
  5. The Python binary (e.g. /usr/local/bin/python3)
  6. The built .app bundle (if packaged)
  7. Ensure the checkbox is enabled
  8. Restart Mouser if it was already running

If Accessibility is not granted, Mouser will print:

[MouseHook] ERROR: Failed to create CGEventTap!

Platform Differences

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

Key Mapping Differences

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

HID Access

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.

Trackpad and Magic Mouse Scroll

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.

Building a Native macOS App

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:

  • Build on the target architecture. On an M1/M2/M3 Mac, use an arm64 Python to produce an Apple Silicon app; on an Intel Mac, use an x86_64 Python to produce an Intel app.
  • You can also set PYINSTALLER_TARGET_ARCH=arm64 or PYINSTALLER_TARGET_ARCH=x86_64 before running ./build_macos_app.sh when your macOS Python environment supports that target.
  • The build flow uses the committed 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 -.
  • The app can then be moved to /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.
  • Release builds publish 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.

Running

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.

Start at Login

Mouser can now manage Start at login from the app UI on macOS.

  • The toggle writes a LaunchAgent plist to ~/Library/LaunchAgents/io.github.tombadash.mouser.plist
  • The setting is designed for the packaged .app, but it also works in a source checkout by launching the current Python interpreter directly
  • If Start minimized is enabled in Mouser, the app still launches tray-first after login because that preference is read from config at startup
  • Turning Start at login back off removes that LaunchAgent plist again

Accessibility for the Packaged App

If you switch from Terminal-based startup to Mouser.app, re-grant Accessibility for the app bundle:

  1. Open System Settings → Privacy & Security → Accessibility
  2. Remove old Terminal / Python entries if needed
  3. Add Mouser.app
  4. Ensure it is enabled
  5. Restart Mouser

Debugging

Send SIGUSR1 to dump all thread stack traces:

kill -USR1 $(pgrep -f main_qml.py)

Core symbols most depended-on inside this repo

_emit_debug
called by 53
core/mouse_hook.py
_qt_enum_int
called by 32
ui/backend.py
_emit_gesture_event
called by 31
core/mouse_hook.py
_dispatch
called by 23
core/mouse_hook.py
save_config
called by 22
core/config.py
_on_connection_change
called by 22
core/engine.py
_request
called by 20
core/hid_gesture.py
write
called by 20
core/log_setup.py

Shape

Method 697
Function 188
Class 93
Route 4

Languages

Python100%
TypeScript1%

Modules by API surface

ui/backend.py122 symbols
tests/test_smart_shift.py111 symbols
core/mouse_hook.py89 symbols
core/hid_gesture.py76 symbols
core/engine.py52 symbols
tests/test_mouse_hook.py51 symbols
tests/test_hid_gesture.py47 symbols
tests/test_engine.py47 symbols
core/app_catalog.py41 symbols
tests/test_backend.py38 symbols
main_qml.py38 symbols
core/key_simulator.py31 symbols

Dependencies from manifests, versioned

Pillow10.0 · 1×
PySide66.6 · 1×
evdev1.6 · 1×
hidapi0.14 · 1×
pyinstaller6.0 · 1×
pyobjc-framework-Cocoa10.0 · 1×
pyobjc-framework-Quartz10.0 · 1×

For agents

$ claude mcp add Mouser \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact