How to Configure Gesture Bindings on Any Button with Live Capture in OpenLogi
Gesture bindings in OpenLogi map directional movements of a held button to custom actions, configured via TOML files or captured live through the GUI's capture mode.
OpenLogi is an open-source input remapping system for Logitech devices. Its gesture binding feature lets any physical button act as a gesture pad—when held, directional movements trigger different commands. This article covers both manual TOML configuration and the live capture workflow, grounded in the actual source implementation.
Understanding Gesture Bindings in OpenLogi
A gesture binding consists of two components: a gesture-owner button (the physical button you hold down) and directional mappings (up, down, left, right, tap). When the owner button is pressed and held, the low-level hook subsystem tracks movement vectors and emits GestureDirection events. The core receives these events through IPC and resolves them to configured actions.
According to the OpenLogi source, gesture events originate in crates/openlogi-hook/src/lib.rs, travel through crates/openlogi-ipc/src/transport.rs, and are processed by crates/openlogi-core/src/binding/gesture.rs before finally being persisted via crates/openlogi-core/src/bindings.rs.
Manual Configuration via TOML
OpenLogi stores all bindings in a profile-based TOML file, typically located at ~/.config/openlogi/config.toml. The gesture table exists inside each profile's bindings section.
Gesture Table Structure
[bindings.my_profile.gesture]
button = "B5" # The physical button that enters gesture mode
up = "volume_up"
down = "volume_down"
left = "prev_track"
right = "next_track"
tap = "play_pause"
button: Identifies which physical button activates gesture mode. This can be any button identifier recognized by the device—common values include"B5","G4", or"G5"on gaming mice.- Direction keys (
up,down,left,right,tap): Map to action names defined elsewhere in the configuration. These actions may invoke system commands, emit keystrokes, or trigger OpenLogi-internal functions.
Example: Media Control Gestures
[bindings.work_profile.gesture]
button = "G4"
up = "brightness_up"
down = "brightness_down"
left = "desktop_left"
right = "desktop_right"
tap = "mission_control"
[bindings.work_profile.actions]
brightness_up = { type = "keyseq", keys = ["XF86MonBrightnessUp"] }
brightness_down = { type = "keyseq", keys = ["XF86MonBrightnessDown"] }
desktop_left = { type = "keyseq", keys = ["Control", "Left"] }
desktop_right = { type = "keyseq", keys = ["Control", "Right"] }
mission_control = { type = "keyseq", keys = ["Command", "Up"] }
The configuration parser in crates/openlogi-core/src/config.rs deserializes this structure into a GestureMap, which the runtime queries when processing incoming GestureDirection events.
Live Capture Workflow in OpenLogi Desktop
The GUI application (openlogi-desktop) provides a live capture mode that eliminates manual TOML editing. This mode streams gesture events in real-time and writes bindings directly to the active profile.
How Live Capture Works
-
Activation: Select a button in the UI and enter capture mode. The GUI signals the hook to begin emitting
GestureDirectionevents for that specific button. -
Event Streaming: While the button is held, the hook in
crates/openlogi-hook/src/lib.rssamples HID++ reports, calculates movement vectors, and translates them into discrete directions. These events travel through the IPC channel defined incrates/openlogi-ipc/src/transport.rs. -
UI Feedback: The GUI displays live directional indicators as the user moves their mouse or trackball. Each detected direction highlights in the interface.
-
Binding Assignment: When the user clicks a direction in the UI and selects an action, the core constructs a
GestureBindingstruct (defined incrates/openlogi-core/src/binding/gesture.rs) and attaches it to the owner button. -
Persistence: On save,
crates/openlogi-core/src/bindings.rsserializes the updatedGestureMapback to the TOML file.
Capture Mode Code Flow
// Simplified representation of the GUI capture implementation
use openlogi_core::binding::gesture::{GestureBinding, GestureDirection};
use openlogi_core::profile::Profile;
fn run_capture_session(profile: &mut Profile, owner_button: String) {
let mut capture = GestureCapture::new(owner_button.clone());
capture.start(); // Signal hook to begin streaming events
// Live preview loop
while let Some(direction) = capture.next_event() {
ui.highlight_direction(direction); // Visual feedback
}
// User finalizes binding
let binding = GestureBinding {
up: ui.selected_action("up"),
down: ui.selected_action("down"),
left: ui.selected_action("left"),
right: ui.selected_action("right"),
tap: ui.selected_action("tap"),
};
profile.gesture_map.insert(owner_button, binding);
profile.save(); // Delegates to bindings.rs for TOML serialization
}
The GestureCapture struct manages the lifecycle of a capture session, ensuring that events from other buttons are filtered and only the designated owner button generates gesture events.
Key Source Files and Their Roles
| File | Purpose | GitHub Link |
|---|---|---|
crates/openlogi-hook/src/lib.rs |
Low-level HID++ hook that emits GestureDirection events from raw device reports |
View source |
crates/openlogi-ipc/src/transport.rs |
IPC channel (tarpc/bincode) carrying events between hook, GUI, and core | View source |
crates/openlogi-core/src/binding/gesture.rs |
GestureBinding definition and From<&GestureDirection> conversion logic |
View source |
crates/openlogi-core/src/config.rs |
TOML deserialization for profiles, including the gesture table |
View source |
crates/openlogi-core/src/bindings.rs |
Persistence layer that writes updated bindings to disk | View source |
docs/CONFIGURATION.md |
Official documentation of the TOML schema | View docs |
Triggering Bound Gestures Programmatically
The openlogi-inject crate allows synthetic gesture injection for testing or automation:
use openlogi_core::binding::gesture::GestureDirection;
fn trigger_bound_action(direction: GestureDirection) {
// Injects a gesture as if it came from the physical device
openlogi_inject::inject_gesture(direction);
}
// Fire the "right" binding on the current gesture-owner button
trigger_bound_action(GestureDirection::Right);
This capability is used by the test suite in crates/openlogi-core/tests/ to verify that gesture bindings resolve to correct actions without requiring physical hardware.
Summary
- Gesture bindings associate directional movements of a held button with actions, configured in the
gesturetable of any profile. - Manual TOML editing works for precise control: set
buttonto any button ID, then assign actions to each direction. - Live capture mode in
openlogi-desktopstreamsGestureDirectionevents through hook → IPC → core, letting you assign bindings visually. - The event pipeline spans
crates/openlogi-hook/src/lib.rs,crates/openlogi-ipc/src/transport.rs, andcrates/openlogi-core/src/binding/gesture.rs, with persistence handled bycrates/openlogi-core/src/bindings.rs. - Any button can become a gesture-owner button, and any action defined in the profile can be bound to any direction.
Frequently Asked Questions
What buttons can be used as gesture-owner buttons?
Any button recognized by your Logitech device can serve as a gesture-owner button. The button field in the TOML accepts standard identifiers like "B5" (thumb button), "G4", "G5" (G-series buttons), or device-specific codes. The hook subsystem in crates/openlogi-hook/src/lib.rs treats all buttons uniformly once configured.
Why aren't my gesture bindings triggering?
Three common causes: the hook is not running (required to emit GestureDirection events), the owner button is misidentified in the button field, or the action names are undefined in the profile. Verify that openlogi-hook has necessary permissions for low-level input access, and check that action references match keys in your [bindings.<profile>.actions] table.
How do I disable live capture without saving?
The live capture UI provides a Discard button that terminates the capture session without invoking profile.save(). This prevents crates/openlogi-core/src/bindings.rs from writing to the TOML file, leaving your configuration unchanged.
Can I bind multiple gesture-owner buttons in the same profile?
Yes. The gesture_map in crates/openlogi-core/src/binding/gesture.rs supports multiple entries—each distinct button value can have its own GestureBinding. This allows, for example, one button for media gestures and another for window management gestures within the same profile.
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 →