How SmartShift Is Configured in OpenLogi: TOML, UI, and HID++ Protocol

SmartShift in OpenLogi is configured through a three-layer architecture: declarative TOML files for static settings, runtime UI/CLI for dynamic changes, and HID++ protocol commands for device communication.

OpenLogi implements Logitech's SmartShift (dynamic ratchet/free-spin wheel mode) as a core device feature in its Rust-based driver stack. This article explains how SmartShift configuration flows from user-facing settings to hardware commands, based on the OpenLogi source code in the AprilNEA/OpenLogi repository.


TOML Configuration File Structure

User-defined SmartShift settings live in config.toml under each device's smartshift table. The example in docs/config.example.toml shows the complete schema:

[devices."receiver:aabbccdd:slot:1".smartshift]
mode           = "ratchet"      # or "free"

auto_disengage = 16            # threshold (0-255)

tunable_torque = 50           # torque (0-255)

The mode field accepts two string values:

  • ratchet — stepped scrolling with tactile feedback
  • free — smooth spinning with no resistance

auto_disengage controls how long the ratchet mode holds before automatic release (higher values = longer hold). tunable_torque sets the mechanical resistance strength in ratchet mode (higher values = stronger detents). Both are u8 values (0-255 range).


Configuration Parsing and Core Types

The TOML deserializes into internal structures defined in openlogi-core. In crates/openlogi-core/src/hid/smartshift.rs, the SmartShiftStatus struct mirrors both the configuration format and the HID++ wire protocol:

  • mode → SmartShiftMode enum (Ratchet or Free)
  • auto_disengage → SmartShiftAutoDisengage::Threshold(u8)
  • tunable_torque → TunableTorque(u8)

This design ensures zero-copy translation between user configuration and device commands.


Device Write Path: From Status to HID++ Commands

When settings change, openlogi-device translates SmartShiftStatus into hardware commands. The high-level API lives in crates/openlogi-device/src/write/smartshift.rs:

// Key functions in the write module
pub async fn set_smartshift(route: &DeviceRoute, status: SmartShiftStatus) -> Result<(), WriteError>;
pub async fn toggle_smartshift(route: &DeviceRoute) -> Result<SmartShiftMode, WriteError>;
pub async fn set_smartshift_sensitivity(route: &DeviceRoute, threshold: u8, torque: u8) -> Result<(), WriteError>;

These functions open the SmartShift feature from openlogi-hidpp and dispatch the appropriate sub-commands:

  • set_status — full configuration write
  • toggle — mode switch only
  • set_sensitivity — threshold and torque adjustment

HID++ Protocol Implementation

The wire-format protocol definitions span two feature files in openlogi-hidpp:

Feature ID File Device Support
0x2110 crates/openlogi-hidpp/src/feature/smartshift.rs Standard SmartShift devices
0x2111 crates/openlogi-hidpp/src/feature/smartshift_enhanced.rs Newer hardware variants

The actual I/O dispatch occurs in crates/openlogi-hid/src/host.rs, which exposes async functions that the agent and UI consume:

use openlogi_hid::host::get_smartshift_status;
use openlogi_core::hid::smartshift::SmartShiftStatus;

async fn print_smartshift(route: &DeviceRoute) -> Result<(), WriteError> {
    let status: SmartShiftStatus = get_smartshift_status(route).await?;
    println!("Mode: {:?}, Auto‑Disengage: {:?}, Torque: {:?}",
             status.mode, status.auto_disengage, status.tunable_torque);
    Ok(())
}

Runtime UI and IPC Architecture

The openlogi-ui crate communicates with the background agent through tarpc RPC defined in crates/openlogi-ipc/src/ipc.rs:

// RPC methods for SmartShift control
async fn read_smartshift(device_key: String) -> Result<SmartShiftStatus, IpcError>;
async fn set_smartshift(device_key: String, status: SmartShiftStatus) -> Result<(), IpcError>;

The UI workflow:

  1. Call read_smartshift on device selection to populate state
  2. Display toggle button and sensitivity slider (localized via crates/openlogi-ui/locales/*.toml)
  3. Call set_smartshift when user changes settings

CLI users bypass the UI entirely:

openlogi set_smartshift --device "receiver:aabbccdd:slot:1" --mode free

Configuration Persistence and Hot-Reload

OpenLogi supports live configuration updates:

  1. File watcher detects config.toml changes
  2. Agent re-parses affected SmartShiftStatus values
  3. New settings push to device via the same write path as UI changes

This unifies declarative (file-based) and imperative (runtime) configuration into a single pipeline.


Summary

  • TOML files provide static SmartShift configuration under [devices."..."].smartshift tables
  • SmartShiftStatus in openlogi-core bridges user settings and HID++ wire format
  • Write helpers in openlogi-device/src/write/smartshift.rs translate status to device commands
  • HID++ features 0x2110 and 0x2111 handle protocol-level communication
  • tarpc IPC enables UI and CLI to control SmartShift without direct hardware access
  • Hot-reload ensures file changes propagate to connected devices immediately

Frequently Asked Questions

What are the valid values for SmartShift mode in OpenLogi?

OpenLogi accepts two string values for the mode field: "ratchet" for stepped scrolling and "free" for smooth spinning. These map to the SmartShiftMode::Ratchet and SmartShiftMode::Free variants in crates/openlogi-core/src/hid/smartshift.rs.

How do I adjust SmartShift sensitivity in OpenLogi?

Use the auto_disengage field (0-255) to control how long ratchet mode holds, and tunable_torque (0-255) to set mechanical resistance. Higher auto_disengage values delay automatic disengagement; higher tunable_torque values create stronger tactile feedback. Both can be set via TOML or adjusted at runtime through the UI slider.

Why does OpenLogi have two HID++ feature IDs for SmartShift?

Feature ID 0x2110 in smartshift.rs supports standard SmartShift hardware, while 0x2111 in smartshift_enhanced.rs handles newer devices with extended capabilities. The openlogi-device crate automatically selects the appropriate feature based on device capability detection.

Can I toggle SmartShift without editing the configuration file?

Yes. The UI toggle button calls toggle_smartshift() via IPC, and the CLI supports openlogi set_smartshift --mode <ratchet|free>. Runtime changes persist only until device disconnect unless you also update config.toml or enable auto-save in UI preferences.

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 →