How to Set Up and Cycle Through DPI Presets in OpenLogi
OpenLogi stores DPI presets per-device in config.toml and cycles through them using the CycleDpiPresets action bound to hardware buttons, with the desktop app managing persistence via AppState and the agent handling hardware writes through IPC.
OpenLogi is an open-source input device customization platform that enables per-device DPI configuration for gaming mice and precision pointers. Setting up and cycling through DPI presets in OpenLogi requires coordinating between the desktop application's state management, the persistent TOML configuration layer, and the agent's hardware control runtime.
Understanding the DPI Preset Architecture
OpenLogi implements a three-tier architecture for DPI management that separates storage, application logic, and hardware communication.
Configuration Layer (config.toml)
Per-device DPI presets persist in config.toml under device-specific keys using the hardware serial number. The configuration stores presets as arrays of integer DPI values indexed by device identifier.
Application State Management
The desktop application maintains an in-memory representation through AppState in crates/openlogi-desktop/src/state/dpi.rs. The primary methods include:
dpi_for_current()– Returns the cached DPI value for the selected device fromAppState.pointer.readsdpi_presets()– Retrieves the currentVec<Dpi>preset list from statecommit_dpi_presets()– Persists changes to disk and triggers a UI reload viapersist_and_reload("DPI presets")
Agent Runtime and IPC
The openlogi-agent-core crate handles physical hardware communication through openlogi-ipc. When cycling presets, the agent invokes ipc_sender.set_dpi(route, value) to write values and read_dpi to query capabilities, as defined in crates/openlogi-ipc/src/ipc.rs.
Configuring DPI Presets
Discovering Device Capabilities
When a device is selected in the UI, the pointer service queries hardware capabilities. In crates/openlogi-desktop/src/state/dpi.rs (lines 65-76), the system caches the queried DPI values in AppState.pointer.reads, exposing them through AppState.dpi_for_current() for UI display.
Adding Presets via the UI
The Pointer panel renders DPI presets as interactive chips. The "+" chip triggers add_preset_chip() in crates/openlogi-desktop/src/features/pointer/dpi.rs (lines 421-428), which appends the current DPI value to the device's preset list and invokes AppState.commit_dpi_presets(presets) to persist the configuration:
Button::new("dpi-preset-add")
.on_click(move |cx| {
let mut presets = state.dpi_presets();
presets.push(state.dpi());
state.commit_dpi_presets(presets);
})
Manual Configuration
Advanced users can pre-define presets by editing config.toml directly:
[device."2b042"]
dpi_presets = [800, 1600, 3200]
[device."4082d"]
dpi_presets = [400, 1600]
Cycling Through Presets at Runtime
The CycleDpiPresets Action
The default binding configuration in crates/openlogi-core/src/binding/defaults.rs (line 53) maps CycleDpiPresets to the scroll-wheel thumb-button. This action triggers the preset rotation sequence when activated.
Agent Processing Logic
When the agent receives Action::CycleDpiPresets, it executes the rotation logic in crates/openlogi-agent-core/src/runtime.rs (lines 83-86):
match action {
Action::CycleDpiPresets => {
let next_dpi = self.dpi_cycle.write().next();
self.ipc_sender.set_dpi(route, next_dpi)?;
}
_ => {}
}
The dpi_cycle state maintains the preset list and current index. The cycle index resets to 0 every time commit_dpi_presets() rewrites the preset list, ensuring the rotation always starts from the first entry after modifications.
UI Reflection and Chip Interaction
The Pointer panel implements immediate-mode interaction in crates/openlogi-desktop/src/features/pointer/dpi.rs (lines 358-403). Clicking a preset chip writes that DPI value to the hardware immediately, while the "×" button removes the preset from the list and triggers configuration persistence.
State Persistence and Temporary Devices
The commit_dpi_presets() method in crates/openlogi-desktop/src/state/dpi.rs (lines 52-55) coordinates persistence through persist_and_reload(). This writes the updated config.toml and triggers a UI state reload so new presets appear immediately.
For temporary devices without persistent keys (indicated by missing serial associations), OpenLogi maintains the preset list only in memory. These values generate debug messages indicating non-persistence and will not survive application restarts.
Summary
- OpenLogi stores DPI presets per-device in
config.tomlunder the device serial number (e.g.,[device."2b042"].dpi_presets). - The desktop app manages state through
AppStatemethods likecommit_dpi_presets()incrates/openlogi-desktop/src/state/dpi.rs, bridging the UI and configuration file. - Hardware cycling uses the
CycleDpiPresetsaction, which the agent processes incrates/openlogi-agent-core/src/runtime.rsby advancing through the preset list viaipc_sender.set_dpi(). - UI interactions in
crates/openlogi-desktop/src/features/pointer/dpi.rsprovide immediate application of presets and removal functionality.
Frequently Asked Questions
Where are DPI presets stored in OpenLogi?
DPI presets persist in the config.toml configuration file under device-specific sections identified by serial numbers (e.g., [[device."<serial>".dpi_presets]]). The AppState.commit_dpi_presets() method in crates/openlogi-desktop/src/state/dpi.rs handles writing these values to disk and reloading the application state.
How does the DPI cycling action work in the agent?
When the CycleDpiPresets action triggers, the agent runtime in crates/openlogi-agent-core/src/runtime.rs locks the shared dpi_cycle state, advances the internal index using next(), and writes the resulting DPI value to the hardware via ipc_sender.set_dpi(). The cycle automatically resets to the first preset when the preset list is modified.
Can I set DPI presets for temporary or unpaired devices?
Yes, but with limitations. If a device lacks a persistent key (indicating a temporary connection), OpenLogi maintains the preset list only in memory within AppState. These values will not survive application restarts and generate debug messages indicating the lack of persistence.
What happens when I click a DPI preset chip in the UI?
Clicking a preset chip in the Pointer panel immediately writes that DPI value to the device and updates the application state. The removal button ("×") deletes the preset from the list and triggers commit_dpi_presets() to synchronize the configuration file, as implemented in crates/openlogi-desktop/src/features/pointer/dpi.rs.
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 →