API index
Every Python call, linked to what it doesThe full Device surface, grouped. Each row gives the Python signature and a one-line summary; the semantics live in the Rust Library and Native API, so follow the link for what a call does. Types and enums are on Types & errors; streams on Streams.
Most calls are fire-and-forget. They return once the frame is queued. The query calls, plus Device.open / find, block for the box's reply. Any call raises a MediusError on failure.
Connecting & lifecycle
Open, share, and release the linkSee Connection and Lifecycle.
| Call | Does |
|---|---|
Device.open(path) | Open a serial path and handshake. |
Device.find() | Open the first box found, or raise NotFoundError. |
dev.clone() | Another handle to the same link; the connection is shared. |
dev.close() | Free the handle. Called automatically by a with 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 identityPick a box out of several by a stable identity (device MAC or CH343 serial), or by the kind of device it clones. See Discovery.
| Call | Does |
|---|---|
medius.list_boxes(cap=16) | Enumerate every connected box as a 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 wheelSee Move. +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) or Motion.wheel(delta). |
Inject
Press and release any usage: button, key, or mediaSee Inject and the injection model (press / soft-release / force-release). One usage vocabulary drives every verb; build a Usage with Usage.button / key / media. Ids are on Usage IDs.
| Call | Does |
|---|---|
dev.inject(input, action) | Apply an Action to a built Usage (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. |
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 inputSee Lock. Build axis/usage targets with LockTarget.x/y/wheel/usage (or the button/key/media shortcuts); a 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 class (buttons, keys, media, aim, wheel). |
LED, admin & options
Status light, resets, persistent settings| Call | Does |
|---|---|
dev.led(target, mode, level) | Drive the status LED. See LED. |
dev.reset() | Clear all overrides. See Admin. |
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. |
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. |
dev.set_name(name) | Set the box's human-readable name (1 to 32 printable ASCII). See Name. |
dev.clear_name() | Clear the name, back to the synthesized default. Read it back on Version.name. |
Queries
Read box state, each blocks for one replySee Requests. Each blocks for the box's reply and returns a dataclass documented on Types & errors.
| Call | Returns |
|---|---|
dev.query_version() | Version: protocol + firmware version. |
dev.query_health() | Health: link, mouse, clone, injection flags. |
dev.device_info() | DeviceInfo: the cloned device's USB identity, kind, and product. |
dev.caps() | Caps: mouse/keyboard capabilities. |
dev.query_rate() | Rate: native report rate and poll period. |
dev.query_stats() | Stats: box-side telemetry. |
dev.query_locks() | Locks: active locks (.entries, .is_locked(...)). |
dev.query_catch() | CatchState: subscription mask + dropped count. |
dev.query_imperfect() | ImperfectStatus: imperfect-clone state. |
dev.query_movement_riding() | int ms, or None when off. |
dev.query_emit_pace() | EmitPaceStatus: pacing mode + rate in effect. |
dev.counters() | Counters: host-side wire counters. |
Streams
Subscribe to live input and logsConsuming events is covered on Streams; the catch feature itself on Catch and Logs & counters.
| Call | Returns |
|---|---|
dev.catch_events(mask=CatchMask.ALL) | EventStream of physical mouse/key/media events. |
dev.logs() | LogStream of device log lines. |
Buffered clip playback
Preload a per-frame stream, box-clockedBuild a stream with ClipBuilder, then drive it with the ClipHandle from dev.clip(). Concept on Clip.
| 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 (button, key, or media). |
.edge(usage, action) | A one-edge frame for any Usage with an explicit Action (default press). |
.frame(dx, dy, wheel, edges) | A motion delta plus up to 8 Usage / Action edges on one frame. |
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)])| 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 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: a physical Usage + Edge fires a 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: ring depth, playback state, held usages, counters. |
clip.query_config() | 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 (now including the CH343 serial). |
medius.list_boxes(cap=16) | Enumerate every connected box as a BoxInfo. See 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 version the library exposes. |
medius.version_string() | The library version string. |
medius.flash(port, bin_path, host=False) | Flash firmware via esptool. Needs the flash feature. |