diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index c751eaf53..dfc545d0b 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -223,11 +223,11 @@ class HomeScreen : public UIScreen { } bool handleInput(char c) override { - if (c == KEY_LEFT) { + if (c == KEY_LEFT || c == KEY_PREV) { _page = (_page + HomePage::Count - 1) % HomePage::Count; return true; } - if (c == KEY_RIGHT || c == KEY_SELECT) { + if (c == KEY_NEXT || c == KEY_RIGHT) { _page = (_page + 1) % HomePage::Count; if (_page == HomePage::RECENT) { _task->showAlert("Recent adverts", 800); @@ -325,7 +325,7 @@ class MsgPreviewScreen : public UIScreen { } bool handleInput(char c) override { - if (c == KEY_SELECT || c == KEY_RIGHT) { + if (c == KEY_NEXT || c == KEY_RIGHT) { num_unread--; if (num_unread == 0) { _task->gotoHomeScreen(); @@ -492,9 +492,13 @@ void UITask::loop() { #if defined(PIN_USER_BTN) int ev = user_btn.check(); if (ev == BUTTON_EVENT_CLICK) { - c = checkDisplayOn(KEY_SELECT); + c = checkDisplayOn(KEY_NEXT); } else if (ev == BUTTON_EVENT_LONG_PRESS) { 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 #if defined(WIO_TRACKER_L1) @@ -514,9 +518,13 @@ void UITask::loop() { #if defined(PIN_USER_BTN_ANA) ev = analog_btn.check(); if (ev == BUTTON_EVENT_CLICK) { - c = checkDisplayOn(KEY_SELECT); + c = checkDisplayOn(KEY_NEXT); } else if (ev == BUTTON_EVENT_LONG_PRESS) { 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 @@ -604,20 +612,53 @@ char UITask::handleLongPress(char c) { return c; } -/* -void UITask::handleButtonTriplePress() { - MESH_DEBUG_PRINTLN("UITask: triple press triggered"); - // Toggle buzzer quiet mode +char UITask::handleDoubleClick(char c) { + MESH_DEBUG_PRINTLN("UITask: double click triggered"); + checkDisplayOn(c); + 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 if (buzzer.isQuiet()) { buzzer.quiet(false); soundBuzzer(UIEventType::ack); - showAlert("Buzzer: ON", 600); + showAlert("Buzzer: ON", 800); } else { buzzer.quiet(true); - showAlert("Buzzer: OFF", 600); + showAlert("Buzzer: OFF", 800); } _next_refresh = 0; // trigger refresh #endif } -*/ diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index f9e015506..a96abf897 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -37,6 +37,8 @@ class UITask : public AbstractUITask { // Button action handlers char checkDisplayOn(char c); char handleLongPress(char c); + char handleDoubleClick(char c); + char handleTripleClick(char c); void setCurrScreen(UIScreen* c); @@ -55,6 +57,10 @@ class UITask : public AbstractUITask { bool hasDisplay() const { return _display != NULL; } bool isButtonPressed() const; + void toggleBuzzer(); + void toggleGPS(); + + // from AbstractUITask void msgRead(int msgcount) override; void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override; diff --git a/src/helpers/ui/MomentaryButton.cpp b/src/helpers/ui/MomentaryButton.cpp index 36309600f..0ea4b027a 100644 --- a/src/helpers/ui/MomentaryButton.cpp +++ b/src/helpers/ui/MomentaryButton.cpp @@ -1,5 +1,7 @@ #include "MomentaryButton.h" +#define MULTI_CLICK_WINDOW_MS 280 + MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse, bool pulldownup) { _pin = pin; _reverse = reverse; @@ -9,6 +11,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse cancel = 0; _long_millis = long_press_millis; _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) { @@ -20,6 +26,10 @@ MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, int analog_t cancel = 0; _long_millis = long_press_millis; _threshold = analog_threshold; + _click_count = 0; + _last_click_time = 0; + _multi_click_window = MULTI_CLICK_WINDOW_MS; + _pending_click = false; } void MomentaryButton::begin() { @@ -35,6 +45,10 @@ bool MomentaryButton::isPressed() const { void MomentaryButton::cancelClick() { cancel = 1; + down_at = 0; + _click_count = 0; + _last_click_time = 0; + _pending_click = false; } bool MomentaryButton::isPressed(int level) const { @@ -60,13 +74,20 @@ int MomentaryButton::check(bool repeat_click) { // button UP 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 - event = BUTTON_EVENT_CLICK; + _click_count++; + _last_click_time = millis(); + _pending_click = true; } } 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) { event = BUTTON_EVENT_NONE; + _click_count = 0; + _last_click_time = 0; + _pending_click = false; } 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) { - event = BUTTON_EVENT_LONG_PRESS; - down_at = 0; + if (_pending_click) { + // 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) { 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; } \ No newline at end of file diff --git a/src/helpers/ui/MomentaryButton.h b/src/helpers/ui/MomentaryButton.h index d002f6524..1122e56a5 100644 --- a/src/helpers/ui/MomentaryButton.h +++ b/src/helpers/ui/MomentaryButton.h @@ -5,6 +5,8 @@ #define BUTTON_EVENT_NONE 0 #define BUTTON_EVENT_CLICK 1 #define BUTTON_EVENT_LONG_PRESS 2 +#define BUTTON_EVENT_DOUBLE_CLICK 3 +#define BUTTON_EVENT_TRIPLE_CLICK 4 class MomentaryButton { int8_t _pin; @@ -13,6 +15,10 @@ class MomentaryButton { int _long_millis; int _threshold; // analog mode 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; diff --git a/src/helpers/ui/UIScreen.h b/src/helpers/ui/UIScreen.h index 6faa591ad..6aa1d69c1 100644 --- a/src/helpers/ui/UIScreen.h +++ b/src/helpers/ui/UIScreen.h @@ -2,13 +2,17 @@ #include "DisplayDriver.h" -#define KEY_LEFT 0xB4 -#define KEY_UP 0xB5 -#define KEY_DOWN 0xB6 -#define KEY_RIGHT 0xB7 -#define KEY_SELECT 10 -#define KEY_ENTER 13 -#define KEY_BACK 27 // Esc +#define KEY_LEFT 0xB4 +#define KEY_UP 0xB5 +#define KEY_DOWN 0xB6 +#define KEY_RIGHT 0xB7 +#define KEY_SELECT 10 +#define KEY_ENTER 13 +#define KEY_CANCEL 27 // Esc +#define KEY_HOME 0xF0 +#define KEY_NEXT 0xF1 +#define KEY_PREV 0xF2 +#define KEY_CONTEXT_MENU 0xF3 class UIScreen { protected: