|
|
|
@ -13,17 +13,22 @@ |
|
|
|
|
|
|
|
|
|
#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) { |
|
|
|
@ -106,22 +111,148 @@ auto LvglInputDriver::feedback(uint8_t event) -> void { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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& hook : dev->hooks()) { |
|
|
|
|
lua_pushlstring(L, hook.name().data(), hook.name().size()); |
|
|
|
|
hook.pushHooks(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
|
|
|
|
|