Skip to content

Repository files navigation

MX Master 4 on Linux

MX Master 4

Full configuration for the Logitech MX Master 4 wireless mouse on Linux (GNOME/Wayland, Arch-based), getting the most out of the hardware without the proprietary Logi Options+ app.

Feature How it works here
Scroll wheel ratchet (carraca) Solaar owns it: scroll-ratchet = Carraca, smart-shift = 50 (strict ratchet)
Gesture button (large thumb, 0xc3) Screenshot (KEY_PRINT) via logiops
Smart Shift button (behind wheel, 0xc4) Solaar owns it (wheel/DPI) — logid maps it to None
Haptic button (0x1a0) Fly-Pie radial menu: F13 → held Ctrl+Space opens/closes
Haptic feedback mx-haptic.py plays waveforms through the official library

The MX Master 4 (WPID B042) exposes the SMART SHIFT ENHANCED feature (0x2111) and the HIRES WHEEL feature (0x2121). This repo documents how to control the electromagnetic ratchet reliably — including the HID++ gotcha that cost a whole evening (see below).

Why this setup

On Linux there is no official Logi Options+, so the MX4 is handled by three pieces that must not fight each other:

  1. Solaar — the GUI/CLI that owns wheel settings, DPI and the ratchet. It talks HID++ to the device through the Logi Bolt receiver.
  2. logiops (logid) — remaps buttons to keys (screenshot, haptic → F13).
  3. mx-haptic-btn.py — a small user daemon that grabs logid's virtual input and converts F13 into a held Ctrl+Space for Fly-Pie, re-injecting everything else through a uinput device.

Button map (do not re-map without thinking)

CID Physical button Action Owner
0xc3 Gesture (big thumb) Screenshot (KEY_PRINT) logid
0xc4 Smart Shift (behind wheel) Ratchet / DPI Solaar
0x1a0 Haptic Fly-Pie (F13 → Ctrl+Space) mx-haptic-btn.py

Files

  • install.sh — full installer (logiops-git + Solaar, udev/uinput, logid, daemon, ratchet).
  • logid.cfg — logiops config → /etc/logid.cfg. No smartshift {} / hiresscroll {} blocks on purpose (Solaar owns them; having both = contention).
  • mx-haptic-btn.py — user daemon: EVIOCGRAB on logid's virtual input, F13 → held Ctrl+Space for Fly-Pie, re-injects the rest via uinput.
  • mx-haptic-btn.service — user systemd unit (uses %h, Restart=always).
  • mx-haptic.py — play haptic waveforms using the Solaar library (no hardcoded hidraw: it finds the MX4 automatically).

Install

git clone https://github.com/gnacho/mx-master4-linux
cd mx-master4-linux
bash install.sh        # requires an AUR helper (paru/yay)

It installs logiops-git, solaar, the udev/uinput rules, logid, the user daemon, and forces the ratchet mode on the mouse. Run it yourself — it asks for sudo for the root steps.

You also need the Fly-Pie GNOME extension (Ctrl+Space shortcut).

How the ratchet works (the important part)

The wheel mode lives in the SMART SHIFT ENHANCED feature (0x2111), a 4-byte register:

[mode, threshold, torque, reserved]
  mode: 1 = Freespin (free scroll), 2 = Ratcheted (click-click)
  • scroll-ratchet = Carraca + high smart-shift = strict ratchet.
  • The mode is volatile: it resets when the mouse sleeps. Solaar only re-applies it on reconnect, not periodically. If the wheel falls back to free spin, re-apply:
solaar config "MX Master 4" scroll-ratchet Carraca
solaar config "MX Master 4" smart-shift 50

⚠️ HID++ gotcha: feature ID, not index

When talking HID++ 2.0 with Solaar's library, feature_request expects the SupportedFeature NamedInt (0x2111), not the feature index.

from logitech_receiver import base, receiver
from logitech_receiver.hidpp20_constants import SupportedFeature as C

# find the device (any receiver)
def find_mx4():
    for info in base.receivers():
        r = receiver.create_receiver(base, info)
        if not r:
            continue
        for d in r:
            if d.online and "MX Master 4" in str(d.name):
                return d
    return None

d = find_mx4()

# ❌ WRONG — this is the INDEX, not the feature ID
idx = d.features[C.SMART_SHIFT_ENHANCED]   # → 17
d.feature_request(idx, 0x20, ...)           # → FeatureCallError error=5

# ✅ CORRECT — pass the SupportedFeature
d.feature_request(C.SMART_SHIFT_ENHANCED, 0x10)                        # read
d.feature_request(C.SMART_SHIFT_ENHANCED, 0x20, 0x02, 0xc8, 0x4b, 0x00)  # write
# mode=2 (Ratcheted), threshold=200, torque=75 → the state that works

Symptom of this bug: Solaar reports scroll-ratchet = Carraca and the register seems right, but the wheel physically free-spins and no manual write has any effect. This cost a whole evening of "is it hardware?" (it wasn't).

HIRES WHEEL feature (0x2121) — the physical ratchet switch

  • 0x00 caps, 0x10 mode, 0x30 read ratchet, 0x40 set ratchet.
  • ratchet byte & 0x01 = 1 → Normal wheel mode (ratcheted), 0 → free wheel.
  • Solaar only reads the ratchet; it never writes it.

Potential problems

Wheel is in free spin and won't ratchet

  1. solaar config "MX Master 4" scroll-ratchet — if it says Carraca but the wheel is free, the register is out of sync. Re-apply the command above.
  2. Make sure logid is running (systemctl is-active logid) and the daemon (systemctl --user is-active mx-haptic-btn).
  3. If the Solaar GUI was opened, it may have reset hires-smooth-resolution — restart logid and re-apply the ratchet.
  4. Real case (5-Ago-2026): looked like hardware/battery, but the ratchet mode had been lost when the mouse slept and nothing re-applied it. The fix was writing the 0x2111 register with mode=2 using the correct feature.

Screenshot or Fly-Pie buttons don't respond

  • logid active and mapping the three CIDs (systemctl status logid).
  • Daemon active and grabbing event20 (LogiOps Virtual Input): journalctl --user -u mx-haptic-btn -b.
  • If the daemon dies with OSError [Errno 19] No such device it restarts by itself (Restart=always); if it persists, check logid is creating the virtual input.

Ratchet lost after the mouse sleeps (volatile mode)

  • Re-apply: solaar config "MX Master 4" scroll-ratchet Carraca.
  • If it happens often, add a user systemd timer that re-applies it every X min.

Haptic vibration helper

mx-haptic.py wave      # all waveforms: sharp_change, damp_change, knock, wave…
mx-haptic.py knock 60

It uses Solaar's library to find the MX4 — no hardcoded /dev/hidraw path.

References

Acknowledgments

  • Solaar: this config would not exist without it — the wheel, ratchet and haptic handling all run through its library. Thanks to the Solaar maintainers and contributors.
  • logiops: clean button remapping that finally made the gesture button useful on Linux.
  • Fly-Pie: the radial menu that turned the haptic button into something genuinely useful.
  • Logitech for building a mouse that keeps being the best on Linux even without official software.

License

AGPL-3.0. Logitech, Logi and all Logitech trademarks are property of Logitech Europe S.A. and/or its affiliates. This project is not affiliated with or endorsed by Logitech.

About

Logitech MX Master 4 on Linux: Solaar + logiops + Fly-Pie (ratchet, screenshot, haptic button). HID++ feature-ID gotcha documented.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages