#include #include #include #include #include #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" " = 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 {[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); }