Merge pull request #216 from jpirnay/fix-buttonnavig
fix: button navigation in lists
This commit is contained in:
@@ -72,6 +72,7 @@ void ButtonEventManager::drain() {
|
||||
b.releaseTime = 0;
|
||||
}
|
||||
eventHead = eventTail = 0;
|
||||
longPressDispatchedMask = 0;
|
||||
}
|
||||
|
||||
void ButtonEventManager::processButton(const int idx, const Button btn) {
|
||||
@@ -140,6 +141,14 @@ void ButtonEventManager::processButton(const int idx, const Button btn) {
|
||||
}
|
||||
|
||||
void ButtonEventManager::update() {
|
||||
// Clear the long-press-dispatched flag for buttons that are pressed again.
|
||||
// This allows the flag to survive through the release tick (so detectPageTurn
|
||||
// can suppress the page-turn on release) and resets cleanly on the next press.
|
||||
for (int i = 0; i < NUM_BUTTONS; i++) {
|
||||
if ((longPressDispatchedMask & (1u << i)) && input.wasPressed(ALL_BUTTONS[i])) {
|
||||
longPressDispatchedMask &= ~(1u << i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < NUM_BUTTONS; i++) {
|
||||
processButton(i, ALL_BUTTONS[i]);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,17 @@ class ButtonEventManager {
|
||||
// ButtonEventManager queries CrossPointSettings internally.
|
||||
bool hasDoubleAction(Button button) const;
|
||||
|
||||
// Called by the global dispatcher (main.cpp) when a Long event is consumed for a
|
||||
// non-default action on a navigation button. Suppresses the release-based page turn
|
||||
// that would otherwise fire when the button is released after the long action.
|
||||
void markLongPressDispatched(Button button) { longPressDispatchedMask |= (1u << static_cast<int>(button)); }
|
||||
|
||||
// Returns true if markLongPressDispatched was called for this button since the last
|
||||
// update(). detectPageTurn() uses this to skip wasReleased-based page turns.
|
||||
bool wasLongPressDispatched(Button button) const {
|
||||
return (longPressDispatchedMask & (1u << static_cast<int>(button))) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int NUM_BUTTONS = 9;
|
||||
static constexpr Button ALL_BUTTONS[NUM_BUTTONS] = {
|
||||
@@ -79,6 +90,7 @@ class ButtonEventManager {
|
||||
};
|
||||
|
||||
uint32_t forcedDoubleMask = 0;
|
||||
uint32_t longPressDispatchedMask = 0;
|
||||
|
||||
enum class State { Idle, Pressed, ReleasedOnce, DoublePressed };
|
||||
|
||||
|
||||
@@ -64,18 +64,6 @@ void EpubReaderChapterSelectionActivity::loop() {
|
||||
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.onNextList(selectorIndex, totalItems, [this] { requestUpdate(); });
|
||||
|
||||
@@ -55,20 +55,6 @@ void MdReaderTocSelectionActivity::loop() {
|
||||
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.onNextList(selectorIndex, totalItems, [this] { requestUpdate(); });
|
||||
|
||||
@@ -115,16 +115,21 @@ inline PageTurnResult detectPageTurn(const MappedInputManager& input) {
|
||||
}
|
||||
const bool prevButtonReleased = (SETTINGS.btnShortPageBack == BA::BTN_DEFAULT &&
|
||||
!globalButtonEvents().hasDoubleAction(MappedInputManager::Button::PageBack) &&
|
||||
!globalButtonEvents().wasLongPressDispatched(MappedInputManager::Button::PageBack) &&
|
||||
input.wasReleased(MappedInputManager::Button::PageBack)) ||
|
||||
(SETTINGS.btnShortLeft == BA::BTN_DEFAULT &&
|
||||
!globalButtonEvents().hasDoubleAction(MappedInputManager::Button::Left) &&
|
||||
!globalButtonEvents().wasLongPressDispatched(MappedInputManager::Button::Left) &&
|
||||
input.wasReleased(MappedInputManager::Button::Left));
|
||||
const bool nextButtonReleased = (SETTINGS.btnShortPageForward == BA::BTN_DEFAULT &&
|
||||
!globalButtonEvents().hasDoubleAction(MappedInputManager::Button::PageForward) &&
|
||||
input.wasReleased(MappedInputManager::Button::PageForward)) ||
|
||||
(SETTINGS.btnShortRight == BA::BTN_DEFAULT &&
|
||||
!globalButtonEvents().hasDoubleAction(MappedInputManager::Button::Right) &&
|
||||
input.wasReleased(MappedInputManager::Button::Right));
|
||||
const bool nextButtonReleased =
|
||||
(SETTINGS.btnShortPageForward == BA::BTN_DEFAULT &&
|
||||
!globalButtonEvents().hasDoubleAction(MappedInputManager::Button::PageForward) &&
|
||||
!globalButtonEvents().wasLongPressDispatched(MappedInputManager::Button::PageForward) &&
|
||||
input.wasReleased(MappedInputManager::Button::PageForward)) ||
|
||||
(SETTINGS.btnShortRight == BA::BTN_DEFAULT &&
|
||||
!globalButtonEvents().hasDoubleAction(MappedInputManager::Button::Right) &&
|
||||
!globalButtonEvents().wasLongPressDispatched(MappedInputManager::Button::Right) &&
|
||||
input.wasReleased(MappedInputManager::Button::Right));
|
||||
|
||||
const bool prev = tiltPrev || prevButtonReleased;
|
||||
const bool next = tiltNext || nextButtonReleased;
|
||||
|
||||
@@ -71,18 +71,6 @@ void XtcReaderChapterSelectionActivity::loop() {
|
||||
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.onNextList(selectorIndex, totalItems, [this] { requestUpdate(); });
|
||||
|
||||
@@ -532,6 +532,13 @@ void loop() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// When a non-default Long action fires for a page-turn button, mark it so that
|
||||
// detectPageTurn() suppresses the wasReleased-based page turn on button release.
|
||||
if (ev.type == ButtonEventManager::PressType::Long &&
|
||||
(ev.button == B::Left || ev.button == B::Right || ev.button == B::PageBack || ev.button == B::PageForward)) {
|
||||
buttonEventManager.markLongPressDispatched(ev.button);
|
||||
}
|
||||
|
||||
switch (static_cast<BA>(action)) {
|
||||
case BA::BTN_PAGE_FORWARD:
|
||||
activityManager.dispatchButtonAction(BA::BTN_PAGE_FORWARD);
|
||||
|
||||
@@ -272,15 +272,15 @@ void ButtonNavigator::onListNav(const Buttons& buttons, const bool forward, int&
|
||||
|
||||
const bool wasReleased = std::any_of(buttons.begin(), buttons.end(),
|
||||
[](const MappedInputManager::Button b) { return mappedInput->wasReleased(b); });
|
||||
if (wasReleased) {
|
||||
if (!wasReleased) return;
|
||||
|
||||
// Long press already fired: reset the guard and skip navigation — the jump-to-end
|
||||
// already happened on the down-hold, so release produces no additional move.
|
||||
if (longPressFired) {
|
||||
longPressFired = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool wasPressed = std::any_of(buttons.begin(), buttons.end(),
|
||||
[](const MappedInputManager::Button b) { return mappedInput->wasPressed(b); });
|
||||
if (!wasPressed) return;
|
||||
|
||||
const uint32_t now = millis();
|
||||
const bool isDouble = (now - lastPressMs) < listDoubleClickMs;
|
||||
lastPressMs = now;
|
||||
|
||||
Reference in New Issue
Block a user