diff --git a/TLORA_PAGER_SHORTCUTS.md b/TLORA_PAGER_SHORTCUTS.md index 27e225d..031126a 100644 --- a/TLORA_PAGER_SHORTCUTS.md +++ b/TLORA_PAGER_SHORTCUTS.md @@ -65,9 +65,12 @@ Hold **Fn (Alt)** for numbers/symbols instead: Real momentary Shift, just like a normal keyboard. - **Hold Fn (Alt), then press Shift**: while you're editing a text field, toggles **Caps Lock** on/off — stays uppercase until you repeat the chord. - Anywhere else (not editing a field), the same chord instead jumps straight - to the **Home** screen. + Anywhere else (not editing a field), the chord does nothing. - Shift alone, tapped with nothing else, does nothing (as expected). +- **Hold Fn (Alt), then press Backspace**: jumps straight to the **Home** + screen — works everywhere, including while you're actively editing a field + (unlike Alt+Shift above, this one isn't context-dependent). Doesn't delete + a character or trigger the plain-Backspace gestures below. ### Special keys @@ -157,7 +160,8 @@ dimmable brightness curve. | Fn tap alone | Next field | | Hold Shift + letter | Momentary uppercase | | Fn + Shift (editing a field) | Toggle Caps Lock | -| Fn + Shift (not editing a field) | Jump to Home | +| Fn + Shift (not editing a field) | Nothing | +| Fn + Backspace (anywhere) | Jump to Home | | Fn + Space | Enter accent picker | | @ + letters (composer) | Auto-focuses the mention list — no Fn+Space needed | | Enter | Select / send / message action menu | diff --git a/src/helpers/input/PagerKeyboard.cpp b/src/helpers/input/PagerKeyboard.cpp index fad94d1..e357368 100644 --- a/src/helpers/input/PagerKeyboard.cpp +++ b/src/helpers/input/PagerKeyboard.cpp @@ -41,15 +41,21 @@ static constexpr char s_symbolMap[KB_ROWS][KB_COLS] = { // Shift-key semantics) — held Alt THEN a Shift press instead chords into // Alt+Shift, reported via s_alt_shift_chord_pending. What that chord DOES is // a UI-level decision (UITask.cpp): Caps Lock toggle while editing a text -// field, or jump Home otherwise — this driver has no idea which field (if -// any) is focused, so it only reports the chord, it doesn't act on it (see -// pagerKeyboardConsumeAltShiftChord()/pagerKeyboardToggleCaps()). Note: Alt -// (row2,col0) and Shift (row2,col8) share row2, and row0/row1 col8 are -// 'o'/'l' — holding Alt+Shift+O or Alt+Shift+L all three at once will -// phantom-ghost a 'q'/'a' at the row2/col0 intersection (classic -// diode-less-matrix 3-key rectangle, no software fix possible); harmless in -// practice since the intended gesture is hold-Alt-tap-Shift-release-both, -// not holding all three simultaneously. +// field, no-op otherwise — this driver has no idea which field (if any) is +// focused, so it only reports the chord, it doesn't act on it (see +// pagerKeyboardConsumeAltShiftChord()/pagerKeyboardToggleCaps()). Held Alt +// THEN a Backspace press similarly chords into Alt+Backspace +// (s_alt_backspace_chord_pending) — unlike Alt+Shift this one has a single, +// context-independent effect (jump Home, everywhere, including mid-edit), +// so it's just as driver-agnostic to report but never conditional at the UI +// layer. Note: Alt (row2,col0) and Shift (row2,col8) share row2, and +// row0/row1 col8 are 'o'/'l' — holding Alt+Shift+O or Alt+Shift+L all three +// at once will phantom-ghost a 'q'/'a' at the row2/col0 intersection +// (classic diode-less-matrix 3-key rectangle, no software fix possible); +// harmless in practice since the intended gesture is +// hold-Alt-tap-Shift-release-both, not holding all three simultaneously. +// Backspace (row2,col9) sits one column over from Shift, so Alt+Backspace +// doesn't share this exact ghosting risk with any base-layer letter. static constexpr uint8_t kAltPos = 2 * KB_COLS + 0; // row2,col0 ('\0' in both layers) static constexpr uint8_t kShiftPos = 2 * KB_COLS + 8; // row2,col8 ('\0' in both layers) static constexpr uint8_t kBackspacePos = 2 * KB_COLS + 9; // row2,col9 ('\0' in both layers) @@ -63,6 +69,7 @@ static bool s_alt_tap_pending = false; // Alt pressed+released with nothing els static bool s_caps = false; static bool s_shift_held = false; // momentary Shift, mirrors s_backspace_held/s_space_held static bool s_alt_shift_chord_pending = false; // one-shot, see pagerKeyboardConsumeAltShiftChord() +static bool s_alt_backspace_chord_pending = false; // one-shot, see pagerKeyboardConsumeAltBackspaceChord() static bool s_backspace_held = false; static bool s_space_held = false; @@ -128,7 +135,19 @@ void pagerKeyboardPoll() { } continue; } - if (code == kBackspacePos) { s_backspace_held = pressed; if (pressed) ringPush('\b'); continue; } + if (code == kBackspacePos) { + if (pressed) { + // Alt+Backspace is a distinct chord (jump Home, everywhere -- see + // pagerKeyboardConsumeAltBackspaceChord()), not a delete: suppress + // both the '\b' ring-push AND s_backspace_held, so the plain- + // Backspace hold gestures (back / unlock) never also see this press. + if (s_alt) s_alt_backspace_chord_pending = true; + else { s_backspace_held = true; ringPush('\b'); } + } else { + s_backspace_held = false; + } + continue; + } if (code == kSpacePos) { s_space_held = pressed; if (pressed) ringPush(' '); continue; } if (!pressed) continue; // base/symbol keys only emit on press @@ -182,4 +201,10 @@ bool pagerKeyboardConsumeAltShiftChord() { void pagerKeyboardToggleCaps() { s_caps = !s_caps; } +bool pagerKeyboardConsumeAltBackspaceChord() { + if (!s_alt_backspace_chord_pending) return false; + s_alt_backspace_chord_pending = false; + return true; +} + #endif diff --git a/src/helpers/input/PagerKeyboard.h b/src/helpers/input/PagerKeyboard.h index d726db8..774e552 100644 --- a/src/helpers/input/PagerKeyboard.h +++ b/src/helpers/input/PagerKeyboard.h @@ -56,10 +56,12 @@ void pagerKeyboardMarkAltUsed(); * symbol-layer or Alt+turn hold. Consumes the pending flag on read. */ bool pagerKeyboardConsumeAltTap(); -/** True while Backspace is physically held (raw state, mirrors - * pagerKeyboardAltHeld()). A press still immediately ring-pushes '\b' as - * before; this is for callers that want to detect a long hold separately - * (e.g. UITask's press-and-hold "back" gesture). */ +/** True while Backspace is physically held WITHOUT Alt (raw state, mirrors + * pagerKeyboardAltHeld()). A plain press still immediately ring-pushes '\b' + * as before; this is for callers that want to detect a long hold separately + * (e.g. UITask's press-and-hold "back" gesture). Alt+Backspace is a + * different gesture entirely (see pagerKeyboardConsumeAltBackspaceChord()) + * and never sets this or ring-pushes '\b'. */ bool pagerKeyboardBackspaceHeld(); /** True while Space is physically held (raw state, mirrors @@ -80,4 +82,12 @@ bool pagerKeyboardConsumeAltShiftChord(); * above only applying while a text field is actually being edited. */ void pagerKeyboardToggleCaps(); +/** One-shot: true exactly once after Alt(Fn)+Backspace is chorded (Backspace + * pressed while Alt is held) — jumps Home, everywhere (editing a field or + * not), unlike the Alt+Shift chord above. Suppresses the normal Backspace + * press entirely: no '\b' ring-push, and pagerKeyboardBackspaceHeld() never + * reports held for this press, so it can't also fire the plain-Backspace + * hold-to-back/hold-to-unlock gestures. Consumes the pending flag on read. */ +bool pagerKeyboardConsumeAltBackspaceChord(); + #endif diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index 2ac5013..932fe82 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -31177,18 +31177,35 @@ static void updatePagerAltTapNext() { } // Alt(Fn)+Shift chord (PagerKeyboard.cpp only reports it, since the driver has -// no UI visibility): while actually editing a text field, toggle Caps Lock -// (the field is where "Caps Lock" means anything); everywhere else — no field -// focused, or a field merely bound but nav focus has moved off it (same "ta" -// derivation handleHwKey() uses) — jump straight Home instead, since Caps -// Lock silently flipping with no field to see it in was reported as -// surprising/purposeless outside of typing. +// no UI visibility): toggles Caps Lock while actually editing a text field +// (the field is where "Caps Lock" means anything) and is a deliberate no-op +// everywhere else (Home-jump duty moved to Alt+Backspace below, so there's no +// longer a reason to make this chord do anything outside a field — Caps Lock +// silently flipping with no field to see it in was reported as +// surprising/purposeless before this split). static void updatePagerAltShiftChord() { if (!pagerKeyboardConsumeAltShiftChord()) return; lv_obj_t* ta_focused = lv_keyboard_get_textarea(g_lv.keyboard); lv_obj_t* ta = (ta_focused && s_nav_group && lv_group_get_focused(s_nav_group) == ta_focused) ? ta_focused : nullptr; - if (ta) pagerKeyboardToggleCaps(); - else navGoToMainTab(HOME_TAB_INDEX); + if (!ta) return; + pagerKeyboardToggleCaps(); + if (g_lv.task) g_lv.task->noteUserInput(); +} + +// Alt(Fn)+Backspace chord: jump straight Home, unconditionally -- unlike +// Alt+Shift above, this one is NOT context-dependent (works whether or not a +// field is being edited, per explicit request). Fires instead of a normal +// Backspace press: PagerKeyboard.cpp suppresses the '\b' ring-push and the +// hold-to-back/hold-to-unlock tracking entirely for an Alt-held Backspace +// press, so there's no double-action to guard against here. +static void updatePagerAltBackspaceChord() { + if (!pagerKeyboardConsumeAltBackspaceChord()) return; + // The accent/@-mention pickers live on lv_layer_top(), outside the tab + // content navGoToMainTab() switches away from -- close them explicitly + // first so a stray overlay doesn't keep floating over the Home screen. + accentBoxHide(); + mentionBoxHide(); + navGoToMainTab(HOME_TAB_INDEX); if (g_lv.task) g_lv.task->noteUserInput(); } @@ -42834,11 +42851,12 @@ void UITask::loop() { if (pagerKeyboardReadKey() <= 0) break; any = true; } - // Discard any Alt tap / Alt+Shift chord picked up while idle-dimmed -- it - // must not fire updatePagerAltTapNext()'s NEXT / updatePagerAltShiftChord()'s - // toggle-or-Home the instant the screen wakes. + // Discard any Alt tap / Alt+Shift / Alt+Backspace chord picked up while + // idle-dimmed -- none of them may fire (NEXT / Caps toggle / jump Home) + // the instant the screen wakes. pagerKeyboardConsumeAltTap(); pagerKeyboardConsumeAltShiftChord(); + pagerKeyboardConsumeAltBackspaceChord(); // Hard-locked: an ordinary keypress must NOT wake/unlock -- only holding // Backspace does (updatePagerBackspaceUnlockHold, already polled above). if (any && !g_lv.task->isManualLock()) g_lv.task->wakeScreen(); @@ -42850,6 +42868,7 @@ void UITask::loop() { } updatePagerAltTapNext(); updatePagerAltShiftChord(); + updatePagerAltBackspaceChord(); updatePagerBackspaceHold(now); updatePagerSpaceHold(now); }