mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Long button press support (#1188)
This commit is contained in:
parent
199570d4a5
commit
407fee23b9
@ -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() {
|
||||||
|
@ -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"};
|
||||||
|
@ -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;
|
||||||
|
@ -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__*/
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user