Long button press support (#1188)

This commit is contained in:
Mark Thompson 2023-06-25 04:32:37 -05:00 committed by GitHub
parent 199570d4a5
commit 407fee23b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 112 additions and 20 deletions

View File

@ -248,6 +248,7 @@ void ControlsSwitchesWidget::on_show() {
bool ControlsSwitchesWidget::on_key(const KeyEvent key) { bool ControlsSwitchesWidget::on_key(const KeyEvent key) {
key_event_mask = 1 << toUType(key); key_event_mask = 1 << toUType(key);
long_press_key_event_mask = switch_long_press_occurred((size_t)key) ? key_event_mask : 0;
return true; return true;
} }
@ -325,6 +326,14 @@ void ControlsSwitchesWidget::paint(Painter& painter) {
switches_event >>= 1; switches_event >>= 1;
} }
switches_event = long_press_key_event_mask;
for (const auto r : events_rects) {
if (switches_event & 1)
painter.fill_rectangle(r + pos, Color::cyan());
switches_event >>= 1;
}
} }
void ControlsSwitchesWidget::on_frame_sync() { void ControlsSwitchesWidget::on_frame_sync() {
@ -335,12 +344,21 @@ void ControlsSwitchesWidget::on_frame_sync() {
DebugControlsView::DebugControlsView(NavigationView& nav) { DebugControlsView::DebugControlsView(NavigationView& nav) {
add_children({ add_children({
&text_title, &labels,
&switches_widget, &switches_widget,
&options_switches_mode,
&button_done, &button_done,
}); });
button_done.on_select = [&nav](Button&) { nav.pop(); }; button_done.on_select = [&nav](Button&) {
switches_long_press_enable(0);
nav.pop();
};
options_switches_mode.on_change = [this](size_t, OptionsField::value_t v) {
(void)v;
switches_long_press_enable(options_switches_mode.selected_index_value());
};
} }
void DebugControlsView::focus() { void DebugControlsView::focus() {

View File

@ -31,6 +31,7 @@
#include "rffc507x.hpp" #include "rffc507x.hpp"
#include "portapack.hpp" #include "portapack.hpp"
#include "memory_map.hpp" #include "memory_map.hpp"
#include "irq_controls.hpp"
#include <functional> #include <functional>
#include <utility> #include <utility>
@ -220,7 +221,8 @@ class ControlsSwitchesWidget : public Widget {
ControlsSwitchesWidget( ControlsSwitchesWidget(
Rect parent_rect) Rect parent_rect)
: Widget{parent_rect}, : Widget{parent_rect},
key_event_mask(0) { key_event_mask(0),
long_press_key_event_mask{0} {
set_focusable(true); set_focusable(true);
} }
@ -231,6 +233,7 @@ class ControlsSwitchesWidget : public Widget {
private: private:
uint8_t key_event_mask; uint8_t key_event_mask;
uint8_t long_press_key_event_mask;
MessageHandlerRegistration message_handler_frame_sync{ MessageHandlerRegistration message_handler_frame_sync{
Message::ID::DisplayFrameSync, Message::ID::DisplayFrameSync,
@ -250,15 +253,22 @@ class DebugControlsView : public View {
std::string title() const override { return "Buttons Test"; }; std::string title() const override { return "Buttons Test"; };
private: private:
Text text_title{ Labels labels{
{64, 16, 184, 16}, {{8 * 8, 1 * 16}, "Controls State", Color::white()},
"Controls State", {{0 * 8, 14 * 16}, "Long-Press Mode:", Color::grey()}};
};
ControlsSwitchesWidget switches_widget{ ControlsSwitchesWidget switches_widget{
{80, 80, 80, 112}, {80, 80, 80, 112},
}; };
OptionsField options_switches_mode{
{17 * 8, 14 * 16},
8,
{
{"Disabled", 0},
{"Enabled", 0xFF}, // all KeyEvent bits to long-press mode
}};
Button button_done{ Button button_done{
{72, 264, 96, 24}, {72, 264, 96, 24},
"Done"}; "Done"};

View File

@ -30,7 +30,7 @@ bool Debounce::feed(const uint8_t bit) {
// "Repeat" handling - simulated button release // "Repeat" handling - simulated button release
if (repeat_ctr_) { if (repeat_ctr_) {
// Make sure the button is still being held continuously // Make sure the button is still being held continuously
if (history_ == 0xFF) { if ((history_ == 0xFF) && !long_press_enabled_) {
// Simulate button press every REPEAT_SUBSEQUENT_DELAY ticks // Simulate button press every REPEAT_SUBSEQUENT_DELAY ticks
if (--repeat_ctr_ == 0) { if (--repeat_ctr_ == 0) {
state_ = !state_; state_ = !state_;
@ -49,29 +49,59 @@ bool Debounce::feed(const uint8_t bit) {
if ((history_ & DEBOUNCE_MASK) == DEBOUNCE_MASK) { if ((history_ & DEBOUNCE_MASK) == DEBOUNCE_MASK) {
state_ = 1; state_ = 1;
held_time_ = 0; held_time_ = 0;
// If long_press_enabled_, state() function masks the button press until it's released
// or until LONG_PRESS_DELAY is reached
if (long_press_enabled_) {
pulse_upon_release_ = true;
return false;
}
return true; return true;
} }
} else { } else {
// Previous button state was 1 (pressed); // Previous button state was 1 (pressed);
// Has button been released for DEBOUNCE_COUNT ticks? // Has button been released for DEBOUNCE_COUNT ticks?
if ((history_ & DEBOUNCE_MASK) == 0) { if ((history_ & DEBOUNCE_MASK) == 0) {
state_ = 0; // Button has been released when long_press_enabled_ and before LONG_PRESS_DELAY was reached;
// allow state() function to finally return a single press indication
// (in long press mode, apps won't see button press until the button is released)
if (pulse_upon_release_) {
// leaving state_==1 for one cycle
pulse_upon_release_ = 0;
} else {
state_ = 0;
}
// Reset long_press_occurred_ flag after button is released
long_press_occurred_ = false;
return true; return true;
} }
// Repeat support is limited to the 4 directional buttons // Has button been held continuously?
if (repeat_enabled_) { if (history_ == 0xFF) {
// Has button been held continuously for DEBOUNCE_REPEAT_DELAY? held_time_++;
if (history_ == 0xFF) { if (pulse_upon_release_) {
if (++held_time_ == REPEAT_INITIAL_DELAY) { // Button is being held down and long_press support is enabled for this key:
// if LONG_PRESS_DELAY is reached then finally report that switch is pressed and set flag
// indicating it was a LONG press
// (note that repease_support and long_press support are mutually exclusive)
if (held_time_ == LONG_PRESS_DELAY) {
long_press_occurred_ = true;
pulse_upon_release_ = 0;
held_time_ = 0;
return true;
}
} else if (repeat_enabled_ && !long_press_enabled_) {
// Repeat support -- 4 directional buttons only (unless long_press is enabled)
if (held_time_ == REPEAT_INITIAL_DELAY) {
// Delay reached; trigger repeat code on NEXT tick // Delay reached; trigger repeat code on NEXT tick
repeat_ctr_ = 1; repeat_ctr_ = 1;
held_time_ = 0; held_time_ = 0;
} }
} else {
// Button not continuously pressed; reset counter
held_time_ = 0;
} }
} else {
// Button not continuously pressed; reset counter
held_time_ = 0;
} }
} }
return false; return false;

View File

@ -31,25 +31,39 @@
// # of timer0 ticks before a held button starts being counted as repeated presses // # of timer0 ticks before a held button starts being counted as repeated presses
#define REPEAT_INITIAL_DELAY 250 #define REPEAT_INITIAL_DELAY 250
#define REPEAT_SUBSEQUENT_DELAY 92 #define REPEAT_SUBSEQUENT_DELAY 92
#define LONG_PRESS_DELAY 1000
class Debounce { class Debounce {
public: public:
bool feed(const uint8_t bit); bool feed(const uint8_t bit);
uint8_t state() const { uint8_t state() const {
return state_; return (pulse_upon_release_) ? 0 : state_;
} }
void enable_repeat() { void enable_repeat() {
repeat_enabled_ = true; repeat_enabled_ = true;
} }
void set_long_press_support(bool v) {
long_press_enabled_ = v;
}
bool long_press_occurred() {
bool v = long_press_occurred_;
long_press_occurred_ = false;
return v;
}
private: private:
uint8_t history_{0}; uint8_t history_{0};
uint8_t state_{0}; uint8_t state_{0};
bool repeat_enabled_{0}; bool repeat_enabled_{0};
uint16_t repeat_ctr_{0}; uint16_t repeat_ctr_{0};
uint16_t held_time_{0}; uint16_t held_time_{0};
bool pulse_upon_release_{0};
bool long_press_enabled_{0};
bool long_press_occurred_{0};
}; };
#endif /*__DEBOUNCE_H__*/ #endif /*__DEBOUNCE_H__*/

View File

@ -195,16 +195,33 @@ void controls_init() {
SwitchesState get_switches_state() { SwitchesState get_switches_state() {
SwitchesState result; SwitchesState result;
// Right, Left, Down, Up, & Select switches
for (size_t i = 0; i < result.size() - 1; i++) { for (size_t i = 0; i < result.size() - 1; i++) {
// TODO: Ignore multiple keys at the same time? // TODO: Ignore multiple keys at the same time?
result[i] = switch_debounce[i].state(); result[i] = switch_debounce[i].state();
} }
result[result.size() - 1] = switch_debounce[switch_debounce.size() - 1].state(); // Grab Dfu switch from bit 7 and return in bit 5 so that all switches are grouped together in this 6-bit result
result[(size_t)Switch::Dfu] = switch_debounce[7].state();
return result; return result;
} }
// Configure which switches support long press (note those switches will not support Repeat function)
void switches_long_press_enable(SwitchesState switches_long_press_enabled) {
// Right, Left, Down, Up, & Select switches
for (size_t i = 0; i < switches_long_press_enabled.size() - 1; i++) {
switch_debounce[i].set_long_press_support(switches_long_press_enabled[i]);
}
// Dfu switch
switch_debounce[7].set_long_press_support(switches_long_press_enabled[(size_t)Switch::Dfu]);
}
bool switch_long_press_occurred(size_t v) {
return (v == (size_t)Switch::Dfu) ? switch_debounce[7].long_press_occurred() : switch_debounce[v].long_press_occurred();
}
EncoderPosition get_encoder_position() { EncoderPosition get_encoder_position() {
return encoder_position; return encoder_position;
} }

View File

@ -27,6 +27,7 @@
#include "touch.hpp" #include "touch.hpp"
// Must be same values as in ui::KeyEvent
enum class Switch { enum class Switch {
Right = 0, Right = 0,
Left = 1, Left = 1,
@ -44,6 +45,8 @@ void controls_init();
SwitchesState get_switches_state(); SwitchesState get_switches_state();
EncoderPosition get_encoder_position(); EncoderPosition get_encoder_position();
touch::Frame get_touch_frame(); touch::Frame get_touch_frame();
void switches_long_press_enable(SwitchesState v);
bool switch_long_press_occurred(size_t v);
namespace control { namespace control {
namespace debug { namespace debug {