TomBadash/MouserPublic

A lightweight, open-source, fully local alternative to Logitech Options+ for remapping Logitech HID++ mice.

AI summary: A lightweight, local, cloud-free alternative to Logitech Options+ for mouse remapping.

Stars
5.1K
+7 today
Forks
178
Watchers
9
Open issues
73
Open PRs
28
Contributors
~28
Commits
279
Branches
18

PythonMITCreated Feb 24, 2026Last push 9d agoLatest release v3.7.3+43 stars this week+60 this month

Star history

since Mar 8, 2026
02K4KMar 2026Apr 2026Jun 2026Aug 2026
5.1K stars as of Aug 7, 2026, tracked back to Mar 8, 2026. Historical curve reconstructed from public GitHub event archives, calibrated to the current total.

Contribution activity

commits per day, last 52 weeks
AugSepOctNovDecJanFebMarAprMayJunJulMonWedFri2025-08-02: 0 commits2025-08-03: 0 commits2025-08-04: 0 commits2025-08-05: 0 commits2025-08-06: 0 commits2025-08-07: 0 commits2025-08-08: 0 commits2025-08-09: 0 commits2025-08-10: 0 commits2025-08-11: 0 commits2025-08-12: 0 commits2025-08-13: 0 commits2025-08-14: 0 commits2025-08-15: 0 commits2025-08-16: 0 commits2025-08-17: 0 commits2025-08-18: 0 commits2025-08-19: 0 commits2025-08-20: 0 commits2025-08-21: 0 commits2025-08-22: 0 commits2025-08-23: 0 commits2025-08-24: 0 commits2025-08-25: 0 commits2025-08-26: 0 commits2025-08-27: 0 commits2025-08-28: 0 commits2025-08-29: 0 commits2025-08-30: 0 commits2025-08-31: 0 commits2025-09-01: 0 commits2025-09-02: 0 commits2025-09-03: 0 commits2025-09-04: 0 commits2025-09-05: 0 commits2025-09-06: 0 commits2025-09-07: 0 commits2025-09-08: 0 commits2025-09-09: 0 commits2025-09-10: 0 commits2025-09-11: 0 commits2025-09-12: 0 commits2025-09-13: 0 commits2025-09-14: 0 commits2025-09-15: 0 commits2025-09-16: 0 commits2025-09-17: 0 commits2025-09-18: 0 commits2025-09-19: 0 commits2025-09-20: 0 commits2025-09-21: 0 commits2025-09-22: 0 commits2025-09-23: 0 commits2025-09-24: 0 commits2025-09-25: 0 commits2025-09-26: 0 commits2025-09-27: 0 commits2025-09-28: 0 commits2025-09-29: 0 commits2025-09-30: 0 commits2025-10-01: 0 commits2025-10-02: 0 commits2025-10-03: 0 commits2025-10-04: 0 commits2025-10-05: 0 commits2025-10-06: 0 commits2025-10-07: 0 commits2025-10-08: 0 commits2025-10-09: 0 commits2025-10-10: 0 commits2025-10-11: 0 commits2025-10-12: 0 commits2025-10-13: 0 commits2025-10-14: 0 commits2025-10-15: 0 commits2025-10-16: 0 commits2025-10-17: 0 commits2025-10-18: 0 commits2025-10-19: 0 commits2025-10-20: 0 commits2025-10-21: 0 commits2025-10-22: 0 commits2025-10-23: 0 commits2025-10-24: 0 commits2025-10-25: 0 commits2025-10-26: 0 commits2025-10-27: 0 commits2025-10-28: 0 commits2025-10-29: 0 commits2025-10-30: 0 commits2025-10-31: 0 commits2025-11-01: 0 commits2025-11-02: 0 commits2025-11-03: 0 commits2025-11-04: 0 commits2025-11-05: 0 commits2025-11-06: 0 commits2025-11-07: 0 commits2025-11-09: 0 commits2025-11-10: 0 commits2025-11-11: 0 commits2025-11-12: 0 commits2025-11-13: 0 commits2025-11-14: 0 commits2025-11-15: 0 commits2025-11-16: 0 commits2025-11-17: 0 commits2025-11-18: 0 commits2025-11-19: 0 commits2025-11-20: 0 commits2025-11-21: 0 commits2025-11-22: 0 commits2025-11-23: 0 commits2025-11-24: 0 commits2025-11-25: 0 commits2025-11-26: 0 commits2025-11-27: 0 commits2025-11-28: 0 commits2025-11-29: 0 commits2025-11-30: 0 commits2025-12-01: 0 commits2025-12-02: 0 commits2025-12-03: 0 commits2025-12-04: 0 commits2025-12-05: 0 commits2025-12-06: 0 commits2025-12-07: 0 commits2025-12-08: 0 commits2025-12-09: 0 commits2025-12-10: 0 commits2025-12-11: 0 commits2025-12-12: 0 commits2025-12-13: 0 commits2025-12-14: 0 commits2025-12-15: 0 commits2025-12-16: 0 commits2025-12-17: 0 commits2025-12-18: 0 commits2025-12-19: 0 commits2025-12-20: 0 commits2025-12-21: 0 commits2025-12-22: 0 commits2025-12-23: 0 commits2025-12-24: 0 commits2025-12-25: 0 commits2025-12-26: 0 commits2025-12-27: 0 commits2025-12-28: 0 commits2025-12-29: 0 commits2025-12-30: 0 commits2025-12-31: 0 commits2026-01-01: 0 commits2026-01-02: 0 commits2026-01-03: 0 commits2026-01-04: 0 commits2026-01-05: 0 commits2026-01-06: 0 commits2026-01-07: 0 commits2026-01-08: 0 commits2026-01-09: 0 commits2026-01-10: 0 commits2026-01-11: 0 commits2026-01-12: 0 commits2026-01-13: 0 commits2026-01-14: 0 commits2026-01-15: 0 commits2026-01-16: 0 commits2026-01-17: 0 commits2026-01-18: 0 commits2026-01-19: 0 commits2026-01-20: 0 commits2026-01-21: 0 commits2026-01-22: 0 commits2026-01-23: 0 commits2026-01-24: 0 commits2026-01-25: 0 commits2026-01-26: 0 commits2026-01-27: 0 commits2026-01-28: 0 commits2026-01-29: 0 commits2026-01-30: 0 commits2026-01-31: 0 commits2026-02-01: 0 commits2026-02-02: 0 commits2026-02-03: 0 commits2026-02-04: 0 commits2026-02-05: 0 commits2026-02-06: 0 commits2026-02-07: 0 commits2026-02-08: 0 commits2026-02-09: 0 commits2026-02-10: 0 commits2026-02-11: 0 commits2026-02-12: 0 commits2026-02-13: 0 commits2026-02-14: 0 commits2026-02-15: 0 commits2026-02-16: 0 commits2026-02-17: 0 commits2026-02-18: 0 commits2026-02-19: 0 commits2026-02-20: 0 commits2026-02-21: 0 commits2026-02-22: 0 commits2026-02-23: 0 commits2026-02-24: 0 commits2026-02-25: 5 commits2026-02-26: 0 commits2026-02-27: 0 commits2026-02-28: 0 commits2026-03-01: 0 commits2026-03-02: 3 commits2026-03-03: 0 commits2026-03-04: 0 commits2026-03-05: 0 commits2026-03-06: 0 commits2026-03-07: 0 commits2026-03-08: 0 commits2026-03-09: 0 commits2026-03-10: 2 commits2026-03-11: 3 commits2026-03-12: 0 commits2026-03-13: 0 commits2026-03-14: 0 commits2026-03-15: 4 commits2026-03-16: 11 commits2026-03-17: 26 commits2026-03-18: 1 commit2026-03-19: 0 commits2026-03-20: 0 commits2026-03-21: 1 commit2026-03-22: 9 commits2026-03-23: 2 commits2026-03-24: 0 commits2026-03-25: 8 commits2026-03-26: 5 commits2026-03-27: 9 commits2026-03-28: 1 commit2026-03-29: 3 commits2026-03-30: 3 commits2026-03-31: 3 commits2026-04-01: 0 commits2026-04-02: 0 commits2026-04-03: 0 commits2026-04-04: 2 commits2026-04-05: 0 commits2026-04-06: 0 commits2026-04-07: 8 commits2026-04-08: 2 commits2026-04-09: 1 commit2026-04-10: 0 commits2026-04-11: 2 commits2026-04-12: 4 commits2026-04-13: 0 commits2026-04-14: 15 commits2026-04-15: 0 commits2026-04-16: 0 commits2026-04-17: 0 commits2026-04-18: 0 commits2026-04-19: 0 commits2026-04-20: 0 commits2026-04-21: 2 commits2026-04-22: 0 commits2026-04-23: 0 commits2026-04-24: 0 commits2026-04-25: 3 commits2026-04-26: 0 commits2026-04-27: 0 commits2026-04-28: 1 commit2026-04-29: 1 commit2026-04-30: 10 commits2026-05-01: 1 commit2026-05-02: 0 commits2026-05-03: 0 commits2026-05-04: 0 commits2026-05-05: 2 commits2026-05-06: 0 commits2026-05-07: 0 commits2026-05-08: 0 commits2026-05-09: 0 commits2026-05-10: 0 commits2026-05-11: 0 commits2026-05-12: 5 commits2026-05-13: 16 commits2026-05-14: 1 commit2026-05-15: 5 commits2026-05-16: 0 commits2026-05-17: 0 commits2026-05-18: 3 commits2026-05-19: 0 commits2026-05-20: 0 commits2026-05-21: 0 commits2026-05-22: 0 commits2026-05-23: 0 commits2026-05-24: 0 commits2026-05-25: 0 commits2026-05-26: 0 commits2026-05-27: 0 commits2026-05-28: 0 commits2026-05-29: 0 commits2026-05-30: 0 commits2026-05-31: 0 commits2026-06-01: 0 commits2026-06-02: 0 commits2026-06-03: 0 commits2026-06-04: 0 commits2026-06-05: 0 commits2026-06-06: 0 commits2026-06-07: 0 commits2026-06-08: 0 commits2026-06-09: 3 commits2026-06-10: 8 commits2026-06-11: 0 commits2026-06-12: 0 commits2026-06-13: 0 commits2026-06-14: 0 commits2026-06-15: 0 commits2026-06-16: 0 commits2026-06-17: 0 commits2026-06-18: 0 commits2026-06-19: 5 commits2026-06-20: 0 commits2026-06-21: 0 commits2026-06-22: 1 commit2026-06-23: 0 commits2026-06-24: 1 commit2026-06-25: 0 commits2026-06-26: 1 commit2026-06-27: 0 commits2026-06-28: 0 commits2026-06-29: 0 commits2026-06-30: 0 commits2026-07-01: 0 commits2026-07-02: 0 commits2026-07-03: 0 commits2026-07-04: 1 commit2026-07-05: 0 commits2026-07-06: 0 commits2026-07-07: 0 commits2026-07-08: 1 commit2026-07-09: 6 commits2026-07-10: 0 commits2026-07-11: 0 commits2026-07-12: 0 commits2026-07-13: 5 commits2026-07-14: 4 commits2026-07-15: 6 commits2026-07-16: 1 commit2026-07-17: 0 commits2026-07-18: 0 commits2026-07-19: 0 commits2026-07-20: 0 commits2026-07-21: 0 commits2026-07-22: 2 commits2026-07-23: 0 commits2026-07-24: 0 commits2026-07-25: 4 commits2026-07-26: 1 commit2026-07-27: 2 commits2026-07-28: 3 commits2026-07-29: 0 commits2026-07-30: 0 commits2026-07-31: 0 commits2026-08-01: 0 commits
238 commits in the last yearLessMore

Signals and awards

derived from tracked data
  • Outside contributions

    70% of recent commits from the community

  • Permissive license

    MIT

  • Continuous integration

    Automated checks passing

What Mouser does

Mouser provides a fully local, open-source solution for remapping buttons on Logitech HID++ mice, targeting users who want functionality without telemetry or forced cloud accounts. It works entirely offline and provides a lightweight footprint compared to the official Logitech Options+ software. While optimized for the MX Master and MX Anywhere series, it includes detection and fallback UI for other models. The tool handles everything from basic remapping to custom macros without requiring any internet connection.

Privacy-conscious users, developers, and professionals who own Logitech mice but want to avoid the bloat and cloud requirements of official software.

  • Zero telemetry design: operates entirely locally without sending data, requiring cloud accounts, or connecting to external servers.
  • HID++ protocol support: natively communicates with Logitech devices to enable deep hardware-level button remapping.
  • MX series optimization: provides the best out-of-the-box experience for the MX Master and MX Anywhere device families.
  • Fallback UI mode: ensures functionality even for unoptimized or less common Logitech models through generalized detection.
  • Lightweight runtime: consumes significantly fewer system resources compared to the heavily bloated official companion software.

Where teams use it

Privacy-conscious mouse configuration

Users who refuse to install Logitech Options+ due to its mandatory account and telemetry requirements use this for basic setup.

Offline workstation setups

Professionals working on air-gapped or restricted corporate networks use it to configure their mice where cloud software is blocked.

Resource optimization

Developers trying to minimize background process overhead replace the official software with this lightweight alternative.

Cross-platform consistency

Users who switch between multiple operating systems rely on it for a consistent, open-source configuration experience.

Getting started: Download the release archive, extract it, and double-click to run.

README

master branch

Mouser — Logitech Mouse Remapper

Mouser logo

English | 中文文档

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

No telemetry. No cloud. No Logitech account required.


Contents


Download & Run

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

Windows Downloads macOS Apple Silicon Downloads macOS Intel Downloads Linux Downloads
Downloads

  1. Open the latest release page.
  2. Download the zip for your platform:
    • WindowsMouser-Windows.zip
    • macOS (Apple Silicon)Mouser-macOS.zip
    • macOS (Intel)Mouser-macOS-intel.zip
    • LinuxMouser-Linux.zip
  3. Extract it anywhere (Desktop, Documents, /Applications, wherever).
  4. Run the executable: Mouser.exe, Mouser.app, or ./Mouser.

That's it. The app opens, drops a tray / menu-bar icon, and starts remapping immediately.

What to expect on first launch

  • The settings window opens to the device-aware Mouse & Profiles page.
  • A tray icon appears (next to the clock on Windows / Linux, in the menu bar on macOS).
  • Closing the window keeps Mouser running in the tray. Right-click the tray icon → Quit Mouser to fully exit.
  • Mouser remembers language and startup behavior between runs.

First-time notes

  • Windows SmartScreen may warn the first time — click More infoRun anyway.
  • Logitech Options+ must not be running. Both apps fight over HID++ access; quit Options+ before launching Mouser.
  • macOS asks for Accessibility permission so the event tap can intercept mouse events. See readme_mac_osx.md for the full setup walkthrough.
  • Linux needs read access to /dev/hidraw*, /dev/input/event*, and write access to /dev/uinput. Run the bundled helper once after extracting:
    cd /path/to/extracted/Mouser
    ./install-linux-permissions.sh
    Reconnect the mouse, then relaunch.
  • Config is saved automatically to:
    • %APPDATA%\Mouser\config.json (Windows)
    • ~/Library/Application Support/Mouser/config.json (macOS)
    • ~/.config/Mouser/config.json (Linux)
  • Logs rotate automatically (5 × 5 MB) under %APPDATA%\Mouser\logs, ~/Library/Logs/Mouser, or $XDG_STATE_HOME/Mouser/logs.

Screenshots

Mouse & Profiles Point & Scroll
Mouser — Mouse & Profiles page Mouser — Point & Scroll settings

Features

Button remapping

  • Remap any programmable button — middle click, gesture button, back, forward, mode shift, DPI switch (MX Vertical), and horizontal scroll.
  • Mouse-to-mouse remap — bind any button to act as left, right, middle, back, or forward click.
  • Per-application profiles — Mouser auto-switches mappings when the foreground app changes (e.g. Chrome vs. VS Code).
  • Custom keyboard shortcuts — record any key combination (e.g. Ctrl+Shift+P) directly in the UI.
  • 40+ built-in actions — navigation, browser, editing, media, scroll-mode, and DPI shortcuts that adapt per platform.

Device control

  • DPI / pointer speed — slider from 200 to the device max (8000 on MX Master) with quick presets, plus a Cycle DPI Presets action you can map to a button.
  • Smart Shift — toggle Logitech's ratchet ↔ free-spin scroll mode (HID++ 0x2111), with a sensitivity threshold and a mappable Toggle SmartShift action.
  • Switch scroll mode — bind a button to flip ratchet / free-spin without opening the UI; defaults to mode-shift.
  • Scroll direction inversion — independent toggles for vertical and horizontal scroll.
  • Gesture button + swipe actions — tap for one action, swipe up/down/left/right for four others.

Cross-platform

  • Windows, macOS, and Linux — native hooks per platform (WH_MOUSE_LL, CGEventTap, evdev + uinput).
  • Native Intel and Apple Silicon macOS builds — separate Mouser-macOS-intel.zip and Mouser-macOS.zip artifacts; the menu-bar app runs as LSUIElement (no Dock icon).
  • Resizable UI — main window starts at 1060 × 700 with a 920 × 620 minimum; the mouse diagram and controls reflow as you resize.
  • Start at login — Windows registry key, macOS LaunchAgent, and Linux XDG autostart, with an independent Start minimized option that boots straight into the tray. Linux autostart intentionally waits about 15 seconds after login so Bluetooth / HID devices are usually ready before Mouser restores device settings.
  • Single-instance guard — launching a second copy brings the existing window to the front instead of starting a duplicate.

Smart connectivity

  • Bluetooth and Logi Bolt — both transports are supported on all three platforms; the UI labels the live connection (Logi Bolt only when the receiver PID is positively identified).
  • Auto-reconnection — Mouser watches for power-off / on cycles and rebinds HID++ + the OS mouse hook without a restart; SmartShift settings are replayed on every reconnect (including wake-from-sleep).
  • Live connection status — real-time Connected / Not Connected badge, model name, and active layout in the UI.
  • Device-aware UI — interactive MX Master and MX Anywhere diagrams with clickable hotspots; generic fallback card for other models, with an experimental layout-override picker.

Multi-language UI

  • English / Simplified Chinese / Traditional Chinese — switch instantly, no restart required.
  • Language preference is saved to config.json and restored on next launch.
  • Covers nav, mouse page, settings page, dialogs, system tray / menu bar, and permission prompts.

Privacy first

  • Fully local — config is a plain JSON file, all processing happens on your machine.
  • System tray / menu bar — runs quietly in the background.
  • Zero telemetry, zero cloud, zero account required.

Device coverage

Family / model Detection + HID++ probing UI support
MX Master 4 / 3S / 3 / 2S / MX Master Yes Dedicated interactive per-model layouts
MX Anywhere 3S / 3 / 2S Yes Dedicated interactive per-model layouts
MX Vertical Yes Generic fallback card (with DPI switch button support)
Unknown Logitech HID++ mice Best effort by PID/name Generic fallback card

MX Master and MX Anywhere devices have dedicated visual overlays. Other devices are still detected, show their model name, and can opt into an experimental layout override — button positions just may not line up until a real overlay lands. See CONTRIBUTING_DEVICES.md to add yours.


Default mappings

Button Default action
Back button (XButton1) Alt + Tab (Switch Windows)
Forward button (XButton2) Alt + Tab (Switch Windows)
Middle click Pass-through
Gesture button Pass-through
Gesture swipes (up / down / left / right) Pass-through
Mode shift (scroll click) Switch Scroll Mode (Ratchet / Free Spin)
Horizontal scroll left Browser Back
Horizontal scroll right Browser Forward
DPI switch (MX Vertical) Pass-through

Available actions

Action labels adapt per platform. Windows exposes Win+D and Task View; macOS exposes Mission Control, Show Desktop, App Exposé, and Launchpad; Linux falls back to compositor-native equivalents.

Category Actions
Navigation Alt+Tab, Alt+Shift+Tab, Show Desktop, Previous Desktop, Next Desktop, Task View (Windows), Mission Control / App Exposé / Launchpad (macOS), Page Up / Page Down / Home / End
Browser Back, Forward, Close Tab (Ctrl+W), New Tab (Ctrl+T), Next Tab (Ctrl+Tab), Previous Tab (Ctrl+Shift+Tab)
Editing Copy, Paste, Cut, Undo, Select All, Save, Find
Media Volume Up, Volume Down, Volume Mute, Play / Pause, Next Track, Previous Track
Scroll Switch Scroll Mode (Ratchet / Free Spin), Toggle SmartShift, Cycle DPI Presets
Mouse Left Click, Right Click, Middle Click, Back (Mouse Button 4), Forward (Mouse Button 5)
Custom User-defined keyboard shortcuts (any key combination, captured in the UI)
Other Do Nothing (pass-through)

Build from source

You only need this if you want to hack on Mouser or run a development build. Most users should grab a release zip — see Download & Run.

Common prerequisites

  • Windows 10/11, macOS 12+ (Monterey), or Linux (X11; KDE Wayland for app detection)
  • Python 3.10+ (tested up to 3.14)
  • A supported Logitech HID++ mouse paired via Bluetooth or a USB receiver
  • Logitech Options+ must NOT be running — it conflicts with HID++ access
  • git and a working build toolchain
git clone https://github.com/TomBadash/Mouser.git
cd Mouser
python -m venv .venv
Windows
.\.venv\Scripts\activate
pip install -r requirements.txt

# Run from source
python main_qml.py

# Or start straight into the tray
python main_qml.py --start-hidden

# Build a portable zip
build.bat                # standard
build.bat --clean        # force clean rebuild

build.bat installs requirements, verifies that hidapi is importable, and packages with PyInstaller. The output lives in dist\Mouser\ — zip the folder and ship it.

To launch a source checkout without a console window, create a shortcut that uses pythonw.exe; see DEVELOPMENT.md.

macOS
source .venv/bin/activate
pip install -r requirements.txt

# Run from source
python main_qml.py
python main_qml.py --start-hidden     # launch directly to menu bar

# Build the native menu-bar bundle
pip install pyinstaller
./build_macos_app.sh

The output is dist/Mouser.app. The script reuses images/AppIcon.icns when present, otherwise generates one from images/logo_icon.png. Signing depends on whether MOUSER_SIGN_IDENTITY is set in the environment:

  • Unset (default): ad-hoc signs with codesign --sign -. Convenient for one-off builds, but the bundle's code identity can change on rebuild, so macOS may ask for Accessibility permission again.
  • Set to a codesigning identity (security find-identity -v -p codesigning to list them — SHA-1 form preferred): signs every nested .dylib / .so / .framework with hardened runtime options, then signs the outer app with the hardened-runtime exceptions at build_resources/Mouser.entitlements. This is a local developer signing path for repeated builds; stable macOS permission behavior depends on keeping the same source, resolved Python interpreter, dependency versions, architecture, signing identity, entitlements, and timestamp policy. A failing codesign --verify --deep --strict check aborts the build.
MOUSER_SIGN_IDENTITY="ABCD1234..." ./build_macos_app.sh   # local signed build
  • This is not a notarized release-signing flow. Public macOS release zips remain ad-hoc signed until a separate Developer ID signing, secure timestamp, notarization, stapling, and Gatekeeper validation workflow exists.
  • Build on the architecture you want to ship: an arm64 Python produces an Apple Silicon bundle, an x86_64 Python produces an Intel bundle. Set PYINSTALLER_TARGET_ARCH=arm64|x86_64|universal2 to override.
  • Release CI publishes both Mouser-macOS.zip (Apple Silicon) and Mouser-macOS-intel.zip (Intel) automatically on tag pushes.
  • Accessibility permission is required. See readme_mac_osx.md for the full grant flow and platform-specific notes.
Linux
source .venv/bin/activate
pip install -r requirements.txt

# Run from source
python main_qml.py

# Install device permissions (only needed once, then reconnect the mouse)
./packaging/linux/install-linux-permissions.sh

# Build a portable bundle
sudo apt-get install libhidapi-dev
pip install pyinstaller
pyinstaller Mouser-linux.spec --noconfirm

The helper installs 69-mouser-logitech.rules, reloads udev, and tries to modprobe uinput. After a successful run, reconnect the mouse, fully quit Mouser, and launch normally — no sudo. On systems without logind / uaccess, adding the user to the input group is the distro-specific fallback.

The first normal Linux launch creates or refreshes:

~/.local/share/applications/io.github.tombadash.mouser.desktop

The generated launcher uses absolute paths for the current portable app or source checkout, and syncs Mouser's app icon into the per-user hicolor icon theme when possible. If you move the checkout, launch Mouser once from the new path to refresh the app-menu entry. Enabling Start at login also manages:

~/.config/autostart/io.github.tombadash.mouser.desktop

That Linux autostart entry includes a short GNOME startup delay so Mouser does not race Bluetooth / HID initialization immediately after login.

xdotool enables per-app profile switching on X11; kdotool adds KDE Wayland support. Other Wayland compositors fall back to the default profile.

Automated releases: pushing a v* tag triggers .github/workflows/release.yml, which builds Windows, macOS (Apple Silicon + Intel), and Linux artifacts in CI and uploads them to the GitHub Release.

For project layout, the architecture diagram, the HID++ gesture detector, the Engine + reconnection flow, debug CLI flags (--hid-backend=iokit|hidapi|auto), and how to run the test suite, see DEVELOPMENT.md. To add a new device, see CONTRIBUTING_DEVICES.md.


Limitations

  • Per-device mappings aren't fully separated yet — layout overrides are stored per detected device, but profile mappings are still global.
  • Conflicts with Logitech Options+ — both apps fight over HID++ access. Quit Options+ before running Mouser.
  • Scroll inversion uses coalesced post-injection on Windows to avoid LL-hook deadlocks; it's stable in mainstream apps but may misbehave in some games or low-level drivers.
  • Admin not required — but injected keystrokes may not reach elevated windows or some games. Run Mouser elevated if you need that path.
  • Linux app detection is partial — X11 works via xdotool, KDE Wayland works via kdotool, GNOME / other Wayland compositors still fall back to the default profile.
  • Linux device permissions — Mouser needs access to /dev/hidraw*, /dev/input/event*, and /dev/uinput. Use install-linux-permissions.sh once instead of running as root.

Roadmap

  • Dedicated overlays for more devices — real hotspot maps and artwork for MX Vertical and other Logitech families
  • True per-device config — separate mappings 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 the current fixed sets
  • Improved scroll inversion — explore driver-level or interception-driver approaches
  • Gesture swipe tuning — improve swipe reliability and defaults across more devices
  • 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 the active profile name in the tray tooltip
  • Broader Wayland support — extend app detection beyond X11 / KDE and validate across more distros
  • Plugin system — allow third-party action providers

Contributing

Contributions are welcome.

  • Code, fixes, and features: fork → branch → PR. The dev setup, architecture overview, debug flags, and test instructions live in DEVELOPMENT.md.
  • Adding a new Logitech mouse: follow the discovery-dump walkthrough in CONTRIBUTING_DEVICES.md. Even a partial dump helps.
  • Help wanted:
    • Testing with other Logitech HID++ devices
    • Scroll inversion improvements
    • Broader Linux / Wayland validation
    • UI/UX polish, accessibility, and translations

Support the project

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

Sponsor

Every bit helps keep the project going — thank you.


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 triage of open issues.
  • @awkure — cross-platform login startup (Windows registry + macOS LaunchAgent), single-instance guard, start-minimized option, and MX Master 4 detection.
  • @hieshima — Linux support (evdev + HID++ + uinput), mode-shift mapping, Smart Shift toggle, custom keyboard shortcut support, Linux connection-state stabilization, and macOS CGEventTap reliability fixes (auto re-enable on timeout, trackpad scroll filtering).
  • @pavelzaichyk — Next Tab / Previous Tab browser actions, persistent rotating log file storage, Smart Shift enhanced support (HID++ 0x2111) with sensitivity control and scroll-mode sync.
  • @nellwhoami — Multi-language UI system (English, Simplified Chinese, Traditional Chinese) and Page Up / Page Down / Home / End navigation actions.
  • @guilamu — Mouse-to-mouse button remapping (left, right, middle, back, forward click) and HID++ stability fixes (stuck-button auto-release, auto-reconnect after consecutive timeouts, async dispatch queue for the Windows hook).
  • @vcanuel — Logi Bolt receiver support on macOS via the hidapi fallback path.
  • @farfromrefug — smaller macOS bundle (Qt Quick Controls trim, QtDBus, Qt asset filtering).
  • @MysticalMike60t — README structure ideas (collapsible per-OS build sections).
  • @davidnoyes - Full Logitech MX Master 4 support: Actions Ring radial menu, per-slot haptics, stroke-aware gestures, dual-CID HID++ routing, and force-sensitivity control, integrating and adapting a range of community contributions; plus a charging-state indicator on the battery badge.
  • @hughesyadaddy - MX Master 4 firmware-first HID++ runtime, hardware-reported DPI persistence, Backend list-property memoization, and OS mouse-event passthrough when no Logitech device is connected.
  • @laziukdavid - Reworked swipe-gesture recognition and faster HID++ device detection.
  • @FunJim - Shift+wheel horizontal scroll on macOS/Windows/Linux, and preserving a symlinked config.json on atomic save.
  • @chenqianhe - macOS nested app-identity matching for per-app profiles.
  • @liuxuAP369 - Fractional macOS horizontal scroll delta handling.
  • @winniesi - Ping-pong desktop cycling action (macOS).
  • @Archetipo95 - Physical scroll-wheel tilt support and reduced remapping latency on macOS.
  • @zeward-lee - Scan-code injection on remapped keystrokes so side-button copy/paste reaches UWP / Store apps.
  • @ArtisticZhao - Background HID polling no longer resets the system idle timer, so the display can sleep and the system can idle while Mouser runs (visibility-gated polling with an idle-grace period).
  • @mizi - Scroll Force control: adjustable ratchet firmness for enhanced SmartShift (HID++ 0x2111) devices, with a per-device Scroll page slider.
  • @kevin-nous - Original per-button slide-gesture concept (event-tap arming, dual-mode tap/gesture), which inspired the cross-platform "Gesture Swipe" action: any device-advertised button becomes a hold-and-slide gesture pad on Windows, macOS, and Linux.
  • @unijiang - Logitech M585/M590 Multi-Device Mouse support: device catalog entry (name/alias matched to avoid over-claiming the shared receiver PID), interactive hotspot layout, and wheel-tilt exposure as configurable left/right controls.

License

This project is licensed under the MIT License.

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

View on GitHub

Recent activity

commits and pull requests

Releases and announcements

13 total
  1. Mouser v3.7.3v3.7.3Jul 28, 20264 downloads

    # Mouser v3.7.3 **A hotfix for v3.7.2.** Opening the custom shortcut recorder on Windows froze the mouse pointer for the rest of the session. If you are on v3.7.2, update. ## 🖱️ The freeze Assigning a custom shortcut left the mouse completely unresponsive. The shortcut could be typed but not saved, because the Save button could no longer be clicked, and nothing short of a sign-out or a reboot brought the pointer back. Reported by **@327607501** (#259) on Windows 11 with an M590 over a Bolt receiver, though it was never device-specific: any mouse, any connection, on any Windows machine running v3.7.2. The cause was two hooks quietly sharing one object. `ctypes.windll.user32` is a single process-global handle, and ctypes stores function prototypes on the handle itself rather than per call site. Mouser's low-level mouse hook declares `CallNextHookEx` to take a mouse event; the shortcut recorder's keyboard hook declared the same function to take a keyboard event. Whichever ran second won. Opening the recorder rewrote the prototype the mouse hook depended on, so from that moment every mouse event failed on the way into the hook and no click, move or scroll reached Windows. The re

  2. Mouser v3.7.2v3.7.2Jul 27, 2026180 downloads

    # Mouser v3.7.2 **A Windows crash fix.** If Mouser vanished mid-use — on a right click, on a scroll, seemingly at random — this release is for you. Two users chasing what looked like two unrelated bugs turned out to be hitting the same line of code. ## 💥 The crash Mouser read a field on every mouse event as if it were a memory address. It isn't — `dwExtraInfo` is an opaque tag the event's sender attaches, and it's usually zero. Whenever something on the system set it to anything else, Mouser dereferenced that number as a pointer and the process died instantly: no error dialog, no traceback, nothing in the log. The line only ran with **debug mode enabled**, which is why it looked so arbitrary. @lazyzyf hit it on every right click (#252); @327607501 hit it on every scroll and narrowed it down by testing with debug mode off (#253). Same bug, different events. Two related fixes went in alongside it: - **Debug logging no longer floods.** A hi-res wheel emits ~15 events per detent, and each one wrote a debug line — a Qt signal plus a UI list rebuild every time. Wheel bursts are now coalesced to one line per 250 ms with a count of what was skipped. - **Shell popups no longer freeze

  3. Mouser v3.7.1v3.7.1Jul 25, 2026559 downloads

    # Mouser v3.7.1 **The macOS memory leak is fixed.** If Mouser's memory usage grew into the hundreds of MB (or GB) over long sessions on your Mac, this release is for you: a long-running instance now stays flat instead of climbing until restart. ## 🧠 Memory fixes (macOS) Three complementary fixes, each validated on real hardware by the community: - **HID reconnect leak** (#240) — the IOKit backend never called `IOHIDManagerClose`, so every BLE discovery/reconnect cycle leaked a manager plus Mach ports; a 24-hour session could reach 3.3 GB with 33,000 leaked managers and 67,000 ports. Managers are now closed and reconnect probing is throttled with exponential backoff. *Validated: manager count pinned at 2 across thousands of cycles.* - **Click-path leak** (#242) — the threads that execute your remapped actions had no `NSAutoreleasePool`, so every injected click/keystroke left native `CGEvent` temporaries behind forever. All action-execution paths now drain pools. *Validated: click bursts no longer accumulate.* - **Scroll-path leak** (#247) — the native HID read loop delivered input reports (15 per hi-res wheel detent!) on threads that never drained a pool, leaking `HIDEvent` obj

  4. Mouser v3.7.0v3.7.0Jul 13, 20261.7K downloads

    ## Logitech MX Master 4 support Mouser v3.7.0 adds full support for the **Logitech MX Master 4**, built on a large collaborative effort. Big thanks to @davidnoyes for leading the integration, and to everyone whose work it builds on (credits below). ### Highlights - **Actions Ring** radial menu (glassmorphism UI) with per-slot actions, custom-shortcut slots, and a configurable hold-to-open delay. Slot actions can be **global** (one ring for every app) or **per-app**. - **Haptics**: feedback as the cursor lands on each ring slot (immediate, low-latency), a per-button haptic picker, a global haptic on/off toggle, level control, and pulse de-duplication. - **Gestures**: stroke-aware gesture recognition with dual gesture-swipe sets, plus physical-button key naming. - **HID++**: firmware-first runtime, dual-CID routing, faster Bluetooth detection, reconnection handling, and force-sensitivity control. ### Fixes (MX Master 4 work) - Guard the Actions Ring against an empty slot list (no more ZeroDivisionError when the ring is enabled but has no slots). - Ring-slot "Custom Shortcut" now captures keys and stores the combo instead of a placeholder. - Config migrations squashed into a clean

  5. Mouser v3.6.0v3.6.0Apr 29, 202610.8K downloads

    ## Mouser v3.6.0 This one is a pretty practical release: better Linux support, fewer macOS headaches, smaller downloads, and more useful diagnostics when something goes wrong. The big things: **Linux Bluetooth Logitech mice should work much better now**, **macOS no longer leaks memory during long sessions**, **custom shortcuts are more reliable**, and **release packages are smaller and cleaner**. ### Highlights - Fixed Linux Bluetooth Logitech detection, including MX Master devices over Bluetooth. - Added a Linux permissions setup helper with bundled udev rules. - Fixed a large macOS memory leak in long-running sessions. - Fixed macOS custom shortcut capture, including Command/Control handling. - Added an Ignore Trackpad setting for macOS. - Added full macOS Logi Bolt receiver support. - Added an About dialog and build/version diagnostics. - Reduced macOS and Linux release bundle sizes. ### Linux - Fixed Bluetooth Logitech HID++ detection by preferring the Linux `hidraw` backend where needed. - Added support for known Logitech HID devices even when Linux does not report vendor usage metadata. - Added detailed diagnostics for blocked access to `/dev/hidraw*`, `/dev/input/event

Commits per week

last 52 weeks
430Week of 2025-08-02: 0 commitsWeek of 2025-08-09: 0 commitsWeek of 2025-08-16: 0 commitsWeek of 2025-08-23: 0 commitsWeek of 2025-08-30: 0 commitsWeek of 2025-09-06: 0 commitsWeek of 2025-09-13: 0 commitsWeek of 2025-09-20: 0 commitsWeek of 2025-09-27: 0 commitsWeek of 2025-10-04: 0 commitsWeek of 2025-10-11: 0 commitsWeek of 2025-10-18: 0 commitsWeek of 2025-10-25: 0 commitsWeek of 2025-11-01: 0 commitsWeek of 2025-11-09: 0 commitsWeek of 2025-11-16: 0 commitsWeek of 2025-11-23: 0 commitsWeek of 2025-11-30: 0 commitsWeek of 2025-12-07: 0 commitsWeek of 2025-12-14: 0 commitsWeek of 2025-12-21: 0 commitsWeek of 2025-12-28: 0 commitsWeek of 2026-01-04: 0 commitsWeek of 2026-01-11: 0 commitsWeek of 2026-01-18: 0 commitsWeek of 2026-01-25: 0 commitsWeek of 2026-02-01: 0 commitsWeek of 2026-02-08: 0 commitsWeek of 2026-02-15: 0 commitsWeek of 2026-02-22: 5 commitsWeek of 2026-03-01: 3 commitsWeek of 2026-03-08: 5 commitsWeek of 2026-03-15: 43 commitsWeek of 2026-03-22: 34 commitsWeek of 2026-03-29: 11 commitsWeek of 2026-04-05: 13 commitsWeek of 2026-04-12: 19 commitsWeek of 2026-04-19: 5 commitsWeek of 2026-04-26: 13 commitsWeek of 2026-05-03: 2 commitsWeek of 2026-05-10: 27 commitsWeek of 2026-05-17: 3 commitsWeek of 2026-05-24: 0 commitsWeek of 2026-05-31: 0 commitsWeek of 2026-06-07: 11 commitsWeek of 2026-06-14: 5 commitsWeek of 2026-06-21: 3 commitsWeek of 2026-06-28: 1 commitsWeek of 2026-07-05: 7 commitsWeek of 2026-07-12: 16 commitsWeek of 2026-07-19: 6 commitsWeek of 2026-07-26: 6 commitsAug 2, 2025Jul 26, 2026
238 commits in the last 52 weeks.

When work happens

weekday and hour
SunMonTueWedThuFriSat036912151821Sun 0:00 — 2 commitsSun 1:00 — 2 commitsSun 2:00 — 0 commitsSun 3:00 — 0 commitsSun 4:00 — 0 commitsSun 5:00 — 0 commitsSun 6:00 — 0 commitsSun 7:00 — 1 commitsSun 8:00 — 0 commitsSun 9:00 — 3 commitsSun 10:00 — 3 commitsSun 11:00 — 0 commitsSun 12:00 — 0 commitsSun 13:00 — 0 commitsSun 14:00 — 0 commitsSun 15:00 — 1 commitsSun 16:00 — 1 commitsSun 17:00 — 2 commitsSun 18:00 — 0 commitsSun 19:00 — 0 commitsSun 20:00 — 0 commitsSun 21:00 — 4 commitsSun 22:00 — 1 commitsSun 23:00 — 1 commitsMon 0:00 — 3 commitsMon 1:00 — 0 commitsMon 2:00 — 2 commitsMon 3:00 — 0 commitsMon 4:00 — 0 commitsMon 5:00 — 0 commitsMon 6:00 — 0 commitsMon 7:00 — 1 commitsMon 8:00 — 1 commitsMon 9:00 — 4 commitsMon 10:00 — 2 commitsMon 11:00 — 0 commitsMon 12:00 — 1 commitsMon 13:00 — 3 commitsMon 14:00 — 2 commitsMon 15:00 — 5 commitsMon 16:00 — 0 commitsMon 17:00 — 1 commitsMon 18:00 — 1 commitsMon 19:00 — 0 commitsMon 20:00 — 2 commitsMon 21:00 — 1 commitsMon 22:00 — 1 commitsMon 23:00 — 0 commitsTue 0:00 — 3 commitsTue 1:00 — 9 commitsTue 2:00 — 9 commitsTue 3:00 — 5 commitsTue 4:00 — 6 commitsTue 5:00 — 0 commitsTue 6:00 — 0 commitsTue 7:00 — 0 commitsTue 8:00 — 0 commitsTue 9:00 — 0 commitsTue 10:00 — 1 commitsTue 11:00 — 6 commitsTue 12:00 — 2 commitsTue 13:00 — 5 commitsTue 14:00 — 11 commitsTue 15:00 — 0 commitsTue 16:00 — 4 commitsTue 17:00 — 1 commitsTue 18:00 — 3 commitsTue 19:00 — 1 commitsTue 20:00 — 2 commitsTue 21:00 — 5 commitsTue 22:00 — 1 commitsTue 23:00 — 0 commitsWed 0:00 — 3 commitsWed 1:00 — 4 commitsWed 2:00 — 6 commitsWed 3:00 — 1 commitsWed 4:00 — 0 commitsWed 5:00 — 5 commitsWed 6:00 — 3 commitsWed 7:00 — 1 commitsWed 8:00 — 0 commitsWed 9:00 — 0 commitsWed 10:00 — 2 commitsWed 11:00 — 2 commitsWed 12:00 — 2 commitsWed 13:00 — 3 commitsWed 14:00 — 2 commitsWed 15:00 — 1 commitsWed 16:00 — 4 commitsWed 17:00 — 2 commitsWed 18:00 — 6 commitsWed 19:00 — 1 commitsWed 20:00 — 0 commitsWed 21:00 — 2 commitsWed 22:00 — 4 commitsWed 23:00 — 0 commitsThu 0:00 — 1 commitsThu 1:00 — 1 commitsThu 2:00 — 0 commitsThu 3:00 — 0 commitsThu 4:00 — 0 commitsThu 5:00 — 3 commitsThu 6:00 — 0 commitsThu 7:00 — 3 commitsThu 8:00 — 0 commitsThu 9:00 — 0 commitsThu 10:00 — 0 commitsThu 11:00 — 1 commitsThu 12:00 — 1 commitsThu 13:00 — 1 commitsThu 14:00 — 1 commitsThu 15:00 — 0 commitsThu 16:00 — 3 commitsThu 17:00 — 0 commitsThu 18:00 — 1 commitsThu 19:00 — 6 commitsThu 20:00 — 1 commitsThu 21:00 — 0 commitsThu 22:00 — 0 commitsThu 23:00 — 1 commitsFri 0:00 — 0 commitsFri 1:00 — 2 commitsFri 2:00 — 0 commitsFri 3:00 — 3 commitsFri 4:00 — 0 commitsFri 5:00 — 0 commitsFri 6:00 — 1 commitsFri 7:00 — 5 commitsFri 8:00 — 1 commitsFri 9:00 — 1 commitsFri 10:00 — 1 commitsFri 11:00 — 1 commitsFri 12:00 — 3 commitsFri 13:00 — 0 commitsFri 14:00 — 0 commitsFri 15:00 — 0 commitsFri 16:00 — 0 commitsFri 17:00 — 1 commitsFri 18:00 — 0 commitsFri 19:00 — 0 commitsFri 20:00 — 1 commitsFri 21:00 — 1 commitsFri 22:00 — 0 commitsFri 23:00 — 0 commitsSat 0:00 — 0 commitsSat 1:00 — 0 commitsSat 2:00 — 0 commitsSat 3:00 — 0 commitsSat 4:00 — 1 commitsSat 5:00 — 1 commitsSat 6:00 — 1 commitsSat 7:00 — 1 commitsSat 8:00 — 1 commitsSat 9:00 — 1 commitsSat 10:00 — 1 commitsSat 11:00 — 2 commitsSat 12:00 — 2 commitsSat 13:00 — 0 commitsSat 14:00 — 1 commitsSat 15:00 — 0 commitsSat 16:00 — 0 commitsSat 17:00 — 0 commitsSat 18:00 — 0 commitsSat 19:00 — 1 commitsSat 20:00 — 0 commitsSat 21:00 — 1 commitsSat 22:00 — 0 commitsSat 23:00 — 0 commits
Commit volume by weekday and hour (UTC). Larger dots mean more commits.

Who is committing

last 52 weeks
Maintainer commits82 (30%)
Community commits194 (70%)

276 commits in total over the last year.

DateListRankStars gained
Mar 16, 2026daily#24+106