Enums
Each is tied to a wire byte. Conversion helpers are listed with the type.
DeviceKind Clone's primary kind
enum DeviceKind { Unknown, Keyboard, Mouse }The kind field of a DeviceInfo, read from the native HID report descriptors and Boot declarations. A device with both kinds reads keyboard if it has a full key bitmap (unless it declares Boot for both) or declares Boot for its keyboard only. Otherwise it reads mouse. It also drives find_mouse_box and find_keyboard_box. Display prints the lowercase name.
| Variant | Byte | Meaning |
|---|---|---|
Unknown | 0 | Neither a mouse nor a keyboard (a device with no HID interface reads this), or nothing cloned: DeviceInfo::is_cloned tells them apart. |
Keyboard | 1 | A keyboard. |
Mouse | 2 | A mouse. |
ActionPress / release tri-state
enum Action { SoftRelease, Press, ForceRelease }The override action for an inject call, on any Usage class (button, key, or media). The discriminant is the wire byte. Convert with as_u8() and from_u8(u8) -> Option<Action>.
| Variant | Byte | Meaning |
|---|---|---|
SoftRelease | 0 | Drop the box's override, press or force. A hold on the real device stays down. |
Press | 1 | Force the input down. |
ForceRelease | 2 | Force the input up, masking a hold on the real device. |
The two releases differ only under a hold on the real device:
| Variant | Not held | Held on the real device |
|---|---|---|
Press | down | down |
SoftRelease | up | down (the native bit stands) |
ForceRelease | up | up (masks native) |
ClassClass of a momentary usage
enum Class { Button, Key, Media }The class byte of a Usage, shared by INJECT, LOCK, and CATCH. Convert with as_u8() and from_u8(u8) -> Option<Class>.
| Variant | Byte | Meaning |
|---|---|---|
Button | 0 | A mouse button; id is a Button id (0 = LEFT .. 4 = SIDE2). |
Key | 1 | A keyboard key; id is a HID keycode (0xE0 .. 0xE7 is a modifier). |
Media | 2 | A media usage; id is a 16-bit Consumer usage. |
CatchClass What a catch subscription addresses
enum CatchClass { Button, Key, Media, Axis, HidIn, HidOut, VendorInterrupt, VendorBulk, Control, Emit, Bus, ClipTransfer }The address space a CatchFilter picks from, and the class of a TrafficEvent. Convert with as_u8() and from_u8(u8) -> Option<CatchClass>. Split it with is_input() and is_traffic().
The first four are LOCK's classes at the same byte values. The other eight address USB traffic. TrafficClass is that half alone.
| Variant | Byte | id | Blanket |
|---|---|---|---|
Button | 0 | a Button id (0 = LEFT .. 4 = SIDE2). | every mouse button. |
Key | 1 | a HID keycode (0xE0 .. 0xE7 is a modifier). | every key and modifier. |
Media | 2 | a 16-bit Consumer usage. | every media usage. |
Axis | 3 | an Axis: X, Y, the wheel, or pan. | every axis. |
HidIn | 4 | an interface number on the real device. | every HID interface. |
HidOut | 5 | an endpoint number. | every interrupt-OUT endpoint. |
VendorInterrupt | 6 | an endpoint number. | every vendor interrupt endpoint. |
VendorBulk | 7 | an endpoint number. | every vendor bulk endpoint. |
Control | 8 | an endpoint number (0 = EP0; on EP0, the requests the clone relays to the real device). | every control endpoint. |
Emit | 9 | an endpoint number on the clone. | every emitting endpoint. |
Bus | 10 | unused; a bus event has no id. | every bus event. |
ClipTransfer | 11 | the endpoint number (0 = EP0) a clip's transfer ran on. | every control endpoint. |
A blanket is one table entry, not one per id. CatchFilter::watch_class(c) and traffic_class(c) are the per-class blankets, and CatchFilter::everything() is the wildcard over all twelve. The wire sentinels never appear in Rust.
The input classes are captured at the emission merge point, before lock suppression and injection, so a locked input still reports. Emit is the far end of the same path: what the clone emitted.
real device --> [ merge point ] --> locks --> injection --> [ clone emits ] --> game PC
| |
Button / Key / Media / Axis EmitThe traffic classes tap each pipe on the chip that owns it. Each event's ClockDomain records which.
use medius::{Button, Capture, CatchFilter, Direction, TrafficClass};
// The same target, once as a lock and once as a catch.
device.lock(Button::SIDE1, Direction::Both)?; // suppressed in the emitted report
let stream = device.catch_events([
CatchFilter::watch(Button::SIDE1).on_press(), // the tap is before suppression
])?;
// A byte-oriented class instead: one vendor interrupt endpoint, IN only, 16 bytes a packet.
let trace = device.catch_events([
CatchFilter::traffic(TrafficClass::VendorInterrupt, 0x83)
.inbound()
.with_capture(Capture::First(16)),
])?;TrafficClass Byte-oriented half of the address space
enum TrafficClass { HidIn, HidOut, VendorInterrupt, VendorBulk, Control, Emit, Bus, ClipTransfer }The eight packet-carrying classes, at their CatchClass byte values. It's a separate enum, so CatchFilter::traffic can't take an input class. TrafficClass::ALL lists them, and From and TryFrom convert both ways.
CaptureHow much of each packet to keep
enum Capture { Whole, First(u8) }Traffic classes only: a capture on an input class, which carries no packet, is refused.
It's a ceiling. The box holds one entry per address and cuts once, so another subscriber naming the same address with a wider capture raises yours too. First(0) is Whole. bytes() returns Option<u8>, and widest() resolves two captures.
InputOne decoded input edge
enum Input { Press(Usage), Release(Usage), Motion { dx: i16, dy: i16, dz: i16, pan: i16 } }What input_events yields, wrapped in an InputEvent with its timestamp. usage(), is_press(), is_release(), direction() and axes() read it without a match.
MotionRelative axis for move_axis
enum Motion { Cursor { dx: i16, dy: i16 }, Wheel(i16), Pan(i16) }What move_axis drives. Every delta spans the full i16 range. A lock names a single Axis instead.
| Variant | Payload | Meaning |
|---|---|---|
Cursor | { dx: i16, dy: i16 } | Relative pointer motion. |
Wheel | i16 | Relative scroll. |
Pan | i16 | Relative AC Pan (horizontal scroll), a full peer of the wheel. |
MoveTiming When a delta reaches the game PC
enum MoveTiming { Ride, Now }The move_axis timing argument, against movement riding. Defaults to Ride.
| Variant | Byte | Meaning |
|---|---|---|
Ride | 0x00 | When movement riding is on, wait for a native cursor-motion report to carry this delta. |
Now | 0x01 | Emit on the next mouse report, native or not, whatever movement riding is set to. |
PendingMotion What a move does to held motion
enum PendingMotion { Keep, Flush, Discard }The move_axis pending argument, for motion already held for a ride. Defaults to Keep.
| Variant | Byte | Meaning |
|---|---|---|
Keep | 0x00 | Leave held motion for its ride. |
Flush | 0x02 | Emit held motion now, ignoring the ride window (flush_motion). |
Discard | 0x04 | Drop held motion (discard_motion). |
AxisSingle relative axis
enum Axis { X, Y, Wheel, Pan }A lock_axis or LockTarget::Axis names one, with a Direction for the sign. Convert with as_u16() and from_u16().
| Variant | id | Meaning |
|---|---|---|
X | 0 | The X cursor axis. |
Y | 1 | The Y cursor axis. |
Wheel | 2 | The wheel. |
Pan | 3 | AC Pan (horizontal scroll). |
RebootTarget Which chip to restart, and how
enum RebootTarget { DeviceDownload, HostDownload, DeviceRun, HostRun }Which chip a REBOOT restarts, and into what mode. Convert with as_u8() and from_u8(u8) -> Option<RebootTarget>.
| Variant | Byte | Meaning |
|---|---|---|
DeviceDownload | 0 | Device chip into ROM download mode, ready to flash over the serial link. |
HostDownload | 1 | Host chip into ROM download mode, ready to flash over USB3. |
DeviceRun | 2 | Restart the device chip and run its firmware. |
HostRun | 3 | Restart the host chip and run its firmware. |
EmitPace What paces injected motion
enum EmitPace { Learned, Interval, Fixed(u16) }What sets the emit-rate ceiling for injected motion, passed to set_emit_pace and returned in EmitPaceStatus. It raises the ceiling only: the box still emits only while motion is pending.
| Variant | Meaning |
|---|---|
Learned | Pace to the learnt native report rate (the default). |
Interval | Pace to the cloned mouse's declared poll rate (its bInterval). |
Fixed(u16) | Pace to a fixed rate in Hz. Snaps to 1000/n and caps at 1 kHz. |
RenderMode Texture the box renders motion with
enum RenderMode { Off, Stock, Despiked, Unsmoothed }Passed to set_render and returned in RenderStatus. The box boots at Despiked, which is also this enum's Default. The model is ABCurves (MIT).
| Variant | Meaning |
|---|---|
Off | Even fill at the paced rate, no model. |
Stock | Render with the bit-exact triangular smoother. |
Despiked | Render with the smoother's onset ramped rather than stepped (the default). |
Unsmoothed | Render with no smoother. The model receives the raw injection. |
LedTarget Which chip's status LED to drive
enum LedTarget { Device, Host, Both }Which chip's LED a LED command drives. The discriminant is the wire target byte. Convert with as_u8() and from_u8(u8) -> Option<LedTarget>.
| Variant | Byte | Meaning |
|---|---|---|
Device | 0 | The device chip's LED. |
Host | 1 | The host chip's LED, relayed over the inter-chip link. |
Both | 2 | Both LEDs at once. |
LedMode What to drive the LED to
enum LedMode { Auto, Off, Solid, Blink }What a LED command drives the LED to. Auto restores the box's status display. The discriminant is the wire mode byte. Convert with as_u8() and from_u8(u8) -> Option<LedMode>.
| Variant | Byte | Meaning |
|---|---|---|
Auto | 0 | Restore the chip's status display. |
Off | 1 | LED dark. |
Solid | 2 | Lit steadily at the command's level. |
Blink | 3 | Blinks at the command's level. |
LockTarget One addressable input field: an axis or a usage
enum LockTarget { Axis(Axis), Usage(Usage) }What a lock weighs and a Transform reads and writes. The box addresses a field the same way everywhere. An Axis and any impl Into<Usage> convert Into<LockTarget>, so either passes straight in. A button locks exactly like a key.
| Variant | Payload | Locked by |
|---|---|---|
Axis | Axis: X, Y, the wheel, or pan | The sign, a Direction of positive, negative or both, or the bearing-relative With / Against. |
Usage | Usage: a button, key, or media usage | The press or release edge, a Direction. |
| Method | Returns | Meaning |
|---|---|---|
.class_id() | (u8, u16) | The wire (class, id) this field encodes to. |
LockTarget::from_class_id(class, id) | Option<LockTarget> | The inverse. None for a class no field names, or an axis id past the declared axes. |
.as_axis() | Option<Axis> | The axis this field names, or None for a momentary usage. |
LockScope What a reported lock covers
enum LockScope { Target(LockTarget), Blanket(Class) }What a LockEntry in a query_locks reply covers.
| Variant | Payload | Covers |
|---|---|---|
Target | LockTarget | A specific axis or usage. |
Blanket | Class | Every button, key, or media usage of the class. |
DirectionWhich way, which edge, or which transfer direction
enum Direction { Both, Positive, Negative, With, Against }The one byte LOCK, CLIP and CATCH all carry. The variants are named for the axis reading. The class picks which of the three readings applies, and no class carries two. Convert with as_u8() and from_u8(u8) -> Option<Direction>.
| Variant | Byte | Axis | Button or key | Traffic class |
|---|---|---|---|---|
Both | 0 | both signs; on a scale, a full pass to the relative pair | press and release | IN and OUT |
Positive | 1 | + | press | IN: device to PC |
Negative | 2 | - | release | OUT: PC to device |
With | 3 | the sign the box is injecting | refused | no meaning |
Against | 4 | the sign opposing it | refused | no meaning |
A media usage has no edges. An edge on one is sent as Both, and reads back as Both in query_locks.
With and Against are measured against the bearing, not a fixed sign, so the sign they cover follows the injection. is_relative() tells them apart. On any class but an axis, a lock or catch call refuses them with Error::RelativeDirection.
The other two readings have separate names: Direction::PRESS and RELEASE for a usage, Direction::IN and OUT for traffic. admits() tests one against another, and of_delta() reads the sign of a delta.
BearingMode How the box reads the injected direction
enum BearingMode { PerAxis, Vector }Set by set_bearing. It resolves Direction::With and Against. Convert with as_u8() and from_u8(u8) -> Option<BearingMode>.
| Variant | Byte | Meaning |
|---|---|---|
PerAxis | 0 | Each axis compares its sign against its bearing. The default. |
Vector | 1 | The native delta is projected onto the injected XY vector, and the relative scale weighs only the part along it. |
In Vector, the relative pair addresses X and Y as one vector. The box applies the lower of X's and Y's scale to both axes, so address them together with scale_all. Locks documents the readback.
The projection is the first of two stages. Each axis's Positive / Negative scale then applies to what the projection left on that axis, so it can weigh motion the projection moved there.
BlanketWhole-group lock selector
enum Blanket { Aim, Wheel, Buttons, Keys, Media }A whole input group. scale_all / lock_all weigh one in a single call, and a clip's ClipSettings auto-lock is a list of them.
| Variant | Meaning | Direction |
|---|---|---|
Aim | The X and Y cursor axes. | A sign on each axis, or the relative pair, which is how Vector mode is addressed. |
Wheel | The wheel. | A sign. |
Buttons | Every mouse button. | An edge, on each button. |
Keys | Every keyboard key and modifier. | An edge: Positive blocks presses, Negative releases, Both both. |
Media | Every media (Consumer) usage. | Nothing; media has no edges. |
LogLevel Severity tag on a log line
enum LogLevel { Error, Warn, Info, Debug, Verbose }The severity tag on a LogLine. from_u8(u8) is infallible: an unknown byte falls back to Info.
| Variant | Byte | Meaning |
|---|---|---|
Error | 0 | A failure the box could not recover from. |
Warn | 1 | Something off that the box handled. |
Info | 2 | Normal operational notices. |
Debug | 3 | Detail for diagnosing a problem. |
Verbose | 4 | The finest-grained trace output. |
CatchEvent One caught event off the stream
enum CatchEvent { Motion(MotionEvent), Usages(UsageSnapshot), Traffic(TrafficEvent) }What an EventStream yields, one variant per event frame the box sends.
| Variant | Payload | Raised by |
|---|---|---|
Motion | MotionEvent | A cursor or wheel change, from a CatchClass::Axis filter. |
Usages | UsageSnapshot | A button, key, or media change, from a Button / Key / Media filter. |
Traffic | TrafficEvent | Bytes off a pipe, from any TrafficClass filter. |
All three carry ts_us and a ClockDomain. Until the ClockEstimate is applied, a stamp compares only with another from the same domain.
One rolling seq counter covers all three frame types. It counts what the box sent, not what it captured, so loss shows in CatchState, not as a seq gap.
use medius::{CatchEvent, CatchFilter};
let stream = device.catch_events([CatchFilter::everything()])?;
match stream.recv()? {
CatchEvent::Motion(m) => println!("{} {} {}", m.dx, m.dy, m.dz),
CatchEvent::Usages(s) => println!("{} held", s.usages.len()),
CatchEvent::Traffic(t) => println!("{:?} 0x{:04X}: {} bytes", t.class, t.id, t.true_len),
}ClockDomain Which chip stamped the event
enum ClockDomain { HostChip, DeviceChip }The clock field beside every event's ts_us. The box runs two unsynchronised microsecond timers. The chip that captured the event stamps it. Convert with as_u8() and from_u8(u8) -> Option<ClockDomain>.
| Variant | Byte | Stamped |
|---|---|---|
HostChip | 0 | On the host chip, in USB interrupt context, when the real device's transfer completed. |
DeviceChip | 1 | On the device chip, at the tap. |
| Domain | Classes stamped there |
|---|---|
HostChip | the input classes (raising Motion and Usages), HidIn, and native IN traffic on the vendor classes. |
DeviceChip | HidOut, the OUT direction of both vendor classes, a raw packet on a vendor IN endpoint, and Control / Emit / Bus / ClipTransfer. |
Both timers are box-local, unrelated to any clock on this machine. They wrap every ~71.6 minutes (a u32 of microseconds) and restart at zero when their chip reboots.
A stamp lower than the one before it means a wrap, a reboot, or a domain change. Only the domain change shows in the value itself. To put both domains on one timeline, apply the ClockEstimate from query_catch.
ControlStatus Handshake the game PC received
enum ControlStatus { Ok, Stalled, Naked, Other(u8) }Read it with TrafficEvent::control_status(), which returns None for any class other than Control. It is flags bits 0-1. Bit 7 is rule_acted().
| Variant | flags b0-b1 | Meaning |
|---|---|---|
Ok | 0 | The transaction completed. |
Stalled | 1 | The PC got a STALL: from the real device, from a rule that refused the request, or, above endpoint 0, for a request that failed. |
Naked | 2 | NAKed until the host gave up, on endpoint 0 only: the real device never replied, or a Nak rule. |
Other(u8) | 3 | A handshake value with no variant in this build, carried verbatim. |
BusEvent What happened on the USB bus
enum BusEvent { Reset, Suspend, Resume, Configured(u8), Deconfigured,
SetInterface { interface: u8, alt: u8 },
DeviceAttached, DeviceDetached, CloneUp, CloneDown }The kind of a CatchClass::Bus event. Read it with TrafficEvent::bus_event(), which returns Option<BusEvent>: None for a kind byte this build does not name. The two kinds with operands parse them into named fields.
| Variant | Byte | Operands | Meaning |
|---|---|---|---|
Reset | 0 | - | The game PC reset the clone's bus. |
Suspend | 1 | - | The bus went idle and the PC suspended the clone. The box suspends the real device with it. |
Resume | 2 | - | The bus came back, and the box resumes the real device with it. |
Configured | 3 | a = configuration index | The PC selected a configuration. The clone is live. |
Deconfigured | 4 | - | The PC dropped the clone back to configuration 0. |
SetInterface | 5 | a = interface, b = alternate setting | The PC switched an interface's alternate setting. |
DeviceAttached | 6 | - | The real device appeared on the host chip. |
DeviceDetached | 7 | - | The real device went away. |
CloneUp | 8 | - | The box started presenting the clone to the game PC. |
CloneDown | 9 | - | The box stopped presenting it. |
DeviceAttached and DeviceDetached are the real device on USB3. The other eight are on the clone's USB1 bus, which the control PC isn't on.
use medius::{BusEvent, CatchEvent, CatchFilter, TrafficClass};
let stream = device.catch_events([CatchFilter::traffic_class(TrafficClass::Bus)])?;
if let CatchEvent::Traffic(t) = stream.recv()? {
match t.bus_event() {
Some(BusEvent::Configured(n)) => println!("configuration {n}"),
Some(BusEvent::SetInterface { interface, alt }) => println!("iface {interface} alt {alt}"),
Some(kind) => println!("{kind:?}"),
None => {}
}
}TransformOp What a transform does to its fields
enum TransformOp { Remap, Swap }How a Transform's source and destination relate. as_u8() and from_u8() convert the wire byte. admits(source, dest) checks a pair, as the crate does before sending.
| Variant | Byte | Fields it admits | Effect |
|---|---|---|---|
Remap | 0 | axis→axis, button→button, button→key, button→media | Move the source's value into the destination, clearing the source. A button to key or media remap holds the destination through that interface's report for as long as the button is down. |
Swap | 1 | two axes | Read both, then write both, so it is not two remaps. |
admits refuses a pair whose source and destination are the same field. To weigh a field, or reverse it, use scale.
ClipState Clip lifecycle state
enum ClipState { Idle, Playing, Paused, Faulted }The box's clip state on ClipStatus::state, from ClipHandle::query_status().
| Variant | Byte | Meaning |
|---|---|---|
Idle | 0 | No clip playing (empty, or a loaded clip parked at its start). |
Playing | 1 | Draining the ring, one entry per native frame. |
Paused | 2 | Held mid-clip, keeping the cursor and any held input. Resumes from the same spot. |
Faulted | 3 | An append was dropped or the ring overflowed. Recover with clear. |
EdgeWhich edge fires a clip trigger
enum Edge { Both, Press, Release }Which edge of a bound usage fires a ClipTrigger. Shares wire values with Direction.
| Variant | Byte | Meaning |
|---|---|---|
Both | 0 | Fire on either edge. |
Press | 1 | Fire on the press edge. |
Release | 2 | Fire on the release edge. |
ClipAction What a fired clip trigger does
enum ClipAction { Start, Stop, Pause, Resume, Restart, Toggle }What a bound ClipTrigger or ClipPacketTrigger does to the clip when it fires. The discriminant doubles as the CLIP_CTRL op byte for the same action.
| Variant | Byte | Meaning |
|---|---|---|
Start | 0 | Play from the ring's head, or resume a pause. |
Stop | 1 | Stop playback and rewind to the head. |
Pause | 2 | Hold playback mid-clip. |
Resume | 3 | Continue a paused clip from where it stopped. |
Restart | 4 | Rewind to the head and play from the start. |
Toggle | 5 | Play if idle or paused, stop if playing. |
UpdateTarget Which chip an update op addresses
enum UpdateTarget { Device, Host }| Variant | Byte | Meaning |
|---|---|---|
Device | 0 | The PC-facing chip, written directly over the control port. |
Host | 1 | The chip that reads the real device, relayed over the inter-chip link. |
ImageState Where a booted image is in its probation
enum ImageState { New, PendingVerify, Valid, Invalid, Aborted, Unknown }The bootloader's record for a slot. See rollback.
| Variant | Byte | Meaning |
|---|---|---|
New | 0 | Selected but not yet booted. |
PendingVerify | 1 | Booted and on probation. Rollback is still possible. |
Valid | 2 | Confirmed by the image itself. |
Invalid | 3 | The image asked to be rolled back. |
Aborted | 4 | Booted once and never confirmed. |
Unknown | 0xFF | No entry for this slot. |
TransferStatus How a control transfer ended
enum TransferStatus { Ok, Refused, Stall, Nak, NoDevice, Other(u8) }The status byte of a TransferOutcome, and of a ClipTransfer event through TrafficEvent::transfer_status(). The codes sit at the top of the byte range so they never collide with a length. An unknown byte is carried through as Other.
| Variant | Byte | Meaning |
|---|---|---|
Ok | 0x00 | The transfer completed; any IN data is in data. |
Refused | 0xFC | The box refused before reaching the real device: the opt-in is off, the request was malformed, wLength was >504 or the OUT data shorter than it, or the host chip's control queue was full. |
Stall | 0xFD | The real device STALLed the request. |
Nak | 0xFE | The real device didn't finish within 500 ms, the transfer failed on the bus, the endpoint is undeclared, no reply crossed the link within 800 ms, or the game PC has the clone (and so the real device) suspended. |
NoDevice | 0xFF | No real device is attached on the host chip. |
Other(u8) | any other | A status byte this build does not name. |
Refused comes from the box, before the real device. Stall comes from the real device. Nak can be either: a real device that did not finish, or a request with no reply (native TRANSFER_RESP).
use medius::TransferStatus;
match reply.status {
TransferStatus::Ok => println!("{} bytes", reply.data().len()),
TransferStatus::Stall => println!("device rejected the request"),
TransferStatus::NoDevice => println!("nothing attached on the host chip"),
TransferStatus::Refused => println!("box refused it: opt-in off, malformed, too large, or queue full"),
other => println!("other status: {other:?}"),
}RewriteClass Which traffic a rewrite rule addresses
enum RewriteClass { HidIn, HidOut, VendorInterrupt, VendorBulk, Control, Emit, Any }The class picks the traffic a RewriteRule addresses, and the id picks the address within it. Together they are the writable half of catch's address space.
| Variant | Byte | Traffic | id |
|---|---|---|---|
HidIn | 4 | A native HID report, as it arrived; see motion. | the interface number |
HidOut | 5 | A report the PC writes to the real device. | the endpoint number |
VendorInterrupt | 6 | Interrupt traffic on a vendor interface. | the endpoint number |
VendorBulk | 7 | Bulk traffic on a vendor interface. | the endpoint number |
Control | 8 | A proxied control transfer, and the only class that may answer or rewrite the native reply. On EP0, it covers the requests the clone relays to the real device (class and vendor ones, and a few standard ones). A control endpoint above 0 carries every request. | the endpoint number (0 = EP0) |
Emit | 9 | What the clone emits, after the renderer: injected and rendered frames as well as relayed ones. | the endpoint number |
Any | 0xFF | Every surface a packet crosses, so a report meets the rule at HidIn and again at Emit. Pass, Patch and Replace only, ranked below every other class. | ignored |
The parsed-input and bus classes are not rewritable. as_u8() and from_u8() convert the wire byte.
RewriteAction What the top-ranked rewrite rule does
enum RewriteAction { Pass, Drop, Patch, Replace, Answer, Stall, Nak, ReplyPatch, ReplyReplace }The top-ranked rule's action sets what happens to a matched packet. The class column says which RewriteClass accepts the action. A report-only action on a control class, or the reverse, returns Error::RewriteActionClass.
| Variant | Byte | Class | Payload | Effect |
|---|---|---|---|---|
Pass | 0 | any | no | Matched, but left untouched: a shadow over a broader rule. |
Drop | 1 | report | no | Not delivered. An Emit drop emits nothing; a HidIn drop removes the native report while injection still emits. |
Patch | 2 | any | yes | Overwrite the payload bytes at offset, length preserved. On Control, an OUT request's data stage only. |
Replace | 3 | any | yes | The packet becomes the payload. On Control, the payload overwrites the start of an OUT request's data stage and wLength is kept. |
Answer | 4 | control | yes | Answer from the payload without forwarding the request to the real device. |
Stall | 5 | control | no | Protocol STALL. |
Nak | 6 | control | no | EP0 NAKs until the host times out. A control endpoint above 0 STALLs. |
ReplyPatch | 7 | control | yes | Overwrite the native reply at offset. |
ReplyReplace | 8 | control | yes | Replace the native reply with the payload. |
PatchSection Which descriptor a patch overwrites
enum PatchSection { Device, Config, Report, String, Bos }The section names the descriptor a Patch overwrites, and that patch's cfg and index address within it.
| Variant | Byte | Overwrites | cfg / index |
|---|---|---|---|
Device | 0 | The 18-byte device descriptor. | ignored |
Config | 1 | A configuration descriptor. | cfg is the configuration index, counting from 0 |
Report | 2 | An interface's report descriptor. | cfg is that index, index the interface number |
String | 3 | A string descriptor, replaced whole: ≤126 bytes, one UTF-16 code unit per byte. Index 0, the language list, is not patched. | index is the string index; offset ignored |
Bos | 4 | The BOS descriptor. | ignored |