diff --git a/include/input/input.h b/include/input/input.h index 803af99..afd8ddf 100644 --- a/include/input/input.h +++ b/include/input/input.h @@ -15,6 +15,10 @@ struct kiwmi_input { struct wl_listener new_input; struct kiwmi_cursor *cursor; struct wlr_seat *seat; + + struct { + struct wl_signal keyboard_new; + } events; }; bool input_init(struct kiwmi_input *input); diff --git a/include/input/keyboard.h b/include/input/keyboard.h index 1551026..d31253a 100644 --- a/include/input/keyboard.h +++ b/include/input/keyboard.h @@ -9,6 +9,7 @@ #define KIWMI_INPUT_KEYBOARD_H #include +#include struct kiwmi_keyboard { struct wl_list link; @@ -16,6 +17,18 @@ struct kiwmi_keyboard { struct wlr_input_device *device; struct wl_listener modifiers; struct wl_listener key; + + struct { + struct wl_signal key_down; + struct wl_signal key_up; + } events; +}; + +struct kiwmi_keyboard_key_event { + const xkb_keysym_t *syms; + int nsyms; + struct kiwmi_keyboard *keyboard; + bool handled; }; struct kiwmi_keyboard * diff --git a/include/luak/kiwmi_keyboard.h b/include/luak/kiwmi_keyboard.h new file mode 100644 index 0000000..00eb736 --- /dev/null +++ b/include/luak/kiwmi_keyboard.h @@ -0,0 +1,16 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef KIWMI_LUAK_KIWMI_KEYBOARD_H +#define KIWMI_LUAK_KIWMI_KEYBOARD_H + +#include + +int luaK_kiwmi_keyboard_new(lua_State *L); +int luaK_kiwmi_keyboard_register(lua_State *L); + +#endif /* KIWMI_LUAK_KIWMI_KEYBOARD_H */ diff --git a/kiwmi/input/input.c b/kiwmi/input/input.c index 860c6ec..d71a37c 100644 --- a/kiwmi/input/input.c +++ b/kiwmi/input/input.c @@ -84,5 +84,7 @@ input_init(struct kiwmi_input *input) input->new_input.notify = new_input_notify; wl_signal_add(&server->backend->events.new_input, &input->new_input); + wl_signal_init(&input->events.keyboard_new); + return true; } diff --git a/kiwmi/input/keyboard.c b/kiwmi/input/keyboard.c index f381d76..1c59155 100644 --- a/kiwmi/input/keyboard.c +++ b/kiwmi/input/keyboard.c @@ -62,25 +62,28 @@ keyboard_key_notify(struct wl_listener *listener, void *data) const xkb_keysym_t *syms; int nsyms = xkb_state_key_get_syms( keyboard->device->keyboard->xkb_state, keycode, &syms); - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); bool handled = false; if (event->state == WLR_KEY_PRESSED) { handled = switch_vt(syms, nsyms, server->backend); + } - if (!handled && (modifiers & WLR_MODIFIER_LOGO)) { - for (int i = 0; i < nsyms; ++i) { - xkb_keysym_t sym = syms[i]; + if (!handled) { + struct kiwmi_keyboard_key_event data = { + .syms = syms, + .nsyms = nsyms, + .keyboard = keyboard, + .handled = false, + }; - switch (sym) { - case XKB_KEY_Escape: - wl_display_terminate(server->wl_display); - handled = true; - break; - } - } + if (event->state == WLR_KEY_PRESSED) { + wl_signal_emit(&keyboard->events.key_down, &data); + } else { + wl_signal_emit(&keyboard->events.key_up, &data); } + + handled = data.handled; } if (!handled) { @@ -121,5 +124,10 @@ keyboard_create(struct kiwmi_server *server, struct wlr_input_device *device) wlr_seat_set_keyboard(server->input.seat, device); + wl_signal_init(&keyboard->events.key_down); + wl_signal_init(&keyboard->events.key_up); + + wl_signal_emit(&server->input.events.keyboard_new, keyboard); + return keyboard; } diff --git a/kiwmi/luak/ipc.c b/kiwmi/luak/ipc.c index 59662e1..29805e0 100644 --- a/kiwmi/luak/ipc.c +++ b/kiwmi/luak/ipc.c @@ -32,6 +32,7 @@ ipc_eval( wlr_log(WLR_ERROR, "Error running IPC command: %s", error); kiwmi_command_send_done( command_resource, KIWMI_COMMAND_ERROR_FAILURE, error); + lua_pop(L, 1); return; } @@ -44,6 +45,8 @@ ipc_eval( kiwmi_command_send_done( command_resource, KIWMI_COMMAND_ERROR_SUCCESS, lua_tostring(L, -1)); } + + lua_pop(L, results); } static const struct kiwmi_ipc_interface kiwmi_ipc_implementation = { diff --git a/kiwmi/luak/kiwmi_keyboard.c b/kiwmi/luak/kiwmi_keyboard.c new file mode 100644 index 0000000..44a226b --- /dev/null +++ b/kiwmi/luak/kiwmi_keyboard.c @@ -0,0 +1,191 @@ +/* Copyright (c), Niclas Meyer + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "luak/kiwmi_keyboard.h" + +#include +#include +#include +#include +#include + +#include "input/keyboard.h" +#include "luak/kiwmi_lua_callback.h" + +static int +l_kiwmi_keyboard_modifiers(lua_State *L) +{ + struct kiwmi_keyboard *keyboard = + *(struct kiwmi_keyboard **)luaL_checkudata(L, 1, "kiwmi_keyboard"); + + uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + + lua_newtable(L); + + lua_pushboolean(L, modifiers & WLR_MODIFIER_SHIFT); + lua_setfield(L, -2, "shift"); + + lua_pushboolean(L, modifiers & WLR_MODIFIER_CAPS); + lua_setfield(L, -2, "caps"); + + lua_pushboolean(L, modifiers & WLR_MODIFIER_CTRL); + lua_setfield(L, -2, "ctrl"); + + lua_pushboolean(L, modifiers & WLR_MODIFIER_ALT); + lua_setfield(L, -2, "alt"); + + lua_pushboolean(L, modifiers & WLR_MODIFIER_MOD2); + lua_setfield(L, -2, "mod2"); + + lua_pushboolean(L, modifiers & WLR_MODIFIER_MOD3); + lua_setfield(L, -2, "mod3"); + + lua_pushboolean(L, modifiers & WLR_MODIFIER_LOGO); + lua_setfield(L, -2, "super"); + + lua_pushboolean(L, modifiers & WLR_MODIFIER_MOD5); + lua_setfield(L, -2, "mod5"); + + return 1; +} + +static const luaL_Reg kiwmi_keyboard_methods[] = { + {"modifiers", l_kiwmi_keyboard_modifiers}, + {"on", luaK_callback_register_dispatch}, + {NULL, NULL}, +}; + +static void +kiwmi_keyboard_on_key_down_or_up_notify( + struct wl_listener *listener, + void *data) +{ + struct kiwmi_lua_callback *lc = wl_container_of(listener, lc, listener); + struct kiwmi_server *server = lc->server; + lua_State *L = server->lua->L; + struct kiwmi_keyboard_key_event *event = data; + struct kiwmi_keyboard *keyboard = event->keyboard; + + const xkb_keysym_t *syms = event->syms; + int nsyms = event->nsyms; + + char keysym_name[64]; + + for (int i = 0; i < nsyms; ++i) { + xkb_keysym_t sym = syms[i]; + + int namelen = + xkb_keysym_get_name(sym, keysym_name, sizeof(keysym_name)); + + lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); + + lua_newtable(L); + + lua_pushlstring(L, keysym_name, namelen); + lua_setfield(L, -2, "key"); + + lua_pushcfunction(L, luaK_kiwmi_keyboard_new); + lua_pushlightuserdata(L, keyboard); + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + } + lua_setfield(L, -2, "keyboard"); + + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + } + + event->handled |= lua_toboolean(L, -1); + lua_pop(L, 1); + } +} + +static int +l_kiwmi_keyboard_on_key_down(lua_State *L) +{ + struct kiwmi_keyboard *keyboard = + *(struct kiwmi_keyboard **)luaL_checkudata(L, 1, "kiwmi_keyboard"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct kiwmi_server *server = keyboard->server; + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_keyboard_on_key_down_or_up_notify); + lua_pushlightuserdata(L, &keyboard->events.key_down); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + +static int +l_kiwmi_keyboard_on_key_up(lua_State *L) +{ + struct kiwmi_keyboard *keyboard = + *(struct kiwmi_keyboard **)luaL_checkudata(L, 1, "kiwmi_keyboard"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + struct kiwmi_server *server = keyboard->server; + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_keyboard_on_key_down_or_up_notify); + lua_pushlightuserdata(L, &keyboard->events.key_up); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + +static const luaL_Reg kiwmi_keyboard_events[] = { + {"key_down", l_kiwmi_keyboard_on_key_down}, + {"key_up", l_kiwmi_keyboard_on_key_up}, + {NULL, NULL}, +}; + +int +luaK_kiwmi_keyboard_new(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); // kiwmi_keyboard + + struct kiwmi_keyboard *keyboard = lua_touserdata(L, 1); + + struct kiwmi_keyboard **keyboard_ud = + lua_newuserdata(L, sizeof(*keyboard_ud)); + luaL_getmetatable(L, "kiwmi_keyboard"); + lua_setmetatable(L, -2); + + *keyboard_ud = keyboard; + + return 1; +} + +int +luaK_kiwmi_keyboard_register(lua_State *L) +{ + luaL_newmetatable(L, "kiwmi_keyboard"); + + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + luaL_setfuncs(L, kiwmi_keyboard_methods, 0); + + luaL_newlib(L, kiwmi_keyboard_events); + lua_setfield(L, -2, "__events"); + + return 0; +} diff --git a/kiwmi/luak/kiwmi_server.c b/kiwmi/luak/kiwmi_server.c index 61934ef..537c0e2 100644 --- a/kiwmi/luak/kiwmi_server.c +++ b/kiwmi/luak/kiwmi_server.c @@ -18,6 +18,7 @@ #include "desktop/view.h" #include "input/cursor.h" +#include "luak/kiwmi_keyboard.h" #include "luak/kiwmi_lua_callback.h" #include "luak/kiwmi_view.h" #include "server.h" @@ -118,6 +119,30 @@ static const luaL_Reg kiwmi_server_methods[] = { {NULL, NULL}, }; +static void +kiwmi_server_on_keyboard_notify(struct wl_listener *listener, void *data) +{ + struct kiwmi_lua_callback *lc = wl_container_of(listener, lc, listener); + struct kiwmi_server *server = lc->server; + lua_State *L = server->lua->L; + struct kiwmi_keyboard *keyboard = data; + + lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); + + lua_pushcfunction(L, luaK_kiwmi_keyboard_new); + lua_pushlightuserdata(L, keyboard); + if (lua_pcall(L, 1, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return; + } + + if (lua_pcall(L, 1, 0, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + } +} + static void kiwmi_server_on_view_notify(struct wl_listener *listener, void *data) { @@ -132,13 +157,37 @@ kiwmi_server_on_view_notify(struct wl_listener *listener, void *data) lua_pushlightuserdata(L, view); if (lua_pcall(L, 1, 1, 0)) { wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return; } if (lua_pcall(L, 1, 0, 0)) { wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); } } +static int +l_kiwmi_server_on_keyboard(lua_State *L) +{ + struct kiwmi_server *server = + *(struct kiwmi_server **)luaL_checkudata(L, 1, "kiwmi_server"); + luaL_checktype(L, 2, LUA_TFUNCTION); + + lua_pushcfunction(L, luaK_kiwmi_lua_callback_new); + lua_pushlightuserdata(L, server); + lua_pushvalue(L, 2); + lua_pushlightuserdata(L, kiwmi_server_on_keyboard_notify); + lua_pushlightuserdata(L, &server->input.events.keyboard_new); + + if (lua_pcall(L, 4, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + return 0; + } + + return 1; +} + static int l_kiwmi_server_on_view(lua_State *L) { @@ -161,6 +210,7 @@ l_kiwmi_server_on_view(lua_State *L) } static const luaL_Reg kiwmi_server_events[] = { + {"keyboard", l_kiwmi_server_on_keyboard}, {"view", l_kiwmi_server_on_view}, {NULL, NULL}, }; diff --git a/kiwmi/luak/kiwmi_view.c b/kiwmi/luak/kiwmi_view.c index b1bb4bf..04040ce 100644 --- a/kiwmi/luak/kiwmi_view.c +++ b/kiwmi/luak/kiwmi_view.c @@ -110,10 +110,13 @@ kiwmi_view_on_destroy_notify(struct wl_listener *listener, void *data) if (lua_pcall(L, 1, 1, 0)) { wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return; } if (lua_pcall(L, 1, 0, 0)) { wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); } } diff --git a/kiwmi/luak/luak.c b/kiwmi/luak/luak.c index 7fe37e2..a647be7 100644 --- a/kiwmi/luak/luak.c +++ b/kiwmi/luak/luak.c @@ -14,6 +14,7 @@ #include #include "luak/ipc.h" +#include "luak/kiwmi_keyboard.h" #include "luak/kiwmi_lua_callback.h" #include "luak/kiwmi_server.h" #include "luak/kiwmi_view.h" @@ -64,12 +65,14 @@ luaK_create(struct kiwmi_server *server) // register types int error = 0; + lua_pushcfunction(L, luaK_kiwmi_keyboard_register); + error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_lua_callback_register); error |= lua_pcall(L, 0, 0, 0); - lua_pushcfunction(L, luaK_kiwmi_view_register); - error |= lua_pcall(L, 0, 0, 0); lua_pushcfunction(L, luaK_kiwmi_server_register); error |= lua_pcall(L, 0, 0, 0); + lua_pushcfunction(L, luaK_kiwmi_view_register); + error |= lua_pcall(L, 0, 0, 0); if (error) { wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); @@ -106,12 +109,16 @@ luaK_create(struct kiwmi_server *server) bool luaK_dofile(struct kiwmi_lua *lua, const char *config_path) { + int top = lua_gettop(lua->L); + if (luaL_dofile(lua->L, config_path)) { wlr_log( WLR_ERROR, "Error running config: %s", lua_tostring(lua->L, -1)); return false; } + lua_pop(lua->L, top - lua_gettop(lua->L)); + return true; } diff --git a/kiwmi/meson.build b/kiwmi/meson.build index 6cc54a4..2e27441 100644 --- a/kiwmi/meson.build +++ b/kiwmi/meson.build @@ -9,6 +9,7 @@ kiwmi_sources = files( 'input/input.c', 'input/keyboard.c', 'luak/ipc.c', + 'luak/kiwmi_keyboard.c', 'luak/kiwmi_lua_callback.c', 'luak/kiwmi_server.c', 'luak/kiwmi_view.c', diff --git a/kiwmi/server.c b/kiwmi/server.c index ccc86b4..207f7fa 100644 --- a/kiwmi/server.c +++ b/kiwmi/server.c @@ -102,15 +102,15 @@ server_run(struct kiwmi_server *server) wlr_log( WLR_DEBUG, "Running Wayland server on display '%s'", server->socket); - if (!wlr_backend_start(server->backend)) { - wlr_log(WLR_ERROR, "Failed to start backend"); + setenv("WAYLAND_DISPLAY", server->socket, true); + + if (!luaK_dofile(server->lua, server->config_path)) { wl_display_destroy(server->wl_display); return false; } - setenv("WAYLAND_DISPLAY", server->socket, true); - - if (!luaK_dofile(server->lua, server->config_path)) { + if (!wlr_backend_start(server->backend)) { + wlr_log(WLR_ERROR, "Failed to start backend"); wl_display_destroy(server->wl_display); return false; }