# How to Configure Per-Device Bindings in OpenLogi

> Learn to configure per-device button bindings in OpenLogi by editing the TOML config file. Map ButtonIds to Actions or gestures for custom control.

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

---

**You configure per-device button bindings in OpenLogi by editing the TOML configuration file at `~/.config/openlogi/config.toml` and defining entries under the `[devices."<physical-key>".bindings]` table, mapping each **ButtonId** to an **Action** or a directional gesture map.**

OpenLogi stores all user settings in a plain TOML file rather than a GUI preferences panel. Each physical device is addressed by a unique **physical-device key**, allowing you to assign custom actions to buttons on a per-device basis or override mappings when specific applications are active.

## Locating the Configuration File

OpenLogi follows standard platform conventions for its configuration directory.

- **Linux / macOS:** `~/.config/openlogi/config.toml`
- **Windows:** `%USERPROFILE%\.config\openlogi\config.toml`

The complete schema is documented in **[docs/CONFIGURATION.md](https://github.com/AprilNEA/OpenLogi/blob/master/docs/CONFIGURATION.md)**, and a fully-worked example is available in **[docs/config.example.toml](https://github.com/AprilNEA/OpenLogi/blob/master/docs/config.example.toml)**.

## Understanding the Physical-Device Key Format

Every device is identified by a generated physical-device key that OpenLogi assigns at runtime. **Do not replace this with a model ID**; you must use the exact key generated by the application.

- **Receiver devices:** `receiver:<receiver-id>:slot:<number>` (e.g., `receiver:abcd1234:slot:1`)
- **Direct HID / camera devices:** Use other system-generated keys as shown in the OpenLogi interface.

You will use this key inside TOML table headers to scope settings to a specific device.

## Defining Button Bindings

Inside the `[devices."<physical-key>".bindings]` table, you map **ButtonId** values (defined in `openlogi_core::binding::ButtonId`) to bindings. The **ButtonId** enum includes identifiers such as `Back`, `Forward`, `ThumbwheelScrollUp`, and `GestureButton`.

### Simple Button-to-Action Mapping

For standard buttons, assign a single action string directly.

```toml
[devices."receiver:aabbccdd:slot:1".bindings]
Back    = "BrowserBack"
Forward = "BrowserForward"

```

### Gesture-Mode Mapping with Directional Actions

For buttons operating in gesture mode, provide a map of `GestureDirection` to `Action`. This allows distinct actions for click, up, down, left, and right movements.

```toml
[devices."receiver:aabbccdd:slot:1".bindings.GestureButton]
Click = "MissionControl"
Up    = "MissionControl"
Down  = "AppExpose"
Left  = "PreviousDesktop"
Right = "NextDesktop"

```

## Per-Application Overrides

You can overlay different bindings when a specific application is in the foreground by adding a **per-app** table under `per_app_bindings`.

The application key can be:
- A macOS bundle ID (e.g., `com.microsoft.VSCode`)
- A Linux desktop file ID
- A Windows executable name prefixed with `exe:` (e.g., `exe:sharex.exe`)

```toml
[devices."receiver:aabbccdd:slot:1".per_app_bindings."com.microsoft.VSCode"]
Back = "Undo"

```

For Windows-specific overrides using executable names:

```toml
[devices."receiver:aabbccdd:slot:1".per_app_bindings."exe:sharex.exe"]
MiddleClick = { CustomShortcut = "F1" }

```

## How the Configuration is Loaded

At runtime, OpenLogi deserializes the TOML file into the `DeviceConfig` struct defined in **[crates/openlogi-core/src/config/device.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-core/src/config/device.rs)**. The `bindings` field is a `BTreeMap<ButtonId, Binding>`, where `Binding` is either a single `Action` or a `Binding::Gesture` containing a direction map.

The GUI reads the active mappings from `AppState::button_bindings` (see **[crates/openlogi-desktop/src/state/bindings.rs](https://github.com/AprilNEA/OpenLogi/blob/master/crates/openlogi-desktop/src/state/bindings.rs)**), which is populated from `DeviceConfig::bindings`. The application watches the configuration file for changes and reloads automatically on save.

## Summary

- OpenLogi uses a TOML file at `~/.config/openlogi/config.toml` (or the Windows equivalent) for all settings.
- Each device is addressed by a physical-device key (e.g., `receiver:<id>:slot:<n>`) that must be used exactly as generated.
- Bindings are defined under `[devices."<key>".bindings]` using **ButtonId** keys mapped to **Action** strings or gesture direction maps.
- Per-application overrides are supported under `per_app_bindings` using bundle IDs or executable names.
- The configuration is parsed into `DeviceConfig` in [`crates/openlogi-core/src/config/device.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/config/device.rs) and loaded into the GUI state at runtime.

## Frequently Asked Questions

### Where does OpenLogi store its configuration file?

OpenLogi stores settings in `~/.config/openlogi/config.toml` on Linux and macOS, and in `%USERPROFILE%\.config\openlogi\config.toml` on Windows. The application monitors this file and reloads bindings automatically when you save changes.

### What is the physical-device key format?

The physical-device key is a generated identifier assigned by OpenLogi at runtime. For receiver-based devices, it follows the pattern `receiver:<receiver-id>:slot:<number>`. You must use this exact key in your TOML tables; substituting a human-readable model name will not work.

### How do I bind a button to different actions based on swipe direction?

Assign a TOML table to the button key instead of a string. The table should map directions (`Click`, `Up`, `Down`, `Left`, `Right`) to action names. This is commonly used for the `GestureButton` to enable mission control, desktop switching, or app expose behaviors based on movement direction.

### Can I have different bindings for specific applications?

Yes. Add a `[devices."<key>".per_app_bindings."<app-id>"]` table where `<app-id>` is a macOS bundle ID, Linux desktop file ID, or Windows executable name prefixed with `exe:`. Bindings defined inside this table override the global bindings only when that application is the active foreground window.