Choosing a port
When more than one box is plugged infind grabs the first match. With more than one box, find_medius lists every match as a PortInfo (path, vid, pid) without opening, then open the chosen one.
use medius::{Device, find_medius};
let ports = find_medius();
for port in &ports {
println!("{} (vid={:#06x} pid={:#06x})", port.path, port.vid, port.pid);
}
// open a chosen one (here, the first):
let port = ports.first().ok_or(medius::Error::NotFound)?;
let dev = Device::open(&port.path)?;Threading and Clone
Share one connection across threadsDevice is Send + Sync and clones cheaply (an Arc inside), so one connection serves any number of threads; a clone bumps the reference count and doesn't reopen the port.
use std::thread;
let worker = device.clone();
let handle = thread::spawn(move || {
worker.move_rel(10, 0)
});
handle.join().unwrap()?;Running queries concurrently
join and cloning across tasksAsyncDevice clones the same way, so hand a clone to another task and await both queries together with futures::future::join.
let (v, h) = futures::future::join(
device.query_version(),
device.query_health(),
).await;
let v = v?;
let h = h?;
println!("{v}, link_up={}", h.link_up);Only the queries need .await; mutators stay synchronous on either handle.
Keepalive and holds
Holding injected input past the silence windowThe box clears every injected input and pending move once no frame arrives for its silence window. A live Device holds your overrides past that on its own: a background thread (medius-keepalive) sends a QUERY(HEALTH) every DEFAULT_KEEPALIVE_CADENCE (500 ms) while anything is held, so a press survives. There's no keepalive() to call.
| State | Behavior |
|---|---|
| Override held | Keepalive thread runs; the health reply is dropped. |
| Idle | No override held, so the thread sends nothing. |
device.press(Button::Left)?;
// No further calls. The keepalive thread sends QUERY(HEALTH) on its own,
// so the hold survives well past the 1000 ms silence window.
std::thread::sleep(std::time::Duration::from_secs(5));
device.reset()?;An override is the box holding an input down or up itself, set by press or force_release; the library keeps a copy. After a dropped link, reapply and reconnect restore it.
Releasing the device
Drop it; no close() callThere's no close: dropping the last Arc-backed handle tears the connection down. Its Drop stops the threads and closes the port.
| Step | What drop does |
|---|---|
| Signal | Sets the stop flag the reader and keepalive threads watch. |
| Join | Waits for both threads to exit, so none are left running. |
| Close | Releases the serial port as the transport drops. |
For immediate hand-off call reset before drop.
// hand the mouse back right now, not a second from now:
device.reset()?; // box returns to passthrough immediately
drop(device); // tears down threads and closes the port