From adc0a52af1af7426108eac455c4b093eee8be23f Mon Sep 17 00:00:00 2001 From: jpirnay Date: Mon, 27 Apr 2026 13:52:55 +0200 Subject: [PATCH] Some fixes --- src/ButtonEventManager.cpp | 7 ++ src/ButtonEventManager.h | 6 +- .../EpubReaderChapterSelectionActivity.cpp | 40 ++++++++--- .../reader/EpubReaderFootnotesActivity.cpp | 63 +++++++++++++---- .../EpubReaderPercentSelectionActivity.cpp | 40 +++++++---- .../reader/MdReaderTocSelectionActivity.cpp | 43 ++++++++---- src/activities/reader/QrDisplayActivity.cpp | 11 +-- .../reader/StarredPagesActivity.cpp | 68 ++++++++++++------- .../XtcReaderChapterSelectionActivity.cpp | 36 +++++++--- src/main.cpp | 12 +++- 10 files changed, 236 insertions(+), 90 deletions(-) diff --git a/src/ButtonEventManager.cpp b/src/ButtonEventManager.cpp index af344e09..1741c851 100644 --- a/src/ButtonEventManager.cpp +++ b/src/ButtonEventManager.cpp @@ -33,6 +33,13 @@ void ButtonEventManager::pushEvent(const Button button, const PressType type) { eventTail = next; } +void ButtonEventManager::pushEventFront(const Button button, const PressType type) { + const int prev = (eventHead - 1 + EVENT_BUF) % EVENT_BUF; + if (prev == eventTail) return; // buffer full + eventHead = prev; + eventBuf[eventHead] = {button, type}; +} + bool ButtonEventManager::consumeEvent(ButtonEvent& out) { if (eventHead == eventTail) return false; out = eventBuf[eventHead]; diff --git a/src/ButtonEventManager.h b/src/ButtonEventManager.h index 59b7562d..530dc246 100644 --- a/src/ButtonEventManager.h +++ b/src/ButtonEventManager.h @@ -34,7 +34,7 @@ class ButtonEventManager { }; // Timing constants (milliseconds) - static constexpr unsigned long LONG_PRESS_MS = 600; + static constexpr unsigned long LONG_PRESS_MS = 1000; static constexpr unsigned long DOUBLE_WINDOW_MS = 300; explicit ButtonEventManager(MappedInputManager& input) : input(input) {} @@ -49,6 +49,10 @@ class ButtonEventManager { // Reset all per-button FSMs. Call on activity transitions to prevent bleed-through. void drain(); + // Preserve a default event for activity processing after main loop dispatch. + // This is used when the configured action is BTN_DEFAULT. + void pushEventFront(Button button, PressType type); + // Returns true if a double-click action is configured for this button. // ButtonEventManager queries CrossPointSettings internally. static bool hasDoubleAction(Button button); diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index 39b31c4e..386e4a55 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -42,22 +42,40 @@ void EpubReaderChapterSelectionActivity::loop() { const int pageItems = getPageItems(); const int totalItems = getTotalItems(); - if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - const auto newSpineIndex = epub->getSpineIndexForTocIndex(selectorIndex); - if (newSpineIndex == -1) { + ButtonEventManager::ButtonEvent ev; + while (buttonEvents.consumeEvent(ev)) { + if (ev.button == MappedInputManager::Button::Confirm && ev.type == ButtonEventManager::PressType::Short) { + const auto newSpineIndex = epub->getSpineIndexForTocIndex(selectorIndex); + if (newSpineIndex == -1) { + ActivityResult result; + result.isCancelled = true; + setResult(std::move(result)); + finish(); + } else { + setResult(ChapterResult{newSpineIndex, selectorIndex}); + finish(); + } + return; + } + if (ev.button == MappedInputManager::Button::Back && ev.type == ButtonEventManager::PressType::Short) { ActivityResult result; result.isCancelled = true; setResult(std::move(result)); finish(); - } else { - setResult(ChapterResult{newSpineIndex, selectorIndex}); - finish(); + return; + } + if ((ev.button == MappedInputManager::Button::PageBack || ev.button == MappedInputManager::Button::Left) && + ev.type == ButtonEventManager::PressType::Short) { + selectorIndex = ButtonNavigator::previousIndex(selectorIndex, totalItems); + requestUpdate(); + return; + } + if ((ev.button == MappedInputManager::Button::PageForward || ev.button == MappedInputManager::Button::Right) && + ev.type == ButtonEventManager::PressType::Short) { + selectorIndex = ButtonNavigator::nextIndex(selectorIndex, totalItems); + requestUpdate(); + return; } - } else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { - ActivityResult result; - result.isCancelled = true; - setResult(std::move(result)); - finish(); } buttonNavigator.onNextRelease([this, totalItems] { diff --git a/src/activities/reader/EpubReaderFootnotesActivity.cpp b/src/activities/reader/EpubReaderFootnotesActivity.cpp index 25ed5ca1..7db0e5bc 100644 --- a/src/activities/reader/EpubReaderFootnotesActivity.cpp +++ b/src/activities/reader/EpubReaderFootnotesActivity.cpp @@ -18,30 +18,65 @@ void EpubReaderFootnotesActivity::onEnter() { void EpubReaderFootnotesActivity::onExit() { Activity::onExit(); } void EpubReaderFootnotesActivity::loop() { - if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { - ActivityResult result; - result.isCancelled = true; - setResult(std::move(result)); - finish(); - return; - } - - if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - if (selectedIndex >= 0 && selectedIndex < static_cast(footnotes.size())) { - setResult(FootnoteResult{footnotes[selectedIndex].href}); + ButtonEventManager::ButtonEvent ev; + while (buttonEvents.consumeEvent(ev)) { + if (ev.button == MappedInputManager::Button::Back && ev.type == ButtonEventManager::PressType::Short) { + ActivityResult result; + result.isCancelled = true; + setResult(std::move(result)); finish(); + return; + } + + if (ev.button == MappedInputManager::Button::Confirm && ev.type == ButtonEventManager::PressType::Short) { + if (selectedIndex >= 0 && selectedIndex < static_cast(footnotes.size())) { + setResult(FootnoteResult{footnotes[selectedIndex].href}); + finish(); + } + return; + } + + if ((ev.button == MappedInputManager::Button::PageBack || ev.button == MappedInputManager::Button::Left) && + ev.type == ButtonEventManager::PressType::Short) { + if (!footnotes.empty()) { + selectedIndex = (selectedIndex - 1 + footnotes.size()) % footnotes.size(); + requestUpdate(); + } + return; + } + + if ((ev.button == MappedInputManager::Button::PageForward || ev.button == MappedInputManager::Button::Right) && + ev.type == ButtonEventManager::PressType::Short) { + if (!footnotes.empty()) { + selectedIndex = (selectedIndex + 1) % footnotes.size(); + requestUpdate(); + } + return; } - return; } - buttonNavigator.onNext([this] { + buttonNavigator.onNextRelease([this] { if (!footnotes.empty()) { selectedIndex = (selectedIndex + 1) % footnotes.size(); requestUpdate(); } }); - buttonNavigator.onPrevious([this] { + buttonNavigator.onPreviousRelease([this] { + if (!footnotes.empty()) { + selectedIndex = (selectedIndex - 1 + footnotes.size()) % footnotes.size(); + requestUpdate(); + } + }); + + buttonNavigator.onNextContinuous([this] { + if (!footnotes.empty()) { + selectedIndex = (selectedIndex + 1) % footnotes.size(); + requestUpdate(); + } + }); + + buttonNavigator.onPreviousContinuous([this] { if (!footnotes.empty()) { selectedIndex = (selectedIndex - 1 + footnotes.size()) % footnotes.size(); requestUpdate(); diff --git a/src/activities/reader/EpubReaderPercentSelectionActivity.cpp b/src/activities/reader/EpubReaderPercentSelectionActivity.cpp index 7e122dff..2e2c5b63 100644 --- a/src/activities/reader/EpubReaderPercentSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderPercentSelectionActivity.cpp @@ -34,22 +34,34 @@ void EpubReaderPercentSelectionActivity::adjustPercent(const int delta) { void EpubReaderPercentSelectionActivity::loop() { // Back cancels, confirm selects, arrows adjust the percent. - if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { - ActivityResult result; - result.isCancelled = true; - setResult(std::move(result)); - finish(); - return; - } + ButtonEventManager::ButtonEvent ev; + while (buttonEvents.consumeEvent(ev)) { + if (ev.button == MappedInputManager::Button::Back && ev.type == ButtonEventManager::PressType::Short) { + ActivityResult result; + result.isCancelled = true; + setResult(std::move(result)); + finish(); + return; + } - if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - setResult(PercentResult{percent}); - finish(); - return; - } + if (ev.button == MappedInputManager::Button::Confirm && ev.type == ButtonEventManager::PressType::Short) { + setResult(PercentResult{percent}); + finish(); + return; + } - buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Left}, [this] { adjustPercent(-kSmallStep); }); - buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Right}, [this] { adjustPercent(kSmallStep); }); + if ((ev.button == MappedInputManager::Button::PageBack || ev.button == MappedInputManager::Button::Left) && + ev.type == ButtonEventManager::PressType::Short) { + adjustPercent(-kSmallStep); + return; + } + + if ((ev.button == MappedInputManager::Button::PageForward || ev.button == MappedInputManager::Button::Right) && + ev.type == ButtonEventManager::PressType::Short) { + adjustPercent(kSmallStep); + return; + } + } buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Up}, [this] { adjustPercent(kLargeStep); }); buttonNavigator.onPressAndContinuous({MappedInputManager::Button::Down}, [this] { adjustPercent(-kLargeStep); }); diff --git a/src/activities/reader/MdReaderTocSelectionActivity.cpp b/src/activities/reader/MdReaderTocSelectionActivity.cpp index 89054c7d..771f634f 100644 --- a/src/activities/reader/MdReaderTocSelectionActivity.cpp +++ b/src/activities/reader/MdReaderTocSelectionActivity.cpp @@ -34,24 +34,41 @@ void MdReaderTocSelectionActivity::loop() { const int pageItems = getPageItems(); const int totalItems = getTotalItems(); - if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - if (selectorIndex >= 0 && selectorIndex < totalItems) { - setResult(PageResult{static_cast(headings[selectorIndex].pageIndex)}); - } else { + ButtonEventManager::ButtonEvent ev; + while (buttonEvents.consumeEvent(ev)) { + if (ev.button == MappedInputManager::Button::Confirm && ev.type == ButtonEventManager::PressType::Short) { + if (selectorIndex >= 0 && selectorIndex < totalItems) { + setResult(PageResult{static_cast(headings[selectorIndex].pageIndex)}); + } else { + ActivityResult result; + result.isCancelled = true; + setResult(std::move(result)); + } + finish(); + return; + } + + if (ev.button == MappedInputManager::Button::Back && ev.type == ButtonEventManager::PressType::Short) { ActivityResult result; result.isCancelled = true; setResult(std::move(result)); + finish(); + return; } - finish(); - return; - } - if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { - ActivityResult result; - result.isCancelled = true; - setResult(std::move(result)); - finish(); - return; + if ((ev.button == MappedInputManager::Button::PageBack || ev.button == MappedInputManager::Button::Left) && + ev.type == ButtonEventManager::PressType::Short) { + selectorIndex = ButtonNavigator::previousIndex(selectorIndex, totalItems); + requestUpdate(); + return; + } + + if ((ev.button == MappedInputManager::Button::PageForward || ev.button == MappedInputManager::Button::Right) && + ev.type == ButtonEventManager::PressType::Short) { + selectorIndex = ButtonNavigator::nextIndex(selectorIndex, totalItems); + requestUpdate(); + return; + } } buttonNavigator.onNextRelease([this, totalItems] { diff --git a/src/activities/reader/QrDisplayActivity.cpp b/src/activities/reader/QrDisplayActivity.cpp index 9976feb7..72602de6 100644 --- a/src/activities/reader/QrDisplayActivity.cpp +++ b/src/activities/reader/QrDisplayActivity.cpp @@ -16,10 +16,13 @@ void QrDisplayActivity::onEnter() { void QrDisplayActivity::onExit() { Activity::onExit(); } void QrDisplayActivity::loop() { - if (mappedInput.wasReleased(MappedInputManager::Button::Back) || - mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - finish(); - return; + ButtonEventManager::ButtonEvent ev; + while (buttonEvents.consumeEvent(ev)) { + if ((ev.button == MappedInputManager::Button::Back || ev.button == MappedInputManager::Button::Confirm) && + ev.type == ButtonEventManager::PressType::Short) { + finish(); + return; + } } } diff --git a/src/activities/reader/StarredPagesActivity.cpp b/src/activities/reader/StarredPagesActivity.cpp index 6735a15b..7fa12e1a 100644 --- a/src/activities/reader/StarredPagesActivity.cpp +++ b/src/activities/reader/StarredPagesActivity.cpp @@ -78,33 +78,55 @@ void StarredPagesActivity::deleteSelected() { void StarredPagesActivity::loop() { const int totalItems = static_cast(bookmarkStore.getAll().size()); - if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { - ActivityResult result; - result.isCancelled = true; - setResult(std::move(result)); - finish(); - return; + ButtonEventManager::ButtonEvent ev; + while (buttonEvents.consumeEvent(ev)) { + if (ev.button == MappedInputManager::Button::Back && ev.type == ButtonEventManager::PressType::Short) { + ActivityResult result; + result.isCancelled = true; + setResult(std::move(result)); + finish(); + return; + } + + if (totalItems > 0 && ev.button == MappedInputManager::Button::Confirm && + ev.type == ButtonEventManager::PressType::Short) { + const auto& bm = bookmarkStore.getAll()[selectorIndex]; + setResult(StarredPageResult{bm.spineIndex, bm.pageNumber}); + finish(); + return; + } + + if (totalItems > 0 && + (ev.button == MappedInputManager::Button::PageBack || ev.button == MappedInputManager::Button::Left) && + ev.type == ButtonEventManager::PressType::Short) { + startRename(); + return; + } + + if (totalItems > 0 && + (ev.button == MappedInputManager::Button::PageForward || ev.button == MappedInputManager::Button::Right) && + ev.type == ButtonEventManager::PressType::Short) { + deleteSelected(); + return; + } + + if (totalItems > 0 && ev.button == MappedInputManager::Button::PageBack && + ev.type == ButtonEventManager::PressType::Short) { + selectorIndex = ButtonNavigator::previousIndex(selectorIndex, totalItems); + requestUpdate(); + return; + } + + if (totalItems > 0 && ev.button == MappedInputManager::Button::PageForward && + ev.type == ButtonEventManager::PressType::Short) { + selectorIndex = ButtonNavigator::nextIndex(selectorIndex, totalItems); + requestUpdate(); + return; + } } if (totalItems == 0) return; - if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - const auto& bm = bookmarkStore.getAll()[selectorIndex]; - setResult(StarredPageResult{bm.spineIndex, bm.pageNumber}); - finish(); - return; - } - - if (mappedInput.wasReleased(MappedInputManager::Button::Left)) { - startRename(); - return; - } - - if (mappedInput.wasReleased(MappedInputManager::Button::Right)) { - deleteSelected(); - return; - } - const int pageItems = UITheme::getInstance().getNumberOfItemsPerPage(renderer, true, false, true, false); buttonNavigator.onNextRelease([this, totalItems] { diff --git a/src/activities/reader/XtcReaderChapterSelectionActivity.cpp b/src/activities/reader/XtcReaderChapterSelectionActivity.cpp index 61d283de..7efedfc6 100644 --- a/src/activities/reader/XtcReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/XtcReaderChapterSelectionActivity.cpp @@ -50,17 +50,35 @@ void XtcReaderChapterSelectionActivity::loop() { const int pageItems = getPageItems(); const int totalItems = static_cast(xtc->getChapters().size()); - if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - const auto& chapters = xtc->getChapters(); - if (!chapters.empty() && selectorIndex >= 0 && selectorIndex < static_cast(chapters.size())) { - setResult(PageResult{chapters[selectorIndex].startPage}); + ButtonEventManager::ButtonEvent ev; + while (buttonEvents.consumeEvent(ev)) { + if (ev.button == MappedInputManager::Button::Confirm && ev.type == ButtonEventManager::PressType::Short) { + const auto& chapters = xtc->getChapters(); + if (!chapters.empty() && selectorIndex >= 0 && selectorIndex < static_cast(chapters.size())) { + setResult(PageResult{chapters[selectorIndex].startPage}); + finish(); + } + return; + } + if (ev.button == MappedInputManager::Button::Back && ev.type == ButtonEventManager::PressType::Short) { + ActivityResult result; + result.isCancelled = true; + setResult(std::move(result)); finish(); + return; + } + if ((ev.button == MappedInputManager::Button::PageBack || ev.button == MappedInputManager::Button::Left) && + ev.type == ButtonEventManager::PressType::Short) { + selectorIndex = ButtonNavigator::previousIndex(selectorIndex, totalItems); + requestUpdate(); + return; + } + if ((ev.button == MappedInputManager::Button::PageForward || ev.button == MappedInputManager::Button::Right) && + ev.type == ButtonEventManager::PressType::Short) { + selectorIndex = ButtonNavigator::nextIndex(selectorIndex, totalItems); + requestUpdate(); + return; } - } else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { - ActivityResult result; - result.isCancelled = true; - setResult(std::move(result)); - finish(); } buttonNavigator.onNextRelease([this, totalItems] { diff --git a/src/main.cpp b/src/main.cpp index f857808e..0523df4f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "ButtonEventManager.h" #include "CrossPointSettings.h" @@ -388,6 +389,8 @@ void loop() { using BA = CrossPointSettings::BUTTON_ACTION; using B = MappedInputManager::Button; ButtonEventManager::ButtonEvent ev; + std::vector defaultEvents; + defaultEvents.reserve(8); while (buttonEventManager.consumeEvent(ev)) { auto actionFor = [&](B btn) -> uint8_t { switch (btn) { @@ -468,7 +471,10 @@ void loop() { }; const uint8_t action = actionFor(ev.button); - if (action == BA::BTN_DEFAULT) continue; + if (action == BA::BTN_DEFAULT) { + defaultEvents.push_back(ev); + continue; + } switch (static_cast(action)) { case BA::BTN_PAGE_FORWARD: @@ -525,6 +531,10 @@ void loop() { break; } } + + for (auto it = defaultEvents.rbegin(); it != defaultEvents.rend(); ++it) { + buttonEventManager.pushEventFront(it->button, it->type); + } } const unsigned long activityStartTime = millis();