Support getting a tree of controls + hooks via lua

custom
jacqueline 1 year ago
parent 531475e351
commit 920345b940
  1. 10
      src/input/include/input_device.hpp
  2. 34
      src/input/include/input_hook.hpp
  3. 19
      src/input/include/input_hook_actions.hpp
  4. 3
      src/input/include/input_nav_buttons.hpp
  5. 3
      src/input/include/input_touch_dpad.hpp
  6. 3
      src/input/include/input_touch_wheel.hpp
  7. 3
      src/input/include/input_volume_buttons.hpp
  8. 2
      src/input/include/lvgl_input_driver.hpp
  9. 67
      src/input/input_hook.cpp
  10. 43
      src/input/input_hook_actions.cpp
  11. 12
      src/input/input_nav_buttons.cpp
  12. 18
      src/input/input_touch_dpad.cpp
  13. 18
      src/input/input_touch_wheel.cpp
  14. 12
      src/input/input_volume_buttons.cpp
  15. 20
      src/input/lvgl_input_driver.cpp
  16. 6
      src/ui/ui_fsm.cpp

@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include "hal/lv_hal_indev.h" #include "hal/lv_hal_indev.h"
#include "input_hook.hpp"
#include "property.hpp" #include "property.hpp"
namespace input { namespace input {
@ -27,13 +28,8 @@ class IInputDevice {
virtual auto read(lv_indev_data_t* data) -> void = 0; virtual auto read(lv_indev_data_t* data) -> void = 0;
// TODO: Add hooks and configuration (or are hooks just one kind of virtual auto name() -> std::string = 0;
// configuration?) virtual auto hooks() -> std::vector<TriggerHooks> { return {}; }
virtual auto settings()
-> std::vector<std::pair<std::string, lua::Property>> {
return {};
}
}; };
} // namespace input } // namespace input

@ -8,35 +8,53 @@
#include <functional> #include <functional>
#include <optional> #include <optional>
#include <string>
#include "hal/lv_hal_indev.h" #include "hal/lv_hal_indev.h"
#include "lua.hpp"
#include "input_trigger.hpp" #include "input_trigger.hpp"
namespace input { namespace input {
using HookCb = std::optional<std::function<void(lv_indev_data_t*)>>; struct HookCallback {
std::string name;
std::function<void(lv_indev_data_t*)> fn;
};
class Hook { class Hook {
public: public:
Hook(HookCb); Hook(std::string name, std::optional<HookCallback> cb);
auto invoke(lv_indev_data_t*) -> void; auto invoke(lv_indev_data_t*) -> void;
auto override(HookCb) -> void; auto override(std::optional<HookCallback>) -> void;
auto name() const -> const std::string& { return name_; }
auto callback() -> std::optional<HookCallback>;
private: private:
HookCb default_; std::string name_;
HookCb override_; std::optional<HookCallback> default_;
std::optional<HookCallback> override_;
}; };
class TriggerHooks { class TriggerHooks {
public: public:
TriggerHooks(HookCb cb) : TriggerHooks(cb, cb, cb) {} TriggerHooks(std::string name, std::optional<HookCallback> cb)
TriggerHooks(HookCb, HookCb, HookCb); : TriggerHooks(name, cb, cb, cb) {}
TriggerHooks(std::string name,
std::optional<HookCallback> click,
std::optional<HookCallback> long_press,
std::optional<HookCallback> repeat);
auto update(bool, lv_indev_data_t*) -> void; auto update(bool, lv_indev_data_t*) -> void;
auto override(Trigger::State, HookCb) -> void; auto override(Trigger::State, std::optional<HookCallback>) -> void;
auto name() const -> const std::string&;
auto pushHooks(lua_State*) -> void;
private: private:
std::string name_;
Trigger trigger_; Trigger trigger_;
Hook click_; Hook click_;

@ -7,22 +7,25 @@
#pragma once #pragma once
#include "hal/lv_hal_indev.h" #include "hal/lv_hal_indev.h"
#include "input_hook.hpp"
namespace input { namespace input {
namespace actions { namespace actions {
auto select(lv_indev_data_t*) -> void; auto select() -> HookCallback;
auto scrollUp(lv_indev_data_t*) -> void; auto scrollUp() -> HookCallback;
auto scrollDown(lv_indev_data_t*) -> void; auto scrollDown() -> HookCallback;
auto scrollToTop(lv_indev_data_t*) -> void; auto scrollToTop() -> HookCallback;
auto scrollToBottom(lv_indev_data_t*) -> void; auto scrollToBottom() -> HookCallback;
auto goBack(lv_indev_data_t*) -> void; auto goBack() -> HookCallback;
auto volumeUp(lv_indev_data_t*) -> void; auto volumeUp() -> HookCallback;
auto volumeDown(lv_indev_data_t*) -> void; auto volumeDown() -> HookCallback;
auto allActions() -> std::vector<HookCallback>;
} // namespace actions } // namespace actions
} // namespace input } // namespace input

@ -25,6 +25,9 @@ class NavButtons : public IInputDevice {
auto read(lv_indev_data_t* data) -> void override; auto read(lv_indev_data_t* data) -> void override;
auto name() -> std::string override;
auto hooks() -> std::vector<TriggerHooks> override;
private: private:
drivers::IGpios& gpios_; drivers::IGpios& gpios_;

@ -24,6 +24,9 @@ class TouchDPad : public IInputDevice {
auto read(lv_indev_data_t* data) -> void override; auto read(lv_indev_data_t* data) -> void override;
auto name() -> std::string override;
auto hooks() -> std::vector<TriggerHooks> override;
private: private:
drivers::TouchWheel& wheel_; drivers::TouchWheel& wheel_;

@ -27,6 +27,9 @@ class TouchWheel : public IInputDevice {
auto read(lv_indev_data_t* data) -> void override; auto read(lv_indev_data_t* data) -> void override;
auto name() -> std::string override;
auto hooks() -> std::vector<TriggerHooks> override;
auto sensitivity() -> lua::Property&; auto sensitivity() -> lua::Property&;
private: private:

@ -24,6 +24,9 @@ class VolumeButtons : public IInputDevice {
auto read(lv_indev_data_t* data) -> void override; auto read(lv_indev_data_t* data) -> void override;
auto name() -> std::string override;
auto hooks() -> std::vector<TriggerHooks> override;
private: private:
drivers::IGpios& gpios_; drivers::IGpios& gpios_;

@ -41,6 +41,8 @@ class LvglInputDriver {
auto registration() -> lv_indev_t* { return registration_; } auto registration() -> lv_indev_t* { return registration_; }
auto lock(bool l) -> void { is_locked_ = l; } auto lock(bool l) -> void { is_locked_ = l; }
auto pushHooks(lua_State* L) -> int;
private: private:
drivers::NvsStorage& nvs_; drivers::NvsStorage& nvs_;
DeviceFactory& factory_; DeviceFactory& factory_;

@ -9,25 +9,42 @@
#include <functional> #include <functional>
#include <optional> #include <optional>
#include "hal/lv_hal_indev.h" #include "hal/lv_hal_indev.h"
#include "input_trigger.hpp"
#include "lua.h"
namespace input { namespace input {
Hook::Hook(HookCb fn) : default_(fn), override_() {} Hook::Hook(std::string name, std::optional<HookCallback> cb)
: name_(name), default_(cb), override_() {}
auto Hook::invoke(lv_indev_data_t* d) -> void { auto Hook::invoke(lv_indev_data_t* d) -> void {
if (override_) { auto cb = callback();
std::invoke(*override_, d); if (cb) {
} else if (default_) { std::invoke(cb->fn, d);
std::invoke(*default_, d);
} }
} }
auto Hook::override(HookCb fn) -> void { auto Hook::override(std::optional<HookCallback> cb) -> void {
override_ = fn; override_ = cb;
}
auto Hook::callback() -> std::optional<HookCallback> {
if (override_) {
return override_;
} else if (default_) {
return default_;
}
return {};
} }
TriggerHooks::TriggerHooks(HookCb click, HookCb long_press, HookCb repeat) TriggerHooks::TriggerHooks(std::string name,
: click_(click), long_press_(long_press), repeat_(repeat) {} std::optional<HookCallback> click,
std::optional<HookCallback> long_press,
std::optional<HookCallback> 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 { auto TriggerHooks::update(bool pressed, lv_indev_data_t* d) -> void {
switch (trigger_.update(pressed)) { 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<HookCallback> cb)
-> void {
switch (s) { switch (s) {
case Trigger::State::kClick: case Trigger::State::kClick:
click_.override(fn); click_.override(cb);
break; break;
case Trigger::State::kLongPress: case Trigger::State::kLongPress:
long_press_.override(fn); long_press_.override(cb);
break; break;
case Trigger::State::kRepeatPress: case Trigger::State::kRepeatPress:
repeat_.override(fn); repeat_.override(cb);
break; break;
case Trigger::State::kNone: case Trigger::State::kNone:
default: 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 } // namespace input

@ -16,36 +16,57 @@
namespace input { namespace input {
namespace actions { namespace actions {
auto select(lv_indev_data_t* d) -> void { auto select() -> HookCallback {
return HookCallback{.name = "select", .fn = [&](lv_indev_data_t* d) {
d->state = LV_INDEV_STATE_PRESSED; d->state = LV_INDEV_STATE_PRESSED;
}};
} }
auto scrollUp(lv_indev_data_t* d) -> void { auto scrollUp() -> HookCallback {
d->enc_diff = -1; return HookCallback{.name = "scroll_up",
.fn = [&](lv_indev_data_t* d) { d->enc_diff = -1; }};
} }
auto scrollDown(lv_indev_data_t* d) -> void { auto scrollDown() -> HookCallback {
d->enc_diff = 1; return HookCallback{.name = "scroll_down",
.fn = [&](lv_indev_data_t* d) { d->enc_diff = 1; }};
} }
auto scrollToTop(lv_indev_data_t* d) -> void { auto scrollToTop() -> HookCallback {
return HookCallback{.name = "scroll_to_top", .fn = [&](lv_indev_data_t* d) {
d->enc_diff = INT16_MIN; d->enc_diff = INT16_MIN;
}};
} }
auto scrollToBottom(lv_indev_data_t* d) -> void { auto scrollToBottom() -> HookCallback {
d->enc_diff = INT16_MAX; 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 { auto goBack() -> HookCallback {
return HookCallback{.name = "back", .fn = [&](lv_indev_data_t* d) {
events::Ui().Dispatch(ui::internal::BackPressed{}); events::Ui().Dispatch(ui::internal::BackPressed{});
}};
} }
auto volumeUp(lv_indev_data_t* d) -> void { auto volumeUp() -> HookCallback {
return HookCallback{.name = "volume_up", .fn = [&](lv_indev_data_t* d) {
events::Audio().Dispatch(audio::StepUpVolume{}); events::Audio().Dispatch(audio::StepUpVolume{});
}};
} }
auto volumeDown(lv_indev_data_t* d) -> void { auto volumeDown() -> HookCallback {
return HookCallback{.name = "volume_down", .fn = [&](lv_indev_data_t* d) {
events::Audio().Dispatch(audio::StepDownVolume{}); events::Audio().Dispatch(audio::StepDownVolume{});
}};
}
auto allActions() -> std::vector<HookCallback> {
return {
select(), scrollUp(), scrollDown(), scrollToTop(),
scrollToBottom(), goBack(), volumeUp(), volumeDown(),
};
} }
} // namespace actions } // namespace actions

@ -15,12 +15,20 @@ namespace input {
NavButtons::NavButtons(drivers::IGpios& gpios) NavButtons::NavButtons(drivers::IGpios& gpios)
: gpios_(gpios), : gpios_(gpios),
up_(actions::scrollUp, actions::select, {}), up_("upper", actions::scrollUp(), actions::select(), {}),
down_(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);
down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data); down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data);
} }
auto NavButtons::name() -> std::string {
return "buttons";
}
auto NavButtons::hooks() -> std::vector<TriggerHooks> {
return {up_, down_};
}
} // namespace input } // namespace input

@ -21,11 +21,11 @@ namespace input {
TouchDPad::TouchDPad(drivers::TouchWheel& wheel) TouchDPad::TouchDPad(drivers::TouchWheel& wheel)
: wheel_(wheel), : wheel_(wheel),
centre_(actions::select, {}, {}), centre_("centre", actions::select(), {}, {}),
up_(actions::scrollUp), up_("up", actions::scrollUp()),
right_({}, {}, {}), right_("right", {}, {}, {}),
down_(actions::scrollDown), down_("down", actions::scrollDown()),
left_(actions::goBack) {} left_("left", actions::goBack()) {}
auto TouchDPad::read(lv_indev_data_t* data) -> void { auto TouchDPad::read(lv_indev_data_t* data) -> void {
wheel_.Update(); wheel_.Update();
@ -51,4 +51,12 @@ auto TouchDPad::read(lv_indev_data_t* data) -> void {
data); data);
} }
auto TouchDPad::name() -> std::string {
return "dpad";
}
auto TouchDPad::hooks() -> std::vector<TriggerHooks> {
return {centre_, up_, right_, down_, left_};
}
} // namespace input } // namespace input

@ -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_(actions::select, {}, {}), centre_("centre", actions::select(), {}, {}),
up_({}, actions::scrollToTop, actions::scrollUp), up_("up", {}, actions::scrollToTop(), actions::scrollUp()),
right_({}, {}, {}), right_("right", {}, {}, {}),
down_({}, actions::scrollToBottom, actions::scrollDown), down_("down", {}, actions::scrollToBottom(), actions::scrollDown()),
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),
@ -88,6 +88,14 @@ auto TouchWheel::read(lv_indev_data_t* data) -> void {
data); data);
} }
auto TouchWheel::name() -> std::string {
return "wheel";
}
auto TouchWheel::hooks() -> std::vector<TriggerHooks> {
return {centre_, up_, right_, down_, left_};
}
auto TouchWheel::sensitivity() -> lua::Property& { auto TouchWheel::sensitivity() -> lua::Property& {
return sensitivity_; return sensitivity_;
} }

@ -12,11 +12,21 @@
namespace input { namespace input {
VolumeButtons::VolumeButtons(drivers::IGpios& gpios) 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 { auto VolumeButtons::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);
down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data); down_.update(!gpios_.Get(drivers::IGpios::Pin::kKeyDown), data);
} }
auto VolumeButtons::name() -> std::string {
return "buttons";
}
auto VolumeButtons::hooks() -> std::vector<TriggerHooks> {
return {up_, down_};
}
} // namespace input } // namespace input

@ -16,6 +16,8 @@
#include "input_touch_wheel.hpp" #include "input_touch_wheel.hpp"
#include "input_trigger.hpp" #include "input_trigger.hpp"
#include "input_volume_buttons.hpp" #include "input_volume_buttons.hpp"
#include "lauxlib.h"
#include "lua.h"
#include "lvgl.h" #include "lvgl.h"
#include "nvs.hpp" #include "nvs.hpp"
#include "property.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 } // namespace input

@ -14,6 +14,7 @@
#include "db_events.hpp" #include "db_events.hpp"
#include "device_factory.hpp" #include "device_factory.hpp"
#include "display_init.hpp" #include "display_init.hpp"
#include "esp_spp_api.h"
#include "feedback_haptics.hpp" #include "feedback_haptics.hpp"
#include "freertos/portmacro.h" #include "freertos/portmacro.h"
#include "freertos/projdefs.h" #include "freertos/projdefs.h"
@ -497,9 +498,12 @@ void Lua::entry() {
{"brightness", &sDisplayBrightness}, {"brightness", &sDisplayBrightness},
}); });
registry.AddPropertyModule("controls", { registry.AddPropertyModule(
"controls",
{
{"scheme", &sInput->mode()}, {"scheme", &sInput->mode()},
{"lock_switch", &sLockSwitch}, {"lock_switch", &sLockSwitch},
{"hooks", [&](lua_State* L) { return sInput->pushHooks(L); }},
}); });
if (sDeviceFactory->touch_wheel()) { if (sDeviceFactory->touch_wheel()) {

Loading…
Cancel
Save