Introduce extended button handler
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
#include "ButtonEventManager.h"
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
|
||||
// Required for constexpr array definition in .cpp
|
||||
constexpr ButtonEventManager::Button ButtonEventManager::ALL_BUTTONS[ButtonEventManager::NUM_BUTTONS];
|
||||
|
||||
bool ButtonEventManager::hasDoubleAction(const Button button) {
|
||||
using BA = CrossPointSettings::BUTTON_ACTION;
|
||||
switch (button) {
|
||||
case Button::Back:
|
||||
return SETTINGS.btnDoubleBack != BA::BTN_DEFAULT;
|
||||
case Button::Confirm:
|
||||
return SETTINGS.btnDoubleConfirm != BA::BTN_DEFAULT;
|
||||
case Button::Left:
|
||||
return SETTINGS.btnDoubleLeft != BA::BTN_DEFAULT;
|
||||
case Button::Right:
|
||||
return SETTINGS.btnDoubleRight != BA::BTN_DEFAULT;
|
||||
case Button::Up:
|
||||
return SETTINGS.btnDoubleUp != BA::BTN_DEFAULT;
|
||||
case Button::Down:
|
||||
return SETTINGS.btnDoubleDown != BA::BTN_DEFAULT;
|
||||
case Button::PageBack:
|
||||
return SETTINGS.btnDoublePageBack != BA::BTN_DEFAULT;
|
||||
case Button::PageForward:
|
||||
return SETTINGS.btnDoublePageForward != BA::BTN_DEFAULT;
|
||||
case Button::Power:
|
||||
return SETTINGS.btnDoublePower != BA::BTN_DEFAULT;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ButtonEventManager::pushEvent(const Button button, const PressType type) {
|
||||
const int next = (eventTail + 1) % EVENT_BUF;
|
||||
if (next == eventHead) return; // buffer full, drop oldest not possible — just drop newest
|
||||
eventBuf[eventTail] = {button, type};
|
||||
eventTail = next;
|
||||
}
|
||||
|
||||
bool ButtonEventManager::consumeEvent(ButtonEvent& out) {
|
||||
if (eventHead == eventTail) return false;
|
||||
out = eventBuf[eventHead];
|
||||
eventHead = (eventHead + 1) % EVENT_BUF;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ButtonEventManager::drain() {
|
||||
for (auto& b : buttons) {
|
||||
b.state = State::Idle;
|
||||
b.pressDownTime = 0;
|
||||
b.releaseTime = 0;
|
||||
}
|
||||
eventHead = eventTail = 0;
|
||||
}
|
||||
|
||||
void ButtonEventManager::processButton(const int idx, const Button btn) {
|
||||
PerButton& s = buttons[idx];
|
||||
const unsigned long now = millis();
|
||||
const bool pressed = input.wasPressed(btn);
|
||||
const bool released = input.wasReleased(btn);
|
||||
const bool held = input.isPressed(btn);
|
||||
|
||||
switch (s.state) {
|
||||
case State::Idle:
|
||||
if (pressed) {
|
||||
s.state = State::Pressed;
|
||||
s.pressDownTime = now;
|
||||
}
|
||||
break;
|
||||
|
||||
case State::Pressed:
|
||||
if (released) {
|
||||
const unsigned long heldMs = now - s.pressDownTime;
|
||||
if (heldMs >= LONG_PRESS_MS) {
|
||||
pushEvent(btn, PressType::Long);
|
||||
s.state = State::Idle;
|
||||
} else if (hasDoubleAction(btn)) {
|
||||
// Delay short-press decision until double-click window expires
|
||||
s.releaseTime = now;
|
||||
s.state = State::ReleasedOnce;
|
||||
} else {
|
||||
// No double action configured — fire immediately
|
||||
pushEvent(btn, PressType::Short);
|
||||
s.state = State::Idle;
|
||||
}
|
||||
} else if (!held) {
|
||||
// Button disappeared without wasReleased edge (e.g. after drain) — reset
|
||||
s.state = State::Idle;
|
||||
}
|
||||
break;
|
||||
|
||||
case State::ReleasedOnce:
|
||||
if (pressed) {
|
||||
// Second press within window — start tracking it
|
||||
s.state = State::DoublePressed;
|
||||
s.pressDownTime = now;
|
||||
} else if (now - s.releaseTime >= DOUBLE_WINDOW_MS) {
|
||||
// Window expired without a second press — it was a short press
|
||||
pushEvent(btn, PressType::Short);
|
||||
s.state = State::Idle;
|
||||
}
|
||||
break;
|
||||
|
||||
case State::DoublePressed:
|
||||
if (released) {
|
||||
pushEvent(btn, PressType::Double);
|
||||
s.state = State::Idle;
|
||||
} else if (!held) {
|
||||
// Disappeared without edge — treat as double anyway
|
||||
pushEvent(btn, PressType::Double);
|
||||
s.state = State::Idle;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonEventManager::update() {
|
||||
for (int i = 0; i < NUM_BUTTONS; i++) {
|
||||
processButton(i, ALL_BUTTONS[i]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user