<!-- Source: https://medius.k4tech.net/bindings/python/api -->
# API index

_Every Python call, linked to what it does_

The full `Device` surface, grouped. Each row gives the Python signature and a one-line summary; the semantics live in the [Rust Library](/library.md) and [Native API](/native.md), so follow the link for what a call does. Types and enums are on [Types & errors](/bindings/python/types.md); streams on [Streams](/bindings/python/streams.md).

Most calls are [fire-and-forget](/native/injection.md#fire-and-forget). They return once the frame is queued. The query calls, plus `Device.open` / `find`, block for the [box](/native/hardware.md)'s reply. Any call raises a [`MediusError`](/bindings/python/types.md#errors) on failure.

## Connecting & lifecycle

_Open, share, and release the link_

See [Connection](/library/connection.md) and [Lifecycle](/library/lifecycle.md).

| Call | Does |
| --- | --- |
| `Device.open(path)` | Open a serial path and [handshake](/native/connection.md#handshake). |
| `Device.find()` | Open the first box found, or raise [`NotFoundError`](/bindings/python/types.md#subclasses). |
| `dev.clone()` | Another handle to the same link; the connection is shared. |
| `dev.close()` | Free the handle. Called automatically by a [`with`](https://docs.python.org/3/reference/datamodel.html#context-managers) block and on GC. |
| `with Device.find() as dev:` | Context manager that closes the link on block exit. |

## Discovery

_Enumerate boxes and open one by identity_

Pick a box out of several by a stable identity (device MAC or CH343 serial), or by the kind of device it clones. See [Discovery](/library/discovery.md).

| Call | Does |
| --- | --- |
| `medius.list_boxes(cap=16)` | Enumerate every connected box as a [`BoxInfo`](/bindings/python/types.md#boxinfo) (opens, handshakes, and reads each one's version + device info). |
| `Device.open_by_id(id)` | Open the box whose identity matches `id` (device MAC hex or CH343 serial) and handshake. |
| `Device.find_mouse_box()` | Open the first box whose clone is a mouse. |
| `Device.find_keyboard_box()` | Open the first box whose clone is a keyboard. |

## Movement

_Relative cursor and wheel_

See [Move](/library/move.md). `+x` right, `+y` down.

| Call | Does |
| --- | --- |
| `dev.move_rel(dx, dy)` | Nudge the cursor by a signed 16-bit delta. |
| `dev.wheel(delta)` | Scroll the wheel. |
| `dev.move_axis(motion)` | Drive one axis from a [`Motion.cursor(dx, dy)`](/bindings/python/types.md#motion) or `Motion.wheel(delta)`. |

## Inject

_Press and release any usage: button, key, or media_

See [Inject](/library/inject.md) and the [injection model](/native/injection.md) (press / soft-release / force-release). One usage vocabulary drives every verb; build a [`Usage`](/bindings/python/types.md#input) with `Usage.button` / `key` / `media`. Ids are on [Usage IDs](/native/commands/usage.md).

| Call | Does |
| --- | --- |
| `dev.inject(input, action)` | Apply an [`Action`](/bindings/python/types.md#action) to a built [`Usage`](/bindings/python/types.md#input) (button, key, or media usage). |
| `dev.press(input)` | Hold a usage down (`Action.PRESS`). |
| `dev.soft_release(input)` | Release, unless the user is physically holding it. |
| `dev.force_release(input)` | Release even against a physical hold. |

> **Note**
>
> Every verb takes a `Usage`, so a button, key, and media usage inject the same way: `dev.press(Usage.button(Button.LEFT))`, `dev.press(Usage.key(Key.W))`, `dev.press(Usage.media(MediaKey.MUTE))`.

## Locks

_Block the user's own input_

See [Lock](/library/lock.md). Build axis/usage targets with [`LockTarget.x/y/wheel/usage`](/bindings/python/types.md#locktarget) (or the `button`/`key`/`media` shortcuts); a [`LockDirection`](/bindings/python/types.md#lockdirection) picks an edge.

| Call | Does |
| --- | --- |
| `dev.lock(target, direction)` | Lock an axis or usage (e.g. `LockTarget.button(Button.LEFT)`, `LockTarget.key(Key.W)`). |
| `dev.unlock(target, direction)` | Unlock an axis or usage. |
| `dev.lock_all(what, direction)` / `unlock_all` | Blanket lock / unlock a [`Blanket`](/bindings/python/types.md#blanket) class (buttons, keys, media, aim, wheel). |

> **Warning**
>
> A lock auto-clears; it isn't permanent. The [keepalive](/library/guides/connection.md#keepalive) holds it for you. See [Lock](/library/lock.md).

## LED, admin & options

_Status light, resets, persistent settings_

| Call | Does |
| --- | --- |
| `dev.led(target, mode, level)` | Drive the status LED. See [LED](/library/led.md). |
| `dev.reset()` | Clear all overrides. See [Admin](/library/admin.md). |
| `dev.reapply()` | Re-send the active settings. |
| `dev.reconnect()` | Force a reconnect to the mouse. |
| `dev.reboot(target)` | Reboot a chip to run or download mode. |
| `dev.allow_imperfect_clones(allow)` | Opt in to cloning over-capacity devices. See [Options](/library/options.md). |
| `dev.set_movement_riding(window_ms)` | Set the riding window in ms, or `None` to turn it off. |
| `dev.set_emit_pace(pace)` | Pick what paces injected motion: `EmitPace.learned()` / `.interval()` / `.fixed(hz)`. See [Options](/library/options.md). |
| `dev.set_name(name)` | Set the box's human-readable name (1 to 32 printable ASCII). See [Name](/library/options.md#set-name). |
| `dev.clear_name()` | Clear the name, back to the synthesized default. Read it back on [`Version.name`](/bindings/python/types.md#version). |

## Queries

_Read box state, each blocks for one reply_

See [Requests](/library/requests.md). Each blocks for the box's reply and returns a [dataclass](https://docs.python.org/3/library/dataclasses.html) documented on [Types & errors](/bindings/python/types.md).

| Call | Returns |
| --- | --- |
| `dev.query_version()` | [`Version`](/bindings/python/types.md#version): protocol + firmware version. |
| `dev.query_health()` | [`Health`](/bindings/python/types.md#health): link, mouse, clone, injection flags. |
| `dev.device_info()` | [`DeviceInfo`](/bindings/python/types.md#deviceinfo): the cloned device's USB identity, kind, and product. |
| `dev.caps()` | [`Caps`](/bindings/python/types.md#caps): mouse/keyboard capabilities. |
| `dev.query_rate()` | [`Rate`](/bindings/python/types.md#rate): native report rate and poll period. |
| `dev.query_stats()` | [`Stats`](/bindings/python/types.md#stats): box-side telemetry. |
| `dev.query_locks()` | [`Locks`](/bindings/python/types.md#locks): active locks (`.entries`, `.is_locked(...)`). |
| `dev.query_catch()` | [`CatchState`](/bindings/python/types.md#catchstate): subscription mask + dropped count. |
| `dev.query_imperfect()` | [`ImperfectStatus`](/bindings/python/types.md#imperfectstatus): imperfect-clone state. |
| `dev.query_movement_riding()` | `int` ms, or `None` when off. |
| `dev.query_emit_pace()` | [`EmitPaceStatus`](/bindings/python/types.md#emitpacestatus): pacing mode + rate in effect. |
| `dev.counters()` | [`Counters`](/bindings/python/types.md#counters): [host-side wire counters](/library/diagnostics.md). |

## Streams

_Subscribe to live input and logs_

Consuming events is covered on [Streams](/bindings/python/streams.md); the catch feature itself on [Catch](/library/catch.md) and [Logs & counters](/library/diagnostics.md).

| Call | Returns |
| --- | --- |
| `dev.catch_events(mask=[CatchMask](/bindings/python/types.md#catchmask).ALL)` | [`EventStream`](/bindings/python/streams.md) of physical mouse/key/media events. |
| `dev.logs()` | [`LogStream`](/bindings/python/streams.md) of device log lines. |

## Buffered clip playback

_Preload a per-frame stream, box-clocked_

Build a stream with `ClipBuilder`, then drive it with the [`ClipHandle`](/library/clip.md#handle) from `dev.clip()`. Concept on [Clip](/library/clip.md).

#### CLIPBUILDER

| Call | Appends |
| --- | --- |
| `ClipBuilder() / .clear()` | A new builder (chainable); reset for reuse. |
| `.gap(frames)` | A gap run (0 = no-op). |
| `.move(dx, dy) / .wheel(dz)` | A cursor / wheel motion frame. |
| `.press(usage) / .release(usage) / .force_release(usage)` | A one-edge press / soft-release / force-release frame; `usage` is a [`Usage`](/bindings/python/types.md#input) (button, key, or media). |
| `.edge(usage, action)` | A one-edge frame for any [`Usage`](/bindings/python/types.md#input) with an explicit [`Action`](/bindings/python/types.md#action) (default press). |
| `.frame(dx, dy, wheel, edges)` | A motion delta plus up to 8 [`Usage`](/bindings/python/types.md#input) / [`Action`](/bindings/python/types.md#action) edges on one frame. |

#### MOVE AND CLICK ON ONE FRAME

```python
from medius import Action, Button, ClipBuilder, Usage

b = ClipBuilder()

# move (+10, -4) AND press Left on the same frame
b.frame(10, -4, 0, [(Usage.button(Button.LEFT), Action.PRESS)])
```

#### CLIPHANDLE

| Call | Effect |
| --- | --- |
| `dev.clip()` | A `ClipHandle` (owns the append-seq counter). |
| `clip.append(builder)` | Append the builder's entries to the ring. |
| `clip.set_autolock(blankets)` | Set the auto-lock scope: a list of [`Blanket`](/bindings/python/types.md#blanket) classes locked while the clip plays. |
| `clip.set_loop(on) / clip.set_retain(on)` | Loop the ring on completion; retain entries after playback instead of flushing. |
| `clip.finalize()` | Fix a retained clip's end so it can replay and loop. |
| `clip.bind(trigger)` | Bind a [`ClipTrigger`](/bindings/python/types.md#cliptrigger): a physical [`Usage`](/bindings/python/types.md#input) + [`Edge`](/bindings/python/types.md#edge) fires a [`ClipAction`](/bindings/python/types.md#clipaction) (up to 8). |
| `clip.unbind(usage, edge) / clip.clear_triggers()` | Remove one bound trigger by usage + edge; drop all triggers. |
| `clip.start() / clip.stop()` | Begin playback; stop and flush the ring, releasing the auto-lock. |
| `clip.pause() / clip.resume()` | Halt playback in place; carry on from where it paused. |
| `clip.restart() / clip.toggle()` | Replay from the first frame; start if idle else stop. |
| `clip.clear()` | Drop the ring's entries. |
| `clip.query_status()` | [`ClipStatus`](/bindings/python/types.md#clip-status): ring depth, playback state, held usages, counters. |
| `clip.query_config()` | [`ClipSettings`](/bindings/python/types.md#clipsettings): auto-lock, loop, retain, finalized, bound triggers. |

## Module functions

_Top-level helpers on medius_

| Call | Does |
| --- | --- |
| `medius.find_ports(cap=16)` | List present medius ports as [`PortInfo`](/bindings/python/types.md#portinfo) (now including the CH343 serial). |
| `medius.list_boxes(cap=16)` | Enumerate every connected box as a [`BoxInfo`](/bindings/python/types.md#boxinfo). See [Discovery](/bindings/python/api.md#discovery). |
| `medius.default_query_timeout_ms()` | The default query reply wait (1000 ms). |
| `medius.default_keepalive_cadence_ms()` | The default keepalive interval (500 ms). |
| `medius.abi_version()` | The [C ABI](/bindings/c.md) version the library exposes. |
| `medius.version_string()` | The library version string. |
| `medius.flash(port, bin_path, host=False)` | Flash firmware via [esptool](https://github.com/espressif/esptool). Needs the [flash feature](/bindings/python/build.md#features). |
