OpenLogi DPI Cycling Actions (0x2201): CycleDpiPresets and SetDpiPreset Explained

OpenLogi implements DPI cycling (0x2201) through the CycleDpiPresets action, which sequentially advances the mouse through configured sensitivity presets, while SetDpiPreset provides direct access to specific preset indices.

The OpenLogi project provides open-source device management for Logitech peripherals, exposing hardware features through a structured action system. For mice supporting the 0x2201 DPI switching feature, the codebase defines specific binding actions that translate physical button presses into sensitivity changes. Understanding these actions requires examining the core binding definitions, default hardware mappings, and runtime execution logic in the agent core.

CycleDpiPresets: The Primary DPI Cycling Action

OpenLogi defines the DPI cycling behavior for feature 0x2201 through the CycleDpiPresets variant in the Action enum. When invoked, this action increments the active DPI preset index, wrapping to the first preset after reaching the maximum configured value.

The action is declared in the core binding layer:

// crates/openlogi-core/src/binding/action.rs
pub enum Action {
    // ... other variants
    CycleDpiPresets,
    SetDpiPreset(u8),
}

This definition appears at lines 129-132 of [crates/openlogi-core/src/binding/action.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/binding/action.rs#L129-L132).

Default Button Mapping for DPI Toggle

By default, OpenLogi assigns the physical DPI toggle button to the cycling action. The binding system maps ButtonId::DpiToggle directly to Action::CycleDpiPresets in the default configuration.

The mapping is implemented as follows:

// crates/openlogi-core/src/binding/defaults.rs
ButtonId::DpiToggle => Action::CycleDpiPresets,

This relationship is defined at line 56 of [crates/openlogi-core/src/binding/defaults.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/binding/defaults.rs#L56).

Runtime Execution in the Agent Core

When the agent core receives Action::CycleDpiPresets, it delegates the state transition to the dpi_cycle component. The runtime matches the action and invokes the internal cycle logic to advance the preset pointer.

The execution logic in the runtime:

// crates/openlogi-agent-core/src/runtime.rs
match action {
    Action::CycleDpiPresets => {
        // `dpi_cycle` moves to the next preset in the profile
        self.dpi_cycle.write().map(|mut cycle| cycle.next())?;
    }
    // …other actions
}

This handling occurs at line 83 of [crates/openlogi-agent-core/src/runtime.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-agent-core/src/runtime.rs#L83).

SetDpiPreset: Direct Index Selection

In addition to cycling, OpenLogi supports SetDpiPreset for immediate jumps to specific DPI levels. This action accepts a zero-based u8 index parameter, allowing UI components or macros to select presets without sequential iteration.

Implementation example:

// Directly select the third preset (index 2)
let preset_index = 2;
let action = Action::SetDpiPreset(preset_index);
agent.send_action(action);

Key Source Files for DPI Actions

Understanding the complete DPI control flow requires examining these specific files:

Summary

Frequently Asked Questions

What is the 0x2201 identifier in OpenLogi?

The 0x2201 value represents the DPI cycling feature code in OpenLogi's device protocol implementation. The system maps this hardware capability to the CycleDpiPresets action, enabling users to switch between multiple sensitivity levels using the physical DPI button on supported Logitech mice.

How does CycleDpiPresets differ from SetDpiPreset?

CycleDpiPresets automatically advances to the next preset in the configured list, wrapping back to the first after the last entry, making it ideal for toggle buttons. SetDpiPreset(u8) immediately applies a specific preset by its zero-based index, allowing direct selection without iterating through intermediate values.

Where is the DPI toggle button mapped to the cycling action?

The mapping is defined in [crates/openlogi-core/src/binding/defaults.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/binding/defaults.rs) at line 56, where ButtonId::DpiToggle is bound to Action::CycleDpiPresets within the default binding configuration.

How does the runtime handle the DPI cycle request?

The agent core receives the action in [crates/openlogi-agent-core/src/runtime.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-agent-core/src/runtime.rs) at line 83, matching Action::CycleDpiPresets and calling cycle.next() on the dpi_cycle component to advance the active preset index and apply the new DPI value to the device.

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 →