Use double-clicks instead of long-presses for wheel shortcuts
This commit is contained in:
@@ -45,9 +45,10 @@ class Hook {
|
||||
class TriggerHooks {
|
||||
public:
|
||||
TriggerHooks(std::string name, std::optional<HookCallback> cb)
|
||||
: TriggerHooks(name, cb, cb, cb) {}
|
||||
: TriggerHooks(name, cb, cb, cb, cb) {}
|
||||
TriggerHooks(std::string name,
|
||||
std::optional<HookCallback> click,
|
||||
std::optional<HookCallback> double_click,
|
||||
std::optional<HookCallback> long_press,
|
||||
std::optional<HookCallback> repeat);
|
||||
|
||||
@@ -66,6 +67,7 @@ class TriggerHooks {
|
||||
Trigger trigger_;
|
||||
|
||||
Hook click_;
|
||||
Hook double_click_;
|
||||
Hook long_press_;
|
||||
Hook repeat_;
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
namespace input {
|
||||
|
||||
const uint16_t kDoubleClickDelayMs = 500;
|
||||
const uint16_t kLongPressDelayMs = LV_INDEV_DEF_LONG_PRESS_TIME;
|
||||
const uint16_t kRepeatDelayMs = LV_INDEV_DEF_LONG_PRESS_REP_TIME;
|
||||
|
||||
@@ -21,6 +22,7 @@ class Trigger {
|
||||
enum class State {
|
||||
kNone,
|
||||
kClick,
|
||||
kDoubleClick,
|
||||
kLongPress,
|
||||
kRepeatPress,
|
||||
};
|
||||
@@ -31,7 +33,10 @@ class Trigger {
|
||||
|
||||
private:
|
||||
std::optional<uint64_t> touch_time_ms_;
|
||||
uint16_t times_fired_;
|
||||
bool was_pressed_;
|
||||
|
||||
bool was_double_click_;
|
||||
uint16_t times_long_pressed_;
|
||||
};
|
||||
|
||||
} // namespace input
|
||||
|
||||
@@ -39,10 +39,12 @@ auto Hook::callback() -> std::optional<HookCallback> {
|
||||
|
||||
TriggerHooks::TriggerHooks(std::string name,
|
||||
std::optional<HookCallback> click,
|
||||
std::optional<HookCallback> double_click,
|
||||
std::optional<HookCallback> long_press,
|
||||
std::optional<HookCallback> repeat)
|
||||
: name_(name),
|
||||
click_("click", click),
|
||||
double_click_("double_click", double_click),
|
||||
long_press_("long_press", long_press),
|
||||
repeat_("repeat", repeat) {}
|
||||
|
||||
@@ -51,6 +53,9 @@ auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void {
|
||||
case Trigger::State::kClick:
|
||||
click_.invoke(d);
|
||||
break;
|
||||
case Trigger::State::kDoubleClick:
|
||||
double_click_.invoke(d);
|
||||
break;
|
||||
case Trigger::State::kLongPress:
|
||||
long_press_.invoke(d);
|
||||
break;
|
||||
|
||||
@@ -15,8 +15,8 @@ namespace input {
|
||||
|
||||
NavButtons::NavButtons(drivers::IGpios& gpios)
|
||||
: gpios_(gpios),
|
||||
up_("upper", actions::scrollUp(), actions::select(), {}),
|
||||
down_("lower", actions::scrollDown(), actions::select(), {}) {}
|
||||
up_("upper", {}, actions::scrollUp(), actions::select(), {}),
|
||||
down_("lower", {}, actions::scrollDown(), actions::select(), {}) {}
|
||||
|
||||
auto NavButtons::read(lv_indev_data_t* data) -> void {
|
||||
up_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyUp), data);
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace input {
|
||||
|
||||
TouchDPad::TouchDPad(drivers::TouchWheel& wheel)
|
||||
: wheel_(wheel),
|
||||
centre_("centre", actions::select(), {}, {}),
|
||||
centre_("centre", actions::select(), {}, {}, {}),
|
||||
up_("up", actions::scrollUp()),
|
||||
right_("right", {}, {}, {}),
|
||||
right_("right", {}),
|
||||
down_("down", actions::scrollDown()),
|
||||
left_("left", actions::goBack()) {}
|
||||
|
||||
|
||||
@@ -39,11 +39,11 @@ TouchWheel::TouchWheel(drivers::NvsStorage& nvs, drivers::TouchWheel& wheel)
|
||||
threshold_ = calculateThreshold(int_val);
|
||||
return true;
|
||||
}),
|
||||
centre_("centre", actions::select(), {}, {}),
|
||||
up_("up", {}, actions::scrollToTop(), actions::scrollUp()),
|
||||
right_("right", {}, {}, {}),
|
||||
down_("down", {}, actions::scrollToBottom(), actions::scrollDown()),
|
||||
left_("left", {}, actions::goBack(), {}),
|
||||
centre_("centre", actions::select(), {}, {}, {}),
|
||||
up_("up", {}, actions::scrollToTop(), {}, {}),
|
||||
right_("right", {}),
|
||||
down_("down", {}, actions::scrollToBottom(), {}, {}),
|
||||
left_("left", {}, actions::goBack(), {}, {}),
|
||||
is_scrolling_(false),
|
||||
threshold_(calculateThreshold(nvs.ScrollSensitivity())),
|
||||
is_first_read_(true),
|
||||
@@ -68,7 +68,8 @@ auto TouchWheel::read(lv_indev_data_t* data) -> void {
|
||||
data->enc_diff = 0;
|
||||
}
|
||||
|
||||
centre_.update(!is_scrolling_ && wheel_data.is_button_touched, data);
|
||||
centre_.update(wheel_data.is_button_touched && !wheel_data.is_wheel_touched,
|
||||
data);
|
||||
|
||||
// If the user is touching the wheel but not scrolling, then they may be
|
||||
// clicking on one of the wheel's cardinal directions.
|
||||
|
||||
+30
-14
@@ -8,34 +8,50 @@
|
||||
#include <sys/_stdint.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
namespace input {
|
||||
|
||||
Trigger::Trigger() : touch_time_ms_(), times_fired_(0) {}
|
||||
Trigger::Trigger()
|
||||
: touch_time_ms_(),
|
||||
was_pressed_(false),
|
||||
was_double_click_(false),
|
||||
times_long_pressed_(0) {}
|
||||
|
||||
auto Trigger::update(bool is_pressed) -> State {
|
||||
// Bail out early if we're in a steady-state of not pressed.
|
||||
if (!is_pressed && !touch_time_ms_) {
|
||||
if (!is_pressed && !was_pressed_) {
|
||||
was_double_click_ = false;
|
||||
times_long_pressed_ = 0;
|
||||
return State::kNone;
|
||||
}
|
||||
|
||||
uint64_t now_ms = esp_timer_get_time() / 1000;
|
||||
|
||||
// Initial press of this key: record the current time, and report that we
|
||||
// haven't triggered yet.
|
||||
if (is_pressed && !touch_time_ms_) {
|
||||
// This key wasn't being pressed, but now it is.
|
||||
if (is_pressed && !was_pressed_) {
|
||||
// Is this a double click?
|
||||
if (now_ms - *touch_time_ms_ < kDoubleClickDelayMs) {
|
||||
// Don't update touch_time_ms_, since we don't want triple clicks to
|
||||
// register as double clicks.
|
||||
was_double_click_ = true;
|
||||
was_pressed_ = true;
|
||||
return State::kDoubleClick;
|
||||
}
|
||||
// Not a double click; update our accounting info and wait for the next
|
||||
// call.
|
||||
touch_time_ms_ = now_ms;
|
||||
times_fired_ = 0;
|
||||
was_double_click_ = false;
|
||||
times_long_pressed_ = 0;
|
||||
was_pressed_ = true;
|
||||
return State::kNone;
|
||||
}
|
||||
|
||||
// The key was released. If there were no long-press events fired during the
|
||||
// press, then this was a standard click.
|
||||
if (!is_pressed && touch_time_ms_) {
|
||||
touch_time_ms_.reset();
|
||||
if (times_fired_ == 0) {
|
||||
if (!is_pressed && was_pressed_) {
|
||||
was_pressed_ = false;
|
||||
if (!was_double_click_ && times_long_pressed_ == 0) {
|
||||
return State::kClick;
|
||||
} else {
|
||||
return State::kNone;
|
||||
@@ -43,10 +59,10 @@ auto Trigger::update(bool is_pressed) -> State {
|
||||
}
|
||||
|
||||
// Now the more complicated case: the user is continuing to press the button.
|
||||
if (times_fired_ == 0) {
|
||||
if (times_long_pressed_ == 0) {
|
||||
// We haven't fired yet, so we wait for the long-press event.
|
||||
if (now_ms - *touch_time_ms_ >= kLongPressDelayMs) {
|
||||
times_fired_++;
|
||||
times_long_pressed_++;
|
||||
return State::kLongPress;
|
||||
}
|
||||
} else {
|
||||
@@ -60,8 +76,8 @@ auto Trigger::update(bool is_pressed) -> State {
|
||||
// kRepeatDelayMs since the long-press event.
|
||||
uint16_t expected_times_fired =
|
||||
1 + (time_since_long_press / kRepeatDelayMs);
|
||||
if (times_fired_ < expected_times_fired) {
|
||||
times_fired_++;
|
||||
if (times_long_pressed_ < expected_times_fired) {
|
||||
times_long_pressed_++;
|
||||
return State::kRepeatPress;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user