Support getting a tree of controls + hooks via lua
This commit is contained in:
@@ -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_;
|
||||
|
||||
+54
-13
@@ -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;
|
||||
}
|
||||
|
||||
TriggerHooks::TriggerHooks(HookCb click, HookCb long_press, HookCb repeat)
|
||||
: click_(click), long_press_(long_press), repeat_(repeat) {}
|
||||
auto Hook::callback() -> std::optional<HookCallback> {
|
||||
if (override_) {
|
||||
return override_;
|
||||
} else if (default_) {
|
||||
return default_;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
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 {
|
||||
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<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
|
||||
|
||||
+8
-4
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user