Project 7: Bluetooth HID Keyboard/Mouse Injector
Build a BLE HID keyboard/mouse that pairs reliably, reconnects automatically, and runs macro sequences from the Cardputer keyboard.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Intermediate |
| Time Estimate | 1–2 weeks |
| Main Programming Language | C/C++ (ESP-IDF) |
| Alternative Programming Languages | Arduino |
| Coolness Level | High |
| Business Potential | Medium (assistive devices, automation) |
| Prerequisites | BLE basics, GATT, keyboard scanning |
| Key Topics | HID over GATT, bonding, macro engine, latency tuning |
1. Learning Objectives
By completing this project, you will:
- Implement BLE HID over GATT with correct services and report maps.
- Handle pairing, bonding, and reconnection reliably.
- Map Cardputer key events to HID reports with correct key releases.
- Build a macro engine with timing control.
- Design a UI for pairing status and device selection.
2. All Theory Needed (Per-Concept Breakdown)
2.1 HID over GATT (HOGP) and GATT Services
Fundamentals
BLE HID uses GATT services to expose keyboard and mouse reports. The HID service defines characteristics such as Report Map, Report, and Protocol Mode. A host (phone, tablet, laptop) connects, reads the report map, and subscribes to notifications to receive reports. If the GATT structure is incorrect, pairing may succeed but input will not work.
Deep Dive into the concept
The HID over GATT profile (HOGP) is a standard Bluetooth profile. It requires a HID Service UUID and several mandatory characteristics: Report Map (defines the report format), HID Information (version, country code), and Control Point (to switch protocol mode). Each input report is represented by a Report characteristic with a Report ID. For keyboards, the report format mirrors USB HID: modifiers and keycodes. For mice, it includes X/Y movement and button states. The report map describes these fields.
The BLE connection interval influences latency. Short intervals (e.g., 7.5 ms) yield low latency but higher power use; longer intervals (30–50 ms) save power but introduce lag. For a keyboard/mouse, you typically want responsiveness, so aim for 15–30 ms. The device should request connection parameters but accept host overrides.
HOGP also requires a battery service to report battery level. This is optional but common. Implementing it improves host UI integration. For stable operation, you must implement the correct security mode: usually “Just Works” pairing is enough, but some hosts require bonding for reconnection. Store bonding keys in NVS so the device can reconnect without re-pairing.
How this fits in projects
This BLE HID knowledge complements the USB HID device in P04-badusb-usb-hid-attack-demonstration-tool.md and integrates into P08-complete-cardputer-security-toolkit.md.
Definitions & key terms
- HOGP → HID over GATT Profile
- GATT → Generic Attribute Profile
- Characteristic → data container within a GATT service
- Report Map → descriptor defining HID report format
Mental model diagram (ASCII)
[BLE Host] <-> [HID Service] <-> [Report Characteristics] -> [HID Reports]
How it works (step-by-step, with invariants and failure modes)
- Advertise with HID service UUID.
- Host connects and reads Report Map.
- Host subscribes to Report notifications.
- Device sends HID reports on input events.
Invariants: report map matches reports; notifications enabled. Failure modes: incorrect report map, missing security, connection drops.
Minimal concrete example
ble_hid_send_report(REPORT_ID_KBD, report, sizeof(report));
Common misconceptions
- “BLE HID is the same as USB HID.” → Similar, but delivered via GATT.
- “Pairing once is enough.” → Bonding required for seamless reconnection.
- “Any connection interval is fine.” → It affects latency.
Check-your-understanding questions
- What is the Report Map used for?
- Why is connection interval important for HID?
- What does bonding store?
Check-your-understanding answers
- It defines the format of reports the host will interpret.
- It determines input latency and responsiveness.
- It stores keys to reconnect securely without re-pairing.
Real-world applications
- BLE keyboards, presenters, and assistive tech.
Where you’ll apply it
- This project: see §4.1 and §5.10 Phase 1.
- Also used in:
P08-complete-cardputer-security-toolkit.md.
References
- Bluetooth HID over GATT Profile spec.
- ESP-IDF BLE HID examples.
Key insight
HOGP is about correct GATT structure and timing—if either is wrong, input fails.
Summary
Define the correct HID service and report map, then tune connection parameters for responsiveness.
Homework/Exercises to practice the concept
- Draw the GATT service tree for a BLE keyboard.
- Modify the report map to add a media key.
Solutions to the homework/exercises
- Include HID service, Report Map, Report characteristics, Control Point.
- Add a consumer control report ID and update map accordingly.
2.2 Bonding, Security, and Reconnection Logic
Fundamentals
BLE devices pair with hosts to establish trust. Bonding stores keys so the device can reconnect without re-pairing. Without bonding, users must pair every time, which is frustrating and unreliable. A robust HID device must manage bonding, allow clearing bonds, and handle reconnection attempts gracefully.
Deep Dive into the concept
BLE pairing can be “Just Works,” passkey, or numeric comparison. For most HID peripherals, “Just Works” is acceptable, but some hosts require bonding for reconnection. The device should store bonding keys in NVS and reuse them on startup. If the host is forgotten or the user wants to pair with another device, you need a clear way to clear bonds (e.g., long-press a button).
Reconnection logic should be state-driven. When disconnected, the device should return to advertising mode. If a bonded host is nearby, it will reconnect automatically. You should also handle cases where the host refuses connection due to stale keys. In that case, allow the user to clear bonds and re-pair. Always display connection status clearly: advertising, connected, bonded, or error. If you don’t, users will think the device is broken.
Security also involves preventing unauthorized connections. You can restrict connections to bonded hosts or limit advertising to a pairing window. For example, you might only allow pairing if the user explicitly enters “pair mode.” This prevents random devices from connecting in public spaces. For a tool like this, explicit pairing mode is a good safety practice.
How this fits in projects
Bonding and reconnection logic are also relevant to P08-complete-cardputer-security-toolkit.md, where multiple radio features coexist and must remain stable.
Definitions & key terms
- Pairing → establishing trust and encryption keys
- Bonding → storing keys for future reconnection
- Reconnection → automatic reconnect without user action
- Pair mode → explicit window where new devices can pair
Mental model diagram (ASCII)
[Disconnected] -> [Advertising] -> [Connected] -> [Bonded]
^ |
+----------- Clear Bonds -----------+
How it works (step-by-step, with invariants and failure modes)
- Device boots; checks for stored bonds.
- If bonds exist, advertise with bonded whitelist.
- Host connects and encryption is established.
- If connection fails, fallback to pairing mode.
Invariants: bonds stored securely; pairing only in explicit mode. Failure modes: stale bonds prevent reconnect; user cannot clear bonds.
Minimal concrete example
if (pair_mode) ble_start_advertising_all();
else ble_start_advertising_bonded();
Common misconceptions
- “Bonding is optional.” → Without it, reconnect is unreliable.
- “Pair once and forget.” → Hosts can forget; provide reset.
- “Advertising always is safe.” → It allows unintended pairing.
Check-your-understanding questions
- What is the difference between pairing and bonding?
- Why offer a clear-bonds option?
- Why restrict advertising to a pairing window?
Check-your-understanding answers
- Pairing establishes keys; bonding stores them for future use.
- To recover from stale or broken pairings.
- To prevent unwanted or accidental connections.
Real-world applications
- BLE keyboards that reconnect seamlessly.
- Medical or industrial BLE devices with security needs.
Where you’ll apply it
- This project: see §3.2 requirement 2 and §5.10 Phase 2.
- Also used in:
P08-complete-cardputer-security-toolkit.md.
References
- Bluetooth Core Spec pairing and bonding chapters.
- ESP-IDF NimBLE documentation.
Key insight
Reliable HID devices aren’t just about input—they’re about trust and reconnection.
Summary
Implement bonding, provide a clear pairing mode, and design reconnection as a state machine.
Homework/Exercises to practice the concept
- Implement a “clear bonds” function and test re-pairing.
- Add a pairing window timer that expires after 60 seconds.
Solutions to the homework/exercises
- Erase NVS bonding keys and restart advertising.
- Use a FreeRTOS timer to disable open advertising after timeout.
2.3 Input Mapping and Macro Engine
Fundamentals
The Cardputer keyboard produces key events that must be mapped to HID keycodes. For macros, you need a representation of sequences and delays. The macro engine converts a user-defined sequence into HID reports. Correct handling of key press and release is critical to prevent stuck keys or repeated input.
Deep Dive into the concept
Keyboard mapping requires a translation table from Cardputer key positions to standard HID usage IDs. You must also handle modifiers (Shift, Ctrl). For example, typing “A” requires sending the “A” keycode with the Shift modifier. If you store macros as plain text, you need a conversion table from characters to keycodes and modifiers. If you store macros as explicit keycodes, you avoid layout issues but make editing harder. A hybrid approach can support both.
Macro timing is crucial. A macro is a sequence of actions (press key, release key, wait). The engine should insert a default inter-key delay and allow explicit waits. Without delays, host input buffers may overflow or drop keys. The engine should also allow cancellation; check a stop flag between actions.
For usability, provide a macro editor UI that allows users to create or edit macros on the device. This can be simple: select a macro slot, record keystrokes, then save. Alternatively, you can edit a text file on SD. The macro engine should validate the macro and show errors clearly.
How this fits in projects
Macro sequencing parallels the payload engine in P04-badusb-usb-hid-attack-demonstration-tool.md and supports the capstone P08-complete-cardputer-security-toolkit.md.
Definitions & key terms
- Keycode → HID usage ID for a key
- Modifier → Shift/Ctrl/Alt flags
- Macro → sequence of actions with timing
- Inter-key delay → pause between reports
Mental model diagram (ASCII)
[Cardputer Keys] -> [Mapper] -> [Macro Engine] -> [HID Reports]
How it works (step-by-step, with invariants and failure modes)
- Read key events and map to HID keycodes.
- If macro triggered, load macro sequence.
- Send HID reports with press/release and delays.
- Allow cancel via stop flag.
Invariants: every press has release; delays applied. Failure modes: stuck keys if release missing; macros too fast cause lost input.
Minimal concrete example
send_report(KEY_CTRL | KEY_ALT | KEY_DEL);
Common misconceptions
- “Macro delay doesn’t matter.” → It often does.
- “Layout mismatch is harmless.” → It changes output characters.
- “I don’t need key releases.” → It causes stuck modifiers.
Check-your-understanding questions
- Why must you send a release after each press?
- What’s the risk of too-fast macros?
- How do modifiers affect HID reports?
Check-your-understanding answers
- Without release, host thinks key is held.
- Host may miss keystrokes or ignore input.
- Modifiers change the meaning of keycodes (e.g., Shift).
Real-world applications
- Presentation clickers.
- Assistive typing tools.
Where you’ll apply it
- This project: see §4.4 algorithm and §5.10 Phase 3.
- Also used in:
P04-badusb-usb-hid-attack-demonstration-tool.md.
References
- USB HID usage tables (for keycodes).
Key insight
Macros are just reliable sequences of press/release events with timing discipline.
Summary
Map keys carefully, enforce press/release discipline, and control timing for reliable macros.
Homework/Exercises to practice the concept
- Implement a macro that types “Hello” with a 50 ms delay.
- Add a cancel key to stop macros.
Solutions to the homework/exercises
- Enqueue each character with press/release and 50 ms waits.
- Check a stop flag between each action.
3. Project Specification
3.1 What You Will Build
A BLE HID device that:
- pairs and bonds with hosts,
- sends keyboard and mouse reports,
- runs macros from the Cardputer keyboard,
- shows connection status and battery.
3.2 Functional Requirements
- BLE HID service: correct GATT structure and report map.
- Pairing/bonding: store keys and reconnect automatically.
- Input mapping: map Cardputer keys to HID reports.
- Macro engine: execute sequences with delays.
- UI: status, pairing mode, macro list.
3.3 Non-Functional Requirements
- Latency: typing latency < 50 ms typical.
- Reliability: reconnect across 10 power cycles.
- Usability: clear pairing status.
3.4 Example Usage / Output
1) Enter pairing mode
2) Pair with laptop
3) Press macro key to type a command
3.5 Data Formats / Schemas / Protocols
- BLE HID report map and report formats.
- Macro file format (text or binary).
3.6 Edge Cases
- Host forgets device → requires re-pairing.
- Key release missed → stuck key.
- BLE connection interval too long → lag.
3.7 Real World Outcome
A successful build pairs with a host, reconnects automatically, and types or moves the mouse reliably with low latency.
3.7.1 How to Run (Copy/Paste)
idf.py set-target esp32s3
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor
3.7.2 Golden Path Demo (Deterministic)
- Pair with a laptop.
- Trigger macro “Open Terminal” and observe correct output.
Failure demo (deterministic):
- Attempt to connect from a new host while not in pair mode. Expected: connection rejected and UI shows “PAIR MODE REQUIRED.” Exit code: 1.
3.7.3 If CLI: exact terminal transcript
I (7200) ble: connected addr=AA:BB:CC:DD:EE:FF
I (7201) ble: bonded=YES
I (7202) hid: sent report keys=2
Exit codes: 0 = success, 1 = not in pair mode, 2 = bonding failure, 3 = GATT init error.
3.7.4 If Web App
Not applicable.
3.7.5 If API
Not applicable.
3.7.6 If Library
Not applicable.
3.7.7 If GUI / Desktop / Mobile
Not applicable.
3.7.8 If TUI
+----------------------------+
| BLE HID |
| Status: Connected |
| Device: Laptop |
| [F1] Open Terminal |
+----------------------------+
4. Solution Architecture
4.1 High-Level Design
[Keyboard] -> [Mapper] -> [Macro Engine] -> [BLE HID] -> [Host]
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| BLE stack | GATT + HID | correct report map |
| Bonding manager | store keys | NVS storage |
| Input mapper | key -> HID | layout mapping |
| Macro engine | sequences | delays and cancel |
| UI | pairing status | clear prompts |
4.3 Data Structures (No Full Code)
typedef struct {
uint8_t mod;
uint8_t keys[6];
} hid_kbd_report_t;
4.4 Algorithm Overview
Key Algorithm: Macro Playback
- Load macro actions.
- Send HID reports with delays.
- Stop on cancel flag.
Complexity Analysis:
- Time: O(n) actions
- Space: O(n) actions
5. Implementation Guide
5.1 Development Environment Setup
idf.py set-target esp32s3
idf.py build
5.2 Project Structure
project-root/
├── main/
│ ├── ble_hid.c
│ ├── bonding.c
│ ├── keymap.c
│ ├── macros.c
│ └── ui.c
└── README.md
5.3 The Core Question You’re Answering
“How do I build a BLE HID device that reconnects reliably and feels responsive?”
5.4 Concepts You Must Understand First
- HOGP GATT structure.
- Bonding and reconnection.
- Macro timing discipline.
5.5 Questions to Guide Your Design
- What connection interval yields acceptable latency?
- How do you handle layout differences?
- How do you cancel macros safely?
5.6 Thinking Exercise
Draw the HID report map for a keyboard and mouse combo device.
5.7 The Interview Questions They Will Ask
- How does BLE HID differ from USB HID?
- Why is bonding important?
- How do you avoid stuck keys?
5.8 Hints in Layers
Hint 1: Implement keyboard-only HID first.
Hint 2: Add pairing/bonding and reconnection.
Hint 3: Add macros and UI.
5.9 Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| BLE basics | Getting Started with BLE | Ch. 4–6 |
| Embedded design | Making Embedded Systems | Ch. 4 |
5.10 Implementation Phases
Phase 1: BLE HID basic keyboard (3–4 days)
Phase 2: Bonding + reconnection (3–4 days)
Phase 3: Macros + UI (3–4 days)
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Connection interval | 7.5 ms, 15 ms, 30 ms | 15 ms | responsive yet stable |
| Pairing | always open, pair mode | pair mode | safer |
| Macro format | text, binary | text | easy to edit |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Unit Tests | key mapping | keycode conversion |
| Integration Tests | pairing + typing | host receives text |
| Stress Tests | reconnection | 10 power cycles |
6.2 Critical Test Cases
- Pair and reconnect without re-pairing.
- Macros execute with correct delays.
- Cancel key stops macro immediately.
6.3 Test Data
Macro: TYPE "hello" ENTER
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Missing key release | stuck keys | send empty report |
| No bonding | reconnect fails | store keys |
| High interval | laggy typing | reduce interval |
7.2 Debugging Strategies
- Log BLE disconnect reasons.
- Use a test app to display HID reports on host.
7.3 Performance Traps
- Long macro sequences without pauses.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add media control keys.
8.2 Intermediate Extensions
- Add mouse movement macros.
8.3 Advanced Extensions
- Add multi-host pairing profiles.
9. Real-World Connections
9.1 Industry Applications
- BLE keyboards and presenters.
- Assistive devices.
9.2 Related Open Source Projects
- ESP32 BLE HID examples.
9.3 Interview Relevance
- BLE GATT design and reconnection logic.
10. Resources
10.1 Essential Reading
- Bluetooth HID over GATT spec.
10.2 Video Resources
- BLE HID tutorials.
10.3 Tools & Documentation
- ESP-IDF NimBLE docs.
10.4 Related Projects in This Series
P04-badusb-usb-hid-attack-demonstration-tool.mdP08-complete-cardputer-security-toolkit.md
11. Self-Assessment Checklist
11.1 Understanding
- I can explain GATT and Report Map.
- I can explain bonding vs pairing.
11.2 Implementation
- Device reconnects reliably.
- Macros run without skipped keys.
11.3 Growth
- I can tune connection parameters for latency.
12. Submission / Completion Criteria
Minimum Viable Completion:
- BLE keyboard pairs and sends basic keys.
Full Completion:
- Bonding, macros, and UI.
Excellence (Going Above & Beyond):
- Multi-host profiles and mouse control.