diff options
Diffstat (limited to 'src/config/lua/objects/LuaKeybind.cpp')
| -rw-r--r-- | src/config/lua/objects/LuaKeybind.cpp | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/config/lua/objects/LuaKeybind.cpp b/src/config/lua/objects/LuaKeybind.cpp new file mode 100644 index 00000000..aab2735d --- /dev/null +++ b/src/config/lua/objects/LuaKeybind.cpp @@ -0,0 +1,180 @@ +#include "LuaKeybind.hpp" + +#include <optional> +#include <string_view> + +using namespace Config::Lua; + +static constexpr const char* MT = "HL.Keybind"; + +namespace { + std::optional<SP<SKeybind>> getKeybindFromUserdata(lua_State* L) { + auto* ref = sc<WP<SKeybind>*>(luaL_checkudata(L, 1, MT)); + return ref->lock(); + } + + void pushDeviceList(lua_State* L, const SKeybind& keybind) { + lua_newtable(L); + int i = 1; + for (const auto& device : keybind.devices) { + lua_pushstring(L, device.c_str()); + lua_rawseti(L, -2, i++); + } + } +} + +static int keybindEq(lua_State* L) { + const auto* lhs = sc<WP<SKeybind>*>(luaL_checkudata(L, 1, MT)); + const auto* rhs = sc<WP<SKeybind>*>(luaL_checkudata(L, 2, MT)); + + lua_pushboolean(L, lhs->lock() == rhs->lock()); + return 1; +} + +static int keybindToString(lua_State* L) { + const auto* ref = sc<WP<SKeybind>*>(luaL_checkudata(L, 1, MT)); + const auto keybind = ref->lock(); + + if (!keybind) + lua_pushstring(L, "HL.Keybind(expired)"); + else + lua_pushfstring(L, "HL.Keybind(%p)", keybind.get()); + + return 1; +} + +static int keybindSetEnabled(lua_State* L) { + luaL_checktype(L, 2, LUA_TBOOLEAN); + + const auto keybind = getKeybindFromUserdata(L); + if (!keybind) + return 0; + + (*keybind)->enabled = lua_toboolean(L, 2); + return 0; +} + +static int keybindIsEnabled(lua_State* L) { + const auto keybind = getKeybindFromUserdata(L); + if (!keybind) { + lua_pushnil(L); + return 1; + } + + lua_pushboolean(L, (*keybind)->enabled); + return 1; +} + +static int keybindRemove(lua_State* L) { + const auto keybind = getKeybindFromUserdata(L); + if (!keybind || !g_pKeybindManager) + return 0; + + if ((*keybind)->handler == "__lua") { + try { + const int ref = std::stoi((*keybind)->arg); + if (ref > 0) + luaL_unref(L, LUA_REGISTRYINDEX, ref); + } catch (...) { + // invalid ref, ignore + } + + (*keybind)->arg = std::to_string(LUA_NOREF); + } + + g_pKeybindManager->removeKeybind((*keybind)->modmask, SParsedKey{.key = (*keybind)->key, .keycode = (*keybind)->keycode, .catchAll = (*keybind)->catchAll}); + return 0; +} + +static int keybindGetDescription(lua_State* L) { + const auto keybind = getKeybindFromUserdata(L); + if (!keybind) { + lua_pushnil(L); + return 1; + } + + if (!(*keybind)->hasDescription) + lua_pushnil(L); + else + lua_pushstring(L, (*keybind)->description.c_str()); + + return 1; +} + +static int keybindIndex(lua_State* L) { + const auto keybind = getKeybindFromUserdata(L); + const std::string_view key = luaL_checkstring(L, 2); + + if (key == "set_enabled") + lua_pushcfunction(L, keybindSetEnabled); + else if (key == "is_enabled") + lua_pushcfunction(L, keybindIsEnabled); + else if (key == "remove" || key == "unbind") + lua_pushcfunction(L, keybindRemove); + else if (!keybind) + lua_pushnil(L); + else if (key == "enabled") + lua_pushboolean(L, (*keybind)->enabled); + else if (key == "has_description") + lua_pushboolean(L, (*keybind)->hasDescription); + else if (key == "description") + return keybindGetDescription(L); + else if (key == "display_key") + lua_pushstring(L, (*keybind)->displayKey.c_str()); + else if (key == "submap") + lua_pushstring(L, (*keybind)->submap.name.c_str()); + else if (key == "handler") + lua_pushstring(L, (*keybind)->handler.c_str()); + else if (key == "arg") + lua_pushstring(L, (*keybind)->arg.c_str()); + else if (key == "modmask") + lua_pushinteger(L, sc<lua_Integer>((*keybind)->modmask)); + else if (key == "key") + lua_pushstring(L, (*keybind)->key.c_str()); + else if (key == "keycode") + lua_pushinteger(L, sc<lua_Integer>((*keybind)->keycode)); + else if (key == "catchall") + lua_pushboolean(L, (*keybind)->catchAll); + else if (key == "repeating") + lua_pushboolean(L, (*keybind)->repeat); + else if (key == "locked") + lua_pushboolean(L, (*keybind)->locked); + else if (key == "release") + lua_pushboolean(L, (*keybind)->release); + else if (key == "non_consuming") + lua_pushboolean(L, (*keybind)->nonConsuming); + else if (key == "transparent") + lua_pushboolean(L, (*keybind)->transparent); + else if (key == "ignore_mods") + lua_pushboolean(L, (*keybind)->ignoreMods); + else if (key == "long_press") + lua_pushboolean(L, (*keybind)->longPress); + else if (key == "dont_inhibit") + lua_pushboolean(L, (*keybind)->dontInhibit); + else if (key == "click") + lua_pushboolean(L, (*keybind)->click); + else if (key == "drag") + lua_pushboolean(L, (*keybind)->drag); + else if (key == "submap_universal") + lua_pushboolean(L, (*keybind)->submapUniversal); + else if (key == "mouse") + lua_pushboolean(L, (*keybind)->mouse); + else if (key == "device_inclusive") + lua_pushboolean(L, (*keybind)->deviceInclusive); + else if (key == "devices") + pushDeviceList(L, **keybind); + else + lua_pushnil(L); + + return 1; +} + +void Objects::CLuaKeybind::setup(lua_State* L) { + registerMetatable(L, MT, keybindIndex, gcRef<WP<SKeybind>>, keybindEq, keybindToString); +} + +void Objects::CLuaKeybind::push(lua_State* L, const SP<SKeybind>& keybind) { + new (lua_newuserdata(L, sizeof(WP<SKeybind>))) WP<SKeybind>(keybind); + luaL_getmetatable(L, MT); + lua_setmetatable(L, -2); +} |
