summary refs log tree commit diff stats
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);
+}