From a1ba1b07ef75796ccd56d260aa117a516614d4a7 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Mon, 18 Apr 2022 10:33:19 +0900 Subject: [PATCH] backend/wayland: Support ds_keyboard Change-Id: Ifadcdd2649fd8c7d3d912b107c2d531801cb189e --- src/libds/backend/wayland/backend.h | 8 ++ src/libds/backend/wayland/seat.c | 196 ++++++++++++++++++++++++++++++++++++ src/libds/util.h | 3 + src/libds/util/time.c | 9 ++ 4 files changed, 216 insertions(+) diff --git a/src/libds/backend/wayland/backend.h b/src/libds/backend/wayland/backend.h index 12e594a..c35f7d1 100644 --- a/src/libds/backend/wayland/backend.h +++ b/src/libds/backend/wayland/backend.h @@ -5,6 +5,7 @@ #include "libds/interfaces/output.h" #include "libds/interfaces/input_device.h" #include "libds/interfaces/pointer.h" +#include "libds/interfaces/keyboard.h" struct ds_wl_backend_server { @@ -103,6 +104,13 @@ struct ds_wl_pointer struct wl_pointer *wl_pointer; }; +struct ds_wl_keyboard +{ + struct ds_keyboard base; + + struct wl_keyboard *wl_keyboard; +}; + struct ds_wl_backend * wl_backend_from_backend(struct ds_backend *backend); diff --git a/src/libds/backend/wayland/seat.c b/src/libds/backend/wayland/seat.c index c569947..966bf77 100644 --- a/src/libds/backend/wayland/seat.c +++ b/src/libds/backend/wayland/seat.c @@ -3,11 +3,14 @@ #include #include #include +#include #include +#include #include "libds/log.h" #include "libds/pointer.h" +#include "util.h" #include "backend.h" #ifdef MIN @@ -25,6 +28,7 @@ static struct ds_input_device * create_wl_input_device(struct ds_wl_seat *seat, enum ds_input_device_type type); static struct ds_pointer *create_wl_pointer(struct ds_wl_seat *seat); +static struct ds_keyboard *create_wl_keyboard(struct ds_wl_seat *seat); struct ds_wl_seat * create_wl_seat(struct ds_wl_backend *backend, uint32_t id, @@ -151,6 +155,10 @@ seat_update_capabilities(struct ds_wl_seat *seat, enum wl_seat_capability caps) seat->keyboard_dev = create_wl_input_device(seat, DS_INPUT_DEVICE_KEYBOARD); + seat->keyboard_dev->keyboard = create_wl_keyboard(seat); + + wl_signal_emit(&seat->backend->base.events.new_input, + seat->keyboard_dev); } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard_dev != NULL) { @@ -405,3 +413,191 @@ create_wl_pointer(struct ds_wl_seat *seat) return &pointer->base; } + +static const struct ds_keyboard_interface keyboard_iface; + +static struct ds_wl_keyboard * +get_wl_keyboard_from_keyboard(struct ds_keyboard *ds_keyboard) +{ + assert(ds_keyboard->iface == &keyboard_iface); + return (struct ds_wl_keyboard *)ds_keyboard; +} + +static void +keyboard_iface_destroy(struct ds_keyboard *ds_keyboard) +{ + struct ds_wl_keyboard *keyboard; + + keyboard = get_wl_keyboard_from_keyboard(ds_keyboard); + + wl_keyboard_release(keyboard->wl_keyboard); + + free(keyboard); +} + +static const struct ds_keyboard_interface keyboard_iface = { + .destroy = keyboard_iface_destroy, +}; + +static void +keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, + uint32_t format, int fd, uint32_t size) +{ + struct ds_wl_seat *seat = data; + struct xkb_context *context; + struct xkb_keymap *keymap; + char *map_str; + + ds_dbg("wl_keyboard: keymap"); + + if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (map_str == MAP_FAILED) { + ds_log_errno(DS_ERR, "mmap failed"); + goto end; + } + + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + keymap = xkb_keymap_new_from_string(context, map_str, + XKB_KEYMAP_FORMAT_TEXT_V1, 0); + munmap(map_str, size); + + if (!keymap) { + ds_err("Failed to compile keymap"); + goto end; + } + + ds_keyboard_set_keymap(seat->keyboard_dev->keyboard, keymap); + + xkb_keymap_unref(keymap); + xkb_context_unref(context); + } + + // TODO More case? + +end: + close(fd); +} + +static void +keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface, struct wl_array *keys) +{ + struct ds_wl_seat *seat = data; + uint32_t *keycode_ptr; + uint32_t time; + + ds_dbg("wl_keyboard: enter"); + + time = get_current_time_msec(); + + wl_array_for_each(keycode_ptr, keys) { + struct ds_event_keyboard_key event = { + .keycode = *keycode_ptr, + .state = WL_KEYBOARD_KEY_STATE_PRESSED, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(seat->keyboard_dev->keyboard, &event); + } +} + +static void +keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, struct wl_surface *surface) +{ + struct ds_wl_seat *seat = data; + struct ds_keyboard *keyboard = seat->keyboard_dev->keyboard; + uint32_t *pressed; + uint32_t time, keycode; + size_t num_keycodes; + + ds_dbg("wl_keyboard: leave"); + + time = get_current_time_msec(); + + num_keycodes = keyboard->num_keycodes; + pressed = alloca(num_keycodes + 1); + memcpy(pressed, keyboard->keycodes, num_keycodes * sizeof(uint32_t)); + + for (size_t i = 0; i < num_keycodes; i++) { + keycode = pressed[i]; + + struct ds_event_keyboard_key event = { + .keycode = keycode, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(keyboard, &event); + } +} + +static void +keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +{ + struct ds_wl_seat *seat = data; + + ds_dbg("wl_keyboard: key"); + + struct ds_event_keyboard_key event = { + .keycode = key, + .state = state, + .time_msec = time, + .update_state = false, + }; + + ds_keyboard_notify_key(seat->keyboard_dev->keyboard, &event); +} + +static void +keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial_in, uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ + struct ds_wl_seat *seat = data; + + ds_dbg("wl_keyboard: modifiers"); + + ds_keyboard_notify_modifiers(seat->keyboard_dev->keyboard, + mods_depressed, mods_latched, mods_locked, group); +} + +static void +keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, + int32_t rate, int32_t delay) +{ + ds_dbg("wl_keyboard: repeat_info"); + + // This space is intentionally left blank +} + +static const struct wl_keyboard_listener wl_keyboard_listener = { + .keymap = keyboard_handle_keymap, + .enter = keyboard_handle_enter, + .leave = keyboard_handle_leave, + .key = keyboard_handle_key, + .modifiers = keyboard_handle_modifiers, + .repeat_info = keyboard_handle_repeat_info, +}; + +static struct ds_keyboard * +create_wl_keyboard(struct ds_wl_seat *seat) +{ + struct ds_wl_keyboard *keyboard; + + keyboard = calloc(1, sizeof *keyboard); + if (!keyboard) + return NULL; + + ds_keyboard_init(&keyboard->base, &keyboard_iface); + + keyboard->wl_keyboard = wl_seat_get_keyboard(seat->wl_seat); + wl_keyboard_add_listener(keyboard->wl_keyboard, + &wl_keyboard_listener, seat); + + return &keyboard->base; +} diff --git a/src/libds/util.h b/src/libds/util.h index 1c9326a..4603544 100644 --- a/src/libds/util.h +++ b/src/libds/util.h @@ -7,6 +7,9 @@ int64_t timespec_to_msec(const struct timespec *a); +uint32_t +get_current_time_msec(void); + int allocate_shm_file(size_t size); diff --git a/src/libds/util/time.c b/src/libds/util/time.c index afb0e89..2461cb7 100644 --- a/src/libds/util/time.c +++ b/src/libds/util/time.c @@ -8,3 +8,12 @@ timespec_to_msec(const struct timespec *a) { return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; } + +uint32_t +get_current_time_msec(void) +{ + struct timespec now; + + clock_gettime(CLOCK_MONOTONIC, &now); + return timespec_to_msec(&now); +} -- 2.7.4