How to Map Gestures to Actions in OpenLogi: A Complete Configuration Guide
OpenLogi maps mouse gestures to actions through a three-layer architecture where directional swipes (Up, Down, Left, Right) and clicks are captured in gesture.rs, stored in TOML configuration, and dispatched via hidpp_gesture_maps_for in bindings.rs to execute specific commands like Copy or VolumeUp.
OpenLogi is an open-source Logitech mouse configuration tool that enables advanced gesture control on devices like the MX Master series. When you map gestures to actions in OpenLogi, you translate physical directional swipes into executable commands through a runtime system that bridges raw HID++ events with user-defined configuration.
Understanding the Gesture Mapping Architecture
OpenLogi implements gesture handling through three distinct layers that transform physical input into executed commands.
Configuration Layer stores per-device and per-application gesture bindings in a TOML file. Gestures are represented as a map keyed by GestureDirection (Up, Down, Left, Right, Click). The implementation in crates/openlogi-core/src/config.rs provides Config::set_gesture_mode and Config::bindings_for to manage these mappings.
Binding Projection Layer converts stored TOML data into runtime maps using ButtonId → GestureDirection → Action relationships. The hidpp_gesture_maps_for and oshook_gestures_for functions in crates/openlogi-core/src/bindings.rs handle this projection, automatically assigning default actions to undefined directions.
Runtime Dispatch Layer captures raw HID++ events in crates/openlogi-device/src/session/gesture.rs, constructing CapturedInput::Gesture(button, direction) objects. The GUI then looks up the corresponding Action from the projected map and executes the command.
How to Map Gestures to Actions in OpenLogi
Enable Gesture Mode for the Device
Before mapping specific directions, you must enable gesture mode for the target button. This designates the button (such as the MX Master gesture button or haptic panel) as a gesture source rather than a standard input.
Use the CLI to enable gesture mode for your device:
# Enable gesture mode for device "2b042" (MX Master 2S)
openlogi config set-gesture-mode 2b042 GestureButton true
This command invokes Config::set_gesture_mode in crates/openlogi-core/src/config.rs, which sets the GestureDirection::Click entry and marks the button as a gesture source.
Configure Directional Bindings
Each directional swipe requires a separate entry under bindings.<device>.GestureButton.<direction> in your configuration file. OpenLogi recognizes five directions: Up, Down, Left, Right, and Click (the tap action).
Edit ~/.config/openlogi/config.toml directly:
[bindings."2b042".GestureButton]
Up = "Copy"
Down = "Paste"
Left = "VolumeDown"
Right = "VolumeUp"
Click = "MissionControl"
Alternatively, use the CLI helper to write bindings without manual file editing:
openlogi config set-gesture-binding 2b042 GestureButton Up Copy
openlogi config set-gesture-binding 2b042 GestureButton Down Paste
openlogi config set-gesture-binding 2b042 GestureButton Click MissionControl
These commands call Config::set_gesture_binding, which updates the underlying BTreeMap<GestureDirection, Action> in the configuration store.
Verify Your Configuration
Validate that your mappings project correctly using the configuration show command:
openlogi config show 2b042 GestureButton
The bindings_for function in bindings.rs projects the stored map into a flat ButtonId → Action view. Any direction left undefined will be auto-filled with the default click action via default_binding(button).
Test the Runtime Dispatch
When the capture session is active, swiping on the gesture button generates CapturedInput::Gesture(ButtonId::GestureButton, GestureDirection::Up) events (or the appropriate direction). The GUI looks up the action using hidpp_gesture_maps_for (see bindings.rs line 71) and dispatches the corresponding command.
Programmatic Configuration Example
For custom scripts or extensions, you can configure gestures programmatically using the OpenLogi core library:
use openlogi_core::config::Config;
use openlogi_core::binding::{ButtonId, GestureDirection, Action};
fn main() {
// Load user config with automatic default merging
let mut cfg = Config::load().expect("cannot read config");
// Enable gesture mode for the dedicated button
cfg.set_gesture_mode("2b042", ButtonId::GestureButton, true);
// Bind directional gestures to actions
cfg.set_gesture_binding(
"2b042",
ButtonId::GestureButton,
GestureDirection::Up,
Action::Copy,
);
cfg.set_gesture_binding(
"2b042",
ButtonId::GestureButton,
GestureDirection::Down,
Action::Paste,
);
cfg.set_gesture_binding(
"2b042",
ButtonId::GestureButton,
GestureDirection::Left,
Action::VolumeDown,
);
// Persist changes to disk
cfg.save().expect("cannot write config");
}
This example demonstrates the complete workflow: loading configuration, enabling gesture mode via set_gesture_mode, mapping specific directions with set_gesture_binding, and persisting to the TOML store.
Summary
Mapping gestures to actions in OpenLogi requires understanding the interaction between configuration storage, binding projection, and runtime capture:
- Enable gesture mode first using
openlogi config set-gesture-modeto designate the button as a gesture source - Store bindings in TOML format under
bindings.<device>.GestureButtonwith keys for Up, Down, Left, Right, and Click - Project mappings at runtime through
hidpp_gesture_maps_forincrates/openlogi-core/src/bindings.rs - Capture events in
crates/openlogi-device/src/session/gesture.rsusingCapturedInput::Gesturevariants - Apply defaults automatically when specific directions lack explicit bindings via
default_binding(button)
Frequently Asked Questions
What configuration file format does OpenLogi use for gesture mappings?
OpenLogi uses TOML configuration files stored at ~/.config/openlogi/config.toml. The gesture map resides under the [bindings.<device_id>.GestureButton] section, where each direction (Up, Down, Left, Right, Click) maps to a string representing the action name. The Config struct in crates/openlogi-core/src/config.rs handles serialization and deserialization of these mappings.
Can I set different gesture actions for different applications?
Yes. The configuration layer supports per-application bindings in addition to per-device settings. While the CLI examples show device-level configuration (2b042), the underlying Config::bindings_for method can filter bindings based on the active application context. You can define application-specific sections in the TOML file to override global gesture mappings when specific windows are focused.
What happens if I don't define all five gesture directions?
OpenLogi automatically backfills undefined directions with the default click action. When bindings_for projects the runtime map, any missing GestureDirection entries receive the value returned by default_binding(button). This ensures that swiping in an unconfigured direction still triggers a predictable action rather than failing silently.
How does OpenLogi distinguish between a click and a swipe on the gesture button?
The system treats Click as a distinct GestureDirection variant separate from directional swipes. When you press and release the gesture button without moving, the capture session in crates/openlogi-device/src/session/gesture.rs generates CapturedInput::Gesture(ButtonId::GestureButton, GestureDirection::Click). This allows you to bind the tap action separately from swipe gestures, typically used to open the gesture button menu or trigger Mission Control.
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 →