diff --git a/lib/hal/HalGPIO.h b/lib/hal/HalGPIO.h index 2d89fae1..63592438 100644 --- a/lib/hal/HalGPIO.h +++ b/lib/hal/HalGPIO.h @@ -59,11 +59,9 @@ class HalGPIO { inline bool deviceIsX3() const { return _deviceType == DeviceType::X3; } inline bool deviceIsX4() const { return _deviceType == DeviceType::X4; } - // True on the Xteink X3/X4 transflective C3 boards. Distinct from - // deviceIsX3/X4 (which only tell the two C3 variants apart and both stay - // "X4" on non-C3 boards): this keys off BoardConfig::ACTIVE.board, so it is - // the reliable "is this an Xteink device" check used to gate features that - // are Xteink-only (sunlight fading fix) or non-Xteink-only (touch controls). + // True on the Xteink X3/X4 boards. Unlike deviceIsX3/X4 (which both stay "X4" + // on non-C3 boards), this keys off BoardConfig::ACTIVE.board, so it reliably + // gates Xteink-only features (sunlight fix) and non-Xteink-only ones (touch). bool isXteinkDevice() const; // Start button GPIO and setup SPI for screen and SD card diff --git a/src/MappedInputManager.cpp b/src/MappedInputManager.cpp index 77da09e6..a3a9c43f 100644 --- a/src/MappedInputManager.cpp +++ b/src/MappedInputManager.cpp @@ -57,22 +57,19 @@ bool MappedInputManager::mapButton(const Button button, bool (HalGPIO::*fn)(uint return false; } -// Top-left corner of the panel (panel-native, normalized). Generous so it's easy -// to hit; v1 is not yet orientation-mapped (see wasBackGesture NOTE in header). +// Top-left corner fallback, as a fraction of the logical screen. Generous to hit. static constexpr float BACK_GESTURE_FRAC_X = 0.22f; static constexpr float BACK_GESTURE_FRAC_Y = 0.12f; bool MappedInputManager::wasBackGesture() const { float nx = 0.0f, ny = 0.0f; if (!gpio.wasTouchTap(nx, ny)) return false; - // A tap on the theme's header back area (orientation-mapped) acts as Back. int lx = 0, ly = 0; renderer.tapToLogical(nx, ny, lx, ly); + // A tap on the theme's header Back target acts as Back. int id = 0; if (TouchRegistry::getInstance().hitTest(lx, ly, TouchRegistry::Back, id)) return true; - // Fallback corner gesture: top-left of the LOGICAL screen (orientation-mapped), so - // it lands on the visual top-left in every orientation and works on screens with no - // header/Back target (e.g. the reader). + // Else the top-left corner, for screens with no Back target (e.g. the reader). return lx <= renderer.getScreenWidth() * BACK_GESTURE_FRAC_X && ly <= renderer.getScreenHeight() * BACK_GESTURE_FRAC_Y; } diff --git a/src/MappedInputManager.h b/src/MappedInputManager.h index 1c5be260..d98f0cb0 100644 --- a/src/MappedInputManager.h +++ b/src/MappedInputManager.h @@ -21,28 +21,20 @@ class MappedInputManager { bool wasPressed(Button button) const; bool wasReleased(Button button) const; bool isPressed(Button button) const; - // Reusable touch "back" gesture: a tap released in the top-left corner, OR a tap - // on the header back area registered by the theme. Folded into Back's press/ - // release edges, so every screen gets it with no per-activity code. False on - // non-touch devices. + // Touch "back" gesture: a tap on the theme's header Back target, or in the + // top-left corner. Folded into Back's edges, so every screen gets it for free. bool wasBackGesture() const; - // One-shot: if a tap this frame hit a registered interactive element (theme - // draw methods register them via TouchRegistry), returns true and writes the - // element's id. Activities treat the id as "select + activate". False on - // non-touch devices or when the tap missed every target. + // True (and writes the id) if a tap this frame hit a TouchRegistry item. + // Activities treat the id as "select + activate". False on non-touch devices. bool wasItemTapped(int& id) const; - // Press-edge analogue of wasItemTapped: fires on touch-DOWN over an item, so the - // activity can move its selection to that item (showing the selected state) before - // release. Release still activates via wasItemTapped. Mirrors button nav (move - // selection, then confirm). + // Press-edge of wasItemTapped: fires on touch-DOWN over an item so the activity + // can show it selected before release. Mirrors button nav (move, then confirm). bool wasItemTouchedDown(int& id) const; - // Long-press variant of wasItemTapped: true on release of a touch over an item - // held past the long-press threshold (a subset of wasItemTapped's releases, so - // check this first). Lets a screen distinguish tap vs press-and-hold on touch. + // Subset of wasItemTapped's releases held past the long-press threshold (check + // this first). Distinguishes tap vs press-and-hold. bool wasItemLongPressed(int& id) const; - // Like wasItemTapped, but for tab-bar tabs (id = tab index) and cover/card - // targets (id = item index). Distinct kinds so screens with both a list and a - // tab bar / cover (Home, Settings) don't confuse them. + // wasItemTapped for tab-bar tabs (id = tab index) and cover/card targets + // (id = item index). Distinct kinds so a screen with both doesn't confuse them. bool wasTabTapped(int& id) const; bool wasCoverTapped(int& id) const; bool wasAnyPressed() const; diff --git a/src/SettingsList.h b/src/SettingsList.h index f8ce3e1e..a780fad5 100644 --- a/src/SettingsList.h +++ b/src/SettingsList.h @@ -253,12 +253,8 @@ inline std::vector getSettingsList(const SdCardFontRegistry* regist SettingInfo::Toggle(StrId::STR_CLOCK_SYNCED, &CrossPointSettings::clockHasBeenSynced, "clockHasBeenSynced", StrId::STR_CUSTOMISE_STATUS_BAR), }; - // The sunlight fading fix targets the Xteink X3/X4 transflective panel, so - // it only appears on those devices. Every other (touch) device instead gets - // the touch reader controls toggle (tap page back/forward + press-and-hold, - // mirroring the physical buttons). Keyed off the board identity - // (gpio.isXteinkDevice()), not gpio.hasTouch(), so the reader runtime gate - // and this visibility gate share one source of truth. + // Sunlight fading fix is Xteink-only (transflective panel); other devices get + // the touch reader controls toggle instead. Same gate as the reader runtime. if (!gpio.isXteinkDevice()) { v.erase(std::remove_if(v.begin(), v.end(), [](const SettingInfo& s) { return s.nameId == StrId::STR_SUNLIGHT_FADING_FIX; }), diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index bcb6b613..f21468b1 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -179,12 +179,9 @@ void HomeActivity::loop() { requestUpdate(); }); - // A tap on a menu button selects + activates it. The button menu registers - // menu-local ids (it is drawn with selectorIndex offset by recentBooks.size()), - // so map the tapped id back into the global selector space. (The recent-book - // cover is a separate, single-item draw path — tappable in a later phase.) - // Touch-down moves the selector to the pressed menu button (shows selected state), - // like Up/Down; release opens it below. + // Tap a menu button to select + activate it. The button menu registers + // menu-local ids (drawn with selectorIndex offset by recentBooks.size()), so map + // back into the global selector space. Touch-down shows it selected; release opens. int downId = -1; if (mappedInput.wasItemTouchedDown(downId)) { selectorIndex = static_cast(recentBooks.size()) + downId; diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index af4da25b..31392e30 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -256,12 +256,8 @@ void EpubReaderActivity::loop() { requestUpdate(); } - // Touch reader controls mirror the side page buttons (left third = back, right - // third = forward, press-and-hold = long-press behavior) and the Confirm - // button (center press-and-hold = open menu). The top-left Back corner is - // consumed by wasReleased(Back) earlier, so it never reaches here. No-op on - // Xteink / when the setting is off. wasTouchTap is idempotent within a frame, - // so reading it here and again below is safe. + // Touch page nav (idempotent within a frame, so read here and again below). The + // top-left Back corner is consumed by wasReleased(Back) above, never reaching here. const auto touch = ReaderUtils::detectTouchPageTurn(renderer); // Enter reader menu activity (Confirm release, or a center touch-and-hold). diff --git a/src/activities/reader/ReaderUtils.h b/src/activities/reader/ReaderUtils.h index cf12006f..243dd0f6 100644 --- a/src/activities/reader/ReaderUtils.h +++ b/src/activities/reader/ReaderUtils.h @@ -65,14 +65,10 @@ inline PageTurnResult detectPageTurn(const MappedInputManager& input) { return {prev, next, tiltPrev || tiltNext}; } -// Touch reader controls: a tap on the left third of the (oriented) screen turns -// back a page, the right third turns forward, mirroring the side page buttons. -// The center third opens the reader menu on press-and-hold (see center/heldMs; -// the menu/Back gesture is handled by each reader). heldMs carries the contact -// duration so callers can apply the same long-press behavior (chapter skip / -// orientation change) as the buttons. Gated off the Xteink devices (no touch) -// and behind the touchReaderControls setting; returns all-false otherwise, so -// non-touch readers pay a single branch. +// Touch reader controls: left third = page back, right third = forward, center = +// open menu on press-and-hold (see isTouchMenuGesture). heldMs is the contact +// duration, for the same long-press behavior as the buttons (chapter skip). +// All-false on Xteink (no touch) or when the setting is off. struct TouchPageTurn { bool prev; bool next; diff --git a/src/activities/reader/TxtReaderActivity.cpp b/src/activities/reader/TxtReaderActivity.cpp index 76344e01..7f2e4b71 100644 --- a/src/activities/reader/TxtReaderActivity.cpp +++ b/src/activities/reader/TxtReaderActivity.cpp @@ -72,8 +72,7 @@ void TxtReaderActivity::loop() { return; } - // Touch reader controls mirror the side page buttons (left third = back, - // right third = forward). No-op on Xteink / when the setting is off. + // Touch page nav (left third = back, right third = forward). const auto touch = ReaderUtils::detectTouchPageTurn(renderer); auto [prevTriggered, nextTriggered, fromTilt] = ReaderUtils::detectPageTurn(mappedInput); diff --git a/src/activities/reader/XtcReaderActivity.cpp b/src/activities/reader/XtcReaderActivity.cpp index d398f2e5..d76e7484 100644 --- a/src/activities/reader/XtcReaderActivity.cpp +++ b/src/activities/reader/XtcReaderActivity.cpp @@ -53,10 +53,7 @@ void XtcReaderActivity::onExit() { } void XtcReaderActivity::loop() { - // Touch reader controls mirror the side page buttons (left third = back, right - // third = forward, press-and-hold = chapter skip) and the Confirm button - // (center press-and-hold = chapter selection). No-op on Xteink / when the - // setting is off. + // Touch page nav; center hold opens chapter selection (the Confirm analogue). const auto touch = ReaderUtils::detectTouchPageTurn(renderer); // Enter chapter selection activity (Confirm release, or a center touch-and-hold). diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 42a429ac..5dc33e13 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -115,11 +115,9 @@ void SettingsActivity::onExit() { void SettingsActivity::loop() { bool hasChangedCategory = false; - // A tap on a settings row selects + activates it in one gesture. The list is drawn - // with selectedIndex = selectedSettingIndex - 1 (row 0 is the category tab), so map - // the tapped 0-based row back by +1. (Category tab bar is tappable in a later phase.) - // Touch-down moves the selection to the pressed row (shows selected state); release - // toggles/activates it below. (Row 0 is the tab bar, so settings list id 0 -> index 1.) + // Tap a settings row to select + activate it. Row 0 is the tab bar, so the list + // is drawn at selectedSettingIndex - 1; map the tapped row back by +1. Touch-down + // shows it selected; release toggles/activates below. int downId = -1; if (mappedInput.wasItemTouchedDown(downId) && downId >= 0 && downId < settingsCount) { selectedSettingIndex = downId + 1; diff --git a/src/activities/util/KeyboardEntryActivity.cpp b/src/activities/util/KeyboardEntryActivity.cpp index 53ebe92d..29b3a79f 100644 --- a/src/activities/util/KeyboardEntryActivity.cpp +++ b/src/activities/util/KeyboardEntryActivity.cpp @@ -337,11 +337,9 @@ void KeyboardEntryActivity::loop() { } } - // A tap selects the key and presses it. Encoded id = row*100+col (bottom function - // row = getContentRowCount()). A touch-and-hold inserts the alternate character - // (numbers/symbols on a letter), mirroring the button long-press — wasItemLongPressed - // is checked first since it's a subset of wasItemTapped's releases. Skipped in - // cursor mode, where a tap on a key would be ambiguous with cursor editing. + // Tap a key to press it (encoded id = row*100+col). Touch-and-hold inserts the + // alternate char, like the button long-press (check wasItemLongPressed first, it's + // a subset of these releases). Skipped in cursor mode (ambiguous with editing). int tappedKey = -1; if (!cursorMode && mappedInput.wasItemTapped(tappedKey)) { selectedRow = tappedKey / 100; diff --git a/src/components/TouchRegistry.h b/src/components/TouchRegistry.h index 1b027834..30aee645 100644 --- a/src/components/TouchRegistry.h +++ b/src/components/TouchRegistry.h @@ -8,15 +8,10 @@ #include "components/themes/BaseTheme.h" // Rect // Frame-scoped registry of tappable UI elements. Theme draw methods record each -// interactive element's LOGICAL rect + id during render() (on the render task); -// the input layer hit-tests a tap against it during the next loop() (main task). -// -// Lock-free single-writer (render) / single-reader (loop) via double buffering: -// render writes the back buffer and publish() atomically flips it to live, so the -// reader never observes a half-built frame. No per-frame heap allocation. -// -// Runtime-gated: disabled on boards without touch (setEnabled(gpio.hasTouch())), -// so add()/hitTest() are a single branch on the C3. +// element's logical rect + id during render() (render task); the input layer +// hit-tests a tap in the next loop() (main task). Lock-free via double buffering: +// render writes the back buffer, publish() flips it live. No per-frame heap. +// Runtime-gated off on boards without touch (setEnabled). class TouchRegistry { public: enum Kind : uint8_t { Item = 0, Back = 1, Tab = 2, Cover = 3 }; diff --git a/src/components/themes/BaseTheme.cpp b/src/components/themes/BaseTheme.cpp index 869411f8..79f22948 100644 --- a/src/components/themes/BaseTheme.cpp +++ b/src/components/themes/BaseTheme.cpp @@ -355,9 +355,7 @@ void BaseTheme::drawList(const GfxRenderer& renderer, Rect rect, int itemCount, } void BaseTheme::drawHeader(const GfxRenderer& renderer, Rect rect, const char* title, const char* subtitle) const { - // Left strip of the header is a tap-to-go-back zone (orientation-mapped; the - // title is centered so this area is normally empty). Mirrors the legacy corner - // gesture but as a real, theme-positioned target. + // Left strip of the header is a tap-to-go-back zone (title is centered, so it's empty). TouchRegistry::getInstance().add(Rect{rect.x, rect.y, 64, rect.height + 8}, -1, TouchRegistry::Back); // Hide last battery draw