How the SmartShift Wheel Mode Toggle Works with HID++ Feature 0x1b04 in OpenLogi

OpenLogi implements the SmartShift wheel-mode toggle by mapping Control ID 0xC4 through the HID++ Reprogrammable Controls feature (0x1b04), converting raw wheel events into DPI preset cycles when the dedicated button is held.

OpenLogi is an open-source driver for Logitech HID++ devices that exposes low-level hardware controls through a structured abstraction layer. The SmartShift button—typically used to toggle between normal scrolling and DPI-shifting modes—is managed via the Reprogrammable Controls protocol. This article traces the exact code path from HID++ feature detection to the UI update, using the actual source implementation in the AprilNEA/OpenLogi repository.

Identifying the SmartShift Control ID

The SmartShift button is exposed by the hardware as Control ID 0xC4. This constant is defined in the HID++ crate's control registry.

In crates/openlogi-hidpp/src/feature/reprog_controls/control_ids.rs, the constant is declared as SMART_SHIFT. This identifier represents the physical button located beneath the mouse wheel on supported Logitech devices. When the device reports its available controls via HID++, this ID signals the presence of the wheel-mode toggle mechanism.

Resolving the Default Task ID

Every control in the HID++ protocol has a default Task ID that describes its built-in action. For SmartShift, this task is 0x9D (SMART_SHIFT).

This mapping is defined in crates/openlogi-hidpp/src/feature/reprog_controls/task_ids.rs. The Task ID represents the firmware's native behavior—switching the wheel from scroll mode to DPI-shift mode—which OpenLogi can either preserve or override through its binding system.

Querying Control Information via HID++ 0x1b04

OpenLogi communicates with the device through the Reprogrammable Controls feature (HID++ Feature ID 0x1b04). The ReprogControlsV4 accessor in crates/openlogi-device/src/reprog_controls.rs handles this communication.

The code calls get_ctrl_id_info to retrieve the control's capabilities:

let reprog = ReprogControlsV4::new(chan.clone(), dev_idx, feat_idx);
let ctrl_info = reprog.get_ctrl_id_info(/* index of SMART_SHIFT */).await?;

This function returns a CidInfo structure that the accessor converts into a local CtrlIdInfo type. This metadata includes flags indicating whether the control supports raw wheel reporting—a critical capability for the SmartShift functionality.

Mapping Hardware Controls to OpenLogi Bindings

OpenLogi abstracts hardware-specific Control IDs into generic ButtonId types. The SmartShift control (0xC4) maps to ButtonId::DpiToggle—a historical name preserved in the codebase.

This mapping occurs in crates/openlogi-core/src/binding/button.rs. The abstraction allows the core logic to remain agnostic of hardware-specific IDs while maintaining a consistent API for gesture handling and UI updates.

Enabling Raw Wheel Mode Detection

The wheel-mode toggle relies on the supports_raw_wheel flag exposed in CtrlIdInfo. When the SmartShift button is held, the agent checks this capability to determine if the control can emit raw wheel data instead of processed scroll events.

In crates/openlogi-device/src/reprog_controls.rs, the supports_raw_wheel method returns a boolean indicating this capability. While the button remains pressed, the rawWheelEvent stream from the HID++ device is intercepted by the agent core. The wheel deltas are then routed to the DPI-cycle logic rather than the standard scrolling pipeline.

Executing the DPI Cycle Action

When SmartShift is active, wheel movements trigger Action::CycleDpiPresets. This default binding is established in crates/openlogi-core/src/binding/defaults.rs, where ButtonId::DpiToggle is assigned the cycle action.

The gesture watcher in crates/openlogi-agent-core/src/watchers/gesture.rs processes these events. It monitors for ButtonPulse(ButtonId::DpiToggle) events and translates wheel increments into DPI preset changes. Simultaneously, the GUI layer (openlogi-desktop) listens via IPC channels to update on-screen indicators, providing real-time feedback that the wheel-mode toggle is active.

Code Example: Detecting and Handling SmartShift

The following Rust code demonstrates the complete detection and handling flow:

// 1. Query the device for the Smart Shift control
let reprog = ReprogControlsV4::new(chan.clone(), dev_idx, feat_idx);
let ctrl_info = reprog.get_ctrl_id_info( /* index of SMART_SHIFT */ ).await?;

// 2. Verify it can report raw wheel data
assert!(ctrl_info.supports_raw_wheel());

// 3. Translate to OpenLogi's binding
let button = openlogi_core::binding::ButtonId::DpiToggle;

// 4. In the gesture handler, an active Smart Shift makes wheel deltas
//    become DPI changes instead of scroll events
if button == ButtonId::DpiToggle && button_is_pressed {
    // Apply DPI preset change
    apply_next_dpi_preset();
}

Summary

The SmartShift wheel-mode toggle operates through the following sequence:

  • Control ID 0xC4 (SMART_SHIFT) is exposed via HID++ Feature 0x1b04 and defined in control_ids.rs
  • Task ID 0x9D identifies the default wheel-mode behavior in task_ids.rs
  • ReprogControlsV4 queries device capabilities and detects supports_raw_wheel
  • ButtonId::DpiToggle abstracts the hardware control in the binding layer
  • Action::CycleDpiPresets executes when raw wheel events occur during button hold
  • IPC propagation updates the UI overlay via ButtonPulse events in the gesture watcher

Frequently Asked Questions

What HID++ feature ID controls the SmartShift button in OpenLogi?

OpenLogi accesses the SmartShift button through HID++ Feature 0x1b04 (Reprogrammable Controls), not the dedicated SmartShift feature. The button is identified as Control ID 0xC4 within this interface, queried via the ReprogControlsV4 accessor in crates/openlogi-device/src/reprog_controls.rs.

How does OpenLogi distinguish between normal scrolling and DPI shifting?

The system checks the supports_raw_wheel flag in CtrlIdInfo (defined in crates/openlogi-device/src/reprog_controls.rs). When this flag is true and the SmartShift button is held, raw wheel events are routed to Action::CycleDpiPresets instead of the standard scroll handler.

Where is the SmartShift button mapped to OpenLogi's internal model?

The hardware Control ID 0xC4 is mapped to ButtonId::DpiToggle in crates/openlogi-core/src/binding/button.rs. This abstraction decouples the hardware-specific HID++ protocol from the core binding logic and UI representation.

What is the default action assigned to the SmartShift button?

By default, OpenLogi assigns Action::CycleDpiPresets to ButtonId::DpiToggle in crates/openlogi-core/src/binding/defaults.rs. This action increments through configured DPI presets when the wheel is rotated while the SmartShift button is depressed.

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 →