diff --git a/include/input/keyboard.h b/include/input/keyboard.h index 1fb11bb..cc45206 100644 --- a/include/input/keyboard.h +++ b/include/input/keyboard.h @@ -8,6 +8,8 @@ #ifndef KIWMI_INPUT_KEYBOARD_H #define KIWMI_INPUT_KEYBOARD_H +#include + #include #include @@ -27,8 +29,11 @@ struct kiwmi_keyboard { }; struct kiwmi_keyboard_key_event { - const xkb_keysym_t *syms; - int nsyms; + const xkb_keysym_t *raw_syms; + const xkb_keysym_t *translated_syms; + int raw_syms_len; + int translated_syms_len; + uint32_t keycode; struct kiwmi_keyboard *keyboard; bool handled; }; diff --git a/kiwmi/input/keyboard.c b/kiwmi/input/keyboard.c index 0debbde..3563fa7 100644 --- a/kiwmi/input/keyboard.c +++ b/kiwmi/input/keyboard.c @@ -59,24 +59,36 @@ keyboard_key_notify(struct wl_listener *listener, void *data) struct kiwmi_keyboard *keyboard = wl_container_of(listener, keyboard, key); struct kiwmi_server *server = keyboard->server; struct wlr_event_keyboard_key *event = data; + struct wlr_input_device *device = keyboard->device; uint32_t keycode = event->keycode + 8; - const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms( - keyboard->device->keyboard->xkb_state, keycode, &syms); + + const xkb_keysym_t *raw_syms; + xkb_layout_index_t layout_index = + xkb_state_key_get_layout(device->keyboard->xkb_state, keycode); + int raw_syms_len = xkb_keymap_key_get_syms_by_level( + device->keyboard->keymap, keycode, layout_index, 0, &raw_syms); + + const xkb_keysym_t *translated_syms; + int translated_syms_len = xkb_state_key_get_syms( + keyboard->device->keyboard->xkb_state, keycode, &translated_syms); bool handled = false; if (event->state == WLR_KEY_PRESSED) { - handled = switch_vt(syms, nsyms, server->backend); + handled = + switch_vt(translated_syms, translated_syms_len, server->backend); } if (!handled) { struct kiwmi_keyboard_key_event data = { - .syms = syms, - .nsyms = nsyms, - .keyboard = keyboard, - .handled = false, + .raw_syms = raw_syms, + .translated_syms = translated_syms, + .raw_syms_len = raw_syms_len, + .translated_syms_len = translated_syms_len, + .keycode = keycode, + .keyboard = keyboard, + .handled = false, }; if (event->state == WLR_KEY_PRESSED) { diff --git a/kiwmi/luak/kiwmi_keyboard.c b/kiwmi/luak/kiwmi_keyboard.c index 1d5fcdd..7d5943d 100644 --- a/kiwmi/luak/kiwmi_keyboard.c +++ b/kiwmi/luak/kiwmi_keyboard.c @@ -7,6 +7,8 @@ #include "luak/kiwmi_keyboard.h" +#include + #include #include #include @@ -145,56 +147,88 @@ kiwmi_keyboard_on_destroy_notify(struct wl_listener *listener, void *data) } } +static bool +send_key_event( + struct kiwmi_lua_callback *lc, + xkb_keysym_t sym, + uint32_t keycode, + struct kiwmi_keyboard *keyboard, + bool raw) +{ + struct kiwmi_server *server = lc->server; + lua_State *L = server->lua->L; + + static char keysym_name[64]; + size_t namelen = xkb_keysym_get_name(sym, keysym_name, sizeof(keysym_name)); + + namelen = namelen > sizeof(keysym_name) ? sizeof(keysym_name) : namelen; + + lua_rawgeti(L, LUA_REGISTRYINDEX, lc->callback_ref); + + lua_newtable(L); + + lua_pushlstring(L, keysym_name, namelen); + lua_setfield(L, -2, "key"); + + lua_pushnumber(L, keycode); + lua_setfield(L, -2, "keycode"); + + lua_pushboolean(L, raw); + lua_setfield(L, -2, "raw"); + + lua_pushcfunction(L, luaK_kiwmi_keyboard_new); + lua_pushlightuserdata(L, server->lua); + lua_pushlightuserdata(L, keyboard); + if (lua_pcall(L, 2, 1, 0)) { + wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); + lua_pop(L, 1); + return false; + } + 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); + return false; + } + + bool handled = lua_toboolean(L, -1); + lua_pop(L, 1); + return handled; +} + 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; + const xkb_keysym_t *raw_syms = event->raw_syms; + int raw_syms_len = event->raw_syms_len; - char keysym_name[64]; + const xkb_keysym_t *translated_syms = event->translated_syms; + int translated_syms_len = event->translated_syms_len; - for (int i = 0; i < nsyms; ++i) { - xkb_keysym_t sym = syms[i]; + uint32_t keycode = event->keycode; - size_t namelen = - xkb_keysym_get_name(sym, keysym_name, sizeof(keysym_name)); + bool handled = false; - namelen = namelen > sizeof(keysym_name) ? sizeof(keysym_name) : namelen; - - 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, server->lua); - lua_pushlightuserdata(L, keyboard); - if (lua_pcall(L, 2, 1, 0)) { - wlr_log(WLR_ERROR, "%s", lua_tostring(L, -1)); - lua_pop(L, 1); - return; - } - 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); - return; - } - - event->handled |= lua_toboolean(L, -1); - lua_pop(L, 1); + for (int i = 0; i < translated_syms_len; ++i) { + xkb_keysym_t sym = translated_syms[i]; + handled |= send_key_event(lc, sym, keycode, keyboard, false); } + + if (!handled) { + for (int i = 0; i < raw_syms_len; ++i) { + xkb_keysym_t sym = raw_syms[i]; + handled |= send_key_event(lc, sym, keycode, keyboard, true); + } + } + + event->handled = handled; } static int diff --git a/lua_docs.md b/lua_docs.md index 222499d..5727823 100644 --- a/lua_docs.md +++ b/lua_docs.md @@ -139,7 +139,10 @@ Callback receives the keyboard. #### key_down A key got pressed. -Callback receives a table containing the `key` and the `keyboard`). + +Callback receives a table containing the `key`, `keycode`, `raw`, and the `keyboard`. + +This event gets triggered twice, once with mods applied (i.e. `Shift+3` is `#`) and `raw` set to `false`, and then again with no mods applied and `raw` set to `true`. The callback is supposed to return `true` if the event was handled. The compositor will not forward it to the focused view in that case. @@ -147,7 +150,9 @@ The compositor will not forward it to the focused view in that case. #### key_up A key got released. -Callback receives a table containing the `key` and the `keyboard`). +Callback receives a table containing the `key`, `keycode`, `raw`, and the `keyboard`. + +This event gets triggered twice, once with mods applied (i.e. `Shift+3` is `#`) and `raw` set to `false`, and then again with no mods applied and `raw` set to `true`. The callback is supposed to return `true` if the event was handled. The compositor will not forward it to the focused view in that case.