Tiny CLI for MX Master 4 status and settings.
cargo install mx4Cargo builds mx4 from source. It requires a current stable Rust toolchain, a C build toolchain, pkg-config, and the libudev development files on Linux. On Debian or Ubuntu, install the native build dependencies with:
sudo apt install build-essential pkg-config libudev-devCargo places the binary in ~/.cargo/bin. Make sure that directory is included in PATH.
Download the amd64 .deb from the GitHub release you want to install, then run:
sudo apt install ./mx4_*_amd64.debThe package contains a prebuilt binary and the udev access rule. APT installs its runtime dependencies automatically, so Rust, build-essential, pkg-config, and libudev-dev are not required.
To uninstall, remove the opt-in per-user daemon before purging the package:
mx4 daemon --uninstall
sudo apt purge mx4APT does not remove files generated in a user's home directory. If the package was purged before the daemon was uninstalled, clean up the remaining user service with:
systemctl --user disable --now mx4.service
rm -f ~/.config/systemd/user/mx4.service
systemctl --user daemon-reload
systemctl --user reset-failed mx4.servicegit clone https://github.com/EriksRemess/mx4.git
cd mx4
cargo install --path .cargo run --release -- --help
cargo run --release -- status
cargo run --release -- firmware --jsonThe first -- separates Cargo's arguments from arguments passed to mx4. To build once and run the resulting binary directly:
cargo build --release
./target/release/mx4 --helpcargo test
cargo test hardware -- --ignored --nocaptureNormal tests require no mouse. The opt-in hardware tests require an awake MX Master 4 connected over Bolt or Bluetooth, HID access, and a writable configuration directory. They read all status features and firmware, check repeated concurrent DPI/haptic queries from separate CLI processes, and send haptic effect 14 through the CLI. Leave settings unchanged while they run; the daemon can remain active.
Hardware tests fail if the mouse is unavailable or a command fails. The playback test checks that the effect command sends successfully and leaves the haptic configuration unchanged. Playback has no acknowledgement, so feel the mouse during the test to confirm physical vibration. Tests use the current haptic strength without changing settings.
This crate can also be used as a Rust library:
use mx4::features;
fn main() -> mx4::Result<()> {
let battery = features::battery::read_status()?;
println!("{} {}", battery.pct, battery.charging);
Ok(())
}mx4 status
mx4 status --json
mx4 status battery
mx4 status battery --json
mx4 status dpi
mx4 status dpi --json
mx4 status wheel
mx4 status wheel --json
mx4 status thumb-wheel
mx4 status thumb-wheel --json
mx4 status force-button
mx4 status force-button --json
mx4 status haptic
mx4 status haptic --json
mx4 set host 2
mx4 set dpi 2500
mx4 set strength 100
mx4 set strength off
mx4 set wheel ratchet free
mx4 set wheel ratchet-speed 10
mx4 set wheel force 75
mx4 set wheel invert on
mx4 set wheel resolution off
mx4 set wheel divert off
mx4 set thumb-wheel invert off
mx4 set thumb-wheel divert on
mx4 set force-button 4310
mx4 daemon
mx4 daemon --install
mx4 daemon --once
mx4 daemon --uninstall
mx4 haptic 14
mx4 haptic 0..3
mx4 haptic '{0..14}'
mx4 battery
mx4 battery --json
mx4 firmware
mx4 firmware --jsonHaptic strength presets:
off=0subtle=15low=45medium=60high=100
The daemon is opt-in. Normal status and setting commands never install or start a background service.
Install the binary first, then install and start the per-user service:
mx4 daemon --installThis creates a user systemd service on Linux or a user launchd agent on macOS. It watches for reconnects and reapplies saved settings. No sudo is needed.
The CLI and daemon coordinate device access through a lock file in the configuration directory. Both must use the same configuration directory, which must be writable even for status queries.
Other daemon modes:
mx4 daemon # run in the foreground
mx4 daemon --once # apply saved settings once and exit
mx4 daemon --uninstall # stop and remove the background serviceThe Debian package installs and reloads the udev access rule automatically. For Cargo or source installations, if a targeted command such as mx4 status dpi reports a /dev/hidraw... Permission denied error, install the rule once and reconnect the mouse or Logi Bolt receiver:
sudo install -Dm644 contrib/udev/70-mx4.rules /etc/udev/rules.d/70-mx4.rules
sudo udevadm control --reload-rules
sudo udevadm triggerThe source checkout already contains that rule. A Cargo installation only installs the binary, so download the rule first if you do not have the source tree:
curl -fLO https://raw.githubusercontent.com/EriksRemess/mx4/main/contrib/udev/70-mx4.rules
sudo install -Dm644 70-mx4.rules /etc/udev/rules.d/70-mx4.rules
sudo udevadm control --reload-rules
sudo udevadm triggersudo mx4 status can confirm that the HID++ device is readable, but it is only a diagnostic. Normal use should not need sudo after the udev rule is active.
Notes:
mx4 statusprints battery, DPI, wheel, thumb-wheel, force-button, and haptic state when available.mx4 status --jsonprints all readable status values as one JSON object, usingnullfor unavailable features.mx4 status hapticprints the configured haptic level when the device exposes it.mx4 batteryremains as a shorter alias for battery status.mx4 firmwareprints the mouse firmware entities and Bolt receiver firmware when available.- Persistent
mx4 set ...commands save the applied value to a local config file so it can be restored later. mx4 set host ...andmx4 haptic ...do not persist anything.mx4 daemonpolls for reconnects and reapplies saved settings when the mouse comes back.- The background service is only installed when
mx4 daemon --installis run explicitly. - The saved config file lives at:
- Linux:
~/.config/mx4/config.tomlunlessXDG_CONFIG_HOMEis set - macOS:
~/Library/Application Support/mx4/config.toml
- Linux: