#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "virtual-keyboard-unstable-v1-client-protocol.h"
#include "../error.h"
#include "keyboard.h"
static void handle_wl_event(void *data, struct wl_registry *registry,
uint32_t name, const char *interface,
uint32_t version);
static void handle_wl_event_remove(void *data, struct wl_registry *registry,
uint32_t name);
const struct wl_registry_listener registry_listener = {
.global = handle_wl_event,
.global_remove = handle_wl_event_remove,
};
struct qmk_unicode_type init_qmk_unicode() {
struct qmk_unicode_type qmk_unicode_type;
memset(&qmk_unicode_type, 0, sizeof(qmk_unicode_type));
qmk_unicode_type.display = wl_display_connect(NULL);
if (qmk_unicode_type.display == NULL) {
fail("Wayland connection failed");
}
qmk_unicode_type.registry = wl_display_get_registry(qmk_unicode_type.display);
wl_registry_add_listener(qmk_unicode_type.registry, ®istry_listener,
&qmk_unicode_type);
wl_display_dispatch(qmk_unicode_type.display);
wl_display_roundtrip(qmk_unicode_type.display);
if (qmk_unicode_type.manager == NULL) {
fail("Compositor does not support the virtual keyboard protocol");
}
if (qmk_unicode_type.seat == NULL) {
fail("No seat found");
}
qmk_unicode_type.keyboard =
zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(
qmk_unicode_type.manager, qmk_unicode_type.seat);
return qmk_unicode_type;
}
void destroy_qmk_unicode(struct qmk_unicode_type qmk_unicode_type) {
zwp_virtual_keyboard_v1_destroy(qmk_unicode_type.keyboard);
zwp_virtual_keyboard_manager_v1_destroy(qmk_unicode_type.manager);
wl_registry_destroy(qmk_unicode_type.registry);
wl_display_disconnect(qmk_unicode_type.display);
}
static void upload_keymap(struct qmk_unicode_type *qmk_unicode_type,
uint32_t key_code);
void type_keycode(struct qmk_unicode_type *qmk_unicode_type,
uint32_t key_code) {
upload_keymap(qmk_unicode_type, key_code);
zwp_virtual_keyboard_v1_key(qmk_unicode_type->keyboard, 0, 1,
WL_KEYBOARD_KEY_STATE_PRESSED);
wl_display_roundtrip(qmk_unicode_type->display);
usleep(2000);
zwp_virtual_keyboard_v1_key(qmk_unicode_type->keyboard, 0, 1,
WL_KEYBOARD_KEY_STATE_RELEASED);
wl_display_roundtrip(qmk_unicode_type->display);
usleep(2000);
}
static void handle_wl_event(void *data, struct wl_registry *registry,
uint32_t name, const char *interface,
uint32_t version) {
struct qmk_unicode_type *qmk_unicode_type = (struct qmk_unicode_type *)data;
if (!strcmp(interface, wl_seat_interface.name)) {
qmk_unicode_type->seat = (struct wl_seat *)wl_registry_bind(
registry, name, &wl_seat_interface, version <= 7 ? version : 7);
} else if (!strcmp(interface,
zwp_virtual_keyboard_manager_v1_interface.name)) {
qmk_unicode_type->manager =
(struct zwp_virtual_keyboard_manager_v1 *)wl_registry_bind(
registry, name, &zwp_virtual_keyboard_manager_v1_interface, 1);
}
}
static void
handle_wl_event_remove(__attribute__((unused)) void *data,
__attribute__((unused)) struct wl_registry *_registry,
__attribute__((unused)) uint32_t _name) {}
static void upload_keymap(struct qmk_unicode_type *qmk_unicode_type,
uint32_t key_code) {
char filename[] = "/tmp/qmk_unicode_type-XXXXXX";
int fd = mkstemp(filename);
if (fd < 0) {
fail("Failed to create the temporary keymap file");
}
unlink(filename);
FILE *f = fdopen(fd, "w");
fprintf(f,
"xkb_keymap {\n"
" xkb_keycodes \"(unnamed)\" {\n"
" minimum = 8;\n"
" maximum = 10;\n"
" <K1> = 9;\n"
" };\n"
// TODO: Is including "complete" here really a good idea?
" xkb_types \"(unnamed)\" { include \"complete\" };\n"
" xkb_compatibility \"(unnamed)\" { include \"complete\" };\n"
" xkb_symbols \"(unnamed)\" {\n"
" key <K1> {[U%X]};\n"
" };\n"
"};\n",
key_code);
fputc('\0', f);
fflush(f);
uint32_t keymap_size = (uint32_t)ftell(f);
zwp_virtual_keyboard_v1_keymap(qmk_unicode_type->keyboard,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fileno(f),
keymap_size);
wl_display_roundtrip(qmk_unicode_type->display);
fclose(f);
}