How OpenLogi Captures and Dispatches Live Gestures for Per-Direction Gesture Bindings

OpenLogi implements a three-layer pipeline that converts physical gesture button holds into directional swipe events, enabling real-time per-direction gesture bindings through OS-level hooks, HID++ capture sessions, and IPC dispatch to the GUI.

OpenLogi's gesture system transforms the dedicated HID++ gesture button found on MX-line mice (and haptic panels on newer models) into a live input modality capable of discriminating directional swipes. The AprilNEA/OpenLogi repository implements this through a sophisticated capture-dispatch architecture that processes raw pointer movement in real-time while the button remains depressed. This article examines the exact mechanism by which OpenLogi captures and dispatches live gestures for per-direction gesture bindings across macOS, Linux, and Windows platforms.

The Three-Layer Gesture Capture Pipeline

The implementation spans three architectural layers, each responsible for a specific phase of the gesture lifecycle from hardware interrupt to application action.

OS Hook Layer (openlogi-hook)

At the lowest level, platform-specific event taps intercept low-level mouse events before they reach the operating system's standard input queue. When the gesture button is pressed, the hook initiates a gesture hold state and begins forwarding subsequent pointer movements as raw-XY events to the processing pipeline.

The entry point resides in crates/openlogi-hook/src/lib.rs, which detects the gesture-button press and accumulates movement data. Platform-specific implementations in crates/openlogi-hook/src/macos.rs, crates/openlogi-hook/src/linux.rs, and the corresponding Windows module convert OS-level pointer deltas into normalized raw-XY reports.

Capture Session Layer (openlogi-device)

The run_capture_session function defined in crates/openlogi-device/src/session/gesture.rs opens a dedicated HID++ communication channel for each connected device. This session receives the raw-XY reports generated by the hook layer and translates them into Swipe objects containing both a directional vector (up, down, left, right) and travel distance measured in device-specific units.

The session maintains strict state management: it only reports swipes while the gesture button remains held, automatically discarding spurious motion data upon button release to prevent phantom gestures.

Agent Core and IPC Dispatch (openlogi-agent-core)

The capture session executes within the agent process watcher located at crates/openlogi-agent-core/src/watchers/gesture.rs. As each swipe object is produced, the agent constructs a gesture event and transmits it over the internal tarpc IPC channel to the GUI layer (either desktop application or overlay).

This architecture decouples the low-level hardware polling from the user interface, ensuring that gesture processing does not block the main application thread.

Per-Direction Gesture Binding Configuration

OpenLogi's configuration system defines gesture mappings through the Binding::Gesture type in crates/openlogi-core/src/binding/gesture.rs. This structure encapsulates five distinct sub-bindings: one for a plain click (no directional movement) and four directional variants corresponding to cardinal swipe directions.

// crates/openlogi-core/src/binding/gesture.rs
pub enum Binding {
    Gesture {
        click: Action,
        up: Action,
        down: Action,
        left: Action,
        right: Action,
    },
    // ...
}

The live swipe data produced by the capture session selects the appropriate sub-binding based on accumulated directional data. If the button releases before exceeding the directional threshold, the system triggers the plain-click binding; otherwise, it executes the action associated with the dominant direction.

Default mappings are provisioned in crates/openlogi-core/src/binding/defaults.rs, registering standard gestures such as Mission Control for upward swipes and Desktop Switching for downward movements.

Complete Gesture Flow from Hardware to Action

The end-to-end execution follows a deterministic sequence:

  1. Detection: The OS hook identifies the gesture-button press and initiates a hold state in crates/openlogi-hook/src/lib.rs.
  2. Accumulation: Pointer movement during the hold generates raw-XY events through platform-specific modules (macos.rs, linux.rs).
  3. Translation: The run_capture_session loop in crates/openlogi-device/src/session/gesture.rs aggregates raw data and determines the swipe direction.
  4. Dispatch: The agent watcher in crates/openlogi-agent-core/src/watchers/gesture.rs forwards a Gesture IPC message containing the resolved direction.
  5. Execution: The GUI layer matches the direction against user-defined sub-bindings in crates/openlogi-core/src/bindings.rs and executes the associated command.

This pipeline enables live gesture recognition: the system processes directional data in real-time, allowing distinct actions to fire immediately upon direction confirmation without requiring button release.

Summary

  • OpenLogi captures live gestures through a three-layer pipeline: OS hooks, device sessions, and IPC dispatch.
  • The run_capture_session function in crates/openlogi-device/src/session/gesture.rs converts raw-XY input into directional Swipe objects while filtering noise.
  • Platform-specific implementations in crates/openlogi-hook/src/macos.rs and linux.rs normalize OS-level pointer events for cross-platform consistency.
  • Per-direction bindings are defined via Binding::Gesture in crates/openlogi-core/src/binding/gesture.rs, supporting five sub-actions (click + four directions).
  • The tarpc IPC channel enables asynchronous communication between the low-level agent core and the GUI for responsive gesture execution.

Frequently Asked Questions

How does OpenLogi distinguish between a click and a directional swipe on the gesture button?

OpenLogi measures accumulated movement during the button hold period. If the button releases before the raw-XY delta exceeds the configured directional threshold, the system triggers the plain-click binding defined in Binding::Gesture. Movement exceeding the threshold in any cardinal direction selects the corresponding directional sub-binding.

What happens to gesture input if the GUI process is not running?

The agent core in crates/openlogi-agent-core/src/watchers/gesture.rs runs independently as a background service. It maintains the capture session and buffers gesture events; if the GUI is unavailable, the events are discarded gracefully without blocking the HID++ communication channel or interfering with normal mouse operation.

Does OpenLogi support diagonal swipes or only cardinal directions?

The current implementation in crates/openlogi-device/src/session/gesture.rs categorizes swipes into four cardinal directions (up, down, left, right). Diagonal movements are resolved to the dominant axis based on the greatest magnitude of displacement in either the X or Y direction.

How does the platform-specific hook code handle different operating system event APIs?

Each platform module—macos.rs, linux.rs, and windows.rs—implements a common trait interface that normalizes OS-specific event taps into standardized raw-XY reports. This abstraction allows the run_capture_session logic to remain platform-agnostic while the hook layer handles the specifics of CGEvent for macOS, evdev for Linux, or Raw Input for Windows.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →