How Blankslate handles tablet buttons that use keyboard HID interfaces
Keyboard Input Handling
Some drawing tablets send button presses through a Keyboard HID interface rather than through the digitizer interface. This page explains how Blankslate handles these tablets and the various configuration formats involved.
Background: How Tablets Send Button Data
Drawing tablets can send button data in two fundamentally different ways:
Digitizer-Style Buttons (XP-Pen)
Most tablets include button data in the same HID packet as pen data:
[reportId, status, x_lo, x_hi, y_lo, y_hi, pressure_lo, pressure_hi, tiltX, tiltY, buttonByte]
The button byte contains bit flags or scan codes indicating which buttons are pressed. This data comes through the Digitizer HID interface (usage page 13).
Keyboard-Style Buttons (Huion)
Some tablets (notably Huion) send button presses through a completely separate Keyboard HID interface (usage page 1, usage 6). When you press a tablet button, the tablet sends a keyboard shortcut:
| Report ID | Type | Data Format | Example |
|---|---|---|---|
| 3 | Keyboard | [modifier, 0, keycode, 0, 0, 0, 0, 0] |
Button 1 → keycode: 5 (B key) |
| 4 | Consumer Control | [consumerCode_lo, consumerCode_hi] |
Media keys |
| 5 | Relative Scroll | [scrollDelta] |
Scroll wheel |
Platform Differences
Raw HID Access
| Platform | Can Read Keyboard HID Interface |
|---|---|
| Node.js (Linux) | ✅ Yes |
| Node.js (macOS) | ⚠️ Requires sudo |
| Python (Linux) | ✅ Yes |
| Python (macOS) | ⚠️ Requires sudo |
| WebHID (Browser) | ❌ No (security blocklist) |
macOS Sudo Requirement
On macOS, the Keyboard HID interface is protected by the operating system. Applications cannot read from this interface without elevated privileges:
# Without sudo - pen works, buttons don't
npx tsx src/cli/event-viewer.ts my-config.json --live
# With sudo - everything works
sudo npx tsx src/cli/event-viewer.ts my-config.json --live
WebHID Security Blocklist
WebHID maintains a security blocklist that prevents websites from accessing certain HID device types. This includes:
| Usage Page | Usage | Description |
|---|---|---|
| 0x0001 | 0x0006 | Generic Desktop / Keyboard |
| 0x0001 | 0x0007 | Generic Desktop / Keypad |
This blocklist exists to prevent malicious websites from creating keyloggers. Unfortunately, it also blocks access to tablet buttons that use the keyboard interface.
Impact: WebHID can open and enumerate the keyboard interface, but cannot receive input reports from it. Raw HID button data is not accessible.
Configuration Formats
Blankslate uses different configuration formats depending on how button data is accessed:
tabletButtons - Digitizer Interface Buttons
For tablets where buttons come through the digitizer interface:
"tabletButtons": {
"byteIndex": [10],
"buttonCount": 8,
"type": "bit-flags"
}
Or with scan code mappings:
"tabletButtons": {
"byteIndex": [1],
"buttonCount": 8,
"type": "code",
"values": {
"1": { "button": 1 },
"3": { "button": 2 },
"6": { "button": 3 }
}
}
Used by: All platforms (WebHID, Node.js, Python)
keyboardButtons - Raw Keyboard HID Data
For tablets where buttons come through the keyboard HID interface, with raw USB HID keycodes:
"keyboardButtons": {
"description": "Buttons from keyboard HID interface (requires sudo on macOS)",
"usagePage": 1,
"usage": 6,
"buttonCount": 30,
"buttons": [
{ "button": 1, "reportId": 3, "type": "keyboard", "modifier": 0, "keycode": 5 },
{ "button": 2, "reportId": 3, "type": "keyboard", "modifier": 7, "keycode": 17 },
{ "button": 21, "reportId": 4, "type": "consumer", "consumerCode": 182 },
{ "button": 25, "reportId": 5, "type": "scroll", "scrollDelta": 1 }
]
}
Generated by: Node.js and Python config generators (with sudo on macOS)
Used by: All platforms - WebHID automatically converts to keyboardMappings format at runtime
keyboardMappings - Browser Keyboard Event Codes
For WebHID when the driver is active and converts button presses to keyboard shortcuts:
"keyboardMappings": {
"description": "Keyboard shortcuts for WebHID mode when driver is active",
"buttons": [
{ "button": 1, "keys": ["KeyB"] },
{ "button": 2, "keys": ["KeyE"] },
{ "button": 5, "keys": ["ControlLeft", "NumpadSubtract"] }
]
}
The keys array uses JavaScript KeyboardEvent.code values (physical key positions like KeyB, ControlLeft), not KeyboardEvent.key values (characters like b, Control).
Generated by: Manual configuration only (for driver mode scenarios)
Used by: WebHID dashboard only
How the Formats Relate
The keyboardButtons and keyboardMappings formats represent the same button mappings in different forms:
keyboardButtons (raw HID) |
keyboardMappings (browser events) |
|---|---|
keycode: 5 |
keys: ["KeyB"] |
keycode: 8 |
keys: ["KeyE"] |
modifier: 1, keycode: 86 |
keys: ["ControlLeft", "NumpadSubtract"] |
The WebHID dashboard automatically converts keyboardButtons to keyboardMappings at runtime using a USB HID keycode lookup table. This means:
- Generate configs with Node.js/Python to get raw HID keycodes (
keyboardButtons) - Use in WebHID - the dashboard converts them automatically
- No need to manually create
keyboardMappingsfor Huion-style tablets
Recommendations
For Best Compatibility
- Generate configs using Node.js or Python with
sudoon macOS - Use driverless mode to capture raw HID scan codes
- The resulting
keyboardButtonsformat works everywhere
For WebHID-Only Use
If you only need WebHID support and have the manufacturer's driver active:
- The driver converts button presses to keyboard shortcuts
- WebHID can capture these via browser keyboard events
- Add
keyboardMappingsmanually to your config
Comparison Table
| Scenario | Config Generator | Button Format | Works In |
|---|---|---|---|
| XP-Pen (any mode) | Any | tabletButtons |
All platforms |
| Huion (driverless) | Node.js/Python + sudo | keyboardButtons |
All platforms |
| Huion (driver mode) | Manual | keyboardMappings |
WebHID only |
See Also
- Configuration Schema - Full details on all config formats
- Known Limitations - Platform-specific limitations
- HID Reading - How Blankslate reads HID data