From a8fd1dad2ed3e262f63e2175e9a5309016a95bbb Mon Sep 17 00:00:00 2001 From: Stephen Brown Date: Mon, 27 Jun 2022 17:29:43 +0100 Subject: [PATCH] Long press and double click timeouts in config --- src/config.cpp | 13 ++++++++++ src/config.h | 7 ++++++ src/minidexed.ini | 4 +++ src/uibuttons.cpp | 58 ++++++++++++++++++++++++++++++------------- src/uibuttons.h | 25 +++++++++++++------ src/userinterface.cpp | 4 ++- 6 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index d699b07..e808459 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -94,6 +94,9 @@ void CConfig::Load (void) m_ButtonActionSelect = m_Properties.GetString ("ButtonActionSelect", "click"); m_ButtonActionHome = m_Properties.GetString ("ButtonActionHome", "longpress"); + m_nDoubleClickTimeout = m_Properties.GetNumber ("DoubleClickTimeout", 400); + m_nLongPressTimeout = m_Properties.GetNumber ("LongPressTimeout", 600); + m_bEncoderEnabled = m_Properties.GetNumber ("EncoderEnabled", 0) != 0; m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10); m_nEncoderPinData = m_Properties.GetNumber ("EncoderPinData", 9); @@ -247,6 +250,16 @@ const char *CConfig::GetButtonActionHome (void) const return m_ButtonActionHome.c_str(); } +unsigned CConfig::GetDoubleClickTimeout (void) const +{ + return m_nDoubleClickTimeout; +} + +unsigned CConfig::GetLongPressTimeout (void) const +{ + return m_nLongPressTimeout; +} + bool CConfig::GetEncoderEnabled (void) const { return m_bEncoderEnabled; diff --git a/src/config.h b/src/config.h index f5818da..53c8e2e 100644 --- a/src/config.h +++ b/src/config.h @@ -103,6 +103,10 @@ public: const char *GetButtonActionBack (void) const; const char *GetButtonActionSelect (void) const; const char *GetButtonActionHome (void) const; + + // Timeouts for button events in milliseconds + unsigned GetDoubleClickTimeout (void) const; + unsigned GetLongPressTimeout (void) const; // KY-040 Rotary Encoder // GPIO pin numbers are chip numbers, not header positions @@ -150,6 +154,9 @@ private: std::string m_ButtonActionBack; std::string m_ButtonActionSelect; std::string m_ButtonActionHome; + + unsigned m_nDoubleClickTimeout; + unsigned m_nLongPressTimeout; bool m_bEncoderEnabled; unsigned m_nEncoderPinClock; diff --git a/src/minidexed.ini b/src/minidexed.ini index c680284..567c1be 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -42,6 +42,10 @@ ButtonActionHome=longpress ButtonPinShortcut=11 # (Shortcut doesn't have an action) +# Timeouts in milliseconds for double click and long press +DoubleClickTimeout=400 +LongPressTimeout=600 + # KY-040 Rotary Encoder EncoderEnabled=1 EncoderPinClock=10 diff --git a/src/uibuttons.cpp b/src/uibuttons.cpp index fe26a2a..ff5bb2a 100644 --- a/src/uibuttons.cpp +++ b/src/uibuttons.cpp @@ -32,12 +32,15 @@ CUIButton::CUIButton (void) : m_pinNumber (0), m_pin (0), m_lastValue (1), - m_timer (LONG_PRESS_TIME), - m_debounceTimer (DEBOUNCE_TIME), + m_timer (0), + m_debounceTimer (0), m_numClicks (0), m_clickEvent(BtnEventNone), m_doubleClickEvent(BtnEventNone), - m_longPressEvent(BtnEventNone) { + m_longPressEvent(BtnEventNone), + m_doubleClickTimeout(0), + m_longPressTimeout(0) +{ } CUIButton::~CUIButton (void) @@ -50,15 +53,22 @@ CUIButton::~CUIButton (void) void CUIButton::reset (void) { - m_timer = LONG_PRESS_TIME; + m_timer = m_longPressTimeout; m_numClicks = 0; } -boolean CUIButton::Initialize (unsigned pinNumber) +boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout) { assert (!m_pin); + assert(longPressTimeout >= doubleClickTimeout); m_pinNumber = pinNumber; + m_doubleClickTimeout = doubleClickTimeout; + m_longPressTimeout = longPressTimeout; + + // Initialise timing values + m_timer = m_longPressTimeout; + m_debounceTimer = DEBOUNCE_TIME; if (m_pinNumber != 0) { @@ -98,17 +108,17 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void) unsigned value = m_pin->Read(); // TODO: long press time from config - if (m_timer < LONG_PRESS_TIME) { + if (m_timer < m_longPressTimeout) { m_timer++; - if (m_timer == DOUBLE_CLICK_TIME && m_lastValue == 1 && m_numClicks == 1) { + if (m_timer == m_doubleClickTimeout && m_lastValue == 1 && m_numClicks == 1) { // The user has clicked and released the button once within the // timeout - this must be a single click reset(); LOGDBG ("Click"); return BtnTriggerClick; } - if (m_timer == LONG_PRESS_TIME) { + if (m_timer == m_longPressTimeout) { if (m_lastValue == 0 && m_numClicks == 1) { // Single long press reset(); @@ -162,7 +172,7 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void) if (m_numClicks == 1 && (m_doubleClickEvent == BtnEventNone || - m_timer >= DOUBLE_CLICK_TIME && m_timer < LONG_PRESS_TIME) + m_timer >= m_doubleClickTimeout && m_timer < m_longPressTimeout) ) { // Either the user released the button when there is no double // click mapped @@ -229,9 +239,12 @@ CUIButtons::CUIButtons ( unsigned nextPin, const char *nextAction, unsigned backPin, const char *backAction, unsigned selectPin, const char *selectAction, - unsigned homePin, const char *homeAction + unsigned homePin, const char *homeAction, + unsigned doubleClickTimeout, unsigned longPressTimeout ) -: m_prevPin(prevPin), +: m_doubleClickTimeout(doubleClickTimeout), + m_longPressTimeout(longPressTimeout), + m_prevPin(prevPin), m_prevAction(CUIButton::triggerTypeFromString(prevAction)), m_nextPin(nextPin), m_nextAction(CUIButton::triggerTypeFromString(nextAction)), @@ -252,6 +265,22 @@ CUIButtons::~CUIButtons (void) boolean CUIButtons::Initialize (void) { + // First sanity check and convert the timeouts: + // Internally values are in tenths of a millisecond, but config values + // are in milliseconds + unsigned doubleClickTimeout = m_doubleClickTimeout * 10; + unsigned longPressTimeout = m_longPressTimeout * 10; + + if (longPressTimeout < doubleClickTimeout) { + // This is invalid - long press must be longest timeout + LOGERR("LongPressTimeout (%u) should not be shorter than DoubleClickTimeout (%u)", + m_longPressTimeout, + m_doubleClickTimeout); + + // Just make long press as long as double click + longPressTimeout = doubleClickTimeout; + } + // Each button can be assigned up to 3 actions: click, doubleclick and // longpress. We may not initialise all of the buttons unsigned pins[MAX_BUTTONS] = { @@ -259,11 +288,6 @@ boolean CUIButtons::Initialize (void) }; CUIButton::BtnTrigger triggers[MAX_BUTTONS] = { m_prevAction, m_nextAction, m_backAction, m_selectAction, m_homeAction - // CUIButton::BtnTriggerNone, - // CUIButton::BtnTriggerNone, - // CUIButton::BtnTriggerDoubleClick, - // CUIButton::BtnTriggerClick, - // CUIButton::BtnTriggerLongPress }; CUIButton::BtnEvent events[MAX_BUTTONS] = { CUIButton::BtnEventPrev, @@ -289,7 +313,7 @@ boolean CUIButtons::Initialize (void) } else if (m_buttons[j].getPinNumber() == 0) { // This is un-initialised so can be assigned - m_buttons[j].Initialize(pins[i]); + m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout); break; } } diff --git a/src/uibuttons.h b/src/uibuttons.h index 455f32c..0b3733b 100644 --- a/src/uibuttons.h +++ b/src/uibuttons.h @@ -29,10 +29,10 @@ #define BUTTONS_UPDATE_NUM_TICKS 100 #define DEBOUNCE_TIME 100 -#define DOUBLE_CLICK_TIME 4000 -#define LONG_PRESS_TIME 10000 #define MAX_BUTTONS 5 +class CUIButtons; + class CUIButton { public: @@ -59,7 +59,7 @@ public: ~CUIButton (void); void reset (void); - boolean Initialize (unsigned pinNumber); + boolean Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout); void setClickEvent(BtnEvent clickEvent); void setDoubleClickEvent(BtnEvent doubleClickEvent); @@ -77,6 +77,7 @@ private: unsigned m_pinNumber; // GPIO pin CGPIOPin *m_pin; + // The value of the pin at the end of the last loop unsigned m_lastValue; // Set to 0 on press, increment each read, use to trigger events uint16_t m_timer; @@ -90,7 +91,11 @@ private: BtnEvent m_doubleClickEvent; // Event to fire on long press BtnEvent m_longPressEvent; - // The value of the pin at the end of the last loop + + // Timeout for double click in tenths of a millisecond + unsigned m_doubleClickTimeout; + // Timeout for long press in tenths of a millisecond + unsigned m_longPressTimeout; }; class CUIButtons @@ -104,7 +109,8 @@ public: unsigned nextPin, const char *nextAction, unsigned backPin, const char *backAction, unsigned selectPin, const char *selectAction, - unsigned homePin, const char *homeAction + unsigned homePin, const char *homeAction, + unsigned doubleClickTimeout, unsigned longPressTimeout ); ~CUIButtons (void); @@ -117,8 +123,13 @@ public: void ResetButton (unsigned pinNumber); private: - // Up to 5 buttons can be defined - CUIButton m_buttons[5]; + // Array of 5 buttons + CUIButton m_buttons[MAX_BUTTONS]; + + // Timeout for double click in tenths of a millisecond + unsigned m_doubleClickTimeout; + // Timeout for long press in tenths of a millisecond + unsigned m_longPressTimeout; // Configuration for buttons unsigned m_prevPin; diff --git a/src/userinterface.cpp b/src/userinterface.cpp index c46115a..799b386 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -96,7 +96,9 @@ bool CUserInterface::Initialize (void) m_pConfig->GetButtonPinSelect (), m_pConfig->GetButtonActionSelect (), m_pConfig->GetButtonPinHome (), - m_pConfig->GetButtonActionHome ()); + m_pConfig->GetButtonActionHome (), + m_pConfig->GetDoubleClickTimeout (), + m_pConfig->GetLongPressTimeout () ); assert (m_pUIButtons); if (!m_pUIButtons->Initialize ())