Options
Persistent box settingsOptions are persistent box settings, each one set and read on its own. There are four: imperfect clones, movement riding, emit-rate pacing, and the box name. All persist in NVS and survive a reboot. See the native OPTION command for the wire contract.
| Option | Set | Read |
|---|---|---|
| imperfect clone | allow_imperfect_clones | query_imperfect |
| movement riding | set_movement_riding | query_movement_riding |
| emit-rate pacing | set_emit_pace | query_emit_pace |
| box name | set_name / clear_name | Version::name |
allow_imperfect_clones
Clone an over-capacity device anywayfn allow_imperfect_clones(&self, allow: bool) -> Result<()>
Fire-and-forget
By default the box refuses a device it can't clone faithfully. true opts into cloning an over-capacity device anyway, the rest faithful and the over-capacity interface dead; false is faithful-only (the default). It's persisted in NVS. When the setting changes for an attached over-capacity device the box reboots itself to re-clone, so it lands without unplugging anything; a normal device is unaffected (no reboot).
| Parameter | Type | Description |
|---|---|---|
allow | bool | Clone an over-capacity device anyway, or stay faithful-only. |
use medius::Device;
let device = Device::find()?;
device.allow_imperfect_clones(true)?; // reboots + re-clones if an over-capacity device is attachedset_movement_riding
Inject motion only on a native movefn set_movement_riding(&self, window: Option<Duration>) -> Result<()>
Fire-and-forget
Some(window) turns movement riding on: injected cursor and wheel motion ride a native cursor-motion report seen within window, the box emits no synthetic motion frame, and motion left unridden past the window is dropped rather than dumped on the next move. So injected motion's report density matches the real mouse's, erasing the density tell. None turns it off (the default). The window rounds to whole milliseconds, a non-zero Some is at least 1 ms, and it clamps to 65535 ms; persisted in NVS.
The tradeoff is deliberate: pure idle injection, moving the cursor while the user holds still, stops working while riding is on. Button, key, and media injection are unaffected.
| Parameter | Type | Description |
|---|---|---|
window | Option<Duration> | Some with the ride window, or None to turn it off. |
use std::time::Duration;
use medius::Device;
let device = Device::find()?;
device.set_movement_riding(Some(Duration::from_millis(20)))?; // ride native moves
device.set_movement_riding(None)?; // back to gapless fillset_emit_pace
Pick what paces injected motionfn set_emit_pace(&self, pace: EmitPace) -> Result<()>
Fire-and-forget
Picks what sets the emit-rate ceiling for injected motion. EmitPace::Learned is the default: the box paces injection to the rate the real mouse actually reports at. EmitPace::Interval paces to the cloned mouse's declared poll rate (itsbInterval). EmitPace::Fixed(hz) paces to a rate you set; the 1 ms frame clock snaps it to 1000/n Hz and caps it at 1 kHz. It raises the ceiling only, so idle stays idle (the box still emits a frame solely when injection is pending). Persisted in NVS.
The learnt default keeps injected motion's cadence matched to the native mouse. The other modes are for a host that models its own report density and wants the box to stop re-pacing an already-shaped stream.
| Parameter | Type | Description |
|---|---|---|
pace | EmitPace | Learned, Interval, or Fixed(hz). |
use medius::{Device, EmitPace};
let device = Device::find()?;
device.set_emit_pace(EmitPace::Fixed(1000))?; // emit at a fixed 1 kHz
device.set_emit_pace(EmitPace::Learned)?; // back to the learnt native paceset_name
Give the box a human-readable namefn set_name(&self, name: &str) -> Result<()>
Fire-and-forget
Sets the box's name, its readable partner to the MAC. Like the other setters it sends the value and lets the box own the rules: the firmware keeps the leading printable-ASCII run capped at 32 bytes, and an empty string clears it. Unlike the other options it is read not by a query but off Version::name, like the MAC.
| Parameter | Type | Description |
|---|---|---|
name | &str | The new name, 1 to 32 printable ASCII characters. |
use medius::Device;
let device = Device::find()?;
device.set_name("Loki")?; // the box now answers to "Loki"
let name = device.query_version()?.name; // read it back off Versionclear_name
Back to the synthesized defaultfn clear_name(&self) -> Result<()>
Fire-and-forget
Clears the custom name, reverting the box to a firmware-synthesized Medius-XXXX default derived from its MAC.
use medius::Device;
let device = Device::find()?;
device.clear_name()?; // back to "Medius-XXXX"query_imperfect
Read the imperfect-clone statefn query_imperfect(&self) -> Result<ImperfectStatus>
Blocks
Returns an ImperfectStatus: the opt-in toggle, whether the attached device is over-capacity, and whether the live clone went over-capacity anyway with one interface dead.
use medius::Device;
let device = Device::find()?;
let status = device.query_imperfect()?;
if status.over_capacity && !status.allowed {
// the device was refused; opt in to clone it imperfectly
device.allow_imperfect_clones(true)?;
}query_movement_riding
Read the ride windowfn query_movement_riding(&self) -> Result<Option<Duration>>
Blocks
Returns the current ride window as a Duration, or None when movement riding is off.
use medius::Device;
let device = Device::find()?;
match device.query_movement_riding()? {
Some(window) => println!("riding, window {window:?}"),
None => println!("off"),
}query_emit_pace
Read the pacing mode and ratefn query_emit_pace(&self) -> Result<EmitPaceStatus>
Blocks
Returns an EmitPaceStatus: the selected EmitPace mode plus resolved_hz, the ceiling actually in effect (0 when the pace is learnt/adaptive, or no device is attached yet in Interval mode).
use medius::{Device, EmitPace};
let device = Device::find()?;
let status = device.query_emit_pace()?;
if let EmitPace::Fixed(hz) = status.mode {
println!("fixed {hz} Hz, emitting at {} Hz", status.resolved_hz);
}On AsyncDevice
setters fire, queries awaitAsyncDevice keeps allow_imperfect_clones, set_movement_riding, set_emit_pace, set_name, and clear_name fire-and-forget (no await) and makes query_imperfect, query_movement_riding, and query_emit_pace futures, like the other queries.
use std::time::Duration;
use medius::Device;
let device = Device::find()?.into_async();
device.set_movement_riding(Some(Duration::from_millis(20)))?; // sync, no await
let window = device.query_movement_riding().await?; // awaits