# How openlogi-inject Synthesizes OS Input for Action Replay

> Learn how openlogi-inject synthesizes OS input for action replay across macOS Linux and Windows by translating Action enums into native OS events using three distinct backends.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: internals
- Published: 2026-08-23

---

**TLDR: `openlogi-inject` is the platform-specific crate inside the OpenLogi repository that translates high-level `Action` enums into native OS events via three backends (macOS CGEvent, Linux uinput, Windows SendInput), allowing OpenLogi to replay user actions across all major operating systems.**

OpenLogi is an open-source input automation project by AprilNEA that records and replays user actions. The crate responsible for turning abstract actions into real OS-level events is `openlogi-inject`. As implemented in the `AprilNEA/OpenLogi` repository, this crate keeps the core engine **platform-agnostic and IO-free**, delegating all native input synthesis to platform-specific modules behind a single unified API.

## How openlogi-inject Splits Platform Logic from the Core

The architecture deliberately isolates OS-specific code so that the rest of OpenLogi never needs to care about the host operating system. According to the source in [`crates/openlogi-inject/src/inject.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject.rs), the crate exposes a small public surface:

- `execute(action: &Action)` — replays a recorded action.
- `ax_navigate_browser(pid, forward)` — triggers browser back/forward via the macOS Accessibility API.
- `post_horizontal_scroll(delta)` — re-injects horizontal wheel events.

All three functions are re-exported from [`crates/openlogi-inject/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/lib.rs), which means every caller in OpenLogi uses the same uniform API regardless of whether it runs on macOS, Linux, or Windows.

## Entry Point: The `execute()` Function and Backend Selection

The public function `execute(action: &Action)` is defined in [`crates/openlogi-inject/src/inject.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject.rs). It uses the `cfg_select!` macro at compile time to route to one of three implementations:

- macOS → `macos::execute`
- Linux → `linux::execute`
- Windows → `windows::execute`

Each backend receives the same input — an `Action` from `openlogi_core::binding::Action` — and produces the native events the host OS expects. This design is what makes **openlogi-inject action replay** work transparently across platforms.

```rust
use openlogi_inject::{execute, ax_navigate_browser, post_horizontal_scroll};
use openlogi_core::binding::Action;

/// Replay a stored Action – e.g. a button bound to "Copy".
fn replay_copy() {
    let action = Action::Copy;            // from openlogi_core::binding
    execute(&action);                    // Sends native key-presses
}

```

## macOS Backend: Synthesizing OS Input with CGEvent

The macOS implementation in [`macos.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/macos.rs) is the most feature-complete because it has direct access to the Cocoa and Accessibility APIs. Here's how it synthesizes OS input:

- **Keyboard events** are posted using `CGEventPost(kCGHIDEventTap, …)` with virtual-key codes from the standard US layout.
- **Mouse clicks** (Left/Right/Middle) generate a `CGEvent` at the current cursor location.
- **Window-manager actions** like *MissionControl* are sent directly to the Dock via `CoreDockSendNotification`.

A constant `SYNTHETIC_EVENT_USER_DATA` (value `0x4F4C_4749` — "OLGI") is embedded in every mouse event. This marker is the key to preventing recursive loops: OpenLogi's own `CGEventTap` reads this value and ignores its own injected events, ensuring the system never re-records its own playback.

## Linux Backend: Virtual Devices via uinput

The Linux module in [`crates/openlogi-inject/src/inject/linux.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/linux.rs) takes a different approach. Because the X11 and Wayland APIs are fragmented, OpenLogi relies on a **lazily-created uinput virtual device**.

- **Keyboard and scroll events** are emitted through `uinput` (or the evdev `EV_REL` API for horizontal scroll).
- **Mouse clicks** generate `BTN_*` events.
- **macOS-only window-manager actions** (like *MissionControl*) have no universal Linux equivalent, so they are logged and silently ignored.

### Debugging the uinput Device on Linux

On Linux only, a helper function `action_device_path()` returns the path of the uinput device (e.g., `/dev/input/eventN`). This is invaluable when you want to verify injected events with tools like `evtest` while developing gesture-watcher code.

## Windows Backend: Native SendInput and Key Mapping

The Windows implementation in [`crates/openlogi-inject/src/inject/windows.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/windows.rs) uses the native **`SendInput`** API to synthesize both keyboard and mouse events. Since Windows has no direct equivalent of macOS's MissionControl or Show Desktop notions, the crate maps them to their Windows counterparts:

- **MissionControl** → `Win + Tab`
- **ShowDesktop** → `Win + D`
- **CustomShortcut** converts macOS `kVK_*` codes to Win32 virtual-key codes via the helper function `hid_usage_to_windows`.

## Supporting Helpers for Gesture-Driven Replay

Two additional functions round out the crate's public API and are especially relevant to gesture watchers:

- `ax_navigate_browser(pid, forward)` — uses the macOS Accessibility API (`AXPress`) to trigger the browser's back/forward toolbar buttons. This is a *must-use* function when a gesture-watcher wants to navigate history without simulating keystrokes.
- `post_horizontal_scroll(delta)` — re-injects horizontal wheel movements, required for MX thumb-wheel gestures on trackpads and thumb-wheels.

```rust
/// Move the browser back one page while a gesture is active (macOS only).
fn go_back_in_browser(pid: i32) {
    if ax_navigate_browser(pid, false) {
        println!("Browser back navigation succeeded");
    }
}

/// Re-inject a horizontal scroll generated by a thumb-wheel gesture.
fn inject_scroll(delta: i32) {
    post_horizontal_scroll(delta);       // Platform-specific scroll event
}

```

## Key Source Files in `openlogi-inject`

| File | Role |
|------|------|
| [`crates/openlogi-inject/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/lib.rs) | Re-exports the public API (`execute`, `ax_navigate_browser`, etc.) |
| [`crates/openlogi-inject/src/inject.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject.rs) | Central dispatcher; defines `execute`, `post_horizontal_scroll`, and the synthetic-event marker |
| [`crates/openlogi-inject/src/inject/macos.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/macos.rs) | macOS implementation – CGEvent generation, Accessibility API, Dock notifications |
| [`crates/openlogi-inject/src/inject/linux.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/linux.rs) | Linux implementation – uinput device handling, evdev scroll, mouse button events |
| [`crates/openlogi-inject/src/inject/windows.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/windows.rs) | Windows implementation – SendInput usage, virtual-key mapping |
| [`crates/openlogi-inject/examples/inject_action.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/examples/inject_action.rs) | Minimal example showing how to call `execute` from a standalone binary |

## Summary

- `openlogi-inject` turns the platform-neutral `Action` enum from `openlogi_core` into native OS events.
- The `execute()` function dispatches at compile time to macOS (`CGEvent`), Linux (`uinput`), and Windows (`SendInput`) backends.
- macOS embeds a `SYNTHETIC_EVENT_USER_DATA` marker in all mouse events to prevent infinite loops with its own `CGEventTap`.
- Linux replicates the input stream via a lazily-created uinput virtual device; unsupported window-manager features are logged and ignored.
- Windows maps macOS window-manager semantics (MissionControl, ShowDesktop) to Win32 hotkeys.
- The same three public functions (`execute`, `ax_navigate_browser`, `post_horizontal_scroll`) are offered everywhere, so the rest of OpenLogi remains uniform across platforms.

## Frequently Asked Questions

### How does `openlogi-inject` avoid replaying its own injected events?

On macOS, every injected mouse event carries a constant `SYNTHETIC_EVENT_USER_DATA` value (0x4F4C_4747). OpenLogi's `CGEventTap` checks this field and won't process events tagged with it, which prevents recursive loops during action replay.

### Is `openlogi-inject` used only for replaying keyboard and mouse actions?

It controls keyboard, mouse, and window-manager actions. It also exposes `ax_navigate_browser()` for browser-specific back/forward navigation (macOS only) and `post_horizontal_scroll()` for thumb-wheel gestures, both of which are used by gesture-watcher code.

### What is the actual entry point of `openlogi-inject`?

The public `execute(action: &Action)` function in [`crates/openlogi-inject/src/inject.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject.rs) is the central dispatcher. It uses the `cfg_select!` macro to route to the appropriate platform backend at compile time.

### How do I test input injection on Linux?

Use the `action_device_path()` helper, which is exposed only when `target_os = "linux"`, to get the uinput device path (like `/dev/input/eventN`). Then you can inspect events with tools like `evtest`.