feat(ui): CardKB (I2C keyboard) support with full keyboard-only navigation

Auto-detected at boot on Wire1/Grove (addr 0x5F) -- no setting to flip, and a
no-op on boards without that bus or with nothing attached. This UI's key
codes (KEY_LEFT/UP/DOWN/RIGHT/ENTER/CANCEL) already match CardKB's own byte
protocol, so most input needs zero translation and flows through the same
key queue as physical buttons.

Two bytes get remapped in UITask::pollCardKB():
- Enter, only when the on-screen keyboard's plain grid state is active (no
  placeholder/accent popup, not in cursor-mode), becomes a new KEY_KB_ENTER
  sentinel meaning "submit the field" -- reusing plain KEY_ENTER there would
  insert a stray character, since a CardKB typist's row/col never reflect an
  intentional grid selection. Everywhere else Enter is untouched, so
  selecting a placeholder or committing an accent still works normally.
- Tab (otherwise unused) becomes KEY_CONTEXT_MENU, standing in for the
  "Hold-Enter" long-press gesture CardKB has no way to produce -- without it,
  ~30 context menus across the UI (message reply/navigate, Bot/Admin/
  Repeater, ...) would be unreachable from the keyboard alone.

KeyboardWidget gains a direct-typing path: printable ASCII inserts straight
at the cursor bypassing the grid, Backspace deletes, KEY_KB_ENTER submits.

Build-verified: WioTrackerL1_companion_solo_dual and
WioTrackerL1Eink_companion_solo_dual both compile and link clean; also
smoke-tested Heltec_mesh_solar_companion_radio_ble (no ENV_PIN_SDA/SCL) to
confirm zero regression on boards without the feature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-07-21 23:43:33 +02:00
parent a57d5d67bb
commit 7cae6470bf
5 changed files with 92 additions and 0 deletions

View File

@@ -13,6 +13,13 @@
#define KEY_NEXT 0xF1
#define KEY_PREV 0xF2
#define KEY_CONTEXT_MENU 0xF3
// A literal-ASCII input source's (e.g. an I2C CardKB) Enter, translated only
// when the on-screen keyboard's plain grid state is active (see
// UITask::pollCardKB()) -- means "submit the field", not KEY_ENTER's usual
// "commit whatever grid cell (row,col) is currently selected", which would
// otherwise insert a stray character since direct typing never touches the
// grid.
#define KEY_KB_ENTER 0x05
// "Previous"/"Next" navigation keys: the directional key and its rotary-encoder
// twin. Decrement / increment a value, or step a selection. (Cancel and the