# How OpenLogi Handles Short and Long Press Button Events from Logitech Devices

> Discover how OpenLogi handles short and long press button events from Logitech devices by mapping HID++ control IDs to logical buttons. Learn more today.

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

---

**OpenLogi handles short-press and long-press button events by mapping distinct HID++ control IDs to separate logical button identifiers, eliminating the need for software-based timing measurements.**

OpenLogi is an open-source driver stack for Logitech input devices that translates raw HID++ events into high-level button events. When working with programmable buttons on Logitech presentation remotes and mice, distinguishing between a brief click and a sustained hold is essential for advanced workflows. The project encodes this distinction directly in the device firmware's control ID protocol.

## How HID++ Control IDs Encode Press Types

Logitech's HID++ protocol assigns separate control IDs for short-press and long-press variants of the same physical button. In [`crates/openlogi-hidpp/src/feature/reprog_controls/control_ids.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hidpp/src/feature/reprog_controls/control_ids.rs), OpenLogi defines these constants:

```rust
// Lines 12-16: Laser button control IDs
pub const LASER_BUTTON: u16 = 0xFA;
pub const LASER_BUTTON_SHORT_PRESS: u16 = 0xFB;
pub const LASER_BUTTON_LONG_PRESS: u16 = 0xFC;

```

The firmware itself determines whether a press qualifies as short or long. OpenLogi simply receives the appropriate control ID and routes it through the event pipeline. This design avoids timing ambiguity, reduces latency, and ensures consistent behavior across different host machines.

## From Raw HID++ to MouseEvent::Button

The **hook layer** at [`crates/openlogi-hook/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hook/src/lib.rs) bridges the gap between raw protocol data and application-friendly event structures. It wraps HID++ events into a `MouseEvent::Button` struct:

```rust
pub struct MouseEvent {
    pub id: ButtonId,
    pub pressed: bool,
}

```

The `ButtonId` enum derives from the control ID, so `0xFB` becomes `LaserButtonShortPress` while `0xFC` becomes `LaserButtonLongPress`. The `pressed` boolean tracks the physical state: `true` on button down, `false` on button up.

This separation means short-press and long-press events are handled as **independent logical buttons** throughout the system.

## IPC Event Propagation

Events travel through OpenLogi's inter-process communication layer before reaching UI components. The IPC representation in [`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs) simplifies the event to:

```rust
Button { button: String, pressed: bool },

```

The `button` string carries the discriminated identifier, allowing downstream consumers to match against specific press types without accessing HID++ internals.

## Practical Example: Handling Both Press Types

Below is a complete pattern for reacting to laser button short-press and long-press events in an application consuming OpenLogi's IPC output:

```rust
use openlogi_ipc::ipc::Button;

// Assume `event` is received from the IPC socket
match event {
    Button { button, pressed } => {
        match (button.as_str(), pressed) {
            ("LaserButtonShortPress", true) => {
                // Short press started – do the default action
                println!("Laser button short‑press down");
            }
            ("LaserButtonShortPress", false) => {
                // Short press released
                println!("Laser button short‑press up");
            }
            ("LaserButtonLongPress", true) => {
                // Long‑press started – maybe trigger a different command
                println!("Laser button long‑press down");
            }
            ("LaserButtonLongPress", false) => {
                // Long‑press released
                println!("Laser button long‑press up");
            }
            _ => {}
        }
    }
    _ => {}
}

```

Notice that timing logic is **absent from the application code**—the firmware has already classified the press type.

## Key Source Files

- **[`crates/openlogi-hidpp/src/feature/reprog_controls/control_ids.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hidpp/src/feature/reprog_controls/control_ids.rs)** — Defines raw HID++ control IDs including `LASER_BUTTON_SHORT_PRESS` (`0xFB`) and `LASER_BUTTON_LONG_PRESS` (`0xFC`)
- **[`crates/openlogi-hook/src/lib.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hook/src/lib.rs)** — Wraps HID++ events into the higher-level `MouseEvent::Button` abstraction
- **[`crates/openlogi-ipc/src/ipc.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-ipc/src/ipc.rs)** — Serializes button events for inter-process communication
- **[`crates/openlogi-agent-core/src/runtime/hook.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-agent-core/src/runtime/hook.rs)** — Core runtime that receives HID++ events and forwards them to IPC consumers

## Summary

- OpenLogi receives distinct HID++ control IDs for short-press and long-press variants from the device firmware.
- The hook layer maps these control IDs to separate `ButtonId` enum values.
- Events propagate with a `pressed` boolean indicating physical state, not press classification.
- No timing measurement occurs in software—classification happens entirely in hardware.
- Applications bind separate actions to short-press and long-press identifiers as if they were different buttons.

## Frequently Asked Questions

### Does OpenLogi measure time to detect long presses?

No. OpenLogi relies on the Logitech device firmware to classify press duration. The firmware reports either a short-press control ID (`0xFB`) or long-press control ID (`0xFC`), and OpenLogi passes this classification through unchanged. This approach eliminates timing inconsistencies between machines.

### Can I customize the long-press duration threshold?

The threshold is determined by device firmware, not by OpenLogi. Some Logitech devices expose reprogrammable parameters through the **Reprog Controls** feature, but OpenLogi's current implementation treats the firmware's classification as authoritative. Check your specific hardware's HID++ feature set for available configuration options.

### How do I bind different actions to short-press and long-press in my application?

Treat them as separate buttons. Match against `"LaserButtonShortPress"` and `"LaserButtonLongPress"` (or equivalent identifiers for your button) in the `Button` event handler. Each can trigger independent command sequences without interfering with the other.

### Are all Logitech buttons capable of generating both press types?

No. Only buttons exposed through the **Reprog Controls** feature with distinct short-press and long-press control IDs support this functionality. The laser button on presentation remotes is a common example; standard mouse buttons typically lack long-press variants in their HID++ definitions.