Files
tactility/.claude/skills/tactility-bluetooth/references/combo-keyboard-mouse.md
Adolfo Reyna 12035f2f39 chore: move firmware skills in-repo + AGENTS.md
- Migrates tactility-firmware and tactility-bluetooth from
  ~/.hermes/skills/ into .claude/skills/ for repo co-location
- Adds AGENTS.md with local workstation context, board table,
  board-direct build rule, Hermes PYTHONPATH pitfall, common
  Tactility pitfalls, and in-repo skill index

Refs: personal Gitea mirror
2026-07-17 09:51:08 -04:00

2.3 KiB

Combo Keyboard + Touchpad Devices (Fosmon Example)

Device

Fosmon Mini Bluetooth Keyboard QWERTY + Touchpad, Amazon ASIN B00BX0YKX4 Short link from user: https://a.co/d/0fg4vprm → redirects to B00BX0YKX4 Compatible with Apple TV, Fire Stick, PS4/5, HTPC, smartphones — cheap BLE HID.

BLE HID Report Map Structure (typical)

  • Top-level Collection 1: Generic Desktop, Usage Keyboard (0x06)
    • Report ID 1 (0x85 0x01)
    • Input: mod keys, reserved, 6 keys (8 bytes)
  • Top-level Collection 2: Generic Desktop, Usage Mouse (0x02)
    • Report ID 2 (0x85 0x02)
    • Collection Physical → Input: buttons (5 bits + 3 pad), X, Y, Wheel? → 3-4 bytes
  • Possibly Consumer (0x0C) for media keys on Report ID 3

Example hex fragments:

05 01 09 06 A1 01 85 01 ... 95 06 75 08 81 00 C0
05 01 09 02 A1 01 85 02 09 01 A1 00 05 09 19 01 29 05 15 00 25 01 75 01 95 05 81 02 75 03 95 01 81 01 05 01 09 30 09 31 09 38 15 81 25 7F 75 08 95 03 81 06 C0 C0

Behavior

  • Sleeps after ~5-10 min idle, stops advertising
  • Wakes on any key/touch → sends directed advertising to bonded host for ~30s (RPA, often no complete name, only flags + maybe appearance 0x03C1 keyboard or 0x03C2 mouse or 0x03C0 combo)
  • Some cheap firmwares use PUBLIC address, others use RANDOM resolvable (RPA rotates every ~15 min)
  • After wake, expects central to connect quickly; if missed, sleeps again → need periodic scan retry

Tactility Specifics

  • hid_host_active atomic in BleCtx prevents simultaneous central connect with name resolution chain ble_resolve_next_unnamed_peer (would get BLE_HS_EALREADY)
  • getScanResults() originally filtered nameless → missed directed adv → no auto-connect
  • applyReportMapTypes depth logic only considers depth 0 Collection type; works for Fosmon because collections are top-level, but nested mouse would fail

Testing Checklist

  • Pair → verify Report Map log shows Report val_handle=... reportId=1 type=0/1 etc for 2 reports
  • Move touchpad slowly → cursor should move 1-5 px per packet, not jump 200+
  • Press keyboard keys → modifier handling (shift) works
  • Let KB sleep 10 min → press key → Tactility should scan within 3s and reconnect (log Auto-connect retry timer firedConnecting... addr_type=)
  • Manual Connect from Paired screen with unknown addr_type should try PUBLIC then RANDOM fallback and log rc