Medius - BindingsAPI index

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 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 link

See Connection and Lifecycle.

CallDoes
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 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.

CallDoes
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 wheel

See Move. +x right, +y down.

CallDoes
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 media

See 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.

CallDoes
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 input

See Lock. Build axis/usage targets with LockTarget.x/y/wheel/usage (or the button/key/media shortcuts); a LockDirection picks an edge.

CallDoes
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_allBlanket lock / unlock a Blanket class (buttons, keys, media, aim, wheel).

A lock auto-clears; it isn't permanent. The keepalive holds it for you. See Lock.

LED, admin & options

Status light, resets, persistent settings
CallDoes
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 reply

See Requests. Each blocks for the box's reply and returns a dataclass documented on Types & errors.

CallReturns
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 logs

Consuming events is covered on Streams; the catch feature itself on Catch and Logs & counters.

CallReturns
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-clocked

Build a stream with ClipBuilder, then drive it with the ClipHandle from dev.clip(). Concept on Clip.

CLIPBUILDER
CallAppends
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.
MOVE AND CLICK 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)])
CLIPHANDLE
CallEffect
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
CallDoes
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.