# How SmartShift Wheel Mode Toggles and Sensitivity Controls Work in OpenLogi

> Discover how OpenLogi's SmartShift wheel mode toggles and sensitivity controls leverage HID++ to manage gestures and user configurations. Learn more about its advanced features.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: internals
- Published: 2026-08-30

---

**OpenLogi implements SmartShift wheel mode toggles and sensitivity controls through a layered HID++ architecture that discovers divertable buttons, manages gesture sessions, and exposes user-facing configuration options in the desktop interface.**

OpenLogi is an open-source Rust implementation for managing Logitech HID++ devices. The repository provides complete control over SmartShift functionality, allowing programmatic toggling between free-spin and ratchet modes while adjusting auto-disengage sensitivity through both low-level APIs and desktop UI components.

## The HID++ Architecture for SmartShift Management

OpenLogi organizes SmartShift control across four distinct layers according to the source code in `AprilNEA/OpenLogi`.

### Device-Level HID++ API

The lowest layer handles raw reads and writes to mouse firmware. In [`crates/openlogi-hid/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/lib.rs) and [`crates/openlogi-hid/src/host.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/host.rs), functions like `set_smartshift_sensitivity` and `toggle_smartshift` provide direct hardware communication.

### Reprogrammable Control Discovery

The middle layer discovers and diverts SmartShift-related buttons. The `ReprogControlsV4` feature (ID `0x1b04`) enumerates controls defined in [`crates/openlogi-device/src/reprog_controls.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/reprog_controls.rs), specifically the `DPI_MODE_SHIFT_CIDS` constant containing the three possible control IDs for SmartShift buttons (`0x00c4`, `0x00ed`, `0x00fd`).

### Gesture Session Logic

During active sessions managed in [`crates/openlogi-device/src/session/gesture.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/session/gesture.rs), the system arms divertable controls and maps them to internal button identifiers like `ButtonId::DpiToggle`.

### Desktop UI Layer

The presentation layer in [`crates/openlogi-desktop/src/windows/settings/general.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/windows/settings/general.rs) and [`crates/openlogi-desktop/src/features/pointer/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/features/pointer/smartshift.rs) exposes sliders for thumbwheel and vertical scroll sensitivity, binding user interactions to the underlying HID++ calls.

## How SmartShift Wheel Mode Toggling Works

The toggle mechanism operates through a three-phase process involving hardware discovery, control diversion, and event translation.

### Control Discovery via ReprogControlsV4

The system first enumerates available controls using the `ReprogControlsV4` feature. The constant `DPI_MODE_SHIFT_CIDS` in [`reprog_controls.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/reprog_controls.rs) identifies SmartShift-capable buttons:

```rust
/// Control IDs of the "DPI / ModeShift" button family.
pub const DPI_MODE_SHIFT_CIDS: [u16; 3] = [0x00c4, 0x00ed, 0x00fd];

```

### Arming and Diverting Buttons

During gesture session initialization, the `arm_controls_into` function in [`gesture.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/gesture.rs) iterates through these CIDs. If a control is present and divertable, the system calls `arm_reprog_control` with `raw_xy = false`, preventing raw wheel data transmission during button holds:

```rust
for &cid in &reprog_controls::DPI_MODE_SHIFT_CIDS {
    if controls.iter().any(|c| c.cid == cid && c.is_divertable()) {
        arm_reprog_control(&rc, cid, false, &mut armed.reporting).await?;
        armed.dpi_cids.push(cid);
    }
}

```

### Event Mapping to DpiToggle

Once diverted, the SmartShift button events translate to `ButtonId::DpiToggle` via the `gesture_source_button` mapping function. This allows the desktop UI to receive standardized events regardless of specific hardware control IDs.

## Managing SmartShift Sensitivity Controls

Sensitivity control follows a similar layered approach, bridging user interface elements with hardware registers.

### Low-Level HID++ Host API

The `set_smartshift_sensitivity` function in [`crates/openlogi-hid/src/host.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/host.rs) accepts a `DeviceRoute` and `SmartShiftAutoDisengage` value, forwarding requests to the native backend driver:

```rust
/// Set the SmartShift auto‑disengage sensitivity of the device `route` reaches.
pub async fn set_smartshift_sensitivity(
    route: DeviceRoute,
    value: SmartShiftAutoDisengage,
) -> Result<(), WriteError> {
    device::set_smartshift_sensitivity(&*native_backend(), route, value).await
}

```

### Device Write Wrappers

Higher-level management resides in [`crates/openlogi-device/src/write/smartshift.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/write/smartshift.rs). The `set_sensitivity` method preserves the current SmartShift mode while updating only the auto-disengage threshold.

### Desktop UI Integration

The settings panel in [`general.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/general.rs) binds sliders to `thumbwheel_sensitivity_field` and `vertical_scroll_sensitivity_field`. When users adjust values, the UI invokes `state.set_thumbwheel_sensitivity()`, which ultimately calls `set_smartshift_sensitivity` for thumbwheel adjustments or `set_scroll_resolution` for vertical scrolling.

## Implementation Examples

### Toggling SmartShift Mode Programmatically

To toggle between free-spin and ratchet modes directly:

```rust
use openlogi_hid::set_smartshift;      // low‑level HID++ call
use openlogi_hid::toggle_smartshift;   // convenience wrapper

// `route` identifies the mouse (e.g. from `device::select_route()`).
async fn toggle_smart_shift(route: DeviceRoute) -> Result<(), WriteError> {
    // Directly toggle the mode (free‑spin ↔ ratchet)
    toggle_smartshift(route).await
}

```

### Adjusting Auto-Disengage Sensitivity

Set the threshold that determines when the wheel transitions from free-spin to ratchet mode:

```rust
use openlogi_hid::set_smartshift_sensitivity;
use openlogi_hid::SmartShiftAutoDisengage;

async fn set_smart_shift_sensitivity(route: DeviceRoute, level: u8) -> Result<(), WriteError> {
    // `level` is 0‑255; the driver maps it to a usable auto‑disengage value.
    let sens = SmartShiftAutoDisengage::from(level);
    set_smartshift_sensitivity(route, sens).await
}

```

### Capturing SmartShift Button Events

To intercept SmartShift button presses during gesture sessions:

```rust
use openlogi_device::reprog_controls::DPI_MODE_SHIFT_CIDS;

// Inside a gesture‑session setup:
let mut armed = ArmedControls::default();
for &cid in &DPI_MODE_SHIFT_CIDS {
    if controls.iter().any(|c| c.cid == cid && c.is_divertable()) {
        // Divert the button so the session can see it as a plain press
        arm_reprog_control(&rc, cid, false, &mut armed.reporting).await?;
        armed.dpi_cids.push(cid);
    }
}

```

### Building UI Sensitivity Sliders

For desktop UI implementations using GPUI:

```rust
fn thumbwheel_sensitivity_field(slider: &Entity<SliderState>, cx: &mut App) -> gpui::Div {
    sensitivity_field(
        "Thumbwheel Sensitivity",
        slider.clone(),
        cx,
        |value| {
            let sens = ThumbwheelSensitivity::from_rounded(value.start());
            state.set_thumbwheel_sensitivity(sens);
        },
    )
}

```

## Summary

- OpenLogi implements **SmartShift wheel mode toggles and sensitivity controls** through a four-layer HID++ architecture spanning device firmware, control discovery, gesture management, and desktop UI.
- The system identifies SmartShift buttons via the `DPI_MODE_SHIFT_CIDS` constant (`0x00c4`, `0x00ed`, `0x00fd`) in [`reprog_controls.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/reprog_controls.rs) and diverts them during gesture sessions to prevent raw data interference.
- Sensitivity adjustments flow from UI sliders through `set_smartshift_sensitivity` in the HID++ host API, preserving existing wheel modes while updating auto-disengage thresholds.
- All functionality is accessible programmatically through async Rust APIs in `openlogi-hid` and `openlogi-device` crates, or graphically through the OpenLogi desktop settings panel.

## Frequently Asked Questions

### How does OpenLogi identify which button controls SmartShift on different mouse models?

OpenLogi uses the `ReprogControlsV4` feature (ID `0x1b04`) to enumerate all programmable controls on the device. It specifically checks against the `DPI_MODE_SHIFT_CIDS` array containing three possible control IDs (`0x00c4`, `0x00ed`, `0x00fd`) defined in [`crates/openlogi-device/src/reprog_controls.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/reprog_controls.rs). This covers the SmartShift button family across various Logitech hardware implementations, ensuring compatibility without hardcoding specific device models.

### What is the difference between `toggle_smartshift` and `set_smartshift_sensitivity`?

`toggle_smartshift`, exported from [`crates/openlogi-hid/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/lib.rs), switches the wheel between free-spin and ratchet modes immediately. In contrast, `set_smartshift_sensitivity`, defined in [`crates/openlogi-hid/src/host.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hid/src/host.rs), adjusts the auto-disengage threshold—the force level at which a free-spinning wheel automatically switches to ratchet mode. The former changes the operating mode directly, while the latter configures the sensitivity parameter for automatic mode transitions.

### Why does OpenLogi divert SmartShift buttons during gesture sessions with `raw_xy = false`?

The `arm_reprog_control` call in [`crates/openlogi-device/src/session/gesture.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-device/src/session/gesture.rs) sets `raw_xy = false` when diverting SmartShift buttons to prevent the wheel from transmitting raw motion data while the button is held. This ensures the button acts as a plain modifier or toggle rather than a continuous input source, allowing the gesture system to capture clean button press events without interference from wheel movement data during the diversion period.

### Can SmartShift sensitivity be adjusted independently for thumb wheels and vertical scrolling?

Yes. The desktop UI in [`crates/openlogi-desktop/src/windows/settings/general.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/windows/settings/general.rs) exposes separate sliders for `thumbwheel_sensitivity_field` and `vertical_scroll_sensitivity_field`. Thumbwheel sensitivity adjustments invoke `set_smartshift_sensitivity` specifically for the SmartShift mechanism, while vertical scroll sensitivity uses `set_scroll_resolution`. Both settings persist independently in the device firmware, allowing distinct sensitivity profiles for different wheel types.