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
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.