From fcfa22d8a714ac6c899c2d60b7ee146e2c371288 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Fri, 10 Jul 2020 14:26:27 +0000 Subject: [PATCH] Add keyboards --- include/keyboard.h | 32 ++++++++ meson.build | 3 + src/keyboard.c | 193 +++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 36 +++++++++ 4 files changed, 264 insertions(+) create mode 100644 include/keyboard.h create mode 100644 src/keyboard.c diff --git a/include/keyboard.h b/include/keyboard.h new file mode 100644 index 0000000..b4d4c1a --- /dev/null +++ b/include/keyboard.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +struct xkb_context; +struct xkb_keymap; +struct xkb_state; + +struct keyboard { + struct wl_keyboard* wl_keyboard; + struct wl_list link; + + struct xkb_context* context; + struct xkb_keymap* keymap; + struct xkb_state* state; +}; + +struct keyboard_collection { + struct wl_list keyboards; + void (*on_event)(struct keyboard_collection*, struct keyboard*, + uint32_t key, bool is_pressed); + void* userdata; +}; + +struct keyboard_collection* keyboard_collection_new(void); +void keyboard_collection_destroy(struct keyboard_collection*); + +int keyboard_collection_add_wl_keyboard(struct keyboard_collection* self, + struct wl_keyboard* wl_keyboard); +void keyboard_collection_remove_wl_keyboard(struct keyboard_collection* self, + struct wl_keyboard* wl_keyboard); diff --git a/meson.build b/meson.build index b5d326c..21fdc58 100644 --- a/meson.build +++ b/meson.build @@ -28,6 +28,7 @@ libm = cc.find_library('m', required: false) librt = cc.find_library('rt', required: false) pixman = dependency('pixman-1') +xkbcommon = dependency('xkbcommon') wayland_client = dependency('wayland-client') libvncclient = dependency('libvncclient') @@ -47,6 +48,7 @@ sources = [ 'src/shm.c', 'src/seat.c', 'src/pointer.c', + 'src/keyboard.c', 'src/strlcpy.c', ] @@ -54,6 +56,7 @@ dependencies = [ libm, librt, pixman, + xkbcommon, aml, wayland_client, libvncclient, diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 0000000..14b2c7c --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "keyboard.h" + +struct keyboard* keyboard_new(struct wl_keyboard* wl_keyboard) +{ + struct keyboard* self = calloc(1, sizeof(*self)); + if (!self) + return NULL; + + self->wl_keyboard = wl_keyboard; + self->context = xkb_context_new(0); + + return self; +} + +void keyboard_destroy(struct keyboard* self) +{ + if (self->state) + xkb_state_unref(self->state); + + if (self->keymap) + xkb_keymap_unref(self->keymap); + + xkb_context_unref(self->context); + wl_keyboard_destroy(self->wl_keyboard); + free(self); +} + +struct keyboard_collection* keyboard_collection_new(void) +{ + struct keyboard_collection* self = calloc(1, sizeof(*self)); + if (!self) + return NULL; + + wl_list_init(&self->keyboards); + + return self; +} + +void keyboard_collection_destroy(struct keyboard_collection* self) +{ + struct keyboard* keyboard; + struct keyboard* tmp; + + wl_list_for_each_safe(keyboard, tmp, &self->keyboards, link) { + wl_list_remove(&keyboard->link); + keyboard_destroy(keyboard); + } + + free(self); +} + +struct keyboard* keyboard_collection_find_wl_keyboard( + struct keyboard_collection* self, struct wl_keyboard* wl_keyboard) +{ + struct keyboard* keyboard; + wl_list_for_each(keyboard, &self->keyboards, link) + if (keyboard->wl_keyboard == wl_keyboard) + return keyboard; + + return NULL; +} + +static void keyboard_keymap(void* data, struct wl_keyboard* wl_keyboard, + enum wl_keyboard_keymap_format format, int32_t fd, + uint32_t size) +{ + struct keyboard_collection* self = data; + struct keyboard* keyboard = + keyboard_collection_find_wl_keyboard(self, wl_keyboard); + assert(keyboard); + + // TODO: Ignore keyboard if no proper format is available? + assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); + + char* buffer = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + assert(buffer); + + if (keyboard->state) + xkb_state_unref(keyboard->state); + + if (keyboard->keymap) + xkb_keymap_unref(keyboard->keymap); + + keyboard->keymap = xkb_keymap_new_from_string(keyboard->context, + buffer, XKB_KEYMAP_FORMAT_TEXT_V1, 0); + assert(keyboard->keymap); + + munmap(buffer, size); + + keyboard->state = xkb_state_new(keyboard->keymap); + assert(keyboard->state); +} + +static void keyboard_enter(void* data, struct wl_keyboard* wl_keyboard, + uint32_t serial, struct wl_surface* surface, + struct wl_array* keys) +{ + // TODO +} + +static void keyboard_leave(void* data, struct wl_keyboard* wl_keyboard, + uint32_t serial, struct wl_surface* surface) +{ + // TODO +} + +static enum xkb_key_direction xbk_key_direction_from_wl_keyboard_key_state( + enum wl_keyboard_key_state state) +{ + switch (state) { + case WL_KEYBOARD_KEY_STATE_PRESSED: + return XKB_KEY_DOWN; + case WL_KEYBOARD_KEY_STATE_RELEASED: + return XKB_KEY_UP; + } + + abort(); + return 0; +} + +static void keyboard_key(void* data, struct wl_keyboard* wl_keyboard, + uint32_t serial, uint32_t t, uint32_t key, + enum wl_keyboard_key_state state) +{ + struct keyboard_collection* self = data; + struct keyboard* keyboard = + keyboard_collection_find_wl_keyboard(self, wl_keyboard); + assert(keyboard); + + enum xkb_key_direction dir = + xbk_key_direction_from_wl_keyboard_key_state(state); + xkb_state_update_key(keyboard->state, key + 8, dir); + + self->on_event(self, keyboard, key + 8, + state == WL_KEYBOARD_KEY_STATE_PRESSED); +} + +static void keyboard_modifiers(void* data, struct wl_keyboard* wl_keyboard, + uint32_t serial, uint32_t depressed, uint32_t latched, + uint32_t locked, uint32_t group) +{ + struct keyboard_collection* self = data; + struct keyboard* keyboard = + keyboard_collection_find_wl_keyboard(self, wl_keyboard); + assert(keyboard); + + xkb_state_update_mask(keyboard->state, depressed, latched, locked, 0, 0, + group); +} + +static void keyboard_repeat_info(void* data, struct wl_keyboard* wl_keyboard, + int32_t rate, int32_t delay) +{ + // TODO +} + +static struct wl_keyboard_listener keyboard_listener = { + .keymap = keyboard_keymap, + .enter = keyboard_enter, + .leave = keyboard_leave, + .key = keyboard_key, + .modifiers = keyboard_modifiers, + .repeat_info = keyboard_repeat_info, +}; + +int keyboard_collection_add_wl_keyboard(struct keyboard_collection* self, + struct wl_keyboard* wl_keyboard) +{ + struct keyboard* keyboard = keyboard_new(wl_keyboard); + if (!keyboard) + return -1; + + wl_list_insert(&self->keyboards, &keyboard->link); + wl_keyboard_add_listener(keyboard->wl_keyboard, &keyboard_listener, self); + return 0; +} + +void keyboard_collection_remove_wl_keyboard(struct keyboard_collection* self, + struct wl_keyboard* wl_keyboard) +{ + struct keyboard* keyboard = + keyboard_collection_find_wl_keyboard(self, wl_keyboard); + wl_list_remove(&keyboard->link); + free(keyboard); +} diff --git a/src/main.c b/src/main.c index 8d52ccc..98efcbc 100644 --- a/src/main.c +++ b/src/main.c @@ -11,11 +11,13 @@ #include #include #include +#include #include "xdg-shell.h" #include "shm.h" #include "seat.h" #include "pointer.h" +#include "keyboard.h" struct buffer { int width, height, stride; @@ -41,6 +43,7 @@ static struct wl_shm* wl_shm; static struct xdg_wm_base* xdg_wm_base; static struct wl_list seats; struct pointer_collection* pointers; +struct keyboard_collection* keyboards; static enum wl_shm_format wl_shm_format; static bool have_format = false; @@ -59,6 +62,15 @@ static void on_seat_capability_change(struct seat* seat) } else { // TODO Remove } + + if (seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + // TODO: Make sure this only happens once + struct wl_keyboard* wl_keyboard = + wl_seat_get_keyboard(seat->wl_seat); + keyboard_collection_add_wl_keyboard(keyboards, wl_keyboard); + } else { + // TODO Remove + } } static void registry_add(void* data, struct wl_registry* registry, uint32_t id, @@ -337,6 +349,21 @@ void on_pointer_event(struct pointer_collection* collection, SendPointerEvent(client, x, y, pointer->pressed); } +void on_keyboard_event(struct keyboard_collection* collection, + struct keyboard* keyboard, uint32_t key, bool is_pressed) +{ + rfbClient* client = collection->userdata; + + // TODO handle multiple symbols + xkb_keysym_t symbol = xkb_state_key_get_one_sym(keyboard->state, key); + + char name[256]; + xkb_keysym_get_name(symbol, name, sizeof(name)); + printf("Got %s %d\n", name, is_pressed ? 0 : 1); + + SendKeyEvent(client, symbol, is_pressed); +} + rfbBool rfb_client_alloc_fb(rfbClient* cl) { int stride = cl->width * 4; // TODO? @@ -484,6 +511,12 @@ int main(int argc, char* argv[]) pointers->on_frame = on_pointer_event; + keyboards = keyboard_collection_new(); + if (!keyboards) + goto keyboards_failure; + + keyboards->on_event = on_keyboard_event; + wl_registry = wl_display_get_registry(wl_display); if (!wl_registry) goto registry_failure; @@ -507,6 +540,7 @@ int main(int argc, char* argv[]) goto vnc_failure; pointers->userdata = vnc; + keyboards->userdata = vnc; wl_display_dispatch(wl_display); @@ -528,6 +562,8 @@ vnc_failure: wl_registry_destroy(wl_registry); registry_failure: + keyboard_collection_destroy(keyboards); +keyboards_failure: pointer_collection_destroy(pointers); pointer_failure: event_handler_failure: