Move
Cursor motion and scrollMOVE drives a relative Axis: the cursor pair (X and Y together) or the wheel, picked by a motion byte. It injects on top of the real mouse, so the emitted report carries both, and it's fire-and-forget.
The momentary inputs (buttons, keys, media) have their own verb, INJECT.
| motion | Axis | carries | payload |
|---|---|---|---|
0 | cursor (X, Y) | dx, dy (i16) | 6 bytes |
1 | wheel | dz (i16) | 4 bytes |
MOVE
Relative axis injectionMOVE shifts an axis by a relative amount, not a screen position. Opcode 0x01.
MOVE 0x01 · cursor payload 6 bytes
Fire-and-forget
| Offset | Field | Type | Notes |
|---|---|---|---|
| 0 | motion | u8 | 0 = cursor |
| 1 | dx | i16 | horizontal step; +x = right, little-endian |
| 3 | dy | i16 | vertical step; +y = down, little-endian |
| 5 | flags | u8 | the riding override, 0 for an ordinary move |
exact net move = the sum of every delta you send range full i16 per axis, no clamp signs +x right, +y down (screen-style), +z wheel up paced a large move drains across frames; nothing is dropped
The box carries any remainder in its accumulator; RESET zeroes it. Library binding: move_rel.
Cursor dx = 100, dy = 0 (motion = 0):
+--------+--------+--------+--------+--------+--------+--------+--------+--------+ | A5 | 01 | 00 | 06 00 | 00 | 64 00 | 00 00 | 00 | lo hi | +--------+--------+--------+--------+--------+--------+--------+--------+--------+ | SOF | TYPE | SEQ | LEN | motion | dx | dy | flags | CRC16 | +--------+--------+--------+--------+--------+--------+--------+--------+--------+
MOVE (wheel)
Vertical scrollWith motion = 1, MOVE scrolls the wheel by a relative amount.
MOVE 0x01 · wheel payload 4 bytes
Fire-and-forget
| Offset | Field | Type | Notes |
|---|---|---|---|
| 0 | motion | u8 | 1 = wheel |
| 1 | dz | i16 | scroll steps; + = up, - = down, little-endian |
| 3 | flags | u8 | the riding override, 0 for an ordinary move |
The box adds dz into its accumulator and drains it across frames with carry, no clamp. RESET clears it. Library binding: wheel.
Wheel dz = 1, one step up (motion = 1):
+--------+--------+--------+--------+--------+--------+--------+--------+ | A5 | 01 | 00 | 04 00 | 01 | 01 00 | 00 | lo hi | +--------+--------+--------+--------+--------+--------+--------+--------+ | SOF | TYPE | SEQ | LEN | motion | dz | flags | CRC16 | +--------+--------+--------+--------+--------+--------+--------+--------+
MOVE flags
Per-command movement-riding overrideThe flags byte overrides movement riding for this one command.
MOVE 0x01 · flags at offset 5 (cursor) / 3 (wheel)
| Bit | Name | Effect |
|---|---|---|
0x01 | NOW | This delta emits on the box's own clock instead of waiting for a native cursor-motion report to carry it. |
0x02 | FLUSH | Emit the motion already held for a ride, ignoring the ride window. |
0x04 | DISCARD | Drop the motion already held for a ride. |
Applied discard, then flush, then the delta; FLUSH and DISCARD together refuse the frame. Injected motion lands in one of two accumulators, so a bypassing delta never carries the held one out with it. Library bindings: move_rel_now, flush_motion, discard_motion.
Send the held motion now, with no delta of its own (flags = 0x02):
+--------+--------+--------+--------+--------+--------+--------+--------+--------+ | A5 | 01 | 00 | 06 00 | 00 | 00 00 | 00 00 | 02 | lo hi | +--------+--------+--------+--------+--------+--------+--------+--------+--------+ | SOF | TYPE | SEQ | LEN | motion | dx | dy | flags | CRC16 | +--------+--------+--------+--------+--------+--------+--------+--------+--------+