USB HID Passthrough & KMBox Serial Interface for RP2350
A high-performance dual-role USB HID firmware that creates a transparent USB passthrough device while providing KMBox-compatible serial control for mouse and keyboard automation with advanced humanization and optional visual feedback via ILI9341 display.
Mouse/Keyboard βββΊ [RP2350 Board 1] βββΊ PC
β² UART (crossed)
βΌ
[RP2350 Board 2] βββΊ ILI9341 TFT Display
β²
β USB CDC
[PC Tool / Script]
- Overview
- Key Features
- Hardware Requirements
- Quick Start
- Using KMBox Commands
- Movement Humanization
- KMBox Bridge β Visual Feedback & Autopilot
- Architecture
- Status Indicators
- Development
- Performance Metrics
- Troubleshooting
- Contributing
- License
- Acknowledgments
PIOKMbox turns an RP2350 board into a transparent man-in-the-middle USB HID device. Your PC sees the original mouse or keyboard β not the microcontroller β while serial commands let you inject precise, humanized input alongside physical devices.
| Capability | Description |
|---|---|
| USB Passthrough | Mirrors the connected device's VID/PID, manufacturer, and product name. The PC never sees the RP2350. |
| Serial Control | Accepts KMBox, Macku binary, and Ferrum-compatible commands over UART to inject mouse movements, clicks, and keyboard input. |
| Humanization | Movement-aware jitter, velocity suppression, overshoot simulation, and Bezier easing β all configurable across four intensity levels. |
| Visual Feedback | Optional ILI9341 TFT display shows real-time latency graphs, connection status, and thermal metrics. |
Thermal note: This firmware runs at 240 MHz+ for optimal performance. Monitor temperature during extended sessions, especially with the TFT display enabled.
- Transparent USB Passthrough β PC sees the original device, not the RP2350
- KMBox Protocol Compatibility β works with existing KMBox B+, Ferrum, and Macku tools
- Dual-Core Architecture β dedicated cores for USB host and device operations
- Movement Humanization β 4 configurable modes (OFF / LOW / MEDIUM / HIGH) with adaptive jitter
- Low Latency β < 50 Β΅s binary protocol, < 100 Β΅s text commands
- Hardware Watchdog β automatic recovery from USB stack failures
- Visual Status β NeoPixel RGB feedback and optional ILI9341 TFT display
- Xbox Controller Support β GIP protocol passthrough
Dual Adafruit Metro RP2350 + ILI9341 Display
| Item | Detail |
|---|---|
| Board | Adafruit Metro RP2350 |
| Role | USB HID passthrough + KMBox command execution |
| USB-A | Physical mouse or keyboard |
| USB-C | To PC (appears as the passthrough device) |
| UART | TX/RX to Board 2 (crossed), shared GND |
| Item | Detail |
|---|---|
| Board | Adafruit Metro RP2350 |
| Role | Computer vision tracking + ILI9341 display driver |
| USB-C | To PC (for serial input commands) |
| UART | TX/RX to Board 1 (crossed), shared GND |
| SPI | ILI9341 display + optional touch controller |
| Spec | Value |
|---|---|
| Resolution | 320 x 240 |
| Interface | SPI (hardware accelerated) |
| Features | Real-time latency graphs, status display, touch support |
UART wires must be crossed between boards.
Board 1 (Proxy) Board 2 (Bridge)
TX ββββββββββββββββββΊ RX
RX ββββββββββββββββββ TX
GND ββββββββββββββββββΊ GND
- USB bus powered (5 V)
- Typical draw: 150β300 mA (varies with display)
- TFT display adds ~80β150 mA
- No external power supply required
git clone --recursive https://github.com/ramseymcgrath/RaspberryKMBox.git
cd RaspberryKMBox
# If you already cloned without --recursive:
git submodule update --init --recursive
# Build options:
./build.sh metro # Main KMBox for Metro RP2350
./build.sh bridge-metro # Bridge for Metro RP2350 with display
./build.sh dual-metro # Build both targets
./build.sh all # Build all configurations| Board | Steps |
|---|---|
| Board 1 (USB Proxy) | Hold BOOTSEL while connecting USB-C to PC. Drag build-metro/PIOKMbox.uf2 to the mounted RP2350 drive. |
| Board 2 (Bridge) | Hold BOOTSEL while connecting USB-C to PC. Drag bridge/build-metro/kmbox_bridge.uf2 to the mounted RP2350 drive. |
Both boards reboot automatically after flashing.
Connect UART crossed (TXβRX, RXβTX) with a shared GND. See Serial Wire Configuration above.
For display wiring, see bridge/README.md.
- Mouse / Keyboard β Board 1 USB-A port
- Board 1 USB-C β PC (passthrough device)
- Board 2 USB-C β PC (serial input commands)
- NeoPixel changes color based on connected devices (see Status Indicators)
- Mouse / Keyboard should work normally through the PC
- Display shows connection status and latency (if bridge installed)
- Serial β Board 1 accepts KMBox commands via UART
| Parameter | Value |
|---|---|
| Interface | UART (hardware serial, crossed between boards) |
| Baud Rate | 115200 (configurable; speeds are uncapped in USB CDC mode) |
| Protocol | KMBox-compatible text and binary commands |
km.move(100, 50) # Relative mouse move (+X right, +Y down)
km.left(1) # Press left button
km.left(0) # Release left button
km.click(0) # Left click (0=left, 1=right, 2=middle)
km.wheel(5) # Scroll up (negative = down)
km.lock_mx(1) # Lock X axis (ignore physical mouse X)
km.lock_my(1) # Lock Y axis (ignore physical mouse Y)
km.unlock_mx() # Unlock X axis
km.unlock_my() # Unlock Y axis
For ultra-low latency (< 50 Β΅s), use 8-byte binary packets:
# Fast mouse move (0x01 command)
packet = bytes([0x01, x_lo, x_hi, y_lo, y_hi, buttons, wheel, 0x00])
serial.write(packet)- Bypasses text parsing for minimal latency
- Fixed 8-byte packets for predictable timing
- Supports 1000+ commands/sec
Real-time button state queries for automation:
km.monitor(1) # Enable monitoring
km.isdown_left() # Query left button (returns 0 or 1)
km.isdown_right() # Query right button
km.isdown_middle() # Query middle button
km.isdown_side1() # Query side button 1
km.isdown_side2() # Query side button 2
km.monitor(0) # Disable monitoring
Fully compatible with KMBox B+, Ferrum, and Macku protocols:
| Feature | Status |
|---|---|
| Mouse control (movement, buttons, scroll) | Supported |
| Axis locking (X/Y movement, button masking) | Supported |
| Monitor mode (real-time button state) | Supported |
| Fast binary protocol (< 50 Β΅s) | Supported |
| Smooth injection (velocity matching) | Supported |
| Movement humanization (Bezier easing) | Supported |
An advanced anti-detection system that simulates natural human mouse movement through adaptive jitter, velocity suppression, and overshoot simulation. All features are hardware-accelerated with < 10 cycle overhead per pixel.
Movement-Aware Scaling β intensity adapts to movement distance:
| Distance | Jitter Scale | Behavior |
|---|---|---|
| 0β20 px | 0.7β0.8x | Simulates hand tremor during precise positioning |
| 20β60 px | 0.3β0.7x | Balances precision and speed |
| 60β110 px | 0.1β0.3x | Reduced jitter for intentional movements |
| 110+ px | 0.05β0.09x | Minimal jitter β keeps fast flicks snappy |
Velocity-Based Suppression β jitter fades as movement slows, preventing a "shaky" cursor after motion completes. Mimics natural hand settling.
Physical Input Protection β humanization applies only to synthetic injections. Physical mouse and keyboard input passes through untouched.
Control via button press (GPIO 7) or serial command:
| Mode | Jitter | Overshoot | Onset Delay | Use Case |
|---|---|---|---|---|
| OFF | None | Disabled | None | Testing, maximum precision |
| LOW | Β± 0.06 px | Disabled | 0β1 frames | Competitive gaming, fast reactions |
| MEDIUM | Β± 0.17 px | 5% chance | 1β3 frames | Default β general use |
| HIGH | Β± 0.33 px | 10% chance | 2β6 frames | Maximum stealth |
Detailed mode parameters
OFF β Linear movement, no variations. Max 16 px/frame (fixed). Best for testing and high-speed automation.
LOW β Barely perceptible jitter at sensor noise floor. Β± 1% delivery error. Max 15β17 px/frame (randomized per session). Accumulator clamp: Β± 4 px.
MEDIUM (Default) β Matches physical mouse sensor noise (~Β± 0.17 px). Β± 2% delivery error. Max 13β19 px/frame (randomized per session). 5% overshoot chance on 15β120 px moves (max 0.5 px). Accumulator clamp: Β± 3 px.
HIGH β Upper bound of sensor noise (~Β± 0.33 px). Β± 3% delivery error. Max 10β22 px/frame (randomized per session). 10% overshoot chance on 15β120 px moves (max 1.0 px). Accumulator clamp: Β± 2 px (tightest).
| Technique | Description |
|---|---|
| Bezier Easing | Cubic ease-in-out for large movements; quadratic ease-out for quick corrections. Auto-selected by movement characteristics. |
| Micro-Jitter | Β± 1β2 px hand tremor simulation. Context-aware (more during mid-movement). 40% chance per frame. |
| Overshoot & Correction | 5β10% chance to overshoot by 0.5β1.0 px, smoothly corrected over 2β4 frames. Only on moves > 15 px. |
| Per-Session Randomization | Base parameters vary on init. Β± 1 px per move, Β± 1 frame for moves > 3 frames. Prevents statistical fingerprinting. |
| Action | Result |
|---|---|
| Short press (< 3 s) | Cycle humanization mode. LED: Red β Yellow β Green β Cyan |
| Long press (>= 3 s) | Reset USB stacks |
For full technical details, see HUMANIZATION.md.
An optional companion firmware for a second Adafruit Metro RP2350 with an ILI9341 TFT display. Provides real-time visual feedback and computer vision-based autopilot capabilities.
ββββββββββββ USB CDC βββββββββββββββββββββ UART (crossed) ββββββββββββββββ
β PC Tool βββββββββββββΊβ Metro RP2350 βββββββββββββββββββΊβ KMBox Metro β
β (input) β β (Bridge/Display) β β (USB Proxy) β
ββββββββββββ βββββββββββββββββββββ ββββββββββββββββ
β
βββ ILI9341 TFT (SPI)
βββ Touch Controller (optional)
| Feature | Description |
|---|---|
| ILI9341 Display | 320 x 240 real-time status, latency graphs, connection indicators |
| USB CDC Interface | Receives serial commands from PC for tracking and automation |
| Color Tracking | Hardware-accelerated blob detection and centroid calculation |
| UART Relay | Bidirectional serial between bridge and main KMBox |
| Touch Support | Optional XPT2046 / FT6206 for interactive controls |
| Temperature Monitoring | Real-time thermal tracking with visual gauges |
./build.sh dual-metroβ builds both boards- Wire UART crossed (TXβRX, RXβTX) + GND between boards
- Connect ILI9341 to Bridge Metro SPI pins (see
bridge/README.md) - Flash Board 1:
build-metro/PIOKMbox.uf2 - Flash Board 2:
bridge/build-metro/kmbox_bridge.uf2
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β RP2350 β
β β
β βββββββββββββββββββ βββββββββββββββββββββββ β
β β Core 0 β β Core 1 β β
β β β β β β
β β TinyUSB Device β β TinyUSB Host β β
β β (HID β PC) β β (PIO-USB β Mouse) β β
β β KMBox Parser β β Report Forwarding β β
β β Smooth Inject β β VID/PID Caching β β
β βββββββββββββββββββ βββββββββββββββββββββββ β
β β² β β
β βββββ Shared Memory ββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
- Core 1 runs TinyUSB host on PIO-USB to communicate with your physical mouse/keyboard
- Firmware reads HID report descriptors and caches VID/PID/strings from attached devices
- Core 0 exposes a TinyUSB HID device to the PC, mirroring the attached device's identity
- On VID/PID change, the device re-enumerates to reflect the new identity
- Physical HID input and KMBox serial commands are combined with intelligent axis locking
- Transparent Identity β PC sees original mouse/keyboard, not the RP2350
- Report Mirroring β all HID reports forwarded with < 1 ms latency
- Dynamic Re-enumeration β automatically adapts when devices change
- String Descriptors β manufacturer and product names mirrored
- Dual Input β physical and synthetic input coexist seamlessly
- Axis Locking β selective X/Y/button filtering for precise control
- Smooth Injection β velocity-matched movement with frame-perfect timing
- Priority Handling β physical input takes priority; synthetic fills gaps
| Color | State |
|---|---|
| Blue | Starting up |
| Green | USB device only |
| Orange | USB host only |
| Cyan | Both USB stacks active |
| Magenta | Mouse connected |
| Yellow | Keyboard connected |
| Pink | Mouse + keyboard connected |
| Red | Error state |
| Purple | Suspended |
| Color | Mode |
|---|---|
| Red | OFF (no humanization) |
| Yellow | LOW (minimal) |
| Green | MEDIUM (default) |
| Cyan | HIGH (maximum) |
| Pattern | Meaning |
|---|---|
| Fast blink | Device connected / active |
| Slow blink | Device suspended or error |
| Solid | Normal operation |
RaspberryKMBox/
βββ PIOKMbox.c # Main firmware β core orchestration
βββ usb_hid.* # HID device/host, VID/PID mirroring
βββ kmbox_serial_handler.* # KMBox UART command integration
βββ smooth_injection.* # Humanized movement engine
βββ humanization_lut.* # Precomputed jitter lookup tables
βββ led_control.* # LED & WS2812 NeoPixel control
βββ watchdog.* # Hardware/software watchdog
βββ bridge_handler.* # Bridge communication protocol
βββ xbox_device.*, xbox_host.*# Xbox controller passthrough
βββ ws2812.pio # PIO program for NeoPixel
βββ defines.h, config.h # Configuration and pin definitions
βββ lib/
β βββ Pico-PIO-USB/ # PIO USB library (submodule)
β βββ kmbox-commands/ # KMBox command parser
β βββ fast-protocol/ # Binary protocol definitions
β βββ wire-protocol/ # Wire format utilities
β βββ dma-uart/ # DMA-accelerated UART
β βββ led-utils/ # LED control abstractions
βββ bridge/ # Bridge firmware
β βββ main.c # Bridge entry point
β βββ ili9341.c # ILI9341 TFT display driver
β βββ latency_tracker.* # Performance monitoring
β βββ core1_translator.* # CV processing
β βββ bridge_client.py # Python control client
β βββ ferrum_translator.c # Ferrum protocol support
βββ tools/ # Development utilities
β βββ generate_lut.py # Generate humanization tables
β βββ kmbox_stress_test.py # Stress testing
β βββ logitech_hid_dump.py # HID device analysis
βββ boards/ # Board definitions
β βββ adafruit_metro_rp2350.h
βββ build.sh # Multi-target build script
βββ CMakeLists.txt # Build configuration
./build.sh pico2 # RP2350 (Pico 2)
./build.sh metro # Metro RP2350 (main KMBox)
./build.sh bridge # Bridge (XIAO RP2350)
./build.sh bridge-metro # Bridge (Metro RP2350)
./build.sh dual-metro # Both Metro boards
./build.sh all # All configurationsAppend clean to force a rebuild: ./build.sh all clean
These checks need Python 3 and a C compiler with address and undefined-behavior sanitizers. They run production functions against mocked peripherals; they do not replace firmware builds or testing on the boards.
python3 tests/test_xbox_transfers.py
python3 tests/test_bridge_parsers.py
python3 tests/test_uart_timing.py
python3 tests/test_display_io.py
python3 tests/test_bridge_protocol.py
python3 tests/test_proxy_tx.py
python3 tests/test_proxy_rx.py
python3 tests/test_dma_rx.pyBuild and flash the bridge and proxy from the same revision. Both bridge targets
use eight-byte fast packets. Humanization configuration uses opcode 0x10, and
info requests use 0x11 to avoid the carriage-return opcode 0x0D; info replies
retain 0x0D. The variable-length wire-protocol library is not the proxy's UART
parser and must not be mixed into that stream.
The default software TFT path advances refreshes one DMA row per main-loop pass.
Rendering runs in the main loop, while the timer interrupt only schedules it.
The optional TFT_HW_ACCEL path and explicit splash/error refreshes remain
synchronous.
The proxy's protocol UART has stdio disabled. Command replies use an explicit
output callback into a shared record queue; debug printf calls do not write
onto that UART. The queue supports seven pending records of up to 256 bytes,
including any CRLF suffix. A full queue rejects whole records and accounts for
their bytes in kmbox_get_tx_dropped_bytes(). Startup and DMA-allocation failure
use polled RX and IRQ TX, preserving pending data when DMA starts.
DMA RX on both boards uses RP2350 self-trigger mode with a decrementing count, so complete ring-buffer laps cannot appear empty. Copies are checked against a second coherent count/address snapshot before delivery. A loss discards pending input and partial parser state; the proxy also releases injected controls and cancels queued/timed movement. Reception resumes after at least 1 ms without DMA progress and an empty UART FIFO. The sender must provide that gap at a packet boundary; continuous traffic is discarded during recovery.
The bridge exposes overrun events through hw_uart_get_stats() and discarded
bytes/ambiguous polls through hw_uart_get_rx_loss_stats(). The proxy exposes
all three through kmbox_get_rx_loss_stats() on Core 0. If a scheduling pause
could hide an entire hardware count period, reception fails closed and the byte
count is a lower bound. These counters describe discarded data, not retransmission
or flow control. No additional DMA channels or RX interrupts are required.
Presets defined in defines.h:
| Preset | Description |
|---|---|
BUILD_CONFIG_DEVELOPMENT |
Default β verbose logging |
BUILD_CONFIG_PRODUCTION |
Optimized, minimal logging |
BUILD_CONFIG_TESTING |
Extended diagnostics |
BUILD_CONFIG_DEBUG |
Full debug symbols |
| Target | Frequency | Notes |
|---|---|---|
| Main KMBox (RP2350) | 300 MHz | Optimized for PIO-USB |
| Bridge | 280 MHz | Balanced for display + UART |
- Pico SDK 2.2.0+
- CMake 3.13+
arm-none-eabi-gcc14.2+- Git (for submodules)
Typical results on Metro RP2350 @ 300 MHz:
| Operation | Latency | Notes |
|---|---|---|
| USB passthrough | < 1 ms | Report forwarding |
| Text command | < 100 Β΅s | Parsing + execution |
| Binary command | < 50 Β΅s | Direct execution |
| Humanization overhead | < 10 cycles | Per-pixel calculation |
| Display update | 16β33 ms | 30β60 FPS typical |
| UART transmission | 87 Β΅s | 8 bytes @ 115200 baud |
USB Issues
Device not recognized:
- Verify 5 V power to USB host port
- Check D+/D- wiring (GPIO 16/17)
- Try a different USB cable (some are power-only)
- Check debug UART for device support messages
Re-enumeration loops:
- Usually caused by an unstable attached device
- Check USB cable quality and power supply stability
- Review debug logs on GPIO 0/1 @ 115200 baud
Passthrough not working:
- LED should show device connected state
- Open debug UART to verify device detection
- Devices with complex HID descriptors may need adjustments
Serial Communication
No response to KMBox commands:
- Verify UART wires are crossed (TXβRX, RXβTX)
- Check baud rate (115200 default)
- Ensure common ground connection
- Test with:
km.move(10, 10)
Display not updating:
- Verify SPI connections to ILI9341
- Check bridge firmware is flashed correctly
- Review bridge debug output
- Ensure TFT power (3.3 V or 5 V depending on module)
Performance
High latency:
- Check CPU clock speeds in CMakeLists.txt
- Set humanization mode to OFF for lowest latency
- Monitor temperature (thermal throttling)
- Reduce display update rate if using bridge
Movement feels sluggish:
- Try OFF or LOW humanization mode
- Check mouse polling rate (1000 Hz recommended)
- Verify physical mouse sensor quality
Build Issues
CMake errors:
# Ensure Pico SDK is installed and path is set
export PICO_SDK_PATH=/path/to/pico-sdk
# Clean and rebuild
./build.sh metro cleanFlash failures:
- Hold BOOTSEL button firmly during USB connect
- Try a different USB port or cable
- Verify the .uf2 file isn't corrupted
Edit humanization_lut.c to create custom jitter profiles. The LUT defines jitter multipliers based on movement distance. Regenerate with tools/generate_lut.py.
Extend KMBox commands in lib/kmbox-commands/:
- Define command structure
- Add parser in
kmbox_serial_handler.c - Implement handler logic
- Update protocol documentation
Modify the bridge display in bridge/tft_display.c β color schemes, widgets, refresh rates, and touch controls. See bridge/README.md for the display API.
Contributions welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Test thoroughly on hardware
- Document changes in code and README
- Submit a pull request with a detailed description
See CONTRIBUTING.md for development guidelines.
Main project files follow standard open-source practices. Libraries under lib/ retain their respective licenses:
| Library | License |
|---|---|
| Pico-PIO-USB | See lib/Pico-PIO-USB/LICENSE |
| TinyUSB | MIT |
| Pico SDK | BSD 3-Clause |
- Raspberry Pi Foundation β Pico SDK and documentation
- TinyUSB β USB stack
- Sekigon-gonnoc β Pico-PIO-USB
- Adafruit β RP2350 hardware
- KMBox community β protocol documentation
| Channel | Link |
|---|---|
| Bug Reports | GitHub Issues |
| Discussions | GitHub Discussions |
| Documentation | See individual .md files for detailed topics |
This project is for educational and accessibility purposes. Users are responsible for complying with applicable terms of service and regulations.