summaryrefslogtreecommitdiff
path: root/src/ui/encoder_input.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-10-04 10:18:31 +1100
committerjacqueline <me@jacqueline.id.au>2023-10-04 10:18:31 +1100
commit5c04e2ad8d14616ce3ca09b658d25bab3d8d2460 (patch)
tree411b269ca33ddadb0a95ac74a171b53a5fc7ac07 /src/ui/encoder_input.cpp
parentc851b789faf71d0ef2092ae7d8cd3190c13d85c9 (diff)
downloadtangara-fw-5c04e2ad8d14616ce3ca09b658d25bab3d8d2460.tar.gz
Neaten up the various kinds of inputs, and move volumes to The New Way
Diffstat (limited to 'src/ui/encoder_input.cpp')
-rw-r--r--src/ui/encoder_input.cpp243
1 files changed, 173 insertions, 70 deletions
diff --git a/src/ui/encoder_input.cpp b/src/ui/encoder_input.cpp
index 9aa5d29a..0345665b 100644
--- a/src/ui/encoder_input.cpp
+++ b/src/ui/encoder_input.cpp
@@ -9,13 +9,16 @@
#include <sys/_stdint.h>
#include <memory>
+#include "audio_events.hpp"
#include "core/lv_group.h"
#include "esp_timer.h"
+#include "event_queue.hpp"
#include "gpios.hpp"
#include "hal/lv_hal_indev.h"
#include "nvs.hpp"
#include "relative_wheel.hpp"
#include "touchwheel.hpp"
+#include "ui_events.hpp"
constexpr int kDPadAngleThreshold = 20;
constexpr int kLongPressDelayMs = 500;
@@ -70,83 +73,139 @@ auto EncoderInput::Read(lv_indev_data_t* data) -> void {
}
// Check each button.
- HandleKey(Keys::kVolumeUp, now_ms, !gpios_.Get(drivers::IGpios::Pin::kKeyUp));
- HandleKey(Keys::kVolumeDown, now_ms,
- !gpios_.Get(drivers::IGpios::Pin::kKeyDown));
+ HandleKeyState(Keys::kVolumeUp, now_ms,
+ !gpios_.Get(drivers::IGpios::Pin::kKeyUp));
+ HandleKeyState(Keys::kVolumeDown, now_ms,
+ !gpios_.Get(drivers::IGpios::Pin::kKeyDown));
drivers::TouchWheelData wheel_data = raw_wheel_.GetTouchWheelData();
- HandleKey(Keys::kTouchWheel, now_ms, wheel_data.is_wheel_touched);
- HandleKey(Keys::kTouchWheelCenter, now_ms, wheel_data.is_button_touched);
+ HandleKeyState(Keys::kTouchWheel, now_ms, wheel_data.is_wheel_touched);
+ HandleKeyState(Keys::kTouchWheelCenter, now_ms, wheel_data.is_button_touched);
- HandleKey(
+ HandleKeyState(
Keys::kDirectionalUp, now_ms,
wheel_data.is_wheel_touched &&
IsAngleWithin(wheel_data.wheel_position, 0, kDPadAngleThreshold));
- HandleKey(
+ HandleKeyState(
Keys::kDirectionalLeft, now_ms,
wheel_data.is_wheel_touched &&
IsAngleWithin(wheel_data.wheel_position, 63, kDPadAngleThreshold));
- HandleKey(
+ HandleKeyState(
Keys::kDirectionalDown, now_ms,
wheel_data.is_wheel_touched &&
IsAngleWithin(wheel_data.wheel_position, 127, kDPadAngleThreshold));
- HandleKey(
+ HandleKeyState(
Keys::kDirectionalRight, now_ms,
wheel_data.is_wheel_touched &&
IsAngleWithin(wheel_data.wheel_position, 189, kDPadAngleThreshold));
// We now have enough information to give LVGL its update.
+ Trigger trigger;
switch (mode_) {
case drivers::NvsStorage::InputModes::kButtonsOnly:
data->state = LV_INDEV_STATE_RELEASED;
- if (ShortPressTrigger(Keys::kVolumeUp)) {
- data->enc_diff = -1;
- } else if (ShortPressTrigger(Keys::kVolumeDown)) {
- data->enc_diff = 1;
- } else if (LongPressTrigger(Keys::kVolumeDown, now_ms)) {
- data->state = LV_INDEV_STATE_PRESSED;
- } else if (LongPressTrigger(Keys::kVolumeUp, now_ms)) {
- // TODO: Back button event
+
+ trigger = TriggerKey(Keys::kVolumeUp, KeyStyle::kLongPress, now_ms);
+ switch (trigger) {
+ case Trigger::kNone:
+ break;
+ case Trigger::kClick:
+ data->enc_diff = -1;
+ break;
+ case Trigger::kLongPress:
+ events::Ui().Dispatch(internal::BackPressed{});
+ break;
+ }
+
+ trigger = TriggerKey(Keys::kVolumeDown, KeyStyle::kLongPress, now_ms);
+ switch (trigger) {
+ case Trigger::kNone:
+ break;
+ case Trigger::kClick:
+ data->enc_diff = 1;
+ break;
+ case Trigger::kLongPress:
+ data->state = LV_INDEV_STATE_PRESSED;
+ break;
}
+
break;
case drivers::NvsStorage::InputModes::kButtonsWithWheel:
- data->state = ShortPressTrigger(Keys::kTouchWheel)
- ? LV_INDEV_STATE_PRESSED
- : LV_INDEV_STATE_RELEASED;
- if (ShortPressTriggerRepeating(Keys::kVolumeUp, now_ms)) {
+ trigger = TriggerKey(Keys::kTouchWheel, KeyStyle::kLongPress, now_ms);
+ data->state = trigger == Trigger::kClick ? LV_INDEV_STATE_PRESSED
+ : LV_INDEV_STATE_RELEASED;
+
+ trigger = TriggerKey(Keys::kVolumeUp, KeyStyle::kRepeat, now_ms);
+ if (trigger == Trigger::kClick) {
data->enc_diff = scroller_->AddInput(now_ms, -1);
- } else if (ShortPressTriggerRepeating(Keys::kVolumeDown, now_ms)) {
+ }
+
+ trigger = TriggerKey(Keys::kVolumeDown, KeyStyle::kRepeat, now_ms);
+ if (trigger == Trigger::kClick) {
data->enc_diff = scroller_->AddInput(now_ms, 1);
}
+ // Cancel scrolling if the buttons are released.
if (!touch_time_ms_.contains(Keys::kVolumeDown) &&
!touch_time_ms_.contains(Keys::kVolumeUp)) {
data->enc_diff = scroller_->AddInput(now_ms, 0);
}
- // TODO: Long-press events.
+
break;
case drivers::NvsStorage::InputModes::kDirectionalWheel:
- data->state = ShortPressTrigger(Keys::kTouchWheelCenter)
- ? LV_INDEV_STATE_PRESSED
- : LV_INDEV_STATE_RELEASED;
- if (!ShortPressTriggerRepeating(Keys::kTouchWheel, now_ms)) {
- break;
- }
- if (ShortPressTriggerRepeating(Keys::kDirectionalUp, now_ms)) {
+ trigger =
+ TriggerKey(Keys::kTouchWheelCenter, KeyStyle::kLongPress, now_ms);
+ data->state = trigger == Trigger::kClick ? LV_INDEV_STATE_PRESSED
+ : LV_INDEV_STATE_RELEASED;
+
+ trigger = TriggerKey(Keys::kDirectionalUp, KeyStyle::kRepeat, now_ms);
+ if (trigger == Trigger::kClick) {
data->enc_diff = scroller_->AddInput(now_ms, -1);
- } else if (ShortPressTriggerRepeating(Keys::kDirectionalDown, now_ms)) {
+ }
+
+ trigger = TriggerKey(Keys::kDirectionalDown, KeyStyle::kRepeat, now_ms);
+ if (trigger == Trigger::kClick) {
data->enc_diff = scroller_->AddInput(now_ms, 1);
- } else if (ShortPressTrigger(Keys::kDirectionalRight)) {
+ }
+
+ trigger = TriggerKey(Keys::kDirectionalLeft, KeyStyle::kRepeat, now_ms);
+ if (trigger == Trigger::kClick) {
+ events::Ui().Dispatch(internal::BackPressed{});
+ }
+
+ trigger = TriggerKey(Keys::kDirectionalRight, KeyStyle::kRepeat, now_ms);
+ if (trigger == Trigger::kClick) {
// TODO: ???
- } else if (ShortPressTrigger(Keys::kDirectionalLeft)) {
- // TODO: Back button event.
}
+ // Cancel scrolling if the touchpad is released.
if (!touch_time_ms_.contains(Keys::kDirectionalUp) &&
!touch_time_ms_.contains(Keys::kDirectionalDown)) {
data->enc_diff = scroller_->AddInput(now_ms, 0);
}
- // TODO: Long-press events.
+
+ trigger = TriggerKey(Keys::kVolumeUp, KeyStyle::kLongPress, now_ms);
+ switch (trigger) {
+ case Trigger::kNone:
+ break;
+ case Trigger::kClick:
+ events::Audio().Dispatch(audio::StepUpVolume{});
+ break;
+ case Trigger::kLongPress:
+ break;
+ }
+
+ trigger = TriggerKey(Keys::kVolumeDown, KeyStyle::kLongPress, now_ms);
+ switch (trigger) {
+ case Trigger::kNone:
+ break;
+ case Trigger::kClick:
+ events::Audio().Dispatch(audio::StepDownVolume{});
+ break;
+ case Trigger::kLongPress:
+ break;
+ }
+
break;
case drivers::NvsStorage::InputModes::kRotatingWheel:
if (!raw_wheel_.GetTouchWheelData().is_wheel_touched) {
@@ -156,53 +215,97 @@ auto EncoderInput::Read(lv_indev_data_t* data) -> void {
} else {
data->enc_diff = 0;
}
- data->state = relative_wheel_->is_clicking() ? LV_INDEV_STATE_PRESSED
- : LV_INDEV_STATE_RELEASED;
- // TODO: Long-press events.
+
+ trigger =
+ TriggerKey(Keys::kTouchWheelCenter, KeyStyle::kLongPress, now_ms);
+ switch (trigger) {
+ case Trigger::kNone:
+ data->state = LV_INDEV_STATE_RELEASED;
+ break;
+ case Trigger::kClick:
+ data->state = LV_INDEV_STATE_PRESSED;
+ break;
+ case Trigger::kLongPress:
+ // TODO: ???
+ data->state = LV_INDEV_STATE_PRESSED;
+ break;
+ }
+
+ trigger = TriggerKey(Keys::kVolumeUp, KeyStyle::kLongPress, now_ms);
+ switch (trigger) {
+ case Trigger::kNone:
+ break;
+ case Trigger::kClick:
+ events::Audio().Dispatch(audio::StepUpVolume{});
+ break;
+ case Trigger::kLongPress:
+ break;
+ }
+
+ trigger = TriggerKey(Keys::kVolumeDown, KeyStyle::kLongPress, now_ms);
+ switch (trigger) {
+ case Trigger::kNone:
+ break;
+ case Trigger::kClick:
+ events::Audio().Dispatch(audio::StepDownVolume{});
+ break;
+ case Trigger::kLongPress:
+ break;
+ }
+
break;
}
-
- // TODO: Apply inertia / acceleration.
}
-auto EncoderInput::HandleKey(Keys key, uint64_t ms, bool clicked) -> void {
- if (!clicked) {
- touch_time_ms_.erase(key);
- short_press_fired_.erase(key);
- long_press_fired_.erase(key);
+auto EncoderInput::HandleKeyState(Keys key, uint64_t ms, bool clicked) -> void {
+ if (clicked) {
+ if (!touch_time_ms_.contains(key)) {
+ // Key was just pressed
+ touch_time_ms_[key] = ms;
+ just_released_.erase(key);
+ fired_.erase(key);
+ }
return;
}
- if (!touch_time_ms_.contains(key)) {
- touch_time_ms_[key] = ms;
- }
-}
-auto EncoderInput::ShortPressTrigger(Keys key) -> bool {
- if (touch_time_ms_.contains(key) && !short_press_fired_.contains(key)) {
- short_press_fired_[key] = true;
- return true;
+ // Key is not clicked.
+ if (touch_time_ms_.contains(key)) {
+ // Key was just released.
+ just_released_.insert(key);
+ touch_time_ms_.erase(key);
}
- return false;
}
-auto EncoderInput::ShortPressTriggerRepeating(Keys key, uint64_t ms) -> bool {
- if (touch_time_ms_.contains(key) &&
- (!short_press_fired_.contains(key) ||
- ms - touch_time_ms_[key] >= kRepeatDelayMs)) {
- touch_time_ms_[key] = ms;
- short_press_fired_[key] = true;
- return true;
- }
- return false;
-}
+auto EncoderInput::TriggerKey(Keys key, KeyStyle s, uint64_t ms) -> Trigger {
+ if (s == KeyStyle::kRepeat) {
+ bool may_repeat = fired_.contains(key) && touch_time_ms_.contains(key) &&
+ ms - touch_time_ms_[key] >= kRepeatDelayMs;
-auto EncoderInput::LongPressTrigger(Keys key, uint64_t ms) -> bool {
- if (touch_time_ms_.contains(key) && !long_press_fired_.contains(key) &&
- ms - touch_time_ms_[key] >= kLongPressDelayMs) {
- long_press_fired_[key] = true;
- return true;
+ // Repeatable keys trigger on press.
+ if (touch_time_ms_.contains(key) && (!fired_.contains(key) || may_repeat)) {
+ fired_.insert(key);
+ return Trigger::kClick;
+ } else {
+ return Trigger::kNone;
+ }
+ } else if (s == KeyStyle::kLongPress) {
+ // Long press keys trigger on release, or after holding for a delay.
+ if (just_released_.contains(key)) {
+ just_released_.erase(key);
+ if (!fired_.contains(key)) {
+ fired_.insert(key);
+ return Trigger::kClick;
+ }
+ }
+ if (touch_time_ms_.contains(key) &&
+ ms - touch_time_ms_[key] >= kLongPressDelayMs &&
+ !fired_.contains(key)) {
+ fired_.insert(key);
+ return Trigger::kLongPress;
+ }
}
- return false;
+
+ return Trigger::kNone;
}
auto Scroller::AddInput(uint64_t ms, int direction) -> int {