Injection model
A set of fields, two verbs, added on top of the user's inputA connected device is a set of fields: each is an Axis (relative motion: X, Y, wheel) or a Usage (a momentary button, key, or media control).
| Device | Axes (MOVE) | Momentary (INJECT) |
|---|---|---|
| mouse | cursor X/Y, wheel | buttons |
| keyboard | none | keys, modifiers |
| media | none | volume, play/pause, ... |
Whatever you send is added on top of the user's own input, never replacing it:
physical input (real device) --+
+--> one combined report --> game PC
injected input (your program) --+| You send | The clone emits |
|---|---|
a MOVE while the real mouse moves | The sum of both. |
an INJECT press while the user holds nothing | The injected press. |
| nothing | Only the real device. |
Fire-and-forget
No per-command acknowledgementCommand frames get no echo and no acknowledgement, so you can stream input fast (up to about one command per millisecond). The exception is QUERY, which returns a RESP.
Correctness comes from three places:
| Mechanism | What it does |
|---|---|
| frame checksum | Drops corrupted frames. |
| safety rules | Keep a dropped command from leaving the box stuck. |
HEALTH | Reads the box's actual state. |
A lost movement frame costs one millisecond of motion; the next frame carries on.
What the box tracks
Pending motion and held usagesInjected state is a small set of pending values the box carries between reports, separate from anything the real device is doing.
| State | What it holds |
|---|---|
| riding accumulator | A running total of sent motion and scroll not yet delivered to the PC. An ordinary MOVE, cursor or wheel, adds in. It drains into outgoing reports, except while movement riding is on, where it waits for a real move to carry it. |
| immediate accumulator | The same total for motion that never waits: a MOVE carrying NOW or FLUSH, and clip playback. Both accumulators always exist; riding gates whether the first one drains, not which one a move lands in. |
| usage override | Per usage (button, key, or media), whether the box forces it active, forces it inactive, or leaves it to the real device. Set by the INJECT actions: press forces active, force-release forces inactive, soft-release clears both. |
A report can only carry a limited movement size. A large injected move sends what fits and keeps the remainder in its own accumulator. Nothing is clipped (total seen = total sent), just spread over as many reports as it takes.
When the box sends a report
At the mouse's own report rate, only on activityThe box adds no report cadence of its own. Every row below fires on the cloned mouse's own tick.
| When… | The box sends |
|---|---|
| the real mouse reported | The real movement plus whatever's drained from the accumulator, with buttons combining the physical state and your overrides. |
| the real mouse was still, but you have motion pending | A report carrying just the drained accumulator, paced to the mouse's own report rate (not one every millisecond). With movement riding on, only motion that bypassed riding goes out this way. |
an INJECT or RESET changed a usage | One report reflecting the new state. |
Otherwise the box sends nothing. A held usage is a single report (the edge), then silence until it changes.
Safety
Injected state can't trap the real deviceA force-release always writes 0: it clears an injected hold and masks a physical press.
The box also clears all injection if your program goes quiet, dropping every override and pending move and returning to plain passthrough. Any of these resets it:
| Trigger | What happens |
|---|---|
| silence timeout | No valid frame arrives within the timeout (default 1000 ms), so a crash while holding a button releases it a second later. |
| link drop | The link to the host chip drops. |
| mouse unplugged | The real mouse is detached, so there's nothing left to inject into. |
RESET | You send the reset command explicitly. |
To hold an injected button deliberately, keep the link busy: any valid frame resets the timer, so a periodic QUERY(HEALTH) suffices.
The medius library automates this: it sends keepalives while you hold something, and reconnects and re-applies your state if the link drops.