diff options
Diffstat (limited to 'src/input/lvgl_input_driver.cpp')
| -rw-r--r-- | src/input/lvgl_input_driver.cpp | 258 |
1 files changed, 0 insertions, 258 deletions
diff --git a/src/input/lvgl_input_driver.cpp b/src/input/lvgl_input_driver.cpp deleted file mode 100644 index a82b7438..00000000 --- a/src/input/lvgl_input_driver.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2023 jacqueline <me@jacqueline.id.au> - * - * SPDX-License-Identifier: GPL-3.0-only - */ - -#include "lvgl_input_driver.hpp" -#include <stdint.h> - -#include <cstdint> -#include <memory> -#include <variant> - -#include "device_factory.hpp" -#include "feedback_haptics.hpp" -#include "input_hook.hpp" -#include "input_touch_wheel.hpp" -#include "input_trigger.hpp" -#include "input_volume_buttons.hpp" -#include "lauxlib.h" -#include "lua.h" -#include "lua_thread.hpp" -#include "lvgl.h" -#include "nvs.hpp" -#include "property.hpp" - -[[maybe_unused]] static constexpr char kTag[] = "input"; - -static constexpr char kLuaTriggerMetatableName[] = "input_trigger"; -static constexpr char kLuaOverrideText[] = "lua_callback"; - -namespace input { - -static void read_cb(lv_indev_drv_t* drv, lv_indev_data_t* data) { - LvglInputDriver* instance = - reinterpret_cast<LvglInputDriver*>(drv->user_data); - instance->read(data); -} - -static void feedback_cb(lv_indev_drv_t* drv, uint8_t event) { - LvglInputDriver* instance = - reinterpret_cast<LvglInputDriver*>(drv->user_data); - instance->feedback(event); -} - -auto intToMode(int raw) -> std::optional<drivers::NvsStorage::InputModes> { - switch (raw) { - case 0: - return drivers::NvsStorage::InputModes::kButtonsOnly; - case 1: - return drivers::NvsStorage::InputModes::kButtonsWithWheel; - case 2: - return drivers::NvsStorage::InputModes::kDirectionalWheel; - case 3: - return drivers::NvsStorage::InputModes::kRotatingWheel; - default: - return {}; - } -} - -LvglInputDriver::LvglInputDriver(drivers::NvsStorage& nvs, - DeviceFactory& factory) - : nvs_(nvs), - factory_(factory), - mode_(static_cast<int>(nvs.PrimaryInput()), - [&](const lua::LuaValue& val) { - if (!std::holds_alternative<int>(val)) { - return false; - } - auto mode = intToMode(std::get<int>(val)); - if (!mode) { - return false; - } - nvs.PrimaryInput(*mode); - inputs_ = factory.createInputs(*mode); - return true; - }), - driver_(), - registration_(nullptr), - inputs_(factory.createInputs(nvs.PrimaryInput())), - feedbacks_(factory.createFeedbacks()), - is_locked_(false) { - lv_indev_drv_init(&driver_); - driver_.type = LV_INDEV_TYPE_ENCODER; - driver_.read_cb = read_cb; - driver_.feedback_cb = feedback_cb; - driver_.user_data = this; - driver_.long_press_time = kLongPressDelayMs; - driver_.long_press_repeat_time = kRepeatDelayMs; - - registration_ = lv_indev_drv_register(&driver_); -} - -auto LvglInputDriver::read(lv_indev_data_t* data) -> void { - // TODO: we should pass lock state on to the individual devices, since they - // may wish to either ignore the lock state, or power down until unlock. - if (is_locked_) { - return; - } - for (auto&& device : inputs_) { - device->read(data); - } -} - -auto LvglInputDriver::feedback(uint8_t event) -> void { - if (is_locked_) { - return; - } - for (auto&& device : feedbacks_) { - device->feedback(event); - } -} - -LvglInputDriver::LuaTrigger::LuaTrigger(LvglInputDriver& driver, - IInputDevice& dev, - TriggerHooks& trigger) - : driver_(&driver), device_(dev.name()), trigger_(trigger.name()) { - for (auto& hook : trigger.hooks()) { - auto cb = hook.get().callback(); - if (cb) { - hooks_[hook.get().name()] = hook.get().callback()->name; - } else { - hooks_[hook.get().name()] = ""; - } - } -} - -auto LvglInputDriver::LuaTrigger::get(lua_State* L, int idx) -> LuaTrigger& { - return **reinterpret_cast<LuaTrigger**>( - luaL_checkudata(L, idx, kLuaTriggerMetatableName)); -} - -auto LvglInputDriver::LuaTrigger::luaGc(lua_State* L) -> int { - LuaTrigger& trigger = LuaTrigger::get(L, 1); - delete &trigger; - return 0; -} - -auto LvglInputDriver::LuaTrigger::luaToString(lua_State* L) -> int { - LuaTrigger& trigger = LuaTrigger::get(L, 1); - std::stringstream out; - out << "{ "; - for (const auto& hook : trigger.hooks_) { - if (!hook.second.empty()) { - out << hook.first << "=" << hook.second << " "; - } - } - out << "}"; - lua_pushlstring(L, out.str().data(), out.str().size()); - return 1; -} - -auto LvglInputDriver::LuaTrigger::luaNewIndex(lua_State* L) -> int { - LuaTrigger& trigger = LuaTrigger::get(L, 1); - luaL_checktype(L, 3, LUA_TFUNCTION); - - size_t len = 0; - const char* str = luaL_checklstring(L, 2, &len); - if (!str) { - return 0; - } - OverrideSelector selector{ - .device_name = trigger.device_, - .trigger_name = trigger.trigger_, - .hook_name = std::string{str, len}, - }; - for (const auto& hook : trigger.hooks_) { - if (hook.first == selector.hook_name) { - trigger.driver_->setOverride(L, selector); - trigger.hooks_[hook.first] = kLuaOverrideText; - return 0; - } - } - return 0; -} - -auto LvglInputDriver::pushHooks(lua_State* L) -> int { - if (luaL_getmetatable(L, kLuaTriggerMetatableName) == LUA_TNIL) { - luaL_newmetatable(L, kLuaTriggerMetatableName); - luaL_setfuncs(L, LuaTrigger::kFuncs, 0); - lua_pop(L, 1); - } - lua_pop(L, 1); - - lua_newtable(L); - - for (auto& dev : inputs_) { - lua_pushlstring(L, dev->name().data(), dev->name().size()); - lua_newtable(L); - - for (auto& trigger : dev->triggers()) { - lua_pushlstring(L, trigger.get().name().data(), - trigger.get().name().size()); - LuaTrigger** lua_obj = reinterpret_cast<LuaTrigger**>( - lua_newuserdatauv(L, sizeof(LuaTrigger*), 0)); - *lua_obj = new LuaTrigger(*this, *dev, trigger); - luaL_setmetatable(L, kLuaTriggerMetatableName); - lua_rawset(L, -3); - } - - lua_rawset(L, -3); - } - - return 1; -} - -auto LvglInputDriver::setOverride(lua_State* L, - const OverrideSelector& selector) -> void { - if (overrides_.contains(selector)) { - LuaOverride& prev = overrides_[selector]; - luaL_unref(prev.L, LUA_REGISTRYINDEX, prev.ref); - } - - int ref = luaL_ref(L, LUA_REGISTRYINDEX); - LuaOverride override{ - .L = L, - .ref = ref, - }; - overrides_[selector] = override; - applyOverride(selector, override); -} - -auto LvglInputDriver::applyOverride(const OverrideSelector& selector, - LuaOverride& override) -> void { - // In general, this algorithm is a very slow approach. We could do better - // by maintaing maps from [device|trigger|hook]_name to the relevant - // trigger, but in practice I expect maybe like 5 overrides total ever, - // spread across 2 devices with 2 or 5 hooks each. So it's not that big a - // deal. Don't worry about it!! - - // Look for a matching device. - for (auto& device : inputs_) { - if (device->name() != selector.device_name) { - continue; - } - // Look for a matching trigger - for (auto& trigger : device->triggers()) { - if (trigger.get().name() != selector.trigger_name) { - continue; - } - // Look for a matching hook - for (auto& hook : trigger.get().hooks()) { - if (hook.get().name() != selector.hook_name) { - continue; - } - // We found the target! Apply the override. - auto lua_callback = [=](lv_indev_data_t* d) { - lua_rawgeti(override.L, LUA_REGISTRYINDEX, override.ref); - lua::CallProtected(override.L, 0, 0); - }; - hook.get().override( - HookCallback{.name = kLuaOverrideText, .fn = lua_callback}); - } - } - } -} - -} // namespace input |
