Switch a Logitech Easy-Switch device — MX Master 3S, MX Keys, MX Anywhere and friends — between paired computers with a keyboard shortcut, without reaching for the button on the underside and without running Logitech Options+.
Four independent implementations, one per platform. The native ones need no
third-party dependencies; the Python port needs hidapi except on Windows:
| Platform | File | Needs |
|---|---|---|
| macOS | macos/mxswitch.c |
clang (Command Line Tools) |
| Windows | windows/mxswitch.ps1 |
PowerShell 5.1+ |
| Linux | linux/mxswitch.sh |
bash, coreutils, a udev rule |
| any | python/mxswitch.py |
Python 3; hidapi except on Windows |
Pick one. They are not layered on each other — each is a standalone file
implementing the same protocol against its platform's native HID API. When both
a mouse and a keyboard are present, the mouse is preferred by default; pass
--all to move every ChangeHost device on the machine together.
Easy-Switch devices pair with up to three hosts but only expose channel switching through a recessed button underneath the device. Logitech's own software-side answer is Flow, which needs both machines on a network path that can see each other — frequently blocked by corporate VPN or DLP policy. Options+ can bind Easy-Switch to a button or the Actions Ring, but that requires running Options+ on every machine, and the Actions Ring is missing from some builds.
Underneath all of it is a single documented HID++ command. mxswitch sends that
command and nothing else.
Logitech peripherals speak HID++, a request/response protocol tunnelled over
a vendor-defined HID collection alongside the normal mouse and keyboard reports.
Feature 0x1814 is ChangeHost; its function 1, setCurrentHost, takes a
zero-based host index and moves the device to that channel.
A request is 7 bytes (short) or 20 bytes (long):
byte 0 report id 0x10 short, 0x11 long
byte 1 device index 0xFF direct (Bluetooth/USB), 1..6 behind a receiver
byte 2 feature index position of 0x1814 in this device's feature table
byte 3 (function << 4) | software id
byte 4+ parameters
Two details matter more than they look:
The feature index is not the feature ID. 0x1814 identifies the feature;
where it sits in a given device's table is firmware-specific. Hardcoding an
index works until a firmware update quietly moves it, after which you are
sending setCurrentHost to whatever feature now occupies that slot. Every
implementation here queries the root feature at runtime to resolve it.
A successful setCurrentHost never replies. By the time the device would
answer, it has already dropped off this host. Silence is success.
A channel switch is always initiated from the machine the device is currently
connected to. An idle computer cannot summon the mouse; the active host tells the
device to leave. So mxswitch must be installed on every machine you want to
switch away from, each configured to send the device to the other one.
The practical consequence: if you switch to a channel whose host is asleep, off, or has Bluetooth disabled, the device parks on a dead channel and the button underneath is your only way back. Keep the target awake, or pair it via a receiver, which stays live whenever the machine is powered.
mxswitch 2 # switch to channel 2
mxswitch --info # device, transport, feature index, current channel
mxswitch --all 2 # switch every ChangeHost device, not just the preferred one
mxswitch --name Keys 2 # switch matching keyboards to channel 2
mxswitch --toggle # switch to the other channel in the configured pair--name (repeatable) keeps only devices whose product name contains one of the
given substrings; with --all it moves exactly the matched devices, e.g. a
keyboard and mouse while leaving a third device alone. The config name= list
is combined with it. Devices behind a receiver are matched by their HID++ names;
unnamed receiver slots cannot match a name filter.
PowerShell spells the long options -Info, -All, -Toggle. --toggle reads
the current channel and moves to the other one of a pair you configure, so the
target is not hardcoded in your hotkey. The pair lives in
${XDG_CONFIG_HOME:-$HOME/.config}/mxswitch/config on macOS and Linux,
%LOCALAPPDATA%\mxswitch\config on Windows:
channel_a=1
channel_b=2--toggle --all reads the preferred matching device and moves all matches to
the same target channel.
See config.example for device/name filters. Invalid config values are errors;
--config PATH must exist. --status adds battery/firmware, --dry-run previews
commands, and --verbose shows diagnostics. PowerShell uses -Name, -Config,
-Status, -DryRun and -Verbose.
Exit codes: 0 success, 1 no compatible device or operation failed,
2 bad usage/configuration, 3 partial failure across multiple devices.
“Command sent” confirms the request was written, not connection to the target host.
Run from the tree, or install into a user prefix. Nothing needs a system-wide
sudo make install except the one-time Linux udev rule.
make # builds and ad-hoc signs ./mxswitch
./mxswitch --infoTo put it on your PATH without sudo:
make install PREFIX="$HOME/.local"
# → ~/.local/bin/mxswitch (ensure ~/.local/bin is on PATH)
# Opens Input Monitoring settings if this binary is not already allowed.Grant Input Monitoring in System Settings → Privacy & Security, both to the
binary and to whatever launches it. make install runs mxswitch --setup,
which skips the Settings pane when TCC already allows this binary.
The codesign -s - step in the Makefile is not cosmetic. TCC identifies
unsigned binaries by path and code hash, so an unsigned build silently loses
its Input Monitoring grant on every rebuild.
.\windows\mxswitch.ps1 -Info
.\windows\mxswitch.ps1 -Channel 2No admin rights needed: the vendor-defined collection is not the exclusively claimed mouse collection, so a normal user can open it.
If the execution policy objects:
powershell -NoProfile -ExecutionPolicy Bypass -File .\windows\mxswitch.ps1 -Channel 2One-time: allow your user to open Logitech hidraw devices (this is the only step that needs root):
sudo cp linux/42-logitech-hidpp.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules && sudo udevadm triggerThen run from the tree, or install into a user prefix:
./linux/mxswitch.sh --info
# or:
install -m 755 linux/mxswitch.sh ~/.local/bin/mxswitch
mxswitch --infopip install hidapi # not needed on Windows
python python/mxswitch.py --infoOn Windows the Python version drives hid.dll and setupapi.dll through
ctypes and needs no packages at all. Elsewhere it falls back to hidapi.
Windows — windows/mxswitch.ahk (AutoHotkey v2). Set SCRIPT at the top and
drop a shortcut to it in shell:startup. The main hotkey runs -Toggle, so
your channel pair lives in the config file rather than in the script. It also
binds a variant that switches and locks the workstation, which is the one worth
using day to day. AHK hotkeys do not fire on the lock screen, so trigger the
return switch from the other machine rather than expecting to wake Windows and
press the key.
macOS — BetterTouchTool: keyboard shortcut trigger → Execute Terminal
Command / Shell Script (async, non-blocking) → e.g.
$HOME/.local/bin/mxswitch --toggle or the absolute path to ./mxswitch in this
repo. Raycast script commands and Automator Quick Actions work the same way.
Linux — GNOME Settings → Keyboard → Custom Shortcuts, or the KDE equivalent,
pointing at e.g. $HOME/.local/bin/mxswitch --toggle.
Prefer --toggle to a hardcoded channel: pairing a third host later does not
silently change which channel a bare 2 means.
This is not the first tool to send ChangeHost, and if one of these fits you
better, use it:
- marcelhoffs/input-switcher —
Windows/Linux scripts around a vendored
hidapitester; switches a keyboard and mouse together.mxswitch --allcan also move both; its default is to move the preferred device, usually the mouse. - meliksah/lcs — GUI channel switcher.
- omar16100/logi_mx_auto_switch — makes a mouse follow its keyboard automatically on macOS.
- boyvanamstel/SwitchMX — macOS, MX Master 3S.
- Solaar and
Mouser — full Options+ replacements that
cover
ChangeHostamong much else.
What is different here: no vendored binaries anywhere, one self-contained file per platform, and runtime feature-index discovery rather than hardcoded offsets.
MIT. See LICENSE.