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