How OpenLogi Persists and Restores DPI Presets Across User Sessions
OpenLogi persists DPI cycle states by serializing the DpiCycles struct to a TOML configuration file using serde, then deserializing it on startup to restore preset lists and active indices for each device.
OpenLogi is an open-source input device management framework that maintains user-specific DPI configurations across system reboots. The DPI cycle system achieves session persistence through a serde-backed configuration layer that stores device-specific preset lists and current indices in a user-scoped TOML file, ensuring seamless continuity between launches.
The DpiCycles Runtime Structure
The core state container is the DpiCycles struct defined in openlogi-agent-core/src/dpi.rs. This structure manages a collection of DpiCycleState entries keyed by device identifiers, where each state object tracks:
presets: Vec<Dpi>— The ordered list of DPI values available for cycling.index— The currently active position within the preset vector.target: Option<DeviceRoute>— The HID route specifying which physical device to address.capabilities— Optional device constraints used to round requested DPI values to supported increments.
During operation, the runtime holds this map in memory, allowing the background hook thread and GUI panels to access and modify DPI settings instantaneously.
Serde-Based Configuration Persistence
Long-term storage is handled by the configuration subsystem located in openlogi-core/src/config.rs. When the application state needs to be saved, the entire DpiCycles map is serialized using serde into TOML format and written to ~/.config/openlogi/config.toml.
This approach ensures that complex nested structures—such as the DeviceRoute variants and DPI metadata—are converted into a human-readable, editable format while maintaining type safety during deserialization.
Session Restoration on Startup
When the openlogi-agent-core runtime initializes, it loads the user configuration file from disk. The deserialization process reconstructs the DpiCycles object, populating the internal map with restored DpiCycleState entries. Consequently, the runtime resumes with the exact same preset lists and active indices that were present during the previous session.
This restoration mechanism is transparent to the user; the DPI panel implementation in openlogi-ipc/src/ipc.rs immediately reflects the persisted state without requiring manual reconfiguration.
Runtime Updates and Save Triggers
The DPI cycle pipeline operates through a predictable sequence:
- The OS hook requests the current state via
DpiCycles::state_for(key), retrieving the mutableDpiCycleStatefor the target device. - A call to
DpiCycleState::cycle()increments the internalindexwith wrap-around logic and returns the new DPI value paired with itsDeviceRoute. - The runtime issues a HID++ write command to update the physical device.
- The modified
DpiCyclesstructure remains in memory until the application shuts down or an explicit save event occurs, at which point the configuration layer serializes the updated state back to the TOML file.
This design minimizes disk I/O by batching writes while ensuring no data loss between sessions.
Implementation Example
The following Rust snippet demonstrates how the runtime interacts with the DPI cycle system:
use openlogi_agent_core::{DpiCycles, DpiCycleState};
use openlogi_hid::{DeviceRoute, Dpi};
/// Initialize a DpiCycles map with a preset list for a specific mouse.
let mut cycles = DpiCycles::default();
cycles.by_key.insert(
"my_mouse".to_string(),
DpiCycleState {
presets: vec![Dpi::new(800), Dpi::new(1600), Dpi::new(2400)],
index: 0,
target: Some(DeviceRoute::Bolt {
receiver_uid: "AA00".into(),
slot: 1,
}),
capabilities: None,
},
);
// Advance to the next preset when the user presses the DPI-cycle button.
if let Some((new_dpi, route)) = cycles.state_for(Some("my_mouse")).and_then(|s| s.cycle())
{
// `new_dpi` is applied to the device via the HID layer using `route`.
}
Summary
- The
DpiCyclesstruct inopenlogi-agent-core/src/dpi.rsmaintains active preset states and current indices in memory. - serde serializes the entire state to
~/.config/openlogi/config.tomlvia the configuration layer inopenlogi-core/src/config.rs. - On startup, the runtime deserializes this file to restore previous preset lists and active indices for all configured devices.
- The
DpiCycleState::cycle()method handles wrap-around indexing and returns the targetDeviceRouterequired for HID commands. - Modified states are flushed to disk on application shutdown, ensuring seamless DPI continuity across user sessions.
Frequently Asked Questions
How does OpenLogi know which DPI preset was active before a restart?
The active index is stored as an integer field inside the DpiCycleState structure for each device. When the application restarts, serde deserializes this value from the TOML configuration file back into the runtime's memory, allowing the system to resume with the exact same preset selected.
Where is the DPI configuration file located on disk?
According to the source implementation, the configuration is stored in the user's config directory at ~/.config/openlogi/config.toml. This path is managed by the persistence logic in openlogi-core/src/config.rs.
What serialization library does OpenLogi use for DPI persistence?
The codebase utilizes serde for data serialization. The DpiCycles struct is serialized into TOML format and written to disk, then deserialized back into the runtime structures when the agent core initializes in openlogi-agent-core/src/runtime.rs.
Can DPI presets be modified while the application is running?
Yes. The runtime updates the in-memory DpiCycles map immediately when a user cycles through presets via the OS hook or GUI panel defined in openlogi-ipc/src/ipc.rs. These modifications persist to the TOML file when the application shuts down or when an explicit save operation is triggered.
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 →