# How to Configure Per-Direction Gesture Bindings in OpenLogi: Complete TOML Guide

> Master per-direction gesture bindings in OpenLogi with this TOML guide. Learn to map swipe actions efficiently in your configuration file.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: how-to-guide
- Published: 2026-09-06

---

**OpenLogi uses a plain TOML configuration file where gesture buttons map distinct actions to each swipe direction (up, down, left, right, and optional diagonals) through a gesture-direction hash map in the `bindings` table.**

OpenLogi is an open-source input remapping tool for Logitech devices that reads all user settings from a TOML file shared between its GUI and background agent. For gesture-capable hardware, you can bind individual actions to specific swipe directions rather than treating the button as a simple on/off switch. This per-direction binding system gives precise control over multi-directional input gestures.

## Understanding the Gesture-Direction Map Structure

The `bindings` table under each `[[devices]]` entry supports three configuration patterns. According to the [Configuration documentation](https://github.com/AprilNEA/OpenLogi/blob/master/docs/CONFIGURATION.md#L66-L70), the third pattern enables per-direction gesture bindings:

| Pattern | Syntax | Use Case |
|---------|--------|----------|
| Single action | `Button = "Action"` | Standard press-to-activate buttons |
| Short/long pair | `Button = { short = "ActionA", long = "ActionB" }` | Dual-function buttons with timing differentiation |
| **Gesture-direction map** | `Button = { up = "A", down = "B", left = "C", right = "D" }` | **Per-direction gesture bindings** with distinct actions per swipe |

When a gesture button is held, OpenLogi's agent monitors pointer movement or native gesture sensor data. Upon detecting a directional swipe, it looks up the corresponding key in your map and fires that action. Unspecified directions are silently ignored.

## Required TOML Schema and Device Structure

OpenLogi requires **schema version 7** in your configuration file, as noted in [`docs/CONFIGURATION.md#L39-L40`](https://github.com/AprilNEA/OpenLogi/blob/master/docs/CONFIGURATION.md#L39-L40). Each device entry uses the physical key format `[devices."receiver:<id>:slot:<n>"]` and contains device metadata plus the `bindings` table.

### Complete Device Entry Template

```toml
[devices."receiver:123456:slot:1"]
custom_name = "MX Master 3"
enabled     = true
dpi        = 1200
thumbwheel_sensitivity = 14

# Per-direction gesture bindings

bindings = {
    # Standard buttons

    Button1 = "Copy",
    Button2 = { short = "Back", long = "Forward" },

    # Gesture button with per-direction actions

    GestureButton = {
        up    = "VolumeUp",
        down  = "VolumeDown",
        left  = "PreviousTrack",
        right = "NextTrack"
    }
}

```

## Supported Gesture Directions

OpenLogi recognizes **eight directional inputs** for gesture buttons. The four cardinal directions are required for full functionality; diagonal directions are optional but available.

| Direction Key | Swipe Direction |
|-------------|---------------|
| `up` | Vertical upward |
| `down` | Vertical downward |
| `left` | Horizontal left |
| `right` | Horizontal right |
| `up_left` (optional) | Diagonal up-left |
| `up_right` (optional) | Diagonal up-right |
| `down_left` (optional) | Diagonal down-left |
| `down_right` (optional) | Diagonal down-right |

### Full Eight-Direction Configuration Example

```toml
[devices."receiver:00112233:slot:2"]
custom_name = "MX Master 2S"
dpi        = 1000
thumbwheel_sensitivity = 14

bindings = {
    # CID 0xD0 gesture button with all directions mapped

    Thumbwheel = {
        up         = "ShowDesktop",
        down       = "MissionControl",
        left       = "PreviousSpace",
        right      = "NextSpace",
        up_left    = "BrightnessUp",
        up_right   = "BrightnessDown",
        down_left  = "MediaPlayPause",
        down_right = "MediaStop"
    },

    # Regular buttons for comparison

    Button3 = "PlayPause",
    Button4 = { short = "Back", long = "Forward" }
}

```

## Partial Direction Bindings

You are not required to define all directions. Omitting a direction key disables that gesture entirely—useful when you want to prevent accidental triggers in specific orientations.

```toml
bindings = {
    GestureButton = {
        up   = "VolumeUp",
        down = "VolumeDown"
        # left and right omitted: horizontal swipes are ignored

    }
}

```

## How Per-Direction Gestures Are Processed Internally

The gesture pipeline spans multiple crates in the OpenLogi source tree:

1. **Event Capture**: [[`crates/openlogi-hook/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hook/src/lib.rs)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-hook/src/lib.rs) captures raw HID++ gesture events from the device hardware, as documented in [[`crates/openlogi-hook/AGENTS.md`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hook/AGENTS.md)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-hook/AGENTS.md).

2. **Direction Accumulation**: [`crates/openlogi-device/src/session/gesture/`](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-device/src/session/gesture/) contains the swipe accumulator that tracks pointer displacement while the gesture button remains held.

3. **Action Resolution**: The accumulated direction string (e.g., `"up_left"`) is matched against your TOML map keys. The corresponding action variant—defined in the core `Action` enum—gets queued for execution.

4. **OS Injection**: [[`crates/openlogi-inject/src/inject.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject.rs)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-inject/src/inject.rs) performs the final system-level input injection.

This architecture means your TOML edits directly control the action variant passed through the entire pipeline.

## Configuration File References

| File | Purpose |
|------|---------|
| [`docs/CONFIGURATION.md`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/CONFIGURATION.md) | Complete TOML schema documentation including `bindings` table structure |
| [`docs/config.example.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/config.example.toml) | Validated working example with per-direction gesture configurations |
| [`crates/openlogi-core/src/action.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/action.rs) | Action enum variants available for TOML strings |

## Applying Your Configuration

After editing your [`config.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/config.toml):

1. Save the file with valid TOML syntax (verify with `toml-test` or similar if unsure)
2. Reload through the OpenLogi GUI, or restart the background agent
3. Test gestures on your configured device; omitted directions should produce no response

## Summary

- OpenLogi configures per-direction gesture bindings through **TOML hash maps** in the `bindings` table, not through a graphical binding interface
- Use the pattern `GestureButton = { up = "Action", down = "Action", ... }` to assign distinct actions to each swipe direction
- **Eight directions** are supported: four cardinal and four diagonal; undefined directions are ignored during gesture recognition
- The configuration flows from raw HID++ capture through [`crates/openlogi-hook`](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-hook/), direction accumulation in [`crates/openlogi-device/src/session/gesture/`](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-device/src/session/gesture/), and final injection via [`crates/openlogi-inject`](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-inject/)
- Schema version 7 is mandatory; reference [`docs/config.example.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/config.example.toml) for syntax validation

## Frequently Asked Questions

### What happens if I define both a single action and a gesture-direction map for the same button?

You cannot combine patterns for a single button key. Each `bindings` entry must use exactly one of the three forms: single string, short/long table, or direction map. The TOML parser will reject overlapping definitions. Choose the pattern that matches your button's hardware capabilities—gesture buttons should use the direction map exclusively.

### Can I use mouse movement instead of the native gesture sensor for direction detection?

OpenLogi supports both native HID++ gesture events and pointer-based accumulation. The [`crates/openlogi-device/src/session/gesture/`](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-device/src/session/gesture/) module handles the abstraction; your TOML configuration remains identical regardless of detection method. The engine automatically selects the appropriate source based on device capabilities reported during initialization.

### Why are my diagonal gestures not registering?

Diagonal detection requires sufficient displacement in both axes during the swipe. If your `thumbwheel_sensitivity` or DPI setting is too low, small diagonal movements may be categorized as purely horizontal or vertical. Increase the sensitivity value in your device configuration, or exaggerate diagonal swipe angles during testing. Verify your TOML uses the correct underscore format: `up_left`, not `upLeft` or `up-left`.

### Where can I find the complete list of valid action strings for my gesture map?

Valid action strings are defined as enum variants in [[`crates/openlogi-core/src/action.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/action.rs)](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/action.rs). The [`docs/config.example.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/config.example.toml) file also contains extensively commented examples showing available actions. If you reference an undefined action string, the agent will log a configuration error at startup and skip that binding entry.