<!-- Source: https://medius.k4tech.net/library/catch -->
# Catch

_Stream the physical mouse and keyboard input_

[`catch_events`](/library/catch.md#catch-events) subscribes to the user's real input and hands back an [`EventStream`](/library/catch.md#event-stream) of [`CatchEvent`](/library/types/enums.md#catch-event) snapshots, relative motion and held-usage sets, captured before any [`lock`](/library/lock.md) suppression or [injection](/library/inject.md). Drop the stream to unsubscribe.

## catch_events

_Subscribe to the physical-input stream_

```text
fn catch_events(&self, mask: CatchMask) -> Result<EventStream>
```

_Fire-and-forget_

[`CatchMask`](/library/types/structs.md#catch-mask) picks which classes of change emit an event: `MOTION`, `WHEEL`, `BUTTONS`,`KEYS`, `MEDIA`, combined with `|`, or `CatchMask::all()` for the full mirror. The returned [`EventStream`](/library/catch.md#event-stream) receives every event; the subscribe itself sends one frame and doesn't wait for a reply.

#### PARAMETERS

| Parameter | Type | Description |
| --- | --- | --- |
| `mask` | [`CatchMask`](/library/types/structs.md#catch-mask) | Bitmask selecting which input classes emit events (see above). |

The subscription is held alive by the library's keepalive (which re-asserts it after a device-side blip) and across a [reconnect](/library/lifecycle.md#reconnect); it clears like injection: on control-PC silence, a [`reset`](/library/admin.md#reset) (which ends the stream, so its `recv` returns `Err`), or link loss. The reported input is the user's _physical_ input; a locked or injected target still reports its real hand value here. See the native [`CATCH`](/native/commands/catch.md#catch) command for the wire layout.

#### EXAMPLE

```rust
use medius::{Device, CatchMask, CatchEvent, Button};

let device = Device::find()?;
let events = device.catch_events(CatchMask::all())?;   // or MOTION | BUTTONS | KEYS | MEDIA
while let Ok(event) = events.recv() {
    match event {
        CatchEvent::Motion(m) => println!("dx={} dy={} dz={}", m.dx, m.dy, m.dz),
        CatchEvent::Usages(u) if u.is_held(Button::Side1) => {
            // the side button is held; rebind it...
        }
        CatchEvent::Usages(u) => println!("{} usages held", u.usages.len()),
    }
}
// dropping `events` unsubscribes
```

## EventStream

_Receive physical-input reports_

The handle [`catch_events`](/library/catch.md#catch-events) returns. Pull [`CatchEvent`](/library/types/enums.md#catch-event) snapshots with whichever method fits your loop; cloning shares the queue (like [`LogStream`](/library/diagnostics.md#logs)). When the stream and all its clones drop, the subscription ends and the box returns to passthrough.

#### METHODS

| Method | Returns | Description |
| --- | --- | --- |
| `recv()` | `Result<CatchEvent>` | Block until the next event. |
| `try_recv()` | `Option<CatchEvent>` | The next buffered event, or `None` (never blocks). |
| `recv_timeout(dur)` | `Option<CatchEvent>` | Block up to `dur`; `None` on timeout. |
| `try_iter()` | `impl Iterator` | Drain every buffered event without blocking. |
| `recv_async().await` | `Result<CatchEvent>` | Await the next event (`async` feature), runtime-agnostic. |
| `dropped()` | `u64` | Events lost host-side because this consumer fell behind. |

> **Note**
>
> The buffer is bounded and lossy: a slow consumer drops the OLDEST events, keeping the freshest input (count them with `dropped()`). The box's own drop count, under back-pressure on the wire, is on [`query_catch`](/library/requests.md#query-catch).

## On AsyncDevice

_catch_events fires, the stream awaits_

[`AsyncDevice`](/library/features/async.md) keeps `catch_events` synchronous (it just sends the subscribe and returns the stream) while the stream itself offers `recv_async().await`. `query_catch` is a future, like the other queries.

#### EXAMPLE

```rust
use medius::{AsyncDevice, CatchMask};

let device = AsyncDevice::open("/dev/ttyACM0")?;
let events = device.catch_events(CatchMask::BUTTONS)?;   // sync, no await
let report = events.recv_async().await?;                 // stream awaits
```
