Skip to content

TomBadash/Mouser

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

61 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Mouser β€” Logitech Mouse Remapper

Mouser logo

A lightweight, open-source, fully local alternative to Logitech Options+ for remapping Logitech HID++ mice. The current best experience is on the MX Master family, with early detection and fallback UI support for additional Logitech models.

No telemetry. No cloud. No Logitech account required.


Features

  • macOS support β€” full macOS compatibility using CGEventTap for mouse hooking, Quartz CGEvent for key simulation, and NSWorkspace for app detection. See macOS Setup Guide for details.
  • Remap supported programmable controls β€” MX Master-family layouts expose middle click, gesture button, back, forward, and horizontal scroll actions
  • Per-application profiles β€” automatically switch button mappings when you switch apps (e.g., different bindings for Chrome vs. VS Code)
  • 22 built-in actions across navigation, browser, editing, and media categories
  • DPI / pointer speed control β€” slider from 200–8000 DPI with quick presets, synced to the device via HID++
  • Scroll direction inversion β€” independent toggles for vertical and horizontal scroll
  • Device-aware HID++ gesture support β€” discovers REPROG_CONTROLS_V4, ranks gesture candidates per device, and diverts the best control it can find
  • Auto-reconnection β€” automatically detects when the mouse is turned off/on or disconnected/reconnected and restores full functionality without restarting the app
  • Live connection status β€” the UI shows a real-time "Connected" / "Not Connected" badge that updates as the mouse connects or disconnects
  • Device-aware Qt Quick UI β€” interactive MX Master layout today, plus a generic fallback card and experimental manual map picker for other detected devices
  • System tray β€” runs in background, hides to tray on close, toggle remapping on/off from tray menu
  • Auto-detect foreground app β€” polls the active window and switches profiles instantly
  • Zero external services β€” config is a local JSON file, all processing happens on your machine

Screenshots

Mouser UI

The UI is now device-aware. MX Master-family mice get the interactive diagram; other detected Logitech mice fall back to a generic device card with an experimental map override picker.

Current Device Coverage

Family / model Detection + HID++ probing UI support
MX Master 3S / 3 / 2S / MX Master Yes Dedicated interactive mx_master layout
MX Anywhere 3S / 3 / 2S Yes Generic fallback card, experimental manual override
MX Vertical Yes Generic fallback card
Unknown Logitech HID++ mice Best effort by PID/name Generic fallback card

Note: Only the MX Master family currently has a dedicated visual overlay. Other devices can still be detected, show their model name in the UI, and try the experimental layout override picker, but button positions may not line up until a real overlay is added.

Default Mappings

Button Default Action
Back button Alt + Tab (Switch Windows)
Forward button Alt + Tab (Switch Windows)
Middle click Pass-through
Gesture button Pass-through
Horizontal scroll left Browser Back
Horizontal scroll right Browser Forward

Available Actions

Category Actions
Navigation Alt+Tab, Alt+Shift+Tab, Show Desktop (Win+D), Task View (Win+Tab)
Browser Back, Forward, Close Tab (Ctrl+W), New Tab (Ctrl+T)
Editing Copy, Paste, Cut, Undo, Select All, Save, Find
Media Volume Up, Volume Down, Volume Mute, Play/Pause, Next Track, Previous Track
Other Do Nothing (pass-through)

Download & Run

No install required. Just download, extract, and double-click.

Download Downloads

Steps

  1. Go to the latest release page
  2. Click Mouser.zip to download it
  3. Extract the zip to any folder (Desktop, Documents, wherever you like)
  4. Run Mouser.exe

That's it. The app will open and start remapping your mouse buttons immediately.

What to expect

  • The settings window opens showing the current device-aware mouse page
  • A system tray icon appears near the clock (bottom-right)
  • Button remapping is active immediately
  • Closing the window does not quit the app β€” it keeps running in the tray
  • To fully quit: right-click the tray icon and select Quit Mouser

First-time notes

  • Windows SmartScreen may show a warning the first time β€” click More info then Run anyway
  • Logitech Options+ must not be running (it conflicts with HID++ access and will cause Mouser to malfunction or crash)
  • Config is saved automatically to %APPDATA%\Mouser

Installation (from source)

Prerequisites

  • Windows 10/11 or macOS 12+ (Monterey)
  • Python 3.10+ (tested with 3.14)
  • A supported Logitech HID++ mouse paired via Bluetooth or USB receiver. MX Master-family devices currently have the most complete UI support.
  • Logitech Options+ must NOT be running (it conflicts with HID++ access)
  • macOS only: Accessibility permission required (System Settings β†’ Privacy & Security β†’ Accessibility)

Steps

# 1. Clone the repository
git clone https://github.com/TomBadash/Mouser.git
cd Mouser

# 2. Create a virtual environment
python -m venv .venv

# 3. Activate it
.venv\Scripts\activate        # Windows (PowerShell / CMD)
source .venv/bin/activate      # macOS / Linux

# 4. Install dependencies
pip install -r requirements.txt

Dependencies

Package Purpose
PySide6 Qt Quick / QML UI framework
hidapi HID++ communication with the mouse (gesture button, DPI)
pystray System tray icon (legacy, may be removed)
Pillow Image processing for icon generation

Running

# Option A: Run directly
python main_qml.py

# Option B: Use the batch file (shows a console window)
Mouser.bat

# Option C: Use the desktop shortcut (no console window)
# Double-click Mouser.lnk

Tip: To run without a console window, use pythonw.exe main_qml.py or the .lnk shortcut.

Temporary macOS transport override for debugging:

python main_qml.py --hid-backend=iokit
python main_qml.py --hid-backend=hidapi
python main_qml.py --hid-backend=auto

Use this only for troubleshooting. On macOS, Mouser now defaults to iokit; hidapi and auto remain available as manual overrides for debugging. Other platforms continue to default to auto.

Creating a Desktop Shortcut

A Mouser.lnk shortcut is included. To create one manually:

$s = (New-Object -ComObject WScript.Shell).CreateShortcut("$([Environment]::GetFolderPath('Desktop'))\Mouser.lnk")
$s.TargetPath = "C:\path\to\mouser\.venv\Scripts\pythonw.exe"
$s.Arguments = "main_qml.py"
$s.WorkingDirectory = "C:\path\to\mouser"
$s.IconLocation = "C:\path\to\mouser\images\logo.ico, 0"
$s.Save()

Building the Portable App

To produce a standalone Mouser.exe that anyone can download and run without Python:

# 1. Install PyInstaller (inside your venv)
pip install pyinstaller

# 2. Build using the included spec file
pyinstaller Mouser.spec --noconfirm

# β€” or simply run the build script β€”
build.bat

The output is in dist\Mouser\. Zip that entire folder and distribute it.


How It Works

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Logitech mouse │────▢│ Mouse    │────▢│ Engine         β”‚
β”‚ / HID++ device β”‚     β”‚ Hook     β”‚     β”‚ (orchestrator) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β–²                    β”‚
                    block/pass           β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                                         β”‚ Key         β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚ Simulator   β”‚
β”‚ QML UI      │◀───▢│ Backend  β”‚        β”‚ (SendInput) β”‚
β”‚ (PySide6)   β”‚     β”‚ (QObject)β”‚        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                         β–²
                    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚ App         β”‚
                    β”‚ Detector    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Mouse Hook (mouse_hook.py)

Mouser uses a platform-specific mouse hook behind a shared MouseHook abstraction:

  • Windows β€” SetWindowsHookExW with WH_MOUSE_LL on a dedicated background thread, plus Raw Input for extra mouse data
  • macOS β€” CGEventTap for mouse interception and Quartz events for key simulation

Both paths feed the same internal event model and intercept:

  • WM_XBUTTONDOWN/UP β€” side buttons (back/forward)
  • WM_MBUTTONDOWN/UP β€” middle click
  • WM_MOUSEHWHEEL β€” horizontal scroll
  • WM_MOUSEWHEEL β€” vertical scroll (for inversion)

Intercepted events are either blocked (hook returns 1) and replaced with an action, or passed through to the application.

Device Catalog & Layout Registry

  • core/logi_devices.py resolves known product IDs and model aliases into a ConnectedDeviceInfo record with display name, DPI range, preferred gesture CIDs, and default UI layout key
  • core/device_layouts.py stores image assets, hotspot coordinates, layout notes, and whether a layout is interactive or only a generic fallback
  • ui/backend.py combines auto-detected device info with any persisted per-device layout override and exposes the effective layout to QML

Gesture Button Detection

Logitech gesture/thumb buttons do not always appear as standard mouse events. Mouser uses a layered detector:

  1. HID++ 2.0 (primary) β€” Opens the Logitech HID collection, discovers REPROG_CONTROLS_V4 (feature 0x1B04), ranks gesture CID candidates from the device registry plus control-capability heuristics, and diverts the best candidate. When supported, Mouser also enables RawXY movement data.
  2. Raw Input (Windows fallback) β€” Registers for raw mouse input and detects extra button bits beyond the standard 5.
  3. Gesture tap/swipe dispatch β€” A clean press/release emits gesture_click; once movement crosses the configured threshold, Mouser emits directional swipe actions instead.

App Detector (app_detector.py)

Polls the foreground window every 300ms using GetForegroundWindow β†’ GetWindowThreadProcessId β†’ process name. Handles UWP apps by resolving ApplicationFrameHost.exe to the actual child process.

Engine (engine.py)

The central orchestrator. On app change, it performs a lightweight profile switch β€” clears and re-wires hook callbacks without tearing down the hook thread or HID++ connection. This avoids the latency and instability of a full hook restart. The engine also forwards connected-device identity to the backend so QML can render the right model name and layout state.

Device Reconnection

Mouser handles mouse power-off/on cycles automatically:

  • HID++ layer β€” HidGestureListener detects device disconnection (read errors) and enters a reconnect loop, retrying every 2–5 seconds until the device is back
  • Hook layer β€” MouseHook listens for WM_DEVICECHANGE notifications and reinstalls the low-level mouse hook when devices are added or removed
  • UI layer β€” connection state and device identity flow from HID++ β†’ MouseHook β†’ Engine β†’ Backend (cross-thread safe via Qt signals) β†’ QML, updating the status badge, device name, and active layout in real time

Configuration

All settings are stored in %APPDATA%\Mouser\config.json (Windows) or ~/Library/Application Support/Mouser/config.json (macOS). The config supports:

  • Multiple named profiles with per-profile button mappings, including gesture tap + swipe actions
  • Per-profile app associations (list of .exe names)
  • Global settings: DPI, scroll inversion, gesture tuning, appearance, and debug flags
  • Per-device layout override selections for unsupported devices
  • Automatic migration from older config versions

Project Structure

mouser/
β”œβ”€β”€ main_qml.py              # Application entry point (PySide6 + QML)
β”œβ”€β”€ Mouser.bat               # Quick-launch batch file
β”œβ”€β”€ README.md
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ .gitignore
β”‚
β”œβ”€β”€ core/                    # Backend logic
β”‚   β”œβ”€β”€ engine.py            # Core engine β€” wires hook ↔ simulator ↔ config
β”‚   β”œβ”€β”€ mouse_hook.py        # Low-level mouse hook + HID++ gesture listener
β”‚   β”œβ”€β”€ hid_gesture.py       # HID++ 2.0 gesture button divert (Bluetooth)
β”‚   β”œβ”€β”€ logi_devices.py      # Known Logitech device catalog + connected-device metadata
β”‚   β”œβ”€β”€ device_layouts.py    # Device-family layout registry for QML overlays
β”‚   β”œβ”€β”€ key_simulator.py     # SendInput-based action simulator (22 actions)
β”‚   β”œβ”€β”€ config.py            # Config manager (JSON load/save/migrate)
β”‚   └── app_detector.py      # Foreground app polling
β”‚
β”œβ”€β”€ ui/                      # UI layer
β”‚   β”œβ”€β”€ backend.py           # QML ↔ Python bridge (QObject with properties/slots)
β”‚   └── qml/
β”‚       β”œβ”€β”€ Main.qml         # App shell (sidebar + page stack + tray toast)
β”‚       β”œβ”€β”€ MousePage.qml    # Merged mouse diagram + profile manager
β”‚       β”œβ”€β”€ ScrollPage.qml   # DPI slider + scroll inversion toggles
β”‚       β”œβ”€β”€ HotspotDot.qml   # Interactive button overlay on mouse image
β”‚       β”œβ”€β”€ ActionChip.qml   # Selectable action pill
β”‚       └── Theme.js         # Shared colors and constants
β”‚
└── images/
    β”œβ”€β”€ mouse.png            # MX Master 3S top-down diagram
    β”œβ”€β”€ icons/mouse-simple.svg # Generic fallback device card artwork
    β”œβ”€β”€ logo.png             # Mouser logo (source)
    β”œβ”€β”€ logo.ico             # Multi-size icon for shortcuts
    β”œβ”€β”€ logo_icon.png        # Square icon with background
    β”œβ”€β”€ chrom.png            # App icon: Chrome
    β”œβ”€β”€ VSCODE.png           # App icon: VS Code
    β”œβ”€β”€ VLC.png              # App icon: VLC
    └── media.webp           # App icon: Windows Media Player

UI Overview

The app has two pages accessible from a slim sidebar:

Mouse & Profiles (Page 1)

  • Left panel: List of profiles. The "Default (All Apps)" profile is always present. Per-app profiles show the app icon and name. Select a profile to edit its mappings.
  • Right panel: Device-aware mouse view. MX Master-family devices get clickable hotspot dots on the image; unsupported layouts fall back to a generic device card with an experimental "try another supported map" picker.
  • Add profile: ComboBox at the bottom lists known apps (Chrome, Edge, VS Code, VLC, etc.). Click "+" to create a per-app profile.

Point & Scroll (Page 2)

  • DPI slider: 200–8000 with quick presets (400, 800, 1000, 1600, 2400, 4000, 6000, 8000). Reads the current DPI from the device on startup.
  • Scroll inversion: Independent toggles for vertical and horizontal scroll direction.

Known Limitations

  • Windows & macOS only β€” Linux is not yet supported
  • Early multi-device support β€” only the MX Master family currently has a dedicated interactive overlay; MX Anywhere, MX Vertical, and unknown Logitech mice still use the generic fallback card
  • Per-device mappings are not fully separated yet β€” layout overrides are stored per detected device, but profile mappings are still global rather than truly device-specific
  • Bluetooth recommended β€” HID++ gesture button divert works best over Bluetooth; USB receiver has partial support
  • Conflicts with Logitech Options+ β€” both apps fight over HID++ access; quit Options+ before running Mouser
  • Scroll inversion is experimental β€” uses coalesced PostMessage injection to avoid LL hook deadlocks; may not work perfectly in all apps
  • Admin not required β€” but some games or elevated windows may not receive injected keystrokes

Future Work

  • Dedicated overlays for more devices β€” add real hotspot maps and artwork for MX Anywhere, MX Vertical, and other Logitech families
  • True per-device config β€” separate mappings and layout state cleanly when multiple Logitech mice are used on the same machine
  • Dynamic button inventory β€” build button lists from discovered REPROG_CONTROLS_V4 controls instead of relying on the current fixed mapping set
  • Custom key combos β€” let users define arbitrary key sequences (e.g., Ctrl+Shift+P)
  • Start with Windows β€” autostart via registry or Task Scheduler
  • Improved scroll inversion β€” explore driver-level or interception-driver approaches
  • Gesture button actions β€” swipe gestures (up/down/left/right) for multi-action gesture button
  • Per-app profile auto-creation β€” detect new apps and prompt to create a profile
  • Export/import config β€” share configurations between machines
  • Tray icon badge β€” show active profile name in tray tooltip
  • macOS support β€” added via CGEventTap, Quartz CGEvent, and NSWorkspace
  • Linux support β€” investigate libevdev / evdev hooks
  • Plugin system β€” allow third-party action providers

Contributing

Contributions are welcome! To get started:

  1. Fork the repo and create a feature branch
  2. Set up the dev environment (see Installation)
  3. Make your changes and test with a supported Logitech HID++ mouse (MX Master family preferred for now)
  4. Submit a pull request with a clear description

Areas where help is needed

  • Testing with other Logitech HID++ devices
  • Scroll inversion improvements
  • Linux porting
  • UI/UX polish and accessibility

Support the Project

If Mouser saves you from installing Logitech Options+, consider supporting development:

Sponsor

Every bit helps keep the project going β€” thank you!

License

This project is licensed under the MIT License.


Acknowledgments

  • @andrew-sz β€” macOS port: CGEventTap mouse hooking, Quartz key simulation, NSWorkspace app detection, and NSEvent media key support
  • @thisislvca β€” significant expansion of the project including macOS compatibility improvements, multi-device support, new UI features, and active involvement in triaging and resolving open issues

Mouser is not affiliated with or endorsed by Logitech. "Logitech", "MX Master", and "Options+" are trademarks of Logitech International S.A.

About

A lightweight, open-source alternative to Logitech Options+ for remapping buttons on the Logitech MX Master 3S mouse

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Packages

 
 
 

Contributors

Languages