# How openlogi-inject Synthesizes Input Events: Cross-Platform Implementation Guide

> Learn how openlogi-inject synthesizes input events across Windows macOS and Linux. This guide details its cross-platform implementation using native OS APIs for seamless event injection.

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

---

**openlogi-inject synthesizes keyboard, mouse, and scroll events by translating high-level Actions into native OS APIs—SendInput on Windows, CGEvent on macOS, and uinput on Linux—through a unified facade that delegates to platform-specific modules.**

The `openlogi-inject` crate in the AprilNEA/OpenLogi repository provides the low-level machinery that turns logical user actions into real operating system input events. This Rust library abstracts away platform differences to offer a consistent API for synthesizing keyboard shortcuts, mouse clicks, and scroll gestures across Windows, macOS, and Linux. Understanding how openlogi-inject synthesizes input events reveals the careful balance between unsafe system calls and safe Rust abstractions required for reliable cross-platform automation.

## Architecture of the Injection Facade

The entry point for all synthetic input is [`crates/openlogi-inject/src/inject.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject.rs), which exposes a platform-agnostic API through functions like `execute`, `post_scroll`, and `post_smooth_scroll`. This module defines the **Effect** enum—variants that describe keyboard presses, mouse clicks, and relative scroll movements—and uses conditional compilation (`#[cfg(target_os = "...")]`) to dispatch calls to the appropriate backend. Helper types such as **HeldKey**, **HeldModifiers**, **KeyPhase**, and **SmoothScrollPhase** capture high-level intent before translation into native structures.

## Platform-Specific Implementation Strategies

### Windows: Low-Level SendInput Integration

On Windows, the implementation resides in [`crates/openlogi-inject/src/inject/windows.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/windows.rs). The code constructs arrays of Win32 **INPUT** structures that describe keyboard, mouse, or scroll events, then passes them to the **SendInput** API. An explicitly marked `unsafe` block around line 345 performs the actual system call, ensuring that raw pointer operations are contained while the public API remains safe.

### macOS: CoreGraphics Event Posting

The macOS backend in [`crates/openlogi-inject/src/inject/macos.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/macos.rs) uses the **CGEvent** API to synthesize input. For each logical event, the code creates a `CGEvent` via `CGEventCreateKeyboardEvent` or `CGEventCreateMouseEvent`, sets modifier flags, and posts it with `CGEventPost`. To prevent feedback loops, the injector attaches a **SYNTHETIC_EVENT_USER_DATA** identifier to every event it creates, allowing the system-wide hook to recognize and ignore its own injections.

### Linux: Virtual Device via uinput

For Linux, [`crates/openlogi-inject/src/inject/linux.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/linux.rs) opens `/dev/uinput` and creates a virtual input device named “OpenLogi action injector.” The backend writes **input_event** structures directly to the device file, which the kernel then emits as hardware events. The device is initialized lazily on first use (see the logic around line 187), and the module handles edge cases such as mouse-wheel-only devices by ensuring that injected events are not re-captured by the monitoring hook.

## From Action to OS Event: The Execution Pipeline

When an **Action** reaches the injector, it flows through a structured pipeline:

1. The `execute` function in [`inject.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/inject.rs) receives the **Action** and translates it into an **Effect** variant.
2. Based on the target platform, the code dispatches to `windows::execute`, `macos::execute`, or `linux::execute`.
3. The platform-specific module builds native event structures—`INPUT` for Windows, `CGEvent` for macOS, or `input_event` for Linux—and posts them to the OS.
4. The function returns the count of successfully injected events, allowing callers to verify delivery.

For continuous gestures like smooth scrolling, the **SmoothScrollPhase** type drives `post_smooth_scroll`, which the macOS and Linux backends use to emit relative wheel events over time rather than discrete jumps.

## Code Examples

### Injecting a Keyboard Shortcut

```rust
use openlogi_inject::execute;
use openlogi_core::binding::action::Action;

// Inject a "Copy" (Ctrl+C) shortcut
let copy_action = Action::shortcut("Copy");
execute(copy_action);

```

### Simulating Smooth Scrolling on macOS

```rust
use openlogi_inject::{post_smooth_scroll, SmoothScrollPhase};

let delta = 120; // typical scroll delta
post_smooth_scroll(delta, SmoothScrollPhase::Began);
post_smooth_scroll(delta, SmoothScrollPhase::Changed);
post_smooth_scroll(delta, SmoothScrollPhase::Ended);

```

### Low-Level uinput Event Construction

```rust
// Inside crates/openlogi-inject/src/inject/linux.rs
fn inject_key(fd: RawFd, keycode: u16, press: bool) -> io::Result<()> {
    let ev = input_event {
        time: TimeVal { tv_sec: 0, tv_usec: 0 },
        type_: EV_KEY,
        code: keycode,
        value: if press { 1 } else { 0 },
    };
    // Write the event to the uinput device
    write(fd, &ev as *const _ as *const u8, mem::size_of::<input_event>())?;
    Ok(())
}

```

## Key Source Files

| 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`, `post_scroll`, etc.). |
| [`crates/openlogi-inject/src/inject.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject.rs) | Core facade; defines **Effect**, helper types, and platform dispatch. |
| [`crates/openlogi-inject/src/inject/windows.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/windows.rs) | Implements injection via Windows **SendInput**. |
| [`crates/openlogi-inject/src/inject/macos.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/macos.rs) | Implements injection via macOS **CGEvent**. |
| [`crates/openlogi-inject/src/inject/linux.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/linux.rs) | Implements injection via Linux **uinput**. |
| [`crates/openlogi-inject/examples/inject_action.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/examples/inject_action.rs) | Demonstrates calling the injector from a standalone binary. |

## Summary

- **openlogi-inject** uses a facade pattern to expose platform-agnostic functions while hiding OS-specific details.
- The Windows backend relies on Win32 **SendInput** with `INPUT` structures constructed in an `unsafe` block.
- The macOS backend posts **CGEvent** objects and marks them with **SYNTHETIC_EVENT_USER_DATA** to prevent feedback loops.
- The Linux backend creates a virtual **uinput** device to emit kernel-level **input_event** structures.
- The pipeline converts high-level **Action** types into low-level **Effect** enums before dispatching to native code.

## Frequently Asked Questions

### What native APIs does openlogi-inject use to synthesize input events on each platform?

On Windows, the crate calls the Win32 **SendInput** API; on macOS, it uses CoreGraphics **CGEventCreateKeyboardEvent** and **CGEventPost**; on Linux, it writes **input_event** structures to a **uinput** virtual device.

### How does openlogi-inject prevent infinite loops when injecting events?

The macOS implementation attaches a **SYNTHETIC_EVENT_USER_DATA** flag to every injected event, allowing the system hook to filter out its own events. The Linux backend similarly isolates its virtual device to avoid re-capturing synthesized input.

### Can openlogi-inject simulate smooth scrolling gestures?

Yes, the crate provides `post_smooth_scroll` and the **SmoothScrollPhase** enum, which allow continuous scroll injection with distinct begin, change, and end phases, mapped to relative wheel events on macOS and Linux.

### Is openlogi-inject safe to use within Rust's ownership model?

While the crate necessarily wraps unsafe OS APIs—explicitly marked in [`windows.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/windows.rs) around line 345—it exposes a memory-safe public API that manages raw file descriptors and input contexts, ensuring that callers never handle uninitialized memory or dangling pointers.