summaryrefslogtreecommitdiffstats
path: root/rust/qmk-hid-com/src_c/src/keyboard/keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'rust/qmk-hid-com/src_c/src/keyboard/keyboard.c')
-rw-r--r--rust/qmk-hid-com/src_c/src/keyboard/keyboard.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/rust/qmk-hid-com/src_c/src/keyboard/keyboard.c b/rust/qmk-hid-com/src_c/src/keyboard/keyboard.c
new file mode 100644
index 0000000..4949085
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/src/keyboard/keyboard.c
@@ -0,0 +1,135 @@
+#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, &registry_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);
+}