How to Configure OpenLogi Using TOML Files: A Complete Guide
OpenLogi stores all user-customizable settings in a config.toml file located in the user’s configuration directory, which the application parses at startup using the toml crate and validates against schema version 6.
The AprilNEA/OpenLogi project uses a hierarchical TOML configuration system defined in the Config module. When the application launches, it reads this file to resolve device settings, button mappings, and UI preferences into a fully populated Config struct that drives runtime behavior.
Configuration File Location and Discovery
OpenLogi resolves the configuration path using platform-specific conventions implemented in crates/openlogi-core/src/paths.rs.
On Linux, the file resides at:
$XDG_CONFIG_HOME/openlogi/config.toml
On macOS, the path is:
~/Library/Application Support/OpenLogi/config.toml
If the file is missing or contains parse errors, OpenLogi falls back to default values and writes a fresh config.toml on exit. Errors during deserialization are logged with warn! macros, and the GUI disables config writes to prevent file corruption.
Core Configuration Structure
The root of config.toml requires a schema version identifier and supports optional global flags.
schema_version = 6
selected_device = "receiver:aabbccdd:slot:1"
[app_settings]
launch_at_login = true
language = "en"
ui_scale = "normal"
The schema_version field is mandatory and tells OpenLogi which parsing rules to apply. The current version is 6. The selected_device key optionally forces the GUI to open a specific device on launch.
According to crates/openlogi-core/src/config.rs, the [app_settings] table controls global UI behavior, including launch-at-login preferences, localization, and interface scaling.
Device-Specific Configuration
Per-device settings live under [devices.<id>] tables. The <id> format depends on your schema version:
- Legacy (pre-schema 5): Uses receiver routes like
receiver:aabbccdd:slot:1 - Schema 5+: Uses unit identifiers like
unit:6be9d300
[devices."receiver:aabbccdd:slot:1"]
dpi = 1600
dpi_presets = [800, 1600, 3200]
Schema 5 introduces link-specific overrides via the links subtable, allowing you to customize settings when a device connects through specific USB paths:
[devices."unit:6be9d300".links."direct:046d:c08d".overrides]
dpi = 800
Button Bindings and Action Mappings
The bindings table under each device defines button-to-action mappings. OpenLogi supports three descriptor types:
- Simple strings for predefined actions
CustomShortcutobjects for complex key combinationsHoldShortcutdescriptors for time-based triggers
[devices."receiver:aabbccdd:slot:1".bindings]
Back = "BrowserBack"
MiddleClick = { HoldShortcut = "Ctrl+Space" }
DpiToggle = { short = "ShowDesktop", long = "MissionControl" }
The binding logic is implemented across crates/openlogi-core/src/binding/*.rs, where the parser validates action names and shortcut syntax.
Per-Application and Advanced Overrides
Per-application bindings override global mappings only when specific applications are focused. Define these under per_app_bindings.<bundle_id>:
[devices."receiver:aabbccdd:slot:1".per_app_bindings."com.microsoft.VSCode"]
Back = "Undo"
Additional specialized modules include:
action_ring: Configures the on-screen Actions Ring, including haptics and slot definitionslighting: Controls LED color and brightnesssmartshift: Manages SmartShift/DPI-shift behavior, including torque settings and auto-disengage modeskeyboard.bindings: Global shortcut remappings that apply system-wide regardless of device
Action Ring example:
[devices."receiver:aabbccdd:slot:1".action_ring.default.slots]
Top = { action = "Copy", icon = "Keyboard" }
Right = { action = { OpenApplication = { path = "/Applications/Safari.app", display_name = "Safari" } }, icon = "Applications" }
Error Handling and Validation
When crates/openlogi-core/src/config.rs reads the TOML file, it validates the structure against the declared schema version. Deserialization errors trigger fallback behavior:
- Missing files generate default configurations
- Parse errors log warnings but do not crash the application
- The GUI enters a read-only mode to prevent corruption of invalid files
The Config struct merges hierarchical settings—global defaults, per-device configurations, link-specific overrides, and per-app bindings—into a single resolved state consumed by the rest of the system.
Summary
- OpenLogi reads settings from
config.tomlin the user’s configuration directory, resolved viacrates/openlogi-core/src/paths.rs - The schema version (currently 6) determines parsing rules and device identifier formats
- Device configurations support both receiver routes (
receiver:...) and unit IDs (unit:...), with schema 5+ enabling link-specific overrides - Bindings support simple strings,
CustomShortcut, andHoldShortcutdescriptors for button remapping - Per-application bindings allow context-sensitive overrides based on the focused application
- Invalid configurations trigger safe fallbacks and logging via
warn!macros without crashing the application
Frequently Asked Questions
Where does OpenLogi store the configuration file on Windows?
The raw source analysis focuses on Linux and macOS paths. However, following XDG conventions, Windows typically uses %APPDATA%\OpenLogi\config.toml or %LOCALAPPDATA%\OpenLogi\config.toml, though you should verify the exact path in crates/openlogi-core/src/paths.rs for your specific release.
What happens if I omit the schema_version field?
OpenLogi requires schema_version to determine which parsing rules to apply. If this field is missing or contains an unsupported version, the configuration parser will fail to deserialize the file, trigger a warning log, and fall back to default settings.
Can I mix receiver-based and unit-based device IDs in the same file?
While technically possible if upgrading configurations, you should maintain consistency within your schema version. Schema 5+ prefers unit:... identifiers, while older schemas use receiver:... routes. Mixing formats without proper link tables may cause device recognition issues.
Why are my button bindings not applying to specific applications?
Ensure you are using the correct bundle identifier under per_app_bindings (e.g., com.microsoft.VSCode rather than "VS Code"). The matching logic in crates/openlogi-core/src/binding/*.rs requires exact bundle ID strings to trigger per-application overrides.
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 →