Merge pull request #720 from oltaco/newui-multiclick-toggles

new-ui: add double/triple clicks, buzzer and gps toggle functions
This commit is contained in:
ripplebiz
2025-09-04 13:41:54 +10:00
committed by GitHub
5 changed files with 134 additions and 23 deletions

View File

@@ -225,11 +225,11 @@ public:
} }
bool handleInput(char c) override { bool handleInput(char c) override {
if (c == KEY_LEFT) { if (c == KEY_LEFT || c == KEY_PREV) {
_page = (_page + HomePage::Count - 1) % HomePage::Count; _page = (_page + HomePage::Count - 1) % HomePage::Count;
return true; return true;
} }
if (c == KEY_RIGHT || c == KEY_SELECT) { if (c == KEY_NEXT || c == KEY_RIGHT) {
_page = (_page + 1) % HomePage::Count; _page = (_page + 1) % HomePage::Count;
if (_page == HomePage::RECENT) { if (_page == HomePage::RECENT) {
_task->showAlert("Recent adverts", 800); _task->showAlert("Recent adverts", 800);
@@ -331,7 +331,7 @@ public:
} }
bool handleInput(char c) override { bool handleInput(char c) override {
if (c == KEY_SELECT || c == KEY_RIGHT) { if (c == KEY_NEXT || c == KEY_RIGHT) {
num_unread--; num_unread--;
if (num_unread == 0) { if (num_unread == 0) {
_task->gotoHomeScreen(); _task->gotoHomeScreen();
@@ -494,9 +494,13 @@ void UITask::loop() {
#if defined(PIN_USER_BTN) #if defined(PIN_USER_BTN)
int ev = user_btn.check(); int ev = user_btn.check();
if (ev == BUTTON_EVENT_CLICK) { if (ev == BUTTON_EVENT_CLICK) {
c = checkDisplayOn(KEY_SELECT); c = checkDisplayOn(KEY_NEXT);
} else if (ev == BUTTON_EVENT_LONG_PRESS) { } else if (ev == BUTTON_EVENT_LONG_PRESS) {
c = handleLongPress(KEY_ENTER); c = handleLongPress(KEY_ENTER);
} else if (ev == BUTTON_EVENT_DOUBLE_CLICK) {
c = handleDoubleClick(KEY_PREV);
} else if (ev == BUTTON_EVENT_TRIPLE_CLICK) {
c = handleTripleClick(KEY_SELECT);
} }
#endif #endif
#if defined(WIO_TRACKER_L1) #if defined(WIO_TRACKER_L1)
@@ -516,9 +520,13 @@ void UITask::loop() {
#if defined(PIN_USER_BTN_ANA) #if defined(PIN_USER_BTN_ANA)
ev = analog_btn.check(); ev = analog_btn.check();
if (ev == BUTTON_EVENT_CLICK) { if (ev == BUTTON_EVENT_CLICK) {
c = checkDisplayOn(KEY_SELECT); c = checkDisplayOn(KEY_NEXT);
} else if (ev == BUTTON_EVENT_LONG_PRESS) { } else if (ev == BUTTON_EVENT_LONG_PRESS) {
c = handleLongPress(KEY_ENTER); c = handleLongPress(KEY_ENTER);
} else if (ev == BUTTON_EVENT_DOUBLE_CLICK) {
c = handleDoubleClick(KEY_PREV);
} else if (ev == BUTTON_EVENT_TRIPLE_CLICK) {
c = handleTripleClick(KEY_SELECT);
} }
#endif #endif
#if defined(DISP_BACKLIGHT) && defined(BACKLIGHT_BTN) #if defined(DISP_BACKLIGHT) && defined(BACKLIGHT_BTN)
@@ -615,20 +623,53 @@ char UITask::handleLongPress(char c) {
return c; return c;
} }
/* char UITask::handleDoubleClick(char c) {
void UITask::handleButtonTriplePress() { MESH_DEBUG_PRINTLN("UITask: double click triggered");
MESH_DEBUG_PRINTLN("UITask: triple press triggered"); checkDisplayOn(c);
// Toggle buzzer quiet mode return c;
}
char UITask::handleTripleClick(char c) {
MESH_DEBUG_PRINTLN("UITask: triple click triggered");
checkDisplayOn(c);
toggleBuzzer();
c = 0;
return c;
}
void UITask::toggleGPS() {
if (_sensors != NULL) {
// toggle GPS on/off
int num = _sensors->getNumSettings();
for (int i = 0; i < num; i++) {
if (strcmp(_sensors->getSettingName(i), "gps") == 0) {
if (strcmp(_sensors->getSettingValue(i), "1") == 0) {
_sensors->setSettingValue("gps", "0");
soundBuzzer(UIEventType::ack);
showAlert("GPS: Disabled", 800);
} else {
_sensors->setSettingValue("gps", "1");
soundBuzzer(UIEventType::ack);
showAlert("GPS: Enabled", 800);
}
_next_refresh = 0;
break;
}
}
}
}
void UITask::toggleBuzzer() {
// Toggle buzzer quiet mode
#ifdef PIN_BUZZER #ifdef PIN_BUZZER
if (buzzer.isQuiet()) { if (buzzer.isQuiet()) {
buzzer.quiet(false); buzzer.quiet(false);
soundBuzzer(UIEventType::ack); soundBuzzer(UIEventType::ack);
showAlert("Buzzer: ON", 600); showAlert("Buzzer: ON", 800);
} else { } else {
buzzer.quiet(true); buzzer.quiet(true);
showAlert("Buzzer: OFF", 600); showAlert("Buzzer: OFF", 800);
} }
_next_refresh = 0; // trigger refresh _next_refresh = 0; // trigger refresh
#endif #endif
} }
*/

View File

@@ -43,6 +43,8 @@ class UITask : public AbstractUITask {
// Button action handlers // Button action handlers
char checkDisplayOn(char c); char checkDisplayOn(char c);
char handleLongPress(char c); char handleLongPress(char c);
char handleDoubleClick(char c);
char handleTripleClick(char c);
void setCurrScreen(UIScreen* c); void setCurrScreen(UIScreen* c);
@@ -61,6 +63,10 @@ public:
bool hasDisplay() const { return _display != NULL; } bool hasDisplay() const { return _display != NULL; }
bool isButtonPressed() const; bool isButtonPressed() const;
void toggleBuzzer();
void toggleGPS();
// from AbstractUITask // from AbstractUITask
void msgRead(int msgcount) override; void msgRead(int msgcount) override;
void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override; void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override;

View File

@@ -1,5 +1,7 @@
#include "MomentaryButton.h" #include "MomentaryButton.h"
#define MULTI_CLICK_WINDOW_MS 280
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup) { MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup) {
_pin = pin; _pin = pin;
_reverse = reverse; _reverse = reverse;
@@ -9,6 +11,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse
cancel = 0; cancel = 0;
_long_millis = long_press_millis; _long_millis = long_press_millis;
_threshold = 0; _threshold = 0;
_click_count = 0;
_last_click_time = 0;
_multi_click_window = MULTI_CLICK_WINDOW_MS;
_pending_click = false;
} }
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_threshold) { MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_threshold) {
@@ -20,6 +26,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_t
cancel = 0; cancel = 0;
_long_millis = long_press_millis; _long_millis = long_press_millis;
_threshold = analog_threshold; _threshold = analog_threshold;
_click_count = 0;
_last_click_time = 0;
_multi_click_window = MULTI_CLICK_WINDOW_MS;
_pending_click = false;
} }
void MomentaryButton::begin() { void MomentaryButton::begin() {
@@ -35,6 +45,10 @@ bool MomentaryButton::isPressed() const {
void MomentaryButton::cancelClick() { void MomentaryButton::cancelClick() {
cancel = 1; cancel = 1;
down_at = 0;
_click_count = 0;
_last_click_time = 0;
_pending_click = false;
} }
bool MomentaryButton::isPressed(int level) const { bool MomentaryButton::isPressed(int level) const {
@@ -60,13 +74,20 @@ int MomentaryButton::check(bool repeat_click) {
// button UP // button UP
if (_long_millis > 0) { if (_long_millis > 0) {
if (down_at > 0 && (unsigned long)(millis() - down_at) < _long_millis) { // only a CLICK if still within the long_press millis if (down_at > 0 && (unsigned long)(millis() - down_at) < _long_millis) { // only a CLICK if still within the long_press millis
event = BUTTON_EVENT_CLICK; _click_count++;
_last_click_time = millis();
_pending_click = true;
} }
} else { } else {
event = BUTTON_EVENT_CLICK; // any UP results in CLICK event when NOT using long_press feature _click_count++;
_last_click_time = millis();
_pending_click = true;
} }
if (event == BUTTON_EVENT_CLICK && cancel) { if (event == BUTTON_EVENT_CLICK && cancel) {
event = BUTTON_EVENT_NONE; event = BUTTON_EVENT_NONE;
_click_count = 0;
_last_click_time = 0;
_pending_click = false;
} }
down_at = 0; down_at = 0;
} }
@@ -77,8 +98,16 @@ int MomentaryButton::check(bool repeat_click) {
} }
if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) { if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) {
event = BUTTON_EVENT_LONG_PRESS; if (_pending_click) {
down_at = 0; // long press during multi-click detection - cancel pending clicks
cancelClick();
} else {
event = BUTTON_EVENT_LONG_PRESS;
down_at = 0;
_click_count = 0;
_last_click_time = 0;
_pending_click = false;
}
} }
if (down_at > 0 && repeat_click) { if (down_at > 0 && repeat_click) {
unsigned long diff = (unsigned long)(millis() - down_at); unsigned long diff = (unsigned long)(millis() - down_at);
@@ -87,5 +116,30 @@ int MomentaryButton::check(bool repeat_click) {
} }
} }
if (_pending_click && (millis() - _last_click_time) >= _multi_click_window) {
if (down_at > 0) {
// still pressed - wait for button release before processing clicks
return event;
}
switch (_click_count) {
case 1:
event = BUTTON_EVENT_CLICK;
break;
case 2:
event = BUTTON_EVENT_DOUBLE_CLICK;
break;
case 3:
event = BUTTON_EVENT_TRIPLE_CLICK;
break;
default:
// For 4+ clicks, treat as triple click?
event = BUTTON_EVENT_TRIPLE_CLICK;
break;
}
_click_count = 0;
_last_click_time = 0;
_pending_click = false;
}
return event; return event;
} }

View File

@@ -5,6 +5,8 @@
#define BUTTON_EVENT_NONE 0 #define BUTTON_EVENT_NONE 0
#define BUTTON_EVENT_CLICK 1 #define BUTTON_EVENT_CLICK 1
#define BUTTON_EVENT_LONG_PRESS 2 #define BUTTON_EVENT_LONG_PRESS 2
#define BUTTON_EVENT_DOUBLE_CLICK 3
#define BUTTON_EVENT_TRIPLE_CLICK 4
class MomentaryButton { class MomentaryButton {
int8_t _pin; int8_t _pin;
@@ -13,6 +15,10 @@ class MomentaryButton {
int _long_millis; int _long_millis;
int _threshold; // analog mode int _threshold; // analog mode
unsigned long down_at; unsigned long down_at;
uint8_t _click_count;
unsigned long _last_click_time;
int _multi_click_window;
bool _pending_click;
bool isPressed(int level) const; bool isPressed(int level) const;

View File

@@ -2,13 +2,17 @@
#include "DisplayDriver.h" #include "DisplayDriver.h"
#define KEY_LEFT 0xB4 #define KEY_LEFT 0xB4
#define KEY_UP 0xB5 #define KEY_UP 0xB5
#define KEY_DOWN 0xB6 #define KEY_DOWN 0xB6
#define KEY_RIGHT 0xB7 #define KEY_RIGHT 0xB7
#define KEY_SELECT 10 #define KEY_SELECT 10
#define KEY_ENTER 13 #define KEY_ENTER 13
#define KEY_BACK 27 // Esc #define KEY_CANCEL 27 // Esc
#define KEY_HOME 0xF0
#define KEY_NEXT 0xF1
#define KEY_PREV 0xF2
#define KEY_CONTEXT_MENU 0xF3
class UIScreen { class UIScreen {
protected: protected: