# How to Toggle SmartShift Wheel Mode in OpenLogi: A Complete Technical Guide

> Master OpenLogi SmartShift wheel mode toggling with this technical guide. Learn to switch between free-spin and ratchet efficiently by reading and writing HID++ features.

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

---

**OpenLogi toggles SmartShift wheel mode between free-spin and ratchet by reading the current HID++ feature 0x2110 status, flipping the mode enum, and writing the new state back to the device with automatic retry logic.**

OpenLogi is an open-source Rust library for managing Logitech HID++ devices programmatically. Whether you are building a GUI application or automating mouse settings, understanding how to toggle SmartShift wheel mode allows you to switch between free-spin scrolling and tactile ratchet mode on compatible Logitech hardware. The implementation follows a layered architecture that separates protocol definitions from device communication.

## Architecture Overview

The OpenLogi codebase organizes SmartShift functionality into four distinct layers, each handling a specific aspect of wheel mode toggling:

- **Core definitions** – Exposes the `SmartShiftMode` enum and `SmartShiftStatus` structs in [`crates/openlogi-core/src/hid/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/hid/smartshift.rs)
- **HID++ feature implementation** – Manages low-level protocol communication using feature **0x2110** (or **0x2111** for the enhanced variant) in [`crates/openlogi-hidpp/src/feature/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hidpp/src/feature/smartshift.rs)
- **Device write helpers** – Provides high-level retry logic and race-condition handling in [`crates/openlogi-device/src/write/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/write/smartshift.rs)
- **Host façade** – Offers the public async API that interfaces with the native backend in [`crates/openlogi-hid/src/host.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/host.rs)

## Core SmartShift Definitions

The foundational types for SmartShift wheel mode toggling 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 `SmartShiftMode` enum with variants `Free` (free-spin) and `Ratchet` (tactile clicking), along with the `SmartShiftStatus` struct that captures the current device state.

All higher-level operations reference these core types, ensuring type safety across the asynchronous communication boundary.

## HID++ Protocol Implementation

The low-level device communication implements Logitech's HID++ feature **0x2110** (SmartShift) and its enhanced variant **0x2111**. The source file [`crates/openlogi-hidpp/src/feature/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hidpp/src/feature/smartshift.rs) contains the `SmartShiftFeature` struct that handles:

- `read_status()` – Queries the current wheel mode from the device
- Write commands – Transmits mode changes via the `WriteSmartShift` HID++ command

This layer manages the binary protocol encoding and checksum validation required for reliable device communication.

## Device-Level Write Logic

The high-level toggle logic lives in [`crates/openlogi-device/src/write/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/write/smartshift.rs), specifically between lines 301-313. The `toggle_smartshift` function implements a robust state machine that:

1. Calls `SmartShiftFeature::read_status` to retrieve the current `SmartShiftMode`
2. Computes the opposite variant (`Free ↔ Ratchet`)
3. Executes the `WriteSmartShift` command with the new mode
4. Returns the updated `SmartShiftMode` to the caller

To handle transient race conditions where the device briefly rejects writes, the implementation includes `toggle_smartshift_on_channel` with a short pause and retry block. This ensures reliable toggling even when the device is processing other HID reports.

## Host API Integration

The public API surface in [`crates/openlogi-hid/src/host.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/host.rs) (lines 69-73) exposes `toggle_smartshift` as an async function that selects the appropriate native backend (async-hid on the host) and forwards calls to the device layer. This façade pattern allows the same code to run on desktop applications, background agents, or embedded environments without modification.

## CLI Command Interface

For manual testing and scripting, [`crates/openlogi-cli/src/cmd/diag/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-cli/src/cmd/diag/smartshift.rs) implements the `openlogi diag smartshift` subcommand. This diagnostic tool provides:

- `--index` flag to target specific devices by inventory position
- `--read` flag to query current mode without changing state
- Automatic mode toggling when invoked without flags

## How the Toggle Mechanism Works

The complete SmartShift wheel mode toggling sequence operates through three distinct phases:

1. **Read current status** – The system calls `get_smartshift_status`, which returns a `SmartShiftStatus` struct containing the active `SmartShiftMode` enum variant.

2. **Flip the mode** – The `toggle_smartshift` function determines the opposite variant (switching `Free` to `Ratchet` or vice versa) and transmits the change via the HID++ write command.

3. **Retry logic** – If the device reports a temporary failure, the implementation pauses briefly and retries the write operation through `toggle_smartshift_on_channel`, handling the race condition where the device buffer is temporarily busy.

All operations are fully asynchronous (`async fn`), enabling non-blocking use from GUI event loops, background services, or command-line interfaces.

## Practical Implementation Examples

### Rust API Usage

To toggle SmartShift programmatically from a Rust application:

```rust
use openlogi_hid::{backend, toggle_smartshift};
use openlogi_device::DeviceRoute;

// Toggle SmartShift mode for a specific device route
async fn flip_smartshift(route: &DeviceRoute) -> Result<(), openlogi_core::hid::WriteError> {
    let new_mode = toggle_smartshift(route).await?;
    println!("SmartShift is now {:?}", new_mode);
    Ok(())
}

// Usage within an async runtime:
// flip_smartshift(&device_route).await?;

```

### CLI Usage

To toggle SmartShift from the terminal:

```bash

# List available devices to find the target index

openlogi list

# Toggle SmartShift for device at index 0

openlogi diag smartshift --index 0

# Read current mode without toggling

openlogi diag smartshift --index 0 --read

```

The CLI prints the new mode name (`Free` or `Ratchet`) after successful execution.

## Summary

- OpenLogi implements SmartShift toggling through HID++ feature **0x2110** (or **0x2111**) using a layered Rust architecture
- Core definitions in [`crates/openlogi-core/src/hid/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/hid/smartshift.rs) provide the `SmartShiftMode` enum and status types
- The `toggle_smartshift` function in [`crates/openlogi-device/src/write/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/write/smartshift.rs) handles mode flipping with automatic retry logic for race conditions
- Async APIs in [`crates/openlogi-hid/src/host.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/host.rs) expose the functionality to applications without blocking the event loop
- Command-line access is available via `openlogi diag smartshift --index <n>`

## Frequently Asked Questions

### What HID++ feature ID controls SmartShift in OpenLogi?

OpenLogi uses HID++ feature **0x2110** for standard SmartShift control and **0x2111** for the enhanced variant, as implemented in [`crates/openlogi-hidpp/src/feature/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hidpp/src/feature/smartshift.rs). These feature IDs correspond to Logitech's official protocol specifications for wheel mode switching.

### How does OpenLogi handle write failures when toggling SmartShift?

The `toggle_smartshift_on_channel` function in [`crates/openlogi-device/src/write/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/write/smartshift.rs) implements a retry mechanism with a short pause to handle transient race conditions. If the device briefly rejects the write command due to busy buffers, the library automatically retries the operation before returning an error to the caller.

### Can I use OpenLogi to toggle SmartShift from a command-line script?

Yes. The `openlogi diag smartshift --index <n>` command in [`crates/openlogi-cli/src/cmd/diag/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-cli/src/cmd/diag/smartshift.rs) allows scripted toggling of the wheel mode. You can query the current state with the `--read` flag or toggle directly by omitting it, making it suitable for shell scripts and automation workflows.

### Is the SmartShift toggle operation synchronous or asynchronous in OpenLogi?

All SmartShift operations are **asynchronous** (`async fn`). The public API in [`crates/openlogi-hid/src/host.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/host.rs) exposes `toggle_smartshift` as an async function that integrates with the async-hid backend, ensuring non-blocking operation in GUI applications and background services.