Transform your Raspberry Pi into a professional USB keyboard, mouse, and media controller with web-based management.
Control a computer from another computer, customize per-keyboard mappings, suppress keys or functions that auto-enter, and manage everything through a modern Bootstrap 5 dark theme web interface. But why does this exist BHB.buzz
๐ GitHub: github.com/mcyork/keybird
The Pi HID Bridge turns a Raspberry Pi into a composite USB HID device that emulates:
- โจ๏ธ Keyboard with 100+ mapped keys
- ๐ฑ๏ธ Mouse with 3 buttons + scroll wheel
- ๐ต Media keys (volume, play/pause, etc.)
Plus unique features:
- ๐น Multi-keyboard pass-through - Monitor YubiKey, Dell, Apple, Microsoft keyboards simultaneously
- ๐ง Per-keyboard custom mappings - YubiKey Enter suppression, key remapping, text macros
- ๐ Emulation profile switching - Pretend to be different keyboard models
- ๐ฑ๏ธ Web trackpad with automatic calibration for different displays
- ๐ Web UI - Control from laptop, phone, or tablet
- Raspberry Pi 4 Model B (tested and validated)
- Full functionality including keyboard pass-through
- Raspberry Pi Zero 2 W (tested and validated)
โ ๏ธ Keyboard functionality only - no pass-through capability due to single USB port hardware limitation
โ ๏ธ NOT compatible with Pi 5 (USB gadget mode unresolved issues)- USB-C data cable - Must support data, not just charging (Pi 4B)
- Micro-USB data cable - Must support data, not just charging (Pi Zero 2 W)
- Pi connected to network (WiFi or Ethernet)
- Pi has SSH enabled (default on Raspberry Pi OS)
# 1. Install pi-shell and keybird on YOUR COMPUTER
pip install pi-shell keybird
# 2. Add your Pi (one-time setup with password-less SSH)
pi-shell add mypi --host 192.168.1.50 --user pi --password raspberry --push-key
# 3. Deploy to Pi (single command!)
keybird-deploy mypiDone! ๐ Access web UI at http://192.168.1.50:8080
๐ฆ Note: Keybird not yet on PyPI. For now, install from source:
pip install pi-shell git clone https://github.com/mcyork/keybird.git cd keybird pip install . pi-shell add mypi --host 192.168.1.50 --user pi --password raspberry --push-key keybird-deploy mypi
โ
Flask web app with Bootstrap 5 dark theme UI
โ
USB HID gadget (keyboard + mouse + media keys)
โ
Systemd services (auto-start on boot)
โ
Boot configuration (enables USB gadget mode)
โ
Dependencies (flask, evdev)
Want transparency? See manual-deploy/README.md for step-by-step SSH deployment.
Connect your Pi's USB-C port to your target computer's USB port.
open http://<pi-ip>:8080Done! ๐
Note: This feature requires Raspberry Pi 4 Model B (Pi Zero 2 W lacks physical USB host ports for keyboards)
Monitor all keyboards at once:
- YubiKey NEO
- Dell WK636 Wireless Keyboard
- Apple Magic Keyboard
- Microsoft keyboards
- Any USB keyboard
Each keyboard can have its own custom key mappings!
Example: Suppress YubiKey's auto-Enter key while keeping Enter normal on other keyboards.
Pretend to be different keyboards:
- Dell WK636 (VID: 046d, PID: c52b)
- Apple Magic Keyboard (VID: 05ac, PID: 029f)
- Logitech Unifying Receiver (VID: 046d, PID: 4049)
- Any keyboard you clone!
Why? Some software only works with specific keyboard models. Clone the required keyboard and switch profiles as needed.
Two ways to control the mouse:
-
Web Trackpad - Beautiful 500x350px trackpad in browser
- Click on trackpad โ sends click to target PC
- Move in trackpad โ cursor moves
- Right-click โ context menu
- Scroll wheel โ page scrolling
- Auto-calibration for your display size
-
Physical Mouse Pass-Through - Plug real mice into Pi
- Forwards all movements and clicks
- Multi-mouse support
- Zero latency
Three mapping types:
-
HID Remap - Map key X to key Y
- Example: Map F13 to Print Screen
-
Text Replacement - Map key to type text
- Example: Map F14 to type "show ip interface brief"
-
Suppress - Ignore specific keys
- Example: Suppress Enter key on YubiKey only
Management UI:
- Select keyboard from dropdown
- View all mappings in table
- Add/Edit/Delete mappings
- Export/Import for backup
Access at http://<pi-ip>:8080
Modern Bootstrap 5 dark theme with tabbed interface:
- Status Bar: USB connection and emulation profile status
- Mode Toggles: Keyboard and mouse pass-through switches
- Quick Actions: Reboot button
- Send Text: Batch send text as keystrokes to connected computer
- Trackpad: Interactive mouse control with sensitivity and calibration
- Unmapped Keys: Auto-detected unknown keys with one-click mapping
- HID Reference: Quick lookup for common HID codes
- Keyboard Management: Select any connected keyboard
- Custom Mappings: Suppress keys, remap, or send text macros
- Per-Keyboard Rules: Different mappings for each physical device
- Emulation Profiles: Switch which keyboard device the Pi pretends to be
- Detected Keyboards: See all physically connected keyboards
- Export/Import: Backup your profiles and mappings
Problem: YubiKey OTP mode sends Enter after password
Solution: Suppress Enter key on YubiKey only
1. Go to Mappings tab
2. Select "Yubico Yubikey NEO OTP+U2F+CCID"
3. Add Mapping:
- Key Code: 28 (Enter)
- Action Type: ๐ซ Suppress
4. Done! YubiKey outputs password without auto-submit
Problem: Different screens need different sensitivities
Solution: Calibrate for each display
1. Enable Mouse Pass-through toggle in header
2. Go to Control tab โ Click ๐ฏ Calibrate button
3. Use physical mouse to click 4 corners of screen
4. Save as "Windows Desktop" or "MacBook Pro"
5. Disable mouse pass-through toggle
6. Use web trackpad with perfect sensitivity!
Problem: Some software requires specific keyboard models
Solution: Clone and switch profiles
1. Plug target keyboard into Pi
2. Go to Settings tab โ Detected Physical Keyboards
3. Click "Clone" button next to the keyboard
4. Pi reboots as that keyboard
5. Use Emulation Profile dropdown to switch between saved profiles anytime
Best Practice with KVM:
[Powered USB Hub] โ Constant power
โ
[KVM] โ Switches USB data
โ
[Computer A] [Computer B] [Computer C]
Connected to hub:
- Raspberry Pi (via USB-C data cable)
- Your keyboards
- Your mice
- Microphone
- Other USB devices
Benefits:
- Pi stays powered (no reboot when switching)
- All devices switch together
- Web UI always accessible
- Different calibrations per computer
Application Files:
/home/pi/pi-hid-bridge/
โโโ app/pi_kb.py # Flask app (2,850+ lines)
โโโ scripts/
โ โโโ setup_gadget_composite.sh # Creates USB gadget
โ โโโ cleanup_gadget.sh # Removes USB gadget
โ โโโ gadget.conf # VID/PID configuration
โโโ systemd/
โ โโโ hid-gadget.service # Auto-start gadget
โ โโโ pi-hid-bridge.service # Auto-start Flask
โโโ requirements.txt # Python deps
Runtime Data Files:
/home/pi/
โโโ keyboard_profiles.json # Emulation profiles
โโโ keyboard_mappings.json # Per-keyboard custom mappings
โโโ trackpad_calibrations.json # Trackpad calibrations
System Configuration:
/boot/firmware/config.txt # dtoverlay=dwc2 added
/boot/firmware/cmdline.txt # modules-load=dwc2 added
/etc/systemd/system/ # Services installed
USB Devices Created:
/dev/hidg0 # Keyboard
/dev/hidg1 # Consumer Control (media keys)
/dev/hidg2 # Mouse
This project uses Pi Shell - a pip-installable CLI tool for managing Raspberry Pis via SSH.
Install: pip install pi-shell
GitHub: github.com/mcyork/pi-shell
After adding your Pi with pi-shell add mypi ..., you can use the symlink:
# Check status
pi-shell status mypi
# Execute commands (streaming output)
mypi run-stream "command"
# Send files
mypi send /local/file /remote/path
# Read files
mypi read /remote/file > local-file
# List all Pis
pi-shell list# Deploy from scratch
keybird-deploy mypi
# Quick restart (already deployed)
cd keybird/manual-deploy
./quick-start.sh mypiUSB Ports:
- USB-C port
- USB gadget output (connects to target computer)
- 4ร USB-A ports - Connect keyboards, mice, YubiKey, etc.
- Ethernet - Management network
- Wi-Fi - Wireless management (optional)
Wiring:
Target Computer USB Port
โ
[USB-C Cable] โ Data + Power
โ
Pi USB-C Port
Pi USB-A Ports:
โโ Keyboard 1 (Dell)
โโ Keyboard 2 (YubiKey)
โโ Mouse 1 (Logitech)
โโ Mouse 2 (Microsoft)
Power Options:
- Via USB-C from target - If target provides enough power
- Via GPIO pins - 5V to pins 2/4, GND to pin 6
- PoE HAT - Power over Ethernet
- Manual Deployment README - Deploy without pip install
- Manual Deployment Guide - Step-by-step SSH deployment
- Uninstall Guide - Complete removal instructions
Check USB status:
mypi run-stream 'cat /sys/class/udc/*/state'Should show: configured
If shows: not attached โ Check USB cable is data-capable
Manually recreate gadget:
mypi run-stream 'sudo systemctl restart hid-gadget.service'Check logs:
mypi run-stream 'sudo journalctl -u pi-hid-bridge.service -n 50'
mypi run-stream 'sudo journalctl -u hid-gadget.service -n 50'Manual restart:
mypi run-stream 'sudo systemctl restart hid-gadget.service'
mypi run-stream 'sudo systemctl restart pi-hid-bridge.service'Check keyboards detected:
curl http://<pi-ip>:8080/detected_keyboardsEnable pass-through:
- Open web UI
- Toggle "Keyboard Pass-through" in header
Check logs:
mypi run-stream 'sudo journalctl -u pi-hid-bridge.service -f'Check mouse devices exist:
mypi run-stream 'ls -la /dev/hidg*'Should see: /dev/hidg0, /dev/hidg1, /dev/hidg2
If missing hidg2:
mypi run-stream 'sudo systemctl restart hid-gadget.service'Check Flask is running:
mypi run-stream 'sudo systemctl status pi-hid-bridge.service'Check it's listening:
mypi run-stream 'sudo ss -tlnp | grep 8080'View live logs:
mypi run-stream 'sudo journalctl -u pi-hid-bridge.service -f'mypi send app/pi_kb.py /home/pi/pi-hid-bridge/app/pi_kb.py
mypi run-stream 'sudo systemctl restart pi-hid-bridge.service'mypi send templates/index.html /home/pi/pi-hid-bridge/templates/index.html
mypi send static/css/style.css /home/pi/pi-hid-bridge/static/css/style.css
mypi send static/js/app.js /home/pi/pi-hid-bridge/static/js/app.js
# Just refresh browser# Download from Pi
mypi read /home/pi/keyboard_profiles.json > backup_profiles.json
mypi read /home/pi/keyboard_mappings.json > backup_mappings.json
mypi read /home/pi/trackpad_calibrations.json > backup_calibrations.jsonOr use Web UI โ Export buttons.
# Upload to Pi
mypi send backup_profiles.json /home/pi/keyboard_profiles.json
mypi send backup_mappings.json /home/pi/keyboard_mappings.json
mypi send backup_calibrations.json /home/pi/trackpad_calibrations.json
# Restart service
mypi run-stream 'sudo systemctl restart pi-hid-bridge.service'keybird-deploy mypiGET /healthGET /usb_status
# Returns: {"state": "configured", "attached": true}GET /passthrough
# Check status
POST /passthrough
# Body: {"enabled": true}
# Toggle on/offGET /mouse_passthrough
POST /mouse_passthrough
# Body: {"enabled": true}POST /mouse_move
# Body: {"dx": 10, "dy": -5, "buttons": 0, "wheel": 0}
POST /mouse_click
# Body: {"button": "left"} # or "right", "middle"POST /send_text
# Body: {"text": "Hello, world!"}GET /detected_keyboards
# Returns list of physical keyboards with VID/PIDGET /detected_mice
# Returns list of physical miceGET /emulation_profiles
# List all saved profiles
POST /emulation_profiles/switch
# Body: {"profile_id": "logitech_4049"}GET /keyboard_mappings/all
# List all keyboards with mappings
GET /keyboard_mappings/<kbd_id>
# Get specific keyboard's mappings
POST /keyboard_mappings/<kbd_id>/mapping
# Body: {"code": 28, "type": "suppress"}
DELETE /keyboard_mappings/<kbd_id>/mapping/<code>POST /calibration/start
# Start calibration process
GET /calibration/status
# Check calibration progress
POST /calibration/save
# Body: {"name": "Windows Desktop", "sensitivity": 3.2, "points": [...]}
GET /calibrations
# List all saved calibrations
POST /calibrations/<cal_id>/activate
# Activate a calibration profilePOST /reboot
# Reboot the Pi- Read DEPLOYMENT_QUICK_REFERENCE.md for deployment cheat sheet
- Read DEPLOYMENT_GUIDE.md for detailed manual deployment
- LEARNING_MODE_GUIDE.md - Map unknown keys interactively
- YUBIKEY_SUPPRESS_EXAMPLE.md - Suppress YubiKey Enter key
- MOUSE_CONTROL_GUIDE.md - Use the web trackpad
- TRACKPAD_CALIBRATION_GUIDE.md - Calibrate for your display
- PROFILES_AND_MAPPINGS.md - Understand emulation vs mappings
- KEYBOARD_VENDOR_NOTES.md - Why Dell keyboards show as Logitech
- MOUSE_PASSTHROUGH_GUIDE.md - Physical mouse forwarding
- FINDINGS.md - Pi 5 USB gadget investigation
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Target Computer (Windows/Mac/Linux) โ
โ โฒ โ
โ โ USB HID โ
โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
USB-C Cable
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Raspberry Pi 4 Model B โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Composite USB HID Gadget โ โ
โ โ - /dev/hidg0 (Keyboard) โ โ
โ โ - /dev/hidg1 (Consumer Control) โ โ
โ โ - /dev/hidg2 (Mouse) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โฒ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Flask Web App (pi_kb.py) โ โ
โ โ - Keyboard pass-through โ โ
โ โ - Mouse pass-through โ โ
โ โ - Custom mappings engine โ โ
โ โ - Profile management โ โ
โ โ - Calibration system โ โ
โ โ - Web UI server โ โ
โ โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ โ
โ โ evdev โ
โ โผ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Physical Input Devices โ โ
โ โ - Keyboards (YubiKey, Dell, Apple...) โ โ
โ โ - Mice (Logitech, Microsoft...) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Network: Ethernet + Wi-Fi โโโโ Web Browser โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Keyboard Pass-Through:
Physical Keyboard โ evdev โ Pi โ Custom Mappings โ HID Report โ Target PC
Web Trackpad:
Browser โ HTTP โ Pi โ Calibration โ HID Report โ Target PC
Profile Switching:
User Selection โ Update gadget.conf โ Reboot โ New VID/PID โ Target PC sees different keyboard
This is a personal project, but suggestions welcome!
Areas for improvement:
- Additional mapping types (delays, sequences)
- Drag-and-drop mouse support
- Encrypted macro implementation
- AI command generation
- GamePad emulation
Personal project - use at your own risk!
Built with:
- Flask - Web framework
- evdev - Linux input device interface
- Python - Glue holding it all together
- Pi Shell - Pi management CLI (github.com/mcyork/pi-shell)
Inspired by Black Hat Booze (https://bhb.buzz) and the deep obsession with the distilation process - be it for spirits or code.
Keybird makes system-level changes that need proper cleanup:
# Complete removal (cleans everything)
sudo keybird-uninstall
# Then remove Python package
sudo pip uninstall keybird
# Reboot to apply boot config changes
sudo rebootThe uninstall script removes:
- โ USB gadget configuration (boot files)
- โ Systemd services
- โ
Installed files in
/opt/keybird/
Preserves (in case you reinstall):
- ๐พ Saved profiles, mappings, calibrations in
/home/pi/
See UNINSTALL.md for manual uninstall steps.
Check logs:
sudo journalctl -u pi-hid-bridge.service -fReset everything (pip install users):
sudo systemctl restart hid-gadget.service
sudo systemctl restart pi-hid-bridge.serviceReset everything (manual deploy users):
cd keybird/manual-deploy
./quick-start.sh mypi-
v1.0.12 (Dec 2025) - Pass-Through Initialization Fix: Fixed pass-through flags initialization at module level (now properly enabled on boot), improved deployment script to use source files during development, ensures GUI correctly shows pass-through status on startup
-
v1.0.11 (Dec 2025) - Pass-Through Reliability & Key Mapping Fixes: Fixed pass-through always enabled on boot (flags set before threads start, removed retry limits), fixed key mapping modifier handling to preserve user modifier state, improved mouse polling rate (1ms timeout), fixed indentation error in mouse pass-through loop
-
v1.0.10 (Dec 2025) - Auto-Start & UI Fixes: Pass-through modes (keyboard and mouse) now auto-start on boot by default, UI toggles correctly reflect enabled state, restored missing LED indicators and controls on Control tab
-
v1.0.9 (Nov 2025) - Human-Readable HID Code Dropdown: Added dropdown with human-readable key names (Delete, Enter, F1-F24, etc.) instead of requiring hex codes, with Custom option for unknown keys
-
v1.0.8 (Nov 2025) - Revert to File-Copying Deployment: Restored original deployment approach for better workflow (edit locally, deploy to multiple Pis)
-
v1.0.7 (Nov 2025) - Editable Mappings & Modifier Support: Auto-inject captured keys into editable table, inline editing of all mappings, modifier support (Ctrl+Alt+Shift+Win) for key combinations like Ctrl+Alt+Del
-
v1.0.6 (Nov 2025) - LED Control & Robustness: Added LED forwarding (sync host lock keys to physical keyboards), real-time LED status indicators, clickable lock key toggles in GUI, and improved pass-through crash recovery
-
v1.0.5 (Nov 2025) - Listen Mode & Branding: Added key listening mode for easy keyboard mapping, auto-start pass-through on boot, keyboard deduplication, favicon integration, and rebranded to "Keybird"
-
v1.0.4 (Oct 2025) - PyPI Fix: Corrected package build to include touch support for iPhone/iPad trackpad
-
v1.0.3 (Oct 2025) - Mobile Support: Added touch support for iPhone/iPad trackpad - touch to move cursor, tap to click, two-finger right-click
-
v1.0.2 (Oct 2025) - Modernization: Updated to Python 3.10+, replaced deprecated pkg_resources with importlib.resources
-
v1.0.1 (Oct 2025) - Bug fix: Fixed silent crash in keyboard pass-through mode
-
v1.0 (Oct 2025) - Initial release with keyboard pass-through, web UI, mouse control, trackpad calibration, multi-keyboard support, profiles, per-keyboard mappings, and YubiKey support
-
v0.1 (Oct 2025) - Initial prototype
Ready to control your computers like a pro? Deploy and enjoy! ๐ฎ