Long press and double click timeouts in config

pull/274/head
Stephen Brown 3 years ago
parent 96ad7ecede
commit a8fd1dad2e
  1. 13
      src/config.cpp
  2. 7
      src/config.h
  3. 4
      src/minidexed.ini
  4. 58
      src/uibuttons.cpp
  5. 25
      src/uibuttons.h
  6. 4
      src/userinterface.cpp

@ -94,6 +94,9 @@ void CConfig::Load (void)
m_ButtonActionSelect = m_Properties.GetString ("ButtonActionSelect", "click"); m_ButtonActionSelect = m_Properties.GetString ("ButtonActionSelect", "click");
m_ButtonActionHome = m_Properties.GetString ("ButtonActionHome", "longpress"); 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_bEncoderEnabled = m_Properties.GetNumber ("EncoderEnabled", 0) != 0;
m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10); m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10);
m_nEncoderPinData = m_Properties.GetNumber ("EncoderPinData", 9); m_nEncoderPinData = m_Properties.GetNumber ("EncoderPinData", 9);
@ -247,6 +250,16 @@ const char *CConfig::GetButtonActionHome (void) const
return m_ButtonActionHome.c_str(); 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 bool CConfig::GetEncoderEnabled (void) const
{ {
return m_bEncoderEnabled; return m_bEncoderEnabled;

@ -103,6 +103,10 @@ public:
const char *GetButtonActionBack (void) const; const char *GetButtonActionBack (void) const;
const char *GetButtonActionSelect (void) const; const char *GetButtonActionSelect (void) const;
const char *GetButtonActionHome (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 // KY-040 Rotary Encoder
// GPIO pin numbers are chip numbers, not header positions // GPIO pin numbers are chip numbers, not header positions
@ -150,6 +154,9 @@ private:
std::string m_ButtonActionBack; std::string m_ButtonActionBack;
std::string m_ButtonActionSelect; std::string m_ButtonActionSelect;
std::string m_ButtonActionHome; std::string m_ButtonActionHome;
unsigned m_nDoubleClickTimeout;
unsigned m_nLongPressTimeout;
bool m_bEncoderEnabled; bool m_bEncoderEnabled;
unsigned m_nEncoderPinClock; unsigned m_nEncoderPinClock;

@ -42,6 +42,10 @@ ButtonActionHome=longpress
ButtonPinShortcut=11 ButtonPinShortcut=11
# (Shortcut doesn't have an action) # (Shortcut doesn't have an action)
# Timeouts in milliseconds for double click and long press
DoubleClickTimeout=400
LongPressTimeout=600
# KY-040 Rotary Encoder # KY-040 Rotary Encoder
EncoderEnabled=1 EncoderEnabled=1
EncoderPinClock=10 EncoderPinClock=10

@ -32,12 +32,15 @@ CUIButton::CUIButton (void)
: m_pinNumber (0), : m_pinNumber (0),
m_pin (0), m_pin (0),
m_lastValue (1), m_lastValue (1),
m_timer (LONG_PRESS_TIME), m_timer (0),
m_debounceTimer (DEBOUNCE_TIME), m_debounceTimer (0),
m_numClicks (0), m_numClicks (0),
m_clickEvent(BtnEventNone), m_clickEvent(BtnEventNone),
m_doubleClickEvent(BtnEventNone), m_doubleClickEvent(BtnEventNone),
m_longPressEvent(BtnEventNone) { m_longPressEvent(BtnEventNone),
m_doubleClickTimeout(0),
m_longPressTimeout(0)
{
} }
CUIButton::~CUIButton (void) CUIButton::~CUIButton (void)
@ -50,15 +53,22 @@ CUIButton::~CUIButton (void)
void CUIButton::reset (void) void CUIButton::reset (void)
{ {
m_timer = LONG_PRESS_TIME; m_timer = m_longPressTimeout;
m_numClicks = 0; m_numClicks = 0;
} }
boolean CUIButton::Initialize (unsigned pinNumber) boolean CUIButton::Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout)
{ {
assert (!m_pin); assert (!m_pin);
assert(longPressTimeout >= doubleClickTimeout);
m_pinNumber = pinNumber; m_pinNumber = pinNumber;
m_doubleClickTimeout = doubleClickTimeout;
m_longPressTimeout = longPressTimeout;
// Initialise timing values
m_timer = m_longPressTimeout;
m_debounceTimer = DEBOUNCE_TIME;
if (m_pinNumber != 0) if (m_pinNumber != 0)
{ {
@ -98,17 +108,17 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void)
unsigned value = m_pin->Read(); unsigned value = m_pin->Read();
// TODO: long press time from config // TODO: long press time from config
if (m_timer < LONG_PRESS_TIME) { if (m_timer < m_longPressTimeout) {
m_timer++; 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 // The user has clicked and released the button once within the
// timeout - this must be a single click // timeout - this must be a single click
reset(); reset();
LOGDBG ("Click"); LOGDBG ("Click");
return BtnTriggerClick; return BtnTriggerClick;
} }
if (m_timer == LONG_PRESS_TIME) { if (m_timer == m_longPressTimeout) {
if (m_lastValue == 0 && m_numClicks == 1) { if (m_lastValue == 0 && m_numClicks == 1) {
// Single long press // Single long press
reset(); reset();
@ -162,7 +172,7 @@ CUIButton::BtnTrigger CUIButton::ReadTrigger (void)
if (m_numClicks == 1 && if (m_numClicks == 1 &&
(m_doubleClickEvent == BtnEventNone || (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 // Either the user released the button when there is no double
// click mapped // click mapped
@ -229,9 +239,12 @@ CUIButtons::CUIButtons (
unsigned nextPin, const char *nextAction, unsigned nextPin, const char *nextAction,
unsigned backPin, const char *backAction, unsigned backPin, const char *backAction,
unsigned selectPin, const char *selectAction, 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_prevAction(CUIButton::triggerTypeFromString(prevAction)),
m_nextPin(nextPin), m_nextPin(nextPin),
m_nextAction(CUIButton::triggerTypeFromString(nextAction)), m_nextAction(CUIButton::triggerTypeFromString(nextAction)),
@ -252,6 +265,22 @@ CUIButtons::~CUIButtons (void)
boolean CUIButtons::Initialize (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 // Each button can be assigned up to 3 actions: click, doubleclick and
// longpress. We may not initialise all of the buttons // longpress. We may not initialise all of the buttons
unsigned pins[MAX_BUTTONS] = { unsigned pins[MAX_BUTTONS] = {
@ -259,11 +288,6 @@ boolean CUIButtons::Initialize (void)
}; };
CUIButton::BtnTrigger triggers[MAX_BUTTONS] = { CUIButton::BtnTrigger triggers[MAX_BUTTONS] = {
m_prevAction, m_nextAction, m_backAction, m_selectAction, m_homeAction 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::BtnEvent events[MAX_BUTTONS] = {
CUIButton::BtnEventPrev, CUIButton::BtnEventPrev,
@ -289,7 +313,7 @@ boolean CUIButtons::Initialize (void)
} }
else if (m_buttons[j].getPinNumber() == 0) { else if (m_buttons[j].getPinNumber() == 0) {
// This is un-initialised so can be assigned // This is un-initialised so can be assigned
m_buttons[j].Initialize(pins[i]); m_buttons[j].Initialize(pins[i], doubleClickTimeout, longPressTimeout);
break; break;
} }
} }

@ -29,10 +29,10 @@
#define BUTTONS_UPDATE_NUM_TICKS 100 #define BUTTONS_UPDATE_NUM_TICKS 100
#define DEBOUNCE_TIME 100 #define DEBOUNCE_TIME 100
#define DOUBLE_CLICK_TIME 4000
#define LONG_PRESS_TIME 10000
#define MAX_BUTTONS 5 #define MAX_BUTTONS 5
class CUIButtons;
class CUIButton class CUIButton
{ {
public: public:
@ -59,7 +59,7 @@ public:
~CUIButton (void); ~CUIButton (void);
void reset (void); void reset (void);
boolean Initialize (unsigned pinNumber); boolean Initialize (unsigned pinNumber, unsigned doubleClickTimeout, unsigned longPressTimeout);
void setClickEvent(BtnEvent clickEvent); void setClickEvent(BtnEvent clickEvent);
void setDoubleClickEvent(BtnEvent doubleClickEvent); void setDoubleClickEvent(BtnEvent doubleClickEvent);
@ -77,6 +77,7 @@ private:
unsigned m_pinNumber; unsigned m_pinNumber;
// GPIO pin // GPIO pin
CGPIOPin *m_pin; CGPIOPin *m_pin;
// The value of the pin at the end of the last loop
unsigned m_lastValue; unsigned m_lastValue;
// Set to 0 on press, increment each read, use to trigger events // Set to 0 on press, increment each read, use to trigger events
uint16_t m_timer; uint16_t m_timer;
@ -90,7 +91,11 @@ private:
BtnEvent m_doubleClickEvent; BtnEvent m_doubleClickEvent;
// Event to fire on long press // Event to fire on long press
BtnEvent m_longPressEvent; 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 class CUIButtons
@ -104,7 +109,8 @@ public:
unsigned nextPin, const char *nextAction, unsigned nextPin, const char *nextAction,
unsigned backPin, const char *backAction, unsigned backPin, const char *backAction,
unsigned selectPin, const char *selectAction, unsigned selectPin, const char *selectAction,
unsigned homePin, const char *homeAction unsigned homePin, const char *homeAction,
unsigned doubleClickTimeout, unsigned longPressTimeout
); );
~CUIButtons (void); ~CUIButtons (void);
@ -117,8 +123,13 @@ public:
void ResetButton (unsigned pinNumber); void ResetButton (unsigned pinNumber);
private: private:
// Up to 5 buttons can be defined // Array of 5 buttons
CUIButton m_buttons[5]; 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 // Configuration for buttons
unsigned m_prevPin; unsigned m_prevPin;

@ -96,7 +96,9 @@ bool CUserInterface::Initialize (void)
m_pConfig->GetButtonPinSelect (), m_pConfig->GetButtonPinSelect (),
m_pConfig->GetButtonActionSelect (), m_pConfig->GetButtonActionSelect (),
m_pConfig->GetButtonPinHome (), m_pConfig->GetButtonPinHome (),
m_pConfig->GetButtonActionHome ()); m_pConfig->GetButtonActionHome (),
m_pConfig->GetDoubleClickTimeout (),
m_pConfig->GetLongPressTimeout () );
assert (m_pUIButtons); assert (m_pUIButtons);
if (!m_pUIButtons->Initialize ()) if (!m_pUIButtons->Initialize ())

Loading…
Cancel
Save