# How to Set Up Per-Application Profiles in OpenLogi: Complete Guide

> Learn how to set up per application profiles in OpenLogi to customize bindings for specific apps. This guide details the three-layer architecture for efficient configuration and state management.

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

---

**OpenLogi lets you create per-application profiles that override default bindings only when specific apps are in the foreground, using a three-layer architecture of configuration, state management, and UI components.**

OpenLogi is an open-source input device manager that allows granular control over button mappings. Setting up per-application profiles enables you to customize mouse and keyboard behaviors that activate exclusively when designated applications are active, without affecting your global default settings.

## Understanding the Per-Application Profile Architecture

OpenLogi implements per-application profiles through three distinct layers that work together to manage configuration, runtime state, and user interaction.

### Configuration Layer

The core data model resides in [`crates/openlogi-core/src/config.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/config.rs). This file defines the **profile storage system** and exposes APIs for manipulating app-specific bindings. Key methods include `app_profiles()` for querying existing profiles, `add_app_profile()` for creating new app-specific configurations, and `remove_app_profile()` for deleting them. The configuration persists as TOML, allowing human-readable editing while maintaining structured data integrity.

### State Management Layer

The desktop application maintains live configuration state in [`crates/openlogi-desktop/src/state/bindings.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/state/bindings.rs). This layer tracks which profile is currently active and ensures edits apply to the correct scope. The `remove_editing_app_profile()` method specifically safeguards your global defaults by isolating app-profile modifications from the default profile, preventing accidental global binding changes when customizing for specific applications.

### UI Layer

User-facing functionality lives in two primary locations:

- [`crates/openlogi-desktop/src/features/profiles.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/features/profiles.rs) implements the **Profiles pane**, including the "Add app profile" button and profile management dialogs
- [`crates/openlogi-desktop/src/features/profiles/picker.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/features/profiles/picker.rs) provides the application selection interface when creating new profiles

These components interact with the configuration APIs to provide visual management of your per-application bindings.

## Creating Per-Application Profiles Programmatically

You can create per-application profiles directly using the OpenLogi core API. The following Rust example demonstrates the complete workflow for adding a Firefox-specific profile that customizes the DPI button behavior:

```rust
use openlogi_core::config::Config;

// 1. Load the current configuration (typically done at startup)
let mut cfg = Config::load();

// 2. Register a new profile for a specific app (e.g., "firefox")
let app_name = "firefox";
cfg.add_app_profile("logitech_g403", app_name);   // "logitech_g403" is the device key

// 3. Set a custom binding for a button in that profile
//    Here we bind the left-side DPI button to "Zoom In" only for Firefox.
cfg.edit(|c| {
    c.set_binding(
        "logitech_g403",               // device key
        app_name,                      // app profile
        openlogi_core::Button::Dpi1,  // button identifier
        openlogi_core::Action::ZoomIn,
    );
});

// 4. Persist the configuration
cfg.save().expect("Failed to write config");

```

This code performs the same operations as the GUI when you click "Add app profile," creating an isolated configuration scope that activates only when Firefox is the foreground window.

## Setting Up Profiles via the OpenLogi Desktop UI

For most users, the graphical interface provides the simplest path to configure per-application profiles:

1. Open the **Profiles** pane by clicking the gear icon and selecting *Profiles*
2. Click **"Add app profile"** to launch the application picker dialog
3. Select your target application from the list presented by the picker component in [`crates/openlogi-desktop/src/features/profiles/picker.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/features/profiles/picker.rs)
4. Observe the UI switching to **App-Profile editing mode** (the title bar displays the selected application name)
5. Click any button in the device ring to assign custom actions specific to this application
6. Press **Save** to persist changes to `~/.config/openlogi/openlogi.toml` via the `Config::save()` method

The UI ensures that modifications made while in app-profile mode only affect that specific application's bindings, leaving your default profile untouched.

## How Foreground App Detection Works

Profile switching relies on the **foreground-app watcher** located in [`crates/openlogi-agent-core/src/watchers/foreground_app.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-agent-core/src/watchers/foreground_app.rs). This system component monitors the active window and notifies the UI when the foreground application changes.

When a switch occurs, the state management layer checks whether a per-application profile exists for the new active app. If found, OpenLogi activates that profile's bindings; otherwise, it falls back to the default profile. This transition is a **lightweight state change** that requires no HID communication until you physically press a button, ensuring zero performance impact during application switching.

## Summary

- **Per-application profiles** in OpenLogi override default bindings only when specific apps are active, managed through `add_app_profile()` in the core configuration layer
- The architecture separates concerns across three layers: configuration (`openlogi-core`), runtime state ([`openlogi-desktop/src/state/bindings.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/openlogi-desktop/src/state/bindings.rs)), and UI components ([`features/profiles.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/features/profiles.rs))
- You can create profiles programmatically using the `Config` API or graphically through the Profiles pane with the application picker
- Changes persist to `~/.config/openlogi/openlogi.toml` and activate automatically via the foreground-app watcher without interrupting device communication
- The `remove_editing_app_profile()` method ensures that app-specific edits never corrupt your global default bindings

## Frequently Asked Questions

### Where does OpenLogi store per-application profile configurations?

OpenLogi stores all profile data in a TOML configuration file located at `~/.config/openlogi/openlogi.toml`. The `Config::load()` and `Config::save()` methods in [`crates/openlogi-core/src/config.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/config.rs) handle serialization, with per-application profiles stored as distinct sections keyed by device and application identifiers.

### Can I have multiple per-application profiles for different devices?

Yes. The `add_app_profile()` method accepts a device key as its first parameter (e.g., "logitech_g403"), allowing you to create separate per-application profiles for each connected device. Each device maintains its own independent mapping of application names to binding configurations.

### What happens to my bindings when I switch between applications?

When you switch applications, the foreground-app watcher in [`crates/openlogi-agent-core/src/watchers/foreground_app.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-agent-core/src/watchers/foreground_app.rs) detects the change and triggers a profile switch in the state management layer. If the new application has a specific profile, those bindings activate immediately; otherwise, OpenLogi falls back to the default profile. This switch occurs without requiring HID renegotiation, ensuring instantaneous transitions.

### How do I delete a per-application profile without affecting the default profile?

Use the `remove_app_profile()` method from [`crates/openlogi-core/src/config.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/config.rs) to delete specific app profiles while preserving global settings. In the UI, select the profile from the Profiles pane and choose the delete option—the `remove_editing_app_profile()` logic in the state layer ensures that only the selected app-specific configuration is removed, leaving your default profile intact.