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

> Discover OpenLogi DPI cycling actions 0x2201. Learn how CycleDpiPresets and SetDpiPreset manage mouse sensitivity presets for optimal performance in your OpenLogi setup.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: api-reference
- Published: 2026-09-12

---

**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:

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

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

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

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

- **[[`crates/openlogi-core/src/binding/action.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/binding/action.rs)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/binding/action.rs)** – Defines `Action::CycleDpiPresets` and `Action::SetDpiPreset`.
- **[[`crates/openlogi-core/src/binding/defaults.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/binding/defaults.rs)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/binding/defaults.rs)** – Maps `ButtonId::DpiToggle` to the cycling action.
- **[[`crates/openlogi-agent-core/src/runtime.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-agent-core/src/runtime.rs)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-agent-core/src/runtime.rs)** – Executes the cycle via the `dpi_cycle` component.
- **[`crates/openlogi-desktop/src/state/dpi.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/state/dpi.rs)** – Maintains DPI state for the desktop application layer.

## Summary

- **The 0x2201 DPI cycling feature uses `CycleDpiPresets`**, which sequentially advances through configured mouse sensitivity presets.
- **Default hardware binding** connects the DPI toggle button to `CycleDpiPresets` in [[`defaults.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/defaults.rs)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/binding/defaults.rs).
- **Agent runtime execution** occurs in [[`runtime.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/runtime.rs)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-agent-core/src/runtime.rs) using the `dpi_cycle` component to mutate state.
- **`SetDpiPreset`** offers an alternative for direct, index-based preset selection.
- All action definitions reside in the core binding layer, while the agent core handles hardware communication.

## 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/main/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/main/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.