Fast macOS-only CLI to trigger Logitech Easy-Switch host changes using HID++ 2.0 directly over hidapi.
This project was inspired by Solaar's change-host implementation but optimized for speed and simplicity on macOS. I primarily use it with a keyboard macro tool (Karabiner-Elements) to switch my non-Logitech keyboard and MX Master seamlessly between hosts.
Warning: I haven't done much C coding, and this is a vibe-coded personal project. Contributions and improvements are welcome!
- macOS
- Homebrew packages:
hidapiandpkgconf
brew install hidapi pkgconfFrom the repo root:
makeThis produces the lunaar-switch binary.
Switch the device to host slot 1–3 (1-based):
./lunaar-switch 2
./lunaar-switch --slot 1For faster performance with cached device parameters, use optional flags:
./lunaar-switch --path /dev/hidraw0 --devnum 2 --slot 2Or use built-in cache handling (default behavior):
./lunaar-switch --cache auto 2-s— Silent mode; suppress normal output (errors always printed)--path PATH— Direct hidapi path (e.g.,/dev/hidraw0); skips enumeration--devnum DEVNUM— Device number (0–255, often 0xFF for receiver); skips device discovery--feature-index INDEX— Feature index for CHANGE_HOST (defaults to 14); skips feature lookup--slot SLOT— Host slot number (1–3); can also be positional argument--cache auto|off|refresh— Cache mode (defaultauto)--cache-file PATH— Override cache file location (default/tmp/lunaar-device-cache-<uid>)
-
First run (auto-discovery):
./lunaar-switch 2
This discovers your device and saves path/devnum/feature index in the native cache.
-
Subsequent runs (fast cached path):
./lunaar-switch 2
By default, the binary attempts the cached path first and falls back to discovery when stale.
-
Disable cache when debugging:
./lunaar-switch --cache off 2
-
Force refresh cache:
./lunaar-switch --cache refresh 2
The tool automatically:
- Enumerates Logitech devices via
hidapi(unless--pathis given) - Finds the first HID++ 2.0 endpoint exposing
CHANGE_HOST(feature 0x1814) (unless--devnumand--feature-indexare given) - Sends the host-switch write (fn 0x10) as a long HID++ report with no expected reply
- Only switching is implemented; host-name queries/updates are omitted for speed.
- Automatic device selection stops at the first compatible device; if multiple receivers/devices are attached, unplug extras or use
--pathto target a specific one. - Feature index defaults to 14 (observed constant on most Logitech receivers); use
--feature-indexto override if needed. - Tested flow matches Solaar’s
change-hosthandling (long report 0x11, no reply expected).
For seamless integration with Karabiner Elements, call the binary directly with native cache support. The app cache is stored in /tmp and is automatically refreshed if stale.
{
"conditions": [
{
"identifiers": [{ "vendor_id": "14248" }],
"type": "device_if"
}
],
"description": "Execute Logitech Lunaar Easy-Switch Binary",
"manipulators": [
{
"from": { "key_code": "f24" },
"to": [{ "shell_command": "~/Developer/GitHub/Lunaar/bin/lunaar-switch 2" }],
"type": "basic"
}
]
}Note: If command execution fails, add /Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_console_user_server to the Input Monitoring list in System Preferences > Privacy & Security > Input Monitoring.