Add keyboards

qemu-extended-key-event
Andri Yngvason 2020-07-10 14:26:27 +00:00
parent fe17fc2e68
commit fcfa22d8a7
4 changed files with 264 additions and 0 deletions

32
include/keyboard.h 100644
View File

@ -0,0 +1,32 @@
#pragma once
#include <stdbool.h>
#include <wayland-client.h>
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);

View File

@ -28,6 +28,7 @@ libm = cc.find_library('m', required: false)
librt = cc.find_library('rt', required: false) librt = cc.find_library('rt', required: false)
pixman = dependency('pixman-1') pixman = dependency('pixman-1')
xkbcommon = dependency('xkbcommon')
wayland_client = dependency('wayland-client') wayland_client = dependency('wayland-client')
libvncclient = dependency('libvncclient') libvncclient = dependency('libvncclient')
@ -47,6 +48,7 @@ sources = [
'src/shm.c', 'src/shm.c',
'src/seat.c', 'src/seat.c',
'src/pointer.c', 'src/pointer.c',
'src/keyboard.c',
'src/strlcpy.c', 'src/strlcpy.c',
] ]
@ -54,6 +56,7 @@ dependencies = [
libm, libm,
librt, librt,
pixman, pixman,
xkbcommon,
aml, aml,
wayland_client, wayland_client,
libvncclient, libvncclient,

193
src/keyboard.c 100644
View File

@ -0,0 +1,193 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>
#include <sys/mman.h>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#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);
}

View File

@ -11,11 +11,13 @@
#include <aml.h> #include <aml.h>
#include <wayland-client.h> #include <wayland-client.h>
#include <rfb/rfbclient.h> #include <rfb/rfbclient.h>
#include <xkbcommon/xkbcommon.h>
#include "xdg-shell.h" #include "xdg-shell.h"
#include "shm.h" #include "shm.h"
#include "seat.h" #include "seat.h"
#include "pointer.h" #include "pointer.h"
#include "keyboard.h"
struct buffer { struct buffer {
int width, height, stride; int width, height, stride;
@ -41,6 +43,7 @@ static struct wl_shm* wl_shm;
static struct xdg_wm_base* xdg_wm_base; static struct xdg_wm_base* xdg_wm_base;
static struct wl_list seats; static struct wl_list seats;
struct pointer_collection* pointers; struct pointer_collection* pointers;
struct keyboard_collection* keyboards;
static enum wl_shm_format wl_shm_format; static enum wl_shm_format wl_shm_format;
static bool have_format = false; static bool have_format = false;
@ -59,6 +62,15 @@ static void on_seat_capability_change(struct seat* seat)
} else { } else {
// TODO Remove // 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, 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); 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) rfbBool rfb_client_alloc_fb(rfbClient* cl)
{ {
int stride = cl->width * 4; // TODO? int stride = cl->width * 4; // TODO?
@ -484,6 +511,12 @@ int main(int argc, char* argv[])
pointers->on_frame = on_pointer_event; 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); wl_registry = wl_display_get_registry(wl_display);
if (!wl_registry) if (!wl_registry)
goto registry_failure; goto registry_failure;
@ -507,6 +540,7 @@ int main(int argc, char* argv[])
goto vnc_failure; goto vnc_failure;
pointers->userdata = vnc; pointers->userdata = vnc;
keyboards->userdata = vnc;
wl_display_dispatch(wl_display); wl_display_dispatch(wl_display);
@ -528,6 +562,8 @@ vnc_failure:
wl_registry_destroy(wl_registry); wl_registry_destroy(wl_registry);
registry_failure: registry_failure:
keyboard_collection_destroy(keyboards);
keyboards_failure:
pointer_collection_destroy(pointers); pointer_collection_destroy(pointers);
pointer_failure: pointer_failure:
event_handler_failure: event_handler_failure: