From 920345b940bb3993c389d9e9be1a75a8041d431d Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 24 Apr 2024 16:06:10 +1000 Subject: [PATCH] Support getting a tree of controls + hooks via lua --- src/input/include/input_device.hpp | 10 +--- src/input/include/input_hook.hpp | 34 ++++++++--- src/input/include/input_hook_actions.hpp | 19 +++--- src/input/include/input_nav_buttons.hpp | 3 + src/input/include/input_touch_dpad.hpp | 3 + src/input/include/input_touch_wheel.hpp | 3 + src/input/include/input_volume_buttons.hpp | 3 + src/input/include/lvgl_input_driver.hpp | 2 + src/input/input_hook.cpp | 67 +++++++++++++++++----- src/input/input_hook_actions.cpp | 53 +++++++++++------ src/input/input_nav_buttons.cpp | 12 +++- src/input/input_touch_dpad.cpp | 18 ++++-- src/input/input_touch_wheel.cpp | 18 ++++-- src/input/input_volume_buttons.cpp | 12 +++- src/input/lvgl_input_driver.cpp | 20 +++++++ src/ui/ui_fsm.cpp | 12 ++-- 16 files changed, 220 insertions(+), 69 deletions(-) diff --git a/src/input/include/input_device.hpp b/src/input/include/input_device.hpp index 5fc3e066..59456351 100644 --- a/src/input/include/input_device.hpp +++ b/src/input/include/input_device.hpp @@ -11,6 +11,7 @@ #include #include "hal/lv_hal_indev.h" +#include "input_hook.hpp" #include "property.hpp" namespace input { @@ -27,13 +28,8 @@ class IInputDevice { virtual auto read(lv_indev_data_t* data) -> void = 0; - // TODO: Add hooks and configuration (or are hooks just one kind of - // configuration?) - - virtual auto settings() - -> std::vector> { - return {}; - } + virtual auto name() -> std::string = 0; + virtual auto hooks() -> std::vector { return {}; } }; } // namespace input diff --git a/src/input/include/input_hook.hpp b/src/input/include/input_hook.hpp index 96b9b5cd..81eb80d9 100644 --- a/src/input/include/input_hook.hpp +++ b/src/input/include/input_hook.hpp @@ -8,35 +8,53 @@ #include #include +#include #include "hal/lv_hal_indev.h" +#include "lua.hpp" + #include "input_trigger.hpp" namespace input { -using HookCb = std::optional>; +struct HookCallback { + std::string name; + std::function fn; +}; class Hook { public: - Hook(HookCb); + Hook(std::string name, std::optional cb); auto invoke(lv_indev_data_t*) -> void; - auto override(HookCb) -> void; + auto override(std::optional) -> void; + + auto name() const -> const std::string& { return name_; } + auto callback() -> std::optional; private: - HookCb default_; - HookCb override_; + std::string name_; + std::optional default_; + std::optional override_; }; class TriggerHooks { public: - TriggerHooks(HookCb cb) : TriggerHooks(cb, cb, cb) {} - TriggerHooks(HookCb, HookCb, HookCb); + TriggerHooks(std::string name, std::optional cb) + : TriggerHooks(name, cb, cb, cb) {} + TriggerHooks(std::string name, + std::optional click, + std::optional long_press, + std::optional repeat); auto update(bool, lv_indev_data_t*) -> void; - auto override(Trigger::State, HookCb) -> void; + auto override(Trigger::State, std::optional) -> void; + + auto name() const -> const std::string&; + auto pushHooks(lua_State*) -> void; private: + std::string name_; Trigger trigger_; Hook click_; diff --git a/src/input/include/input_hook_actions.hpp b/src/input/include/input_hook_actions.hpp index a05a14e8..105bd10d 100644 --- a/src/input/include/input_hook_actions.hpp +++ b/src/input/include/input_hook_actions.hpp @@ -7,22 +7,25 @@ #pragma once #include "hal/lv_hal_indev.h" +#include "input_hook.hpp" namespace input { namespace actions { -auto select(lv_indev_data_t*) -> void; +auto select() -> HookCallback; -auto scrollUp(lv_indev_data_t*) -> void; -auto scrollDown(lv_indev_data_t*) -> void; +auto scrollUp() -> HookCallback; +auto scrollDown() -> HookCallback; -auto scrollToTop(lv_indev_data_t*) -> void; -auto scrollToBottom(lv_indev_data_t*) -> void; +auto scrollToTop() -> HookCallback; +auto scrollToBottom() -> HookCallback; -auto goBack(lv_indev_data_t*) -> void; +auto goBack() -> HookCallback; -auto volumeUp(lv_indev_data_t*) -> void; -auto volumeDown(lv_indev_data_t*) -> void; +auto volumeUp() -> HookCallback; +auto volumeDown() -> HookCallback; + +auto allActions() -> std::vector; } // namespace actions } // namespace input diff --git a/src/input/include/input_nav_buttons.hpp b/src/input/include/input_nav_buttons.hpp index 60566ebc..4e4952c9 100644 --- a/src/input/include/input_nav_buttons.hpp +++ b/src/input/include/input_nav_buttons.hpp @@ -25,6 +25,9 @@ class NavButtons : public IInputDevice { auto read(lv_indev_data_t* data) -> void override; + auto name() -> std::string override; + auto hooks() -> std::vector override; + private: drivers::IGpios& gpios_; diff --git a/src/input/include/input_touch_dpad.hpp b/src/input/include/input_touch_dpad.hpp index f80400dc..691e3243 100644 --- a/src/input/include/input_touch_dpad.hpp +++ b/src/input/include/input_touch_dpad.hpp @@ -24,6 +24,9 @@ class TouchDPad : public IInputDevice { auto read(lv_indev_data_t* data) -> void override; + auto name() -> std::string override; + auto hooks() -> std::vector override; + private: drivers::TouchWheel& wheel_; diff --git a/src/input/include/input_touch_wheel.hpp b/src/input/include/input_touch_wheel.hpp index 88ebee40..1f116da9 100644 --- a/src/input/include/input_touch_wheel.hpp +++ b/src/input/include/input_touch_wheel.hpp @@ -27,6 +27,9 @@ class TouchWheel : public IInputDevice { auto read(lv_indev_data_t* data) -> void override; + auto name() -> std::string override; + auto hooks() -> std::vector override; + auto sensitivity() -> lua::Property&; private: diff --git a/src/input/include/input_volume_buttons.hpp b/src/input/include/input_volume_buttons.hpp index 68962908..a684aa48 100644 --- a/src/input/include/input_volume_buttons.hpp +++ b/src/input/include/input_volume_buttons.hpp @@ -24,6 +24,9 @@ class VolumeButtons : public IInputDevice { auto read(lv_indev_data_t* data) -> void override; + auto name() -> std::string override; + auto hooks() -> std::vector override; + private: drivers::IGpios& gpios_; diff --git a/src/input/include/lvgl_input_driver.hpp b/src/input/include/lvgl_input_driver.hpp index 257ccb28..9f43d27f 100644 --- a/src/input/include/lvgl_input_driver.hpp +++ b/src/input/include/lvgl_input_driver.hpp @@ -41,6 +41,8 @@ class LvglInputDriver { auto registration() -> lv_indev_t* { return registration_; } auto lock(bool l) -> void { is_locked_ = l; } + auto pushHooks(lua_State* L) -> int; + private: drivers::NvsStorage& nvs_; DeviceFactory& factory_; diff --git a/src/input/input_hook.cpp b/src/input/input_hook.cpp index d22a0b7a..1bb92196 100644 --- a/src/input/input_hook.cpp +++ b/src/input/input_hook.cpp @@ -9,25 +9,42 @@ #include #include #include "hal/lv_hal_indev.h" +#include "input_trigger.hpp" +#include "lua.h" namespace input { -Hook::Hook(HookCb fn) : default_(fn), override_() {} +Hook::Hook(std::string name, std::optional cb) + : name_(name), default_(cb), override_() {} auto Hook::invoke(lv_indev_data_t* d) -> void { - if (override_) { - std::invoke(*override_, d); - } else if (default_) { - std::invoke(*default_, d); + auto cb = callback(); + if (cb) { + std::invoke(cb->fn, d); } } -auto Hook::override(HookCb fn) -> void { - override_ = fn; +auto Hook::override(std::optional cb) -> void { + override_ = cb; +} + +auto Hook::callback() -> std::optional { + if (override_) { + return override_; + } else if (default_) { + return default_; + } + return {}; } -TriggerHooks::TriggerHooks(HookCb click, HookCb long_press, HookCb repeat) - : click_(click), long_press_(long_press), repeat_(repeat) {} +TriggerHooks::TriggerHooks(std::string name, + std::optional click, + std::optional long_press, + std::optional repeat) + : name_(name), + click_("click", click), + long_press_("long_press", long_press), + repeat_("repeat", repeat) {} auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void { switch (trigger_.update(pressed)) { @@ -46,16 +63,17 @@ auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void { } } -auto TriggerHooks::override(Trigger::State s, HookCb fn) -> void { +auto TriggerHooks::override(Trigger::State s, std::optional cb) + -> void { switch (s) { case Trigger::State::kClick: - click_.override(fn); + click_.override(cb); break; case Trigger::State::kLongPress: - long_press_.override(fn); + long_press_.override(cb); break; case Trigger::State::kRepeatPress: - repeat_.override(fn); + repeat_.override(cb); break; case Trigger::State::kNone: default: @@ -63,4 +81,27 @@ auto TriggerHooks::override(Trigger::State s, HookCb fn) -> void { } } +auto TriggerHooks::name() const -> const std::string& { + return name_; +} + +auto TriggerHooks::pushHooks(lua_State* L) -> void { + lua_newtable(L); + + auto add_trigger = [&](Hook& h) { + lua_pushlstring(L, h.name().data(), h.name().size()); + auto cb = h.callback(); + if (cb) { + lua_pushlstring(L, cb->name.data(), cb->name.size()); + } else { + lua_pushnil(L); + } + lua_rawset(L, -3); + }; + + add_trigger(click_); + add_trigger(long_press_); + add_trigger(repeat_); +} + } // namespace input diff --git a/src/input/input_hook_actions.cpp b/src/input/input_hook_actions.cpp index 0694cccf..26075c4c 100644 --- a/src/input/input_hook_actions.cpp +++ b/src/input/input_hook_actions.cpp @@ -16,36 +16,57 @@ namespace input { namespace actions { -auto select(lv_indev_data_t* d) -> void { - d->state = LV_INDEV_STATE_PRESSED; +auto select() -> HookCallback { + return HookCallback{.name = "select", .fn = [&](lv_indev_data_t* d) { + d->state = LV_INDEV_STATE_PRESSED; + }}; } -auto scrollUp(lv_indev_data_t* d) -> void { - d->enc_diff = -1; +auto scrollUp() -> HookCallback { + return HookCallback{.name = "scroll_up", + .fn = [&](lv_indev_data_t* d) { d->enc_diff = -1; }}; } -auto scrollDown(lv_indev_data_t* d) -> void { - d->enc_diff = 1; +auto scrollDown() -> HookCallback { + return HookCallback{.name = "scroll_down", + .fn = [&](lv_indev_data_t* d) { d->enc_diff = 1; }}; } -auto scrollToTop(lv_indev_data_t* d) -> void { - d->enc_diff = INT16_MIN; +auto scrollToTop() -> HookCallback { + return HookCallback{.name = "scroll_to_top", .fn = [&](lv_indev_data_t* d) { + d->enc_diff = INT16_MIN; + }}; } -auto scrollToBottom(lv_indev_data_t* d) -> void { - d->enc_diff = INT16_MAX; +auto scrollToBottom() -> HookCallback { + return HookCallback{ + .name = "scroll_to_bottom", + .fn = [&](lv_indev_data_t* d) { d->enc_diff = INT16_MAX; }}; } -auto goBack(lv_indev_data_t* d) -> void { - events::Ui().Dispatch(ui::internal::BackPressed{}); +auto goBack() -> HookCallback { + return HookCallback{.name = "back", .fn = [&](lv_indev_data_t* d) { + events::Ui().Dispatch(ui::internal::BackPressed{}); + }}; } -auto volumeUp(lv_indev_data_t* d) -> void { - events::Audio().Dispatch(audio::StepUpVolume{}); +auto volumeUp() -> HookCallback { + return HookCallback{.name = "volume_up", .fn = [&](lv_indev_data_t* d) { + events::Audio().Dispatch(audio::StepUpVolume{}); + }}; } -auto volumeDown(lv_indev_data_t* d) -> void { - events::Audio().Dispatch(audio::StepDownVolume{}); +auto volumeDown() -> HookCallback { + return HookCallback{.name = "volume_down", .fn = [&](lv_indev_data_t* d) { + events::Audio().Dispatch(audio::StepDownVolume{}); + }}; +} + +auto allActions() -> std::vector { + return { + select(), scrollUp(), scrollDown(), scrollToTop(), + scrollToBottom(), goBack(), volumeUp(), volumeDown(), + }; } } // namespace actions diff --git a/src/input/input_nav_buttons.cpp b/src/input/input_nav_buttons.cpp index 9db19a2e..7e579a16 100644 --- a/src/input/input_nav_buttons.cpp +++ b/src/input/input_nav_buttons.cpp @@ -15,12 +15,20 @@ namespace input { NavButtons::NavButtons(drivers::IGpios& gpios) : gpios_(gpios), - up_(actions::scrollUp, actions::select, {}), - down_(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); down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data); } +auto NavButtons::name() -> std::string { + return "buttons"; +} + +auto NavButtons::hooks() -> std::vector { + return {up_, down_}; +} + } // namespace input diff --git a/src/input/input_touch_dpad.cpp b/src/input/input_touch_dpad.cpp index 32ca1ac1..f0805993 100644 --- a/src/input/input_touch_dpad.cpp +++ b/src/input/input_touch_dpad.cpp @@ -21,11 +21,11 @@ namespace input { TouchDPad::TouchDPad(drivers::TouchWheel& wheel) : wheel_(wheel), - centre_(actions::select, {}, {}), - up_(actions::scrollUp), - right_({}, {}, {}), - down_(actions::scrollDown), - left_(actions::goBack) {} + centre_("centre", actions::select(), {}, {}), + up_("up", actions::scrollUp()), + right_("right", {}, {}, {}), + down_("down", actions::scrollDown()), + left_("left", actions::goBack()) {} auto TouchDPad::read(lv_indev_data_t* data) -> void { wheel_.Update(); @@ -51,4 +51,12 @@ auto TouchDPad::read(lv_indev_data_t* data) -> void { data); } +auto TouchDPad::name() -> std::string { + return "dpad"; +} + +auto TouchDPad::hooks() -> std::vector { + return {centre_, up_, right_, down_, left_}; +} + } // namespace input diff --git a/src/input/input_touch_wheel.cpp b/src/input/input_touch_wheel.cpp index 031c21ef..121b1ee5 100644 --- a/src/input/input_touch_wheel.cpp +++ b/src/input/input_touch_wheel.cpp @@ -39,11 +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, {}), + centre_("centre", actions::select(), {}, {}), + up_("up", {}, actions::scrollToTop(), actions::scrollUp()), + right_("right", {}, {}, {}), + down_("down", {}, actions::scrollToBottom(), actions::scrollDown()), + left_("left", {}, actions::goBack(), {}), is_scrolling_(false), threshold_(calculateThreshold(nvs.ScrollSensitivity())), is_first_read_(true), @@ -88,6 +88,14 @@ auto TouchWheel::read(lv_indev_data_t* data) -> void { data); } +auto TouchWheel::name() -> std::string { + return "wheel"; +} + +auto TouchWheel::hooks() -> std::vector { + return {centre_, up_, right_, down_, left_}; +} + auto TouchWheel::sensitivity() -> lua::Property& { return sensitivity_; } diff --git a/src/input/input_volume_buttons.cpp b/src/input/input_volume_buttons.cpp index bc04cd66..607f81f1 100644 --- a/src/input/input_volume_buttons.cpp +++ b/src/input/input_volume_buttons.cpp @@ -12,11 +12,21 @@ namespace input { VolumeButtons::VolumeButtons(drivers::IGpios& gpios) - : gpios_(gpios), up_(actions::volumeUp), down_(actions::volumeDown) {} + : gpios_(gpios), + up_("upper", actions::volumeUp()), + down_("lower", actions::volumeDown()) {} auto VolumeButtons::read(lv_indev_data_t* data) -> void { up_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyUp), data); down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data); } +auto VolumeButtons::name() -> std::string { + return "buttons"; +} + +auto VolumeButtons::hooks() -> std::vector { + return {up_, down_}; +} + } // namespace input diff --git a/src/input/lvgl_input_driver.cpp b/src/input/lvgl_input_driver.cpp index 9698aa79..61a85fa5 100644 --- a/src/input/lvgl_input_driver.cpp +++ b/src/input/lvgl_input_driver.cpp @@ -16,6 +16,8 @@ #include "input_touch_wheel.hpp" #include "input_trigger.hpp" #include "input_volume_buttons.hpp" +#include "lauxlib.h" +#include "lua.h" #include "lvgl.h" #include "nvs.hpp" #include "property.hpp" @@ -104,4 +106,22 @@ auto LvglInputDriver::feedback(uint8_t event) -> void { } } +auto LvglInputDriver::pushHooks(lua_State* L) -> int { + lua_newtable(L); + + for (auto& dev : inputs_) { + lua_pushlstring(L, dev->name().data(), dev->name().size()); + lua_newtable(L); + + for (auto& hook : dev->hooks()) { + lua_pushlstring(L, hook.name().data(), hook.name().size()); + hook.pushHooks(L); + lua_rawset(L, -3); + } + + lua_rawset(L, -3); + } + return 1; +} + } // namespace input diff --git a/src/ui/ui_fsm.cpp b/src/ui/ui_fsm.cpp index ceeb194d..1cbf1be4 100644 --- a/src/ui/ui_fsm.cpp +++ b/src/ui/ui_fsm.cpp @@ -14,6 +14,7 @@ #include "db_events.hpp" #include "device_factory.hpp" #include "display_init.hpp" +#include "esp_spp_api.h" #include "feedback_haptics.hpp" #include "freertos/portmacro.h" #include "freertos/projdefs.h" @@ -497,10 +498,13 @@ void Lua::entry() { {"brightness", &sDisplayBrightness}, }); - registry.AddPropertyModule("controls", { - {"scheme", &sInput->mode()}, - {"lock_switch", &sLockSwitch}, - }); + registry.AddPropertyModule( + "controls", + { + {"scheme", &sInput->mode()}, + {"lock_switch", &sLockSwitch}, + {"hooks", [&](lua_State* L) { return sInput->pushHooks(L); }}, + }); if (sDeviceFactory->touch_wheel()) { registry.AddPropertyModule(