diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 3bc3e39d..4754ba47 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -5,7 +5,8 @@ idf_component_register( SRCS "input_touch_wheel.cpp" "input_touch_dpad.cpp" "input_trigger.cpp" "input_volume_buttons.cpp" "lvgl_input_driver.cpp" "feedback_haptics.cpp" - "device_factory.cpp" "input_nav_buttons.cpp" + "device_factory.cpp" "input_nav_buttons.cpp" "input_hook.cpp" + "input_hook_actions.cpp" INCLUDE_DIRS "include" REQUIRES "drivers" "lvgl" "events" "system_fsm") diff --git a/src/input/include/input_hook.hpp b/src/input/include/input_hook.hpp new file mode 100644 index 00000000..96b9b5cd --- /dev/null +++ b/src/input/include/input_hook.hpp @@ -0,0 +1,47 @@ +/* + * Copyright 2024 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include + +#include "hal/lv_hal_indev.h" +#include "input_trigger.hpp" + +namespace input { + +using HookCb = std::optional>; + +class Hook { + public: + Hook(HookCb); + + auto invoke(lv_indev_data_t*) -> void; + auto override(HookCb) -> void; + + private: + HookCb default_; + HookCb override_; +}; + +class TriggerHooks { + public: + TriggerHooks(HookCb cb) : TriggerHooks(cb, cb, cb) {} + TriggerHooks(HookCb, HookCb, HookCb); + + auto update(bool, lv_indev_data_t*) -> void; + auto override(Trigger::State, HookCb) -> void; + + private: + Trigger trigger_; + + Hook click_; + Hook long_press_; + Hook repeat_; +}; + +} // namespace input diff --git a/src/input/include/input_hook_actions.hpp b/src/input/include/input_hook_actions.hpp new file mode 100644 index 00000000..a05a14e8 --- /dev/null +++ b/src/input/include/input_hook_actions.hpp @@ -0,0 +1,28 @@ +/* + * Copyright 2024 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include "hal/lv_hal_indev.h" + +namespace input { +namespace actions { + +auto select(lv_indev_data_t*) -> void; + +auto scrollUp(lv_indev_data_t*) -> void; +auto scrollDown(lv_indev_data_t*) -> void; + +auto scrollToTop(lv_indev_data_t*) -> void; +auto scrollToBottom(lv_indev_data_t*) -> void; + +auto goBack(lv_indev_data_t*) -> void; + +auto volumeUp(lv_indev_data_t*) -> void; +auto volumeDown(lv_indev_data_t*) -> void; + +} // namespace actions +} // namespace input diff --git a/src/input/include/input_nav_buttons.hpp b/src/input/include/input_nav_buttons.hpp index 29a19a16..60566ebc 100644 --- a/src/input/include/input_nav_buttons.hpp +++ b/src/input/include/input_nav_buttons.hpp @@ -13,6 +13,7 @@ #include "haptics.hpp" #include "input_device.hpp" +#include "input_hook.hpp" #include "input_trigger.hpp" #include "touchwheel.hpp" @@ -27,8 +28,8 @@ class NavButtons : public IInputDevice { private: drivers::IGpios& gpios_; - Trigger up_; - Trigger down_; + TriggerHooks up_; + TriggerHooks down_; }; } // namespace input diff --git a/src/input/include/input_touch_dpad.hpp b/src/input/include/input_touch_dpad.hpp index 03936acb..f80400dc 100644 --- a/src/input/include/input_touch_dpad.hpp +++ b/src/input/include/input_touch_dpad.hpp @@ -6,13 +6,13 @@ #pragma once -#include #include #include "hal/lv_hal_indev.h" #include "haptics.hpp" #include "input_device.hpp" +#include "input_hook.hpp" #include "input_trigger.hpp" #include "touchwheel.hpp" @@ -27,10 +27,11 @@ class TouchDPad : public IInputDevice { private: drivers::TouchWheel& wheel_; - Trigger up_; - Trigger right_; - Trigger down_; - Trigger left_; + TriggerHooks centre_; + TriggerHooks up_; + TriggerHooks right_; + TriggerHooks down_; + TriggerHooks left_; }; } // namespace input diff --git a/src/input/include/input_touch_wheel.hpp b/src/input/include/input_touch_wheel.hpp index c81cbb1a..88ebee40 100644 --- a/src/input/include/input_touch_wheel.hpp +++ b/src/input/include/input_touch_wheel.hpp @@ -13,6 +13,7 @@ #include "haptics.hpp" #include "input_device.hpp" +#include "input_hook.hpp" #include "input_trigger.hpp" #include "nvs.hpp" #include "property.hpp" @@ -37,10 +38,11 @@ class TouchWheel : public IInputDevice { lua::Property sensitivity_; - Trigger up_; - Trigger right_; - Trigger down_; - Trigger left_; + TriggerHooks centre_; + TriggerHooks up_; + TriggerHooks right_; + TriggerHooks down_; + TriggerHooks left_; bool is_scrolling_; uint8_t threshold_; diff --git a/src/input/include/input_volume_buttons.hpp b/src/input/include/input_volume_buttons.hpp index 162ca8d9..68962908 100644 --- a/src/input/include/input_volume_buttons.hpp +++ b/src/input/include/input_volume_buttons.hpp @@ -13,7 +13,7 @@ #include "haptics.hpp" #include "input_device.hpp" -#include "input_trigger.hpp" +#include "input_hook.hpp" #include "touchwheel.hpp" namespace input { @@ -27,8 +27,8 @@ class VolumeButtons : public IInputDevice { private: drivers::IGpios& gpios_; - Trigger up_; - Trigger down_; + TriggerHooks up_; + TriggerHooks down_; }; } // namespace input diff --git a/src/input/input_hook.cpp b/src/input/input_hook.cpp new file mode 100644 index 00000000..d22a0b7a --- /dev/null +++ b/src/input/input_hook.cpp @@ -0,0 +1,66 @@ +/* + * Copyright 2024 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "input_hook.hpp" + +#include +#include +#include "hal/lv_hal_indev.h" + +namespace input { + +Hook::Hook(HookCb fn) : default_(fn), override_() {} + +auto Hook::invoke(lv_indev_data_t* d) -> void { + if (override_) { + std::invoke(*override_, d); + } else if (default_) { + std::invoke(*default_, d); + } +} + +auto Hook::override(HookCb fn) -> void { + override_ = fn; +} + +TriggerHooks::TriggerHooks(HookCb click, HookCb long_press, HookCb repeat) + : click_(click), long_press_(long_press), repeat_(repeat) {} + +auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void { + switch (trigger_.update(pressed)) { + case Trigger::State::kClick: + click_.invoke(d); + break; + case Trigger::State::kLongPress: + long_press_.invoke(d); + break; + case Trigger::State::kRepeatPress: + repeat_.invoke(d); + break; + case Trigger::State::kNone: + default: + break; + } +} + +auto TriggerHooks::override(Trigger::State s, HookCb fn) -> void { + switch (s) { + case Trigger::State::kClick: + click_.override(fn); + break; + case Trigger::State::kLongPress: + long_press_.override(fn); + break; + case Trigger::State::kRepeatPress: + repeat_.override(fn); + break; + case Trigger::State::kNone: + default: + break; + } +} + +} // namespace input diff --git a/src/input/input_hook_actions.cpp b/src/input/input_hook_actions.cpp new file mode 100644 index 00000000..0694cccf --- /dev/null +++ b/src/input/input_hook_actions.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2024 jacqueline + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#include "input_hook_actions.hpp" + +#include + +#include "hal/lv_hal_indev.h" + +#include "event_queue.hpp" +#include "ui_events.hpp" + +namespace input { +namespace actions { + +auto select(lv_indev_data_t* d) -> void { + d->state = LV_INDEV_STATE_PRESSED; +} + +auto scrollUp(lv_indev_data_t* d) -> void { + d->enc_diff = -1; +} + +auto scrollDown(lv_indev_data_t* d) -> void { + d->enc_diff = 1; +} + +auto scrollToTop(lv_indev_data_t* d) -> void { + d->enc_diff = INT16_MIN; +} + +auto scrollToBottom(lv_indev_data_t* d) -> void { + d->enc_diff = INT16_MAX; +} + +auto goBack(lv_indev_data_t* d) -> void { + events::Ui().Dispatch(ui::internal::BackPressed{}); +} + +auto volumeUp(lv_indev_data_t* d) -> void { + events::Audio().Dispatch(audio::StepUpVolume{}); +} + +auto volumeDown(lv_indev_data_t* d) -> void { + events::Audio().Dispatch(audio::StepDownVolume{}); +} + +} // namespace actions +} // namespace input diff --git a/src/input/input_nav_buttons.cpp b/src/input/input_nav_buttons.cpp index d83568c8..9db19a2e 100644 --- a/src/input/input_nav_buttons.cpp +++ b/src/input/input_nav_buttons.cpp @@ -9,36 +9,18 @@ #include "event_queue.hpp" #include "gpios.hpp" #include "hal/lv_hal_indev.h" +#include "input_hook_actions.hpp" namespace input { -NavButtons::NavButtons(drivers::IGpios& gpios) : gpios_(gpios) {} +NavButtons::NavButtons(drivers::IGpios& gpios) + : gpios_(gpios), + up_(actions::scrollUp, actions::select, {}), + down_(actions::scrollDown, actions::select, {}) {} auto NavButtons::read(lv_indev_data_t* data) -> void { - bool vol_up = gpios_.Get(drivers::IGpios::Pin::kKeyUp); - switch (up_.update(!vol_up)) { - case Trigger::State::kClick: - data->enc_diff = -1; - break; - case Trigger::State::kLongPress: - events::Ui().Dispatch(ui::internal::BackPressed{}); - break; - default: - break; - } - - bool vol_down = gpios_.Get(drivers::IGpios::Pin::kKeyDown); - switch (down_.update(!vol_down)) { - case Trigger::State::kClick: - data->enc_diff = 1; - break; - case Trigger::State::kLongPress: - data->state = LV_INDEV_STATE_PRESSED; - break; - default: - data->state = LV_INDEV_STATE_RELEASED; - break; - } + up_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyUp), data); + down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data); } } // namespace input diff --git a/src/input/input_touch_dpad.cpp b/src/input/input_touch_dpad.cpp index 828d6b59..32ca1ac1 100644 --- a/src/input/input_touch_dpad.cpp +++ b/src/input/input_touch_dpad.cpp @@ -13,63 +13,42 @@ #include "event_queue.hpp" #include "haptics.hpp" #include "input_device.hpp" +#include "input_hook_actions.hpp" #include "input_touch_dpad.hpp" #include "touchwheel.hpp" namespace input { -static inline auto IsAngleWithin(int16_t wheel_angle, - int16_t target_angle, - int threshold) -> bool { - int16_t difference = (wheel_angle - target_angle + 127 + 255) % 255 - 127; - return difference <= threshold && difference >= -threshold; -} - -TouchDPad::TouchDPad(drivers::TouchWheel& wheel) : wheel_(wheel) {} +TouchDPad::TouchDPad(drivers::TouchWheel& wheel) + : wheel_(wheel), + centre_(actions::select, {}, {}), + up_(actions::scrollUp), + right_({}, {}, {}), + down_(actions::scrollDown), + left_(actions::goBack) {} auto TouchDPad::read(lv_indev_data_t* data) -> void { wheel_.Update(); auto wheel_data = wheel_.GetTouchWheelData(); - if (wheel_data.is_button_touched) { - data->state = LV_INDEV_STATE_PRESSED; - } else { - data->state = LV_INDEV_STATE_RELEASED; - } + centre_.update(wheel_data.is_button_touched, data); - switch (up_.update( - wheel_data.is_wheel_touched && - drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 0, 32))) { - case Trigger::State::kNone: - break; - default: - data->enc_diff = -1; - break; - } - switch (right_.update( - wheel_data.is_wheel_touched && - drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 192, 32))) { - default: - break; - } - switch (down_.update( + up_.update( wheel_data.is_wheel_touched && - drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 128, 32))) { - case Trigger::State::kNone: - break; - default: - data->enc_diff = 1; - break; - } - switch (left_.update( + drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 0, 32), + data); + right_.update( + wheel_data.is_wheel_touched && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 192, 32), + data); + down_.update( + wheel_data.is_wheel_touched && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 128, 32), + data); + left_.update( wheel_data.is_wheel_touched && - drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 64, 32))) { - case Trigger::State::kLongPress: - events::Ui().Dispatch(ui::internal::BackPressed{}); - break; - default: - break; - } + drivers::TouchWheel::isAngleWithin(wheel_data.wheel_position, 64, 32), + data); } } // namespace input diff --git a/src/input/input_touch_wheel.cpp b/src/input/input_touch_wheel.cpp index 7670e342..031c21ef 100644 --- a/src/input/input_touch_wheel.cpp +++ b/src/input/input_touch_wheel.cpp @@ -5,16 +5,16 @@ */ #include "input_touch_wheel.hpp" -#include #include #include -#include "event_queue.hpp" #include "hal/lv_hal_indev.h" +#include "event_queue.hpp" #include "haptics.hpp" #include "input_device.hpp" +#include "input_hook_actions.hpp" #include "input_trigger.hpp" #include "nvs.hpp" #include "property.hpp" @@ -39,6 +39,11 @@ TouchWheel::TouchWheel(drivers::NvsStorage& nvs, drivers::TouchWheel& wheel) threshold_ = calculateThreshold(int_val); return true; }), + centre_(actions::select, {}, {}), + up_({}, actions::scrollToTop, actions::scrollUp), + right_({}, {}, {}), + down_({}, actions::scrollToBottom, actions::scrollDown), + left_({}, actions::goBack, {}), is_scrolling_(false), threshold_(calculateThreshold(nvs.ScrollSensitivity())), is_first_read_(true), @@ -63,45 +68,24 @@ auto TouchWheel::read(lv_indev_data_t* data) -> void { data->enc_diff = 0; } - if (!is_scrolling_ && wheel_data.is_button_touched) { - data->state = LV_INDEV_STATE_PRESSED; - } else { - data->state = LV_INDEV_STATE_RELEASED; - } + centre_.update(!is_scrolling_ && wheel_data.is_button_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. bool pressing = wheel_data.is_wheel_touched && !is_scrolling_; - switch (up_.update(pressing && drivers::TouchWheel::isAngleWithin( - wheel_data.wheel_position, 0, 32))) { - case Trigger::State::kLongPress: - data->enc_diff = INT16_MIN; - break; - default: - break; - } - switch (right_.update(pressing && drivers::TouchWheel::isAngleWithin( - wheel_data.wheel_position, 192, 32))) { - default: - break; - } - switch (down_.update(pressing && drivers::TouchWheel::isAngleWithin( - wheel_data.wheel_position, 128, 32))) { - case Trigger::State::kLongPress: - data->enc_diff = INT16_MAX; - break; - default: - break; - } - switch (left_.update(pressing && drivers::TouchWheel::isAngleWithin( - wheel_data.wheel_position, 64, 32))) { - case Trigger::State::kLongPress: - events::Ui().Dispatch(ui::internal::BackPressed{}); - break; - default: - break; - } + up_.update(pressing && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 0, 32), + data); + right_.update(pressing && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 192, 32), + data); + down_.update(pressing && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 128, 32), + data); + left_.update(pressing && drivers::TouchWheel::isAngleWithin( + wheel_data.wheel_position, 64, 32), + data); } auto TouchWheel::sensitivity() -> lua::Property& { diff --git a/src/input/input_volume_buttons.cpp b/src/input/input_volume_buttons.cpp index 0413222c..bc04cd66 100644 --- a/src/input/input_volume_buttons.cpp +++ b/src/input/input_volume_buttons.cpp @@ -7,29 +7,16 @@ #include "input_volume_buttons.hpp" #include "event_queue.hpp" #include "gpios.hpp" +#include "input_hook_actions.hpp" namespace input { -VolumeButtons::VolumeButtons(drivers::IGpios& gpios) : gpios_(gpios) {} +VolumeButtons::VolumeButtons(drivers::IGpios& gpios) + : gpios_(gpios), up_(actions::volumeUp), down_(actions::volumeDown) {} auto VolumeButtons::read(lv_indev_data_t* data) -> void { - bool vol_up = gpios_.Get(drivers::IGpios::Pin::kKeyUp); - switch (up_.update(!vol_up)) { - case Trigger::State::kNone: - break; - default: - events::Audio().Dispatch(audio::StepUpVolume{}); - break; - } - - bool vol_down = gpios_.Get(drivers::IGpios::Pin::kKeyDown); - switch (down_.update(!vol_down)) { - case Trigger::State::kNone: - break; - default: - events::Audio().Dispatch(audio::StepDownVolume{}); - break; - } + up_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyUp), data); + down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data); } } // namespace input