pub struct Config {
pub schema_version: u32,
pub app_settings: AppSettings,
pub selected_device: Option<String>,
pub devices: BTreeMap<String, DeviceConfig>,
pub keyboard: KeyboardConfig,
/* private fields */
}Expand description
Top-level config document.
Fields§
§schema_version: u32Schema version the file was written with. Compared against
SCHEMA_VERSION on load: supported older layouts migrate, while zero
and newer layouts are rejected rather than silently losing settings.
app_settings: AppSettingsNon-device-scoped preferences (autostart, tray, language, …).
selected_device: Option<String>Physical config key of the active device, persisted so a
restart restores the last view rather than always landing on the
first paired device. None means “fall back to the first device”.
devices: BTreeMap<String, DeviceConfig>Per-device state, normally keyed by the stable physical-device
identifier (e.g. "receiver:abc123:slot:2"). A serial-less camera’s
custom name instead uses its OS capture id so same-model cameras remain
distinguishable.
keyboard: KeyboardConfigKeyboard remappings, independent of device. The function-key remapper
(M1) reads this; #[serde(default)] keeps older configs without a
[keyboard] section loading unchanged.
Implementations§
Source§impl Config
impl Config
Sourcepub fn load_or_default() -> Result<Self, ConfigError>
pub fn load_or_default() -> Result<Self, ConfigError>
Loads the config from the default user path, returning a default when the file does not exist yet.
Sourcepub fn load_from_path(path: &Path) -> Result<Self, ConfigError>
pub fn load_from_path(path: &Path) -> Result<Self, ConfigError>
Load from path without retaining a writable source revision.
Sourcepub fn save_atomic(&self) -> Result<(), ConfigError>
pub fn save_atomic(&self) -> Result<(), ConfigError>
Atomically save to the default path. Long-lived writers should retain
and use ConfigFile so concurrent edits can be detected.
Sourcepub fn save_to_path(&self, path: &Path) -> Result<(), ConfigError>
pub fn save_to_path(&self, path: &Path) -> Result<(), ConfigError>
Atomically save to path, preserving comments in its current content.
Used by tests and one-shot tools; long-lived writers should use
ConfigFile::save.
Source§impl Config
impl Config
Sourcepub fn resolve_device_key(
&self,
stable: &DeviceStableId,
identity: Option<&DeviceIdentity>,
) -> Option<PhysicalDeviceKey>
pub fn resolve_device_key( &self, stable: &DeviceStableId, identity: Option<&DeviceIdentity>, ) -> Option<PhysicalDeviceKey>
The configuration key to read and write for a device reached by
stable, given whatever identity the current probe could read.
Prefers the device’s own identity — that is the whole point of the
schema-5 model — but only once the settings are actually there. A
receiver:/raw: entry is not renamed by the load-time migration
(nothing on disk says which device occupies a pairing slot), so
immediately after an upgrade every such device’s settings still live
under its route-derived key while its identity key holds nothing.
Answering with the identity key there would silently apply defaults to
every receiver-paired device until the GUI next ran
Self::adopt_route — which happens only when the user opens the GUI,
and the agent runs unattended from login. So the pre-upgrade key wins
for exactly as long as it is the one holding the settings.
“Holding the settings” is DeviceConfig::holds_settings, not mere
existence: an entry carrying only the probed identity and the links
route index is metadata OpenLogi wrote itself, and must not out-rank a
legacy entry holding the user’s actual bindings and DPI.
Failing both, and for a device whose identity is unreadable (asleep),
the route is resolved through the persisted links index, then finally
through the route-derived key that every entry used before this
indirection existed.
Sourcepub fn adopt_route(
&mut self,
canonical: &PhysicalDeviceKey,
route_key: &str,
capabilities: Option<Capabilities>,
) -> bool
pub fn adopt_route( &mut self, canonical: &PhysicalDeviceKey, route_key: &str, capabilities: Option<Capabilities>, ) -> bool
Record that the device keyed canonical was reached by route_key,
folding in any entry still keyed by that route.
capabilities is what the device just measured on this route, and it
is what makes the per-link table a record of the hardware rather than
a leftover of migration: a G502 that answers 0x2121 over its
receiver and not over USB only differs in the config once both links
have been sighted. Stored on every online sighting, so a link whose
capabilities genuinely change stops reporting the old ones. None
leaves whatever the link already recorded — an unprobed sighting is
not evidence the capability went away.
Returns whether anything actually changed — a route was newly
registered in the entry’s links index, its measured capabilities
differ from what was recorded, a stale link pointing a re-paired
route at its previous device was removed, or a legacy entry
was folded in. Callers use this to decide whether the mutation needs
persisting; a false means the entry already recorded this exact
route and there is nothing new to write. Called on an online
sighting, where the device’s identity is known and the route can
therefore be attributed to it with confidence.
Consuming a legacy entry is a rename, and a device key lives in three
places — the devices map, Config::selected_device, and every
entry of some keyboard’s DeviceConfig::host_switch_targets. All
three are re-pointed here, exactly as
Config::migrate_transport_scoped_keys does for the keys it renames
at load; leaving either reference behind would drop the carousel
selection and silently unlink a host-switch target.
Source§impl Config
impl Config
Sourcepub fn ephemeral() -> Self
pub fn ephemeral() -> Self
A config that never touches the on-disk file: Self::save_atomic is
a no-op. For tests that drive the state layer’s persistence paths —
with a default config those would overwrite the developer’s real
config.toml with test fixtures.
Sourcepub fn bindings_for(&self, device_key: &str) -> BTreeMap<ButtonId, Binding>
pub fn bindings_for(&self, device_key: &str) -> BTreeMap<ButtonId, Binding>
Returns the bindings stored for device_key, or an empty map if the
device has no committed bindings yet.
Sourcepub fn set_binding(
&mut self,
device_key: &str,
button: ButtonId,
binding: Binding,
)
pub fn set_binding( &mut self, device_key: &str, button: ButtonId, binding: Binding, )
Records binding for button on device_key, creating the device
entry if needed. Replaces the whole binding (use
Self::set_gesture_direction to edit one direction of a gesture
binding in place).
Sourcepub fn set_keyboard_binding(
&mut self,
trigger: KeyTrigger,
action: Option<Action>,
)
pub fn set_keyboard_binding( &mut self, trigger: KeyTrigger, action: Option<Action>, )
Records (or, with action = None, clears) the F-key trigger binding
in the global [keyboard] map. Keyboard bindings are device-agnostic —
one map applies across all keyboards — so this mirrors Self::set_binding
minus the device key.
Sourcepub fn keyboard_bindings(&self) -> &BTreeMap<KeyTrigger, Action>
pub fn keyboard_bindings(&self) -> &BTreeMap<KeyTrigger, Action>
The global keyboard F-key bindings (read accessor).
Sourcepub fn set_gesture_direction(
&mut self,
device_key: &str,
button: ButtonId,
direction: GestureDirection,
action: Action,
)
pub fn set_gesture_direction( &mut self, device_key: &str, button: ButtonId, direction: GestureDirection, action: Action, )
Records action for one direction of button’s gesture binding,
creating the device entry if needed.
A button with no binding yet is seeded from its canonical
default_binding_for — for ButtonId::GestureButton that is the full
default direction map (including a GestureDirection::Click), so the
merged map never persists a gesture binding whose click projection is a
no-op. A prior Binding::Single is upgraded to Binding::Gesture,
preserving its action as the Click entry.
Sourcepub fn is_gesture_mode(&self, device_key: &str, button: ButtonId) -> bool
pub fn is_gesture_mode(&self, device_key: &str, button: ButtonId) -> bool
Whether button on device_key is in gesture mode — a per-button fact
read straight from the binding shape: a stored Binding::Gesture, or
no stored binding on a button whose canonical default
(default_binding_for) is gesture-shaped (the dedicated HID++ gesture
button starts in gesture mode).
Gesture mode is not exclusive: any number of buttons may gesture at
once, each with its own direction map. This replaces the former
one-gesture-button-per-device owner lock — see Self::set_gesture_mode.
Every button of device_key currently in gesture mode, in ButtonId
declaration order. Purely config-derived: callers cross it with the
device’s actual controls (a model without the dedicated gesture button
simply never captures it).
Sourcepub fn set_gesture_mode(
&mut self,
device_key: &str,
button: ButtonId,
enabled: bool,
)
pub fn set_gesture_mode( &mut self, device_key: &str, button: ButtonId, enabled: bool, )
Turn gesture mode on or off for one button, independently of every other button.
On: restore the button’s stashed map when one exists (see
DeviceConfig::disabled_gestures) — an off/on round trip hands back
the user’s customized arms exactly. Otherwise promote the stored
binding in place (Binding::upgrade_to_gesture keeps a prior single
action as the GestureDirection::Click entry) and seed unbound
directions from default_gesture_binding.
Off: stash the live map, then demote to a Binding::Single of the
map’s Click action, falling back to the button’s canonical
default_binding when the map has no explicit Click — a demoted
button always keeps a meaningful press. A button gesturing only by
default (no stored binding) stashes its seeded default map and is
pinned off with an explicit Single at its canonical default, which
the capture layer leaves native.
Sourcepub fn migrate_transport_scoped_keys(&mut self)
pub fn migrate_transport_scoped_keys(&mut self)
Rewrite v4 transport-scoped direct keys to identity keys.
direct:046d:c08d:unit:6be9d300 names one mouse and the cable it was
plugged into; unit:6be9d300 names the mouse. The route it came from
is kept as a link so the index survives the rename. Receiver keys are
left alone — nothing on disk says which device is in a pairing slot, so
they are folded at runtime instead (see adopt_route).
A direct: key can appear three ways: as a device’s own map key, as
selected_device, or inside another device’s host_switch_targets —
and the last of those can name a device with no [devices.…] table of
its own (nothing but the reference survives). The rename is computed
once over every occurrence so all three are rewritten consistently,
not just the ones that also own a device entry.
Two entries can rename onto the same key — one mouse reached over both USB and Bluetooth-direct has a v4 entry per route — so the second one is folded in rather than inserted over the first. That is the one case where this pass would otherwise not be lossless.
Sourcepub fn effective_bindings(
&self,
device_key: &str,
bundle_id: Option<&str>,
) -> BTreeMap<ButtonId, Binding>
pub fn effective_bindings( &self, device_key: &str, bundle_id: Option<&str>, ) -> BTreeMap<ButtonId, Binding>
Resolve the effective binding map for device_key, overlaying the
per-app entry for bundle_id (if any) on top of the global per-device
bindings. A per-app override replaces the whole button with a
Binding::Single; everything else falls through.
Returns an empty map when the device has no recorded bindings yet. Callers (the GUI / hook) layer their own defaults on top.
Sourcepub fn set_per_app_binding(
&mut self,
device_key: &str,
bundle_id: &str,
button: ButtonId,
action: Option<Action>,
)
pub fn set_per_app_binding( &mut self, device_key: &str, bundle_id: &str, button: ButtonId, action: Option<Action>, )
Records a per-app override. Creates the device + app entries as
needed; passing an action of None removes the override and prunes
the empty app map.
Sourcepub fn per_app_overrides(
&self,
device_key: &str,
app: &str,
) -> Option<&BTreeMap<ButtonId, Action>>
pub fn per_app_overrides( &self, device_key: &str, app: &str, ) -> Option<&BTreeMap<ButtonId, Action>>
The overrides device_key stores for the application key app,
or None when it has no profile for it.
Exact key, deliberately: this answers “what did the user author under
this key”, which is what an editor needs to show and to clear. The
question Self::has_app_override answers — “will the app in front hit
a profile” — is the matcher’s, and goes through the same exe: fallback
the matcher does. The two look interchangeable and are not.
Sourcepub fn app_profiles(&self, device_key: &str) -> impl Iterator<Item = &str>
pub fn app_profiles(&self, device_key: &str) -> impl Iterator<Item = &str>
Every application key device_key has a profile for, in key order.
Sourcepub fn remove_app_profile(&mut self, device_key: &str, app: &str)
pub fn remove_app_profile(&mut self, device_key: &str, app: &str)
Drop device_key’s whole profile for app. Nothing happens when there
is none.
Sourcepub fn action_ring(&self, device_key: &str) -> ActionRingConfig
pub fn action_ring(&self, device_key: &str) -> ActionRingConfig
Actions Ring settings for device_key, falling back to defaults when
the device has no saved ring configuration.
Sourcepub fn set_action_ring_enabled(&mut self, device_key: &str, enabled: bool)
pub fn set_action_ring_enabled(&mut self, device_key: &str, enabled: bool)
Enable or disable device_key’s Actions Ring.
Sourcepub fn set_action_ring_haptics(&mut self, device_key: &str, enabled: bool)
pub fn set_action_ring_haptics(&mut self, device_key: &str, enabled: bool)
Enable or disable ring hover and activation haptics.
Sourcepub fn set_action_ring_slot(
&mut self,
device_key: &str,
slot: ActionRingSlot,
action: Option<RingAction>,
)
pub fn set_action_ring_slot( &mut self, device_key: &str, slot: ActionRingSlot, action: Option<RingAction>, )
Replace or clear one slot in the default Actions Ring layout.
Sourcepub fn set_action_ring_icon(
&mut self,
device_key: &str,
slot: ActionRingSlot,
icon: Option<ActionRingIcon>,
)
pub fn set_action_ring_icon( &mut self, device_key: &str, slot: ActionRingSlot, icon: Option<ActionRingIcon>, )
Set or restore the action-derived icon for one default ring slot.
Sourcepub fn selected_device(&self) -> Option<&str>
pub fn selected_device(&self) -> Option<&str>
HID++ config key of the active device, if any.
Sourcepub fn set_selected_device(&mut self, key: Option<String>)
pub fn set_selected_device(&mut self, key: Option<String>)
Update the active device. Pass None to clear the
selection (e.g. when the previously-selected device disappears).
Sourcepub fn dpi_presets(&self, device_key: &str) -> Vec<Dpi>
pub fn dpi_presets(&self, device_key: &str) -> Vec<Dpi>
The ordered DPI preset list for device_key, or an empty Vec if the
device has none configured yet.
Sourcepub fn set_dpi_presets(&mut self, device_key: &str, presets: Vec<Dpi>)
pub fn set_dpi_presets(&mut self, device_key: &str, presets: Vec<Dpi>)
Replace the DPI preset list for device_key. Pass an empty Vec to
clear (the device block is kept; the field is just omitted on save
thanks to skip_serializing_if).
Sourcepub fn device_identity(&self, device_key: &str) -> Option<&DeviceIdentity>
pub fn device_identity(&self, device_key: &str) -> Option<&DeviceIdentity>
The last-known DeviceIdentity for device_key, or None if the
device has never been seen online (or was configured before identities
were recorded).
Sourcepub fn set_device_identity(
&mut self,
device_key: &str,
identity: DeviceIdentity,
)
pub fn set_device_identity( &mut self, device_key: &str, identity: DeviceIdentity, )
Record (or refresh) the identity captured for device_key while it was
online, creating the device entry if needed.
Sourcepub fn remove_device(&mut self, device_key: &str) -> bool
pub fn remove_device(&mut self, device_key: &str) -> bool
Drop everything recorded for device_key — identity, custom name, and
per-device settings. Returns whether an entry existed.
Sourcepub fn device_custom_name(&self, device_key: &str) -> Option<&str>
pub fn device_custom_name(&self, device_key: &str) -> Option<&str>
The user-assigned name for device_key, if one is configured.
Sourcepub fn set_device_custom_name(
&mut self,
device_key: &str,
custom_name: Option<String>,
)
pub fn set_device_custom_name( &mut self, device_key: &str, custom_name: Option<String>, )
Set the user-assigned name for device_key, or clear it to use the
hardware model name again.
Sourcepub fn has_app_override(&self, device_key: &str, app: &str) -> bool
pub fn has_app_override(&self, device_key: &str, app: &str) -> bool
Whether device_key has a non-empty per-app binding overlay for the
foreground app app (bundle id). Drives the menu-bar popover’s “override
active” badge — when the current app has its own bindings for this
device, the global bindings are (partly) overridden.
Sourcepub fn known_identities(&self) -> impl Iterator<Item = (&str, &DeviceIdentity)>
pub fn known_identities(&self) -> impl Iterator<Item = (&str, &DeviceIdentity)>
Iterate every device we’ve recorded an identity for, as
(config_key, identity). Used to seed offline placeholder cards so a
known device stays visible (with its panels) before any live probe.
Sourcepub fn lighting(&self, device_key: &str) -> Option<Lighting>
pub fn lighting(&self, device_key: &str) -> Option<Lighting>
The lighting config for device_key, or None if unset.
Sourcepub fn set_lighting(&mut self, device_key: &str, lighting: Lighting)
pub fn set_lighting(&mut self, device_key: &str, lighting: Lighting)
Replace the lighting config for device_key.
Sourcepub fn camera_controls(&self, device_key: &str) -> Option<CameraControls>
pub fn camera_controls(&self, device_key: &str) -> Option<CameraControls>
The saved UVC image controls for device_key, or None if never set.
Sourcepub fn set_camera_controls(
&mut self,
device_key: &str,
controls: CameraControls,
)
pub fn set_camera_controls( &mut self, device_key: &str, controls: CameraControls, )
Replace the saved UVC image controls for device_key.
Sourcepub fn camera_profiles(
&self,
device_key: &str,
) -> BTreeMap<String, CameraControls>
pub fn camera_profiles( &self, device_key: &str, ) -> BTreeMap<String, CameraControls>
The saved custom camera profiles for device_key (name → snapshot).
Sourcepub fn save_camera_profile(
&mut self,
device_key: &str,
name: &str,
snap: CameraControls,
)
pub fn save_camera_profile( &mut self, device_key: &str, name: &str, snap: CameraControls, )
Save (or overwrite) a custom camera profile for device_key.
Sourcepub fn delete_camera_profile(&mut self, device_key: &str, name: &str)
pub fn delete_camera_profile(&mut self, device_key: &str, name: &str)
Delete a custom camera profile, clearing the active selection if it named it. Unknown names are a no-op.
Sourcepub fn camera_active_profile(&self, device_key: &str) -> Option<String>
pub fn camera_active_profile(&self, device_key: &str) -> Option<String>
The last-applied camera profile name for device_key, if any.
Sourcepub fn set_camera_active_profile(
&mut self,
device_key: &str,
name: Option<String>,
)
pub fn set_camera_active_profile( &mut self, device_key: &str, name: Option<String>, )
Record which camera profile device_key last applied.
Sourcepub fn light(&self, device_key: &str) -> Option<LightSettings>
pub fn light(&self, device_key: &str) -> Option<LightSettings>
The standalone-light config for device_key, or None if unset.
Sourcepub fn set_light(&mut self, device_key: &str, light: LightSettings)
pub fn set_light(&mut self, device_key: &str, light: LightSettings)
Replace the standalone-light config for device_key.
Sourcepub fn dpi(&self, device_key: &str) -> Option<Dpi>
pub fn dpi(&self, device_key: &str) -> Option<Dpi>
The committed sensor DPI for device_key, or None if never set.
Sourcepub fn set_dpi(&mut self, device_key: &str, dpi: Dpi)
pub fn set_dpi(&mut self, device_key: &str, dpi: Dpi)
Record the committed sensor DPI for device_key, so the agent can
re-apply it when the device reconnects (#189).
Sourcepub fn smartshift(&self, device_key: &str) -> Option<SmartShift>
pub fn smartshift(&self, device_key: &str) -> Option<SmartShift>
The SmartShift wheel config for device_key, or None if never set.
Sourcepub fn fn_lock(&self, device_key: &str) -> Option<bool>
pub fn fn_lock(&self, device_key: &str) -> Option<bool>
The persisted keyboard Fn-lock state for device_key, or None when
the user never set one (the keyboard keeps its own state).
Sourcepub fn set_smartshift(&mut self, device_key: &str, smartshift: SmartShift)
pub fn set_smartshift(&mut self, device_key: &str, smartshift: SmartShift)
Record the SmartShift wheel config for device_key, so the agent can
re-apply it when the device reconnects (#189).
Sourcepub fn invert_scroll(&self, device_key: &str) -> bool
pub fn invert_scroll(&self, device_key: &str) -> bool
Whether device_key’s scroll wheel is inverted (issue #126). false
(the native direction) for an unconfigured or absent device.
Sourcepub fn set_invert_scroll(&mut self, device_key: &str, invert: bool)
pub fn set_invert_scroll(&mut self, device_key: &str, invert: bool)
Set whether device_key’s scroll wheel is inverted. The agent reads this
on the next ReloadConfig and applies it in the OS hook.
Sourcepub fn scroll_resolution(&self, device_key: &str) -> Option<ScrollResolution>
pub fn scroll_resolution(&self, device_key: &str) -> Option<ScrollResolution>
The configured wheel resolution for device_key, or None when
OpenLogi should leave the device’s current resolution unchanged.
Sourcepub fn set_scroll_resolution(
&mut self,
device_key: &str,
resolution: Option<ScrollResolution>,
)
pub fn set_scroll_resolution( &mut self, device_key: &str, resolution: Option<ScrollResolution>, )
Set the wheel resolution OpenLogi should restore for device_key.
Passing None returns the device to its unmanaged default state.
Sourcepub fn device_enabled(&self, device_key: &str) -> bool
pub fn device_enabled(&self, device_key: &str) -> bool
Whether OpenLogi manages device_key at all (capture + volatile
re-apply). Unconfigured devices are managed.
Sourcepub fn set_device_enabled(&mut self, device_key: &str, enabled: bool)
pub fn set_device_enabled(&mut self, device_key: &str, enabled: bool)
Enable or disable OpenLogi’s management of device_key.
Sourcepub fn thumbwheel_sensitivity(&self, device_key: &str) -> ThumbwheelSensitivity
pub fn thumbwheel_sensitivity(&self, device_key: &str) -> ThumbwheelSensitivity
The effective thumb-wheel sensitivity for device_key: the device’s
override when set, else the app-wide default.
Sourcepub fn set_device_thumbwheel_sensitivity(
&mut self,
device_key: &str,
sensitivity: Option<ThumbwheelSensitivity>,
)
pub fn set_device_thumbwheel_sensitivity( &mut self, device_key: &str, sensitivity: Option<ThumbwheelSensitivity>, )
Set (or clear, with None) device_key’s thumb-wheel sensitivity
override.