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:
- [
crates/openlogi-core/src/binding/action.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/binding/action.rs) – DefinesAction::CycleDpiPresetsandAction::SetDpiPreset. - [
crates/openlogi-core/src/binding/defaults.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/binding/defaults.rs) – MapsButtonId::DpiToggleto the cycling action. - [
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 thedpi_cyclecomponent. 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
CycleDpiPresetsin [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/master/crates/openlogi-agent-core/src/runtime.rs) using thedpi_cyclecomponent to mutate state. SetDpiPresetoffers 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/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →