How SmartShift Wheel Modes (Ratchet vs Standard) Work in OpenLogi

OpenLogi implements Logitech’s SmartShift feature through the HID++ protocol, exposing two distinct wheel behaviors—tactile ratchet mode and smooth free-spin mode—via the SmartShiftMode enum and async device control functions.

OpenLogi is an open-source Rust implementation for controlling Logitech peripherals via the HID++ protocol. Understanding how SmartShift wheel modes function is essential for developers building scrolling experiences or automation tools, as the choice between ratchet and standard modes directly impacts both tactile feedback and scroll velocity in supported mice.

How Ratchet and Standard Modes Differ

The SmartShift system supports two primary wheel configurations that determine physical scroll behavior.

Ratchet mode engages mechanical detents that provide tactile feedback with each scroll step, offering precise control for document navigation. This is the default mode for most Logitech mice and is represented in code as SmartShiftMode::Ratchet.

Standard mode (also referred to as "free-spin" mode) removes mechanical resistance, allowing the wheel to rotate smoothly and rapidly with minimal friction. When configured with automatic switching, the mode transitions to free-spin when scroll speed exceeds a configurable threshold, then reverts based on the auto-disengage settings. This auto-disengage flag determines whether the wheel automatically returns to ratchet mode after a period of low scroll speed or inactivity.

Implementation Architecture in OpenLogi

The SmartShift implementation spans three architectural layers in the OpenLogi codebase, separating public API definitions from low-level protocol translation.

Core Type Definitions

The foundational types reside in crates/openlogi-core/src/hid/smartshift.rs. This module defines the public SmartShiftMode enum with Ratchet and Freespin variants, alongside SmartShiftAutoDisengage and SmartShiftStatus structs. These types form the public API contract exposed by the openlogi_core::hid::smartshift module and used throughout the ecosystem.

HID++ Protocol Translation

The device-level mapping between HID++ wire protocol and OpenLogi's internal representations occurs in crates/openlogi-device/src/write/smartshift.rs. This file contains the bidirectional conversion helpers wheel_mode_to_smartshift and smartshift_to_wheel, which translate HID++ WheelMode values to the public SmartShiftMode enum used by higher-level crates.

Host and IPC Interfaces

High-level asynchronous controls are exposed through crates/openlogi-hid/src/host.rs, implementing functions such as set_smartshift, toggle_smartshift, and get_smartshift_status. The IPC contract defined in crates/openlogi-ipc/src/ipc.rs exposes RPC methods set_smartshift and read_smartshift, accepting SmartShiftStatus parameters to enable cross-process communication with the device service.

Programming SmartShift Modes

Developers interact with wheel modes through async Rust functions that handle HID++ communication, error handling, and state management automatically.

Querying Current Status

To read the current SmartShift configuration from a device:

use openlogi_core::hid::smartshift::SmartShiftMode;
use openlogi_device::smartshift::get_smartshift_status;

// Assume `route` is a `DeviceRoute` pointing to the target mouse.
let status = get_smartshift_status(&route).await?;
println!("Wheel mode: {:?}", status.mode);
println!("Auto‑disengage: {:?}", status.auto_disengage);

Toggling Between Modes

The toggle_smartshift function queries the current state, flips the mode between Ratchet and Freespin, and writes the new configuration back to the device:

use openlogi_device::smartshift::toggle_smartshift;

// `route` as before.
let new_mode = toggle_smartshift(&route).await?;
println!("SmartShift now in {:?} mode", new_mode);

Explicit Mode Selection

For applications requiring specific wheel behavior without toggling, construct a SmartShiftStatus and use set_smartshift:

use openlogi_core::hid::smartshift::{SmartShiftMode, SmartShiftStatus};
use openlogi_device::smartshift::set_smartshift;

// Build a status with the desired mode.
let desired = SmartShiftStatus {
    mode: SmartShiftMode::Freespin,          // or SmartShiftMode::Ratchet
    auto_disengage: Some(true),              // optional: enable auto‑disengage
    tunable_torque: None,                    // leave unchanged
};

set_smartshift(&route, desired).await?;

Summary

  • OpenLogi exposes Logitech's SmartShift feature through the HID++ protocol using the SmartShiftMode enum with Ratchet and Freespin variants defined in crates/openlogi-core/src/hid/smartshift.rs.
  • Ratchet mode provides tactile detents for precise scrolling, while standard (free-spin) mode enables smooth, rapid wheel rotation without mechanical resistance.
  • The auto_disengage flag in SmartShiftStatus controls automatic reversion to ratchet mode after low-speed scrolling or inactivity.
  • Device-level protocol translation occurs in crates/openlogi-device/src/write/smartshift.rs via wheel_mode_to_smartshift and smartshift_to_wheel helpers.
  • Async functions get_smartshift_status, toggle_smartshift, and set_smartshift in crates/openlogi-hid/src/host.rs provide the primary API for programmatic wheel mode control.

Frequently Asked Questions

What is the difference between ratchet and standard SmartShift modes in OpenLogi?

Ratchet mode engages mechanical detents that create tactile, stepped feedback suitable for precise navigation, while standard mode (free-spin) removes these detents to allow smooth, frictionless rotation ideal for rapid scrolling through long documents. These modes correspond to the Ratchet and Freespin variants of the SmartShiftMode enum in crates/openlogi-core/src/hid/smartshift.rs.

How does auto-disengage work with SmartShift wheel modes?

When the auto_disengage field in SmartShiftStatus is set to Some(true), the wheel automatically transitions from free-spin back to ratchet mode after detecting low scroll velocity or a period of inactivity. This behavior allows users to benefit from high-speed free-spin scrolling while automatically regaining precision control without manual toggling.

Which source files handle SmartShift mode conversion in OpenLogi?

The conversion between HID++ wire format and OpenLogi's internal representation is handled in crates/openlogi-device/src/write/smartshift.rs by the wheel_mode_to_smartshift and smartshift_to_wheel functions. Public API type definitions are located in crates/openlogi-core/src/hid/smartshift.rs, while high-level async interfaces are implemented in crates/openlogi-hid/src/host.rs.

Can I programmatically toggle SmartShift modes without knowing the current state?

Yes. The toggle_smartshift function in crates/openlogi-hid/src/host.rs automatically queries the current SmartShiftStatus via get_smartshift_status, flips the mode field between Ratchet and Freespin, and writes the updated configuration back to the device using the HID++ protocol, handling the entire transaction atomically.

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 →