Blankslate

Universal HID tablet configuration toolkit

Launch App
Github Logo

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 keyboardMappings for Huion-style tablets

Recommendations

For Best Compatibility

  1. Generate configs using Node.js or Python with sudo on macOS
  2. Use driverless mode to capture raw HID scan codes
  3. The resulting keyboardButtons format works everywhere

For WebHID-Only Use

If you only need WebHID support and have the manufacturer's driver active:

  1. The driver converts button presses to keyboard shortcuts
  2. WebHID can capture these via browser keyboard events
  3. Add keyboardMappings manually 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