diff --git a/include/client/registry.h b/include/client/registry.h index 5e47b18e1..2ab021747 100644 --- a/include/client/registry.h +++ b/include/client/registry.h @@ -2,16 +2,70 @@ #define _SWAY_CLIENT_REGISTRY_H #include +#include #include "wayland-desktop-shell-client-protocol.h" #include "wayland-swaylock-client-protocol.h" #include "list.h" +enum mod_bit { + MOD_SHIFT = 1<<0, + MOD_CAPS = 1<<1, + MOD_CTRL = 1<<2, + MOD_ALT = 1<<3, + MOD_MOD2 = 1<<4, + MOD_MOD3 = 1<<5, + MOD_LOGO = 1<<6, + MOD_MOD5 = 1<<7, +}; + +enum mask { + MASK_SHIFT, + MASK_CAPS, + MASK_CTRL, + MASK_ALT, + MASK_MOD2, + MASK_MOD3, + MASK_LOGO, + MASK_MOD5, + MASK_LAST +}; + struct output_state { struct wl_output *output; uint32_t flags; uint32_t width, height; }; +struct xkb { + struct xkb_state *state; + struct xkb_context *context; + struct xkb_keymap *keymap; + xkb_mod_mask_t masks[MASK_LAST]; +}; + +struct input { + int *repeat_fd; + + struct xkb xkb; + + xkb_keysym_t sym; + uint32_t code; + uint32_t last_code; + uint32_t modifiers; + + xkb_keysym_t repeat_sym; + uint32_t repeat_key; + + int32_t repeat_rate_sec; + int32_t repeat_rate_nsec; + int32_t repeat_delay_sec; + int32_t repeat_delay_nsec; + + struct { + void (*key)(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t code); + } notify; +}; + struct registry { struct wl_compositor *compositor; struct wl_display *display; @@ -22,6 +76,7 @@ struct registry { struct wl_shm *shm; struct desktop_shell *desktop_shell; struct lock *swaylock; + struct input *input; list_t *outputs; }; diff --git a/wayland/CMakeLists.txt b/wayland/CMakeLists.txt index 8e19fc03f..6519cd7dc 100644 --- a/wayland/CMakeLists.txt +++ b/wayland/CMakeLists.txt @@ -2,6 +2,7 @@ include_directories( ${PROTOCOLS_INCLUDE_DIRS} ${PANGO_INCLUDE_DIRS} ${GDK_PIXBUF_INCLUDE_DIRS} + ${XKBCOMMON_INCLUDE_DIRS} ) add_library(sway-wayland @@ -17,4 +18,5 @@ target_link_libraries(sway-wayland sway-protocols ${PANGO_LIBRARIES} ${GDK_PIXBUF_LIBRARIES} + ${XKBCOMMON_LIBRARIES} ) diff --git a/wayland/registry.c b/wayland/registry.c index 883c69d34..45735ccdf 100644 --- a/wayland/registry.c +++ b/wayland/registry.c @@ -1,6 +1,10 @@ #include +#include #include #include +#include +#include +#include #include "wayland-desktop-shell-client-protocol.h" #include "wayland-swaylock-client-protocol.h" #include "client/registry.h" @@ -38,8 +42,73 @@ static const struct wl_output_listener output_listener = { .scale = display_handle_scale }; +const char *XKB_MASK_NAMES[MASK_LAST] = { + XKB_MOD_NAME_SHIFT, + XKB_MOD_NAME_CAPS, + XKB_MOD_NAME_CTRL, + XKB_MOD_NAME_ALT, + "Mod2", + "Mod3", + XKB_MOD_NAME_LOGO, + "Mod5", +}; + +const enum mod_bit XKB_MODS[MASK_LAST] = { + MOD_SHIFT, + MOD_CAPS, + MOD_CTRL, + MOD_ALT, + MOD_MOD2, + MOD_MOD3, + MOD_LOGO, + MOD_MOD5 +}; + static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { + // Keyboard errors are abort-worthy because you wouldn't be able to unlock your screen otherwise. + + struct registry *registry = data; + if (!data) { + close(fd); + return; + } + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + sway_abort("Unknown keymap format %d, aborting", format); + } + + char *map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + close(fd); + sway_abort("Unable to initialized shared keyboard memory, aborting"); + } + + struct xkb_keymap *keymap = xkb_keymap_new_from_string(registry->input->xkb.context, + map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(map_str, size); + close(fd); + + if (!keymap) { + sway_abort("Failed to compile keymap, aborting"); + } + + struct xkb_state *state = xkb_state_new(keymap); + if (!state) { + xkb_keymap_unref(keymap); + sway_abort("Failed to create xkb state, aborting"); + } + + xkb_keymap_unref(registry->input->xkb.keymap); + xkb_state_unref(registry->input->xkb.state); + registry->input->xkb.keymap = keymap; + registry->input->xkb.state = state; + + int i; + for (i = 0; i < MASK_LAST; ++i) { + registry->input->xkb.masks[i] = 1 << xkb_keymap_mod_get_index(registry->input->xkb.keymap, XKB_MASK_NAMES[i]); + } } static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard, @@ -115,6 +184,8 @@ struct registry *registry_poll(void) { struct registry *registry = malloc(sizeof(struct registry)); memset(registry, 0, sizeof(struct registry)); registry->outputs = create_list(); + registry->input = calloc(sizeof(struct input), 1); + registry->input->xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); registry->display = wl_display_connect(NULL); if (!registry->display) {