How to Configure SmartShift with OpenLogi for Logitech Devices: A Complete Guide

OpenLogi configures Logitech SmartShift (free-spin/ratchet wheel modes) through a three-layer architecture that maps TOML configuration values to HID++ protocol commands via Rust structs in openlogi-core/src/hid/smartshift.rs and IPC RPC calls.

OpenLogi is an open-source user-space driver for Logitech HID++ devices that exposes the SmartShift feature—Logitech's proprietary wheel-ratchet toggle mechanism—through a clean configuration interface. Understanding how to configure SmartShift with OpenLogi for Logitech devices requires familiarity with its layered architecture spanning the HID++ driver, core abstraction module, and IPC transport layer.

Understanding the SmartShift Architecture in OpenLogi

SmartShift configuration flows through three distinct layers that bridge raw hardware protocols with user-facing controls:

  • HID++ Driver Layer (openlogi-hidpp): Handles raw byte transmission for SmartShift features 0x2110 and 0x2111
  • Core Abstraction Layer (openlogi-core/src/hid/smartshift.rs): Defines SmartShiftMode, SmartShiftAutoDisengage, and SmartShiftStatus enums with conversion logic between persisted config and wire format
  • IPC/CLI Layer (openlogi-ipc/src/ipc.rs): Exposes async RPC functions set_smartshift and read_smartshift that forward configuration changes to the agent

The Configuration Data Flow

When OpenLogi initializes, the agent reads ~/.config/openlogi/config.toml, converts WheelMode values into the SmartShiftMode enum through SmartShiftMode::from(crate::config::WheelMode), and writes the status to the device. Changes triggered via CLI or GUI invoke the IPC set_smartshift function, which ultimately calls the low-level HID++ write path write::smartshift::set_smartshift.

Configuring SmartShift via TOML

The persistent configuration resides in ~/.config/openlogi/config.toml under the [smart_shift] section:

[smart_shift]

# Mode can be "free" (free-spin) or "ratchet" (clicky)

mode = "ratchet"

# Auto-disengage threshold (0.25 turn/s steps). 255 = permanent ratchet.

auto_disengage = 30   # 30 × 0.25 turn/s = 7.5 turn/s

# Optional tunable-torque value (only on devices that support it)

tunable_torque = 2

The mode field accepts "free" for continuous scrolling or "ratchet" for stepped clicking. The auto_disengage value represents threshold steps where each step equals 0.25 turns per second; setting this to 255 locks the wheel in permanent ratchet mode regardless of spin speed.

Three Methods to Configure SmartShift

Depending on your integration needs, OpenLogi exposes SmartShift controls through CLI commands, programmatic Rust APIs, or direct configuration file editing.

Using the OpenLogi CLI

The openlogi-cli binary provides subcommands that serialize requests and transmit them via IPC:


# Set SmartShift to ratchet mode with a 30-step threshold (7.5 turn/s)

openlogi-cli set smartshift --mode ratchet --threshold 30

# Query the current SmartShift status

openlogi-cli get smartshift

These commands update the TOML file automatically after successfully writing to the device hardware.

Using the Rust Library

For embedded applications or custom tooling, import the core HID types and device write functions:

use openlogi_core::hid::smartshift::{SmartShiftMode, SmartShiftThreshold};
use openlogi_device::write::{set_smartshift, get_smartshift_status};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Assume `device` is a previously opened HID++ device.
    let status = get_smartshift_status(&device).await?;
    println!("Current mode: {:?}, threshold: {:?}", status.mode, status.auto_disengage);

    // Switch to free-spin with a 20-step threshold.
    let new_status = openlogi_core::hid::smartshift::SmartShiftStatus {
        mode: SmartShiftMode::Free,
        auto_disengage: openlogi_core::hid::smartshift::SmartShiftAutoDisengage::Threshold(
            SmartShiftThreshold::try_new(20)?,
        ),
        tunable_torque: status.tunable_torque,
    };
    set_smartshift(&device, new_status).await?;
    Ok(())
}

This approach uses SmartShiftStatus structs defined in crates/openlogi-core/src/hid/smartshift.rs and write helpers in crates/openlogi-device/src/write/smartshift.rs.

Direct Configuration File Editing

Modify ~/.config/openlogi/config.toml directly and restart the OpenLogi agent:

[smart_shift]
mode = "free"
auto_disengage = 20

# tunable_torque omitted → will retain current value

The agent detects configuration changes on startup and applies them through the same conversion logic used by the IPC layer.

The SmartShift Configuration Lifecycle

OpenLogi manages SmartShift state through a five-phase pipeline:

  1. Read: openlogi-hidpp queries feature 0x2110, and SmartShift::status() returns a SmartShiftStatus struct
  2. Convert: The raw status transforms into the core SmartShiftStatus type via impl From<crate::config::SmartShift>
  3. Expose: The IPC layer makes the status available through read_smartshift for GUI consumption
  4. Modify: CLI or GUI constructs a new SmartShiftStatus with desired mode and auto_disengage values
  5. Write: write::smartshift::set_smartshift serializes the struct back to HID++ wire bytes using SmartShiftMode::into() and SmartShiftAutoDisengage::into(), then transmits to the device

Protocol Version Safety

Because the IPC serializes SmartShiftMode enums by their numeric index (Free = 0, Ratchet = 1), OpenLogi implements safeguards in openlogi-ipc/tests/wire_format.rs. Any change to the enum order requires a PROTOCOL_VERSION bump to prevent deserialization errors between agent and client components.

Summary

  • Configure SmartShift with OpenLogi by editing ~/.config/openlogi/config.toml or using openlogi-cli set smartshift commands
  • Configuration flows through openlogi-core/src/hid/smartshift.rs where SmartShiftMode and SmartShiftStatus types bridge TOML values and HID++ protocol bytes
  • The auto_disengage threshold uses 0.25 turn/s steps; set to 255 for permanent ratchet mode
  • Programmatic control requires importing openlogi_device::write::set_smartshift and constructing SmartShiftStatus structs
  • Wire format tests in openlogi-ipc/tests/wire_format.rs ensure binary compatibility across protocol versions

Frequently Asked Questions

Which Logitech devices support SmartShift configuration through OpenLogi?

OpenLogi supports any Logitech device implementing HID++ features 0x2110 and 0x2111, typically found in MX Master series mice and similar high-end input devices. Check openlogi-device/src/write/smartshift.rs for the specific feature detection logic that validates hardware compatibility before attempting configuration.

What values should I use for the auto_disengage threshold?

The auto_disengage field accepts values 0 to 255, where each unit represents 0.25 turns per second. For example, 30 equals 7.5 turns per second. Setting this to 255 disables automatic mode switching and forces permanent ratchet mode, while lower values trigger free-spin earlier during fast scrolling.

Does changing SmartShift mode require restarting the OpenLogi agent?

Changes made through openlogi-cli or the GUI apply immediately via IPC calls to set_smartshift. However, direct edits to ~/.config/openlogi/config.toml require an agent restart to take effect, as the configuration is read at startup time in openlogi-core initialization routines.

Why does the IPC layer serialize SmartShiftMode as an integer index?

The IPC uses numeric indices (Free = 0, Ratchet = 1) for SmartShiftMode to minimize wire format size and parsing complexity. This design requires strict PROTOCOL_VERSION management in openlogi-ipc/tests/wire_format.rs—altering the enum definition without bumping the protocol version breaks compatibility between the agent and CLI components.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →