#include <stdlib.h>
#include <string.h>
#include <alloca.h>
+#include <sys/mman.h>
#include <wayland-client.h>
+#include <xkbcommon/xkbcommon.h>
#include "libds/log.h"
#include "libds/pointer.h"
+#include "util.h"
#include "backend.h"
#ifdef MIN
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,
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) {
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;
+}