Quickstart
The box sits between a USB device and a PC. It clones the device and relays its reports. A program injects over a USB-serial link: cursor and buttons for a mouse, keys and media for a keyboard.
The box speaks in frames, fixed-shape packets of one command each. Most are fire-and-forget, with no reply. QUERY gets one.
WiringSafe 3-port layout
USB1(clone) → game PCUSB2(control) → control PCUSB3(mouse) → real mouse
The clone copies the mouse's USB identity, so the game PC enumerates the same device as on a direct connection.
Never connect USB1 and USB3 to the same machine. The USB3 5V rail can't be pulled low in firmware, so the pair back-feeds power. Back-fed power can force a shutdown and drain the battery.
Open the link Fixed baud, binary
Open /dev/ttyACM0 (Linux) or COMx (Windows) at 6,000,000 baud, 8N1, and send binary immediately. No 115200 handshake or baud-switch frame.
RESP carries the box's replies. To read the protocol version (handshake):
- On first contact the box sends one unsolicited
RESP(VERSION)withSEQ0, the ready signal. Or sendQUERY(VERSION). - Read
proto_ver, the one-byte protocol version, from theVERSIONpayload. - Check
proto_ver == 9before trusting the commands here.
Send a MOVE Relative cursor movement
MOVE moves the PC's cursor.
SEQis a caller-chosen number, incremented per frame. AQUERY'sRESPechoes it. This example uses0.CRC16lets the box reject a corrupted frame: CRC16-CCITT (polynomial0x1021, initial value0xFFFF) overTYPE | SEQ | LEN | PAYLOAD, stored little-endian.
import struct
def crc16_ccitt(data):
crc = 0xFFFF
for b in data:
crc ^= b << 8
for _ in range(8):
crc = (crc << 1) ^ 0x1021 if crc & 0x8000 else crc << 1
crc &= 0xFFFF
return crc
def encode(type, seq, payload):
head = bytes([type, seq]) + struct.pack('<H', len(payload)) + payload
return bytes([0xA5]) + head + struct.pack('<H', crc16_ccitt(head))
frame = encode(0x01, 0, struct.pack('<BhhB', 0, 100, 0, 0))
port.write(frame)MOVE is opcode 0x01. Payload: a motion byte (0 = cursor), signed 16-bit dx then dy, and a flags byte (0 for a plain move). +x is right, +y is down. The example moves 100 right, 0 down.
That builds A5 01 00 06 00 00 64 00 00 00 00 <crc>.
ConfirmCheck the chain before injecting
Injection is input added on top of native input. Before relying on it, send QUERY(HEALTH) and check these bits in the RESP's flags word.
| Flag | Mask | Means |
|---|---|---|
LINK_UP | 0x01 | Host-chip link is up. |
MOUSE_ATTACHED | 0x02 | A mouse is on USB3. |
CLONE_CONFIGURED | 0x04 | The game PC has enumerated the clone. |
A flag is set when (flags & mask) is non-zero. With all three set, a MOVE reaches the game PC.
Rust library
Ready-made client: cargo add medius (library).