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 "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<std::pair<std::string, lua::Property>> {
return {};
}
virtual auto name() -> std::string = 0;
virtual auto hooks() -> std::vector<TriggerHooks> { return {}; }
};
} // namespace input

@ -8,35 +8,53 @@
#include <functional>
#include <optional>
#include <string>
#include "hal/lv_hal_indev.h"
#include "lua.hpp"
#include "input_trigger.hpp"
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 {
public:
Hook(HookCb);
Hook(std::string name, std::optional<HookCallback> cb);
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:
HookCb default_;
HookCb override_;
std::string name_;
std::optional<HookCallback> default_;
std::optional<HookCallback> override_;
};
class TriggerHooks {
public:
TriggerHooks(HookCb cb) : TriggerHooks(cb, cb, cb) {}
TriggerHooks(HookCb, HookCb, HookCb);
TriggerHooks(std::string name, std::optional<HookCallback> cb)
: 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 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:
std::string name_;
Trigger trigger_;
Hook click_;

@ -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<HookCallback>;
} // namespace actions
} // namespace input

@ -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<TriggerHooks> override;
private:
drivers::IGpios& gpios_;

@ -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<TriggerHooks> override;
private:
drivers::TouchWheel& wheel_;

@ -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<TriggerHooks> override;
auto sensitivity() -> lua::Property&;
private:

@ -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<TriggerHooks> override;
private:
drivers::IGpios& gpios_;

@ -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_;

@ -9,25 +9,42 @@
#include <functional>
#include <optional>
#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<HookCallback> 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<HookCallback> cb) -> void {
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)
: click_(click), long_press_(long_press), repeat_(repeat) {}
TriggerHooks::TriggerHooks(std::string name,
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 {
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) {
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

@ -16,36 +16,57 @@
namespace input {
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;
}};
}
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 {
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 {
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 {
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 {
auto volumeDown() -> HookCallback {
return HookCallback{.name = "volume_down", .fn = [&](lv_indev_data_t* d) {
events::Audio().Dispatch(audio::StepDownVolume{});
}};
}
auto allActions() -> std::vector<HookCallback> {
return {
select(), scrollUp(), scrollDown(), scrollToTop(),
scrollToBottom(), goBack(), volumeUp(), volumeDown(),
};
}
} // namespace actions

@ -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<TriggerHooks> {
return {up_, down_};
}
} // namespace input

@ -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<TriggerHooks> {
return {centre_, up_, right_, down_, left_};
}
} // namespace input

@ -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<TriggerHooks> {
return {centre_, up_, right_, down_, left_};
}
auto TouchWheel::sensitivity() -> lua::Property& {
return sensitivity_;
}

@ -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<TriggerHooks> {
return {up_, down_};
}
} // namespace input

@ -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

@ -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,9 +498,12 @@ void Lua::entry() {
{"brightness", &sDisplayBrightness},
});
registry.AddPropertyModule("controls", {
registry.AddPropertyModule(
"controls",
{
{"scheme", &sInput->mode()},
{"lock_switch", &sLockSwitch},
{"hooks", [&](lua_State* L) { return sInput->pushHooks(L); }},
});
if (sDeviceFactory->touch_wheel()) {

Loading…
Cancel
Save