summary refs log blame commit diff stats
path: root/rust/qmk-hid-com/src_c/src/keyboard/keyboard.c
blob: 4949085740cf9c53fff624a5407ed0834e0c4aad (plain) (tree)





































































































































                                                                                
#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);
}