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

> Understand how OpenLogi's SmartShift wheel modes, ratchet and standard, function using the HID++ protocol. Control your device's scroll behavior with async functions and the SmartShiftMode enum.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: how-to-guide
- Published: 2026-09-03

---

**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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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:

```rust
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:

```rust
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`:

```rust
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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/hid/smartshift.rs), while high-level async interfaces are implemented in [`crates/openlogi-hid/src/host.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/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`](https://github.com/AprilNEA/OpenLogi/blob/main/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.