summaryrefslogtreecommitdiffstats
path: root/rust/qmk-hid-com/src_c
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-12-30 18:22:41 +0100
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-12-30 18:22:41 +0100
commitba9f12810f7dc4969ac175f6e959d5fe6407747d (patch)
treef4039e46985d56bac471bd8568f96b159a92b2ae /rust/qmk-hid-com/src_c
parentfeat(src): Make usable (diff)
downloadqmk_layout-ba9f12810f7dc4969ac175f6e959d5fe6407747d.zip
feat(treewide): Migrate the Unicode handling to a custom c program, that works via rawhid
Diffstat (limited to 'rust/qmk-hid-com/src_c')
-rwxr-xr-xrust/qmk-hid-com/src_c/build.sh18
-rw-r--r--rust/qmk-hid-com/src_c/meson.build51
-rw-r--r--rust/qmk-hid-com/src_c/protocol/meson.build37
-rw-r--r--rust/qmk-hid-com/src_c/protocol/virtual-keyboard-unstable-v1.xml113
-rw-r--r--rust/qmk-hid-com/src_c/src/error.c20
-rw-r--r--rust/qmk-hid-com/src_c/src/error.h1
-rw-r--r--rust/qmk-hid-com/src_c/src/hid/hid.c83
-rw-r--r--rust/qmk-hid-com/src_c/src/hid/hid.h5
-rw-r--r--rust/qmk-hid-com/src_c/src/keyboard/keyboard.c135
-rw-r--r--rust/qmk-hid-com/src_c/src/keyboard/keyboard.h17
-rw-r--r--rust/qmk-hid-com/src_c/src/keyboard/virtual-keyboard-unstable-v1-client-protocol.h280
-rw-r--r--rust/qmk-hid-com/src_c/src/main.c28
12 files changed, 788 insertions, 0 deletions
diff --git a/rust/qmk-hid-com/src_c/build.sh b/rust/qmk-hid-com/src_c/build.sh
new file mode 100755
index 0000000..de615f8
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/build.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env sh
+
+# Source: https://mesonbuild.com/Builtin-options.html
+# Use gcc's wrappers to support lto
+CC="gcc" AR="gcc-ar" RANLIB="gcc-ranlib" meson setup build_release \
+ -Dbuildtype=release \
+ -Ddebug=false \
+ -Doptimization=3 \
+ -Dstrip=true \
+ -Dwarning_level=everything \
+ -Dwerror=true \
+ -Db_lundef=true \
+ -Db_lto=true \
+ -Db_ndebug=false \
+ -Db_pgo=generate \
+ -Db_staticpic=true \
+ -Db_pie=false \
+ -Dc_std=gnu2x
diff --git a/rust/qmk-hid-com/src_c/meson.build b/rust/qmk-hid-com/src_c/meson.build
new file mode 100644
index 0000000..9e8357f
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/meson.build
@@ -0,0 +1,51 @@
+# This is heavily based on `wtype`
+
+project(
+ 'qmk-unicode-type', 'c',
+ version: '0.1',
+ license: 'GPL-3.0-or-later',
+ default_options : [
+ 'buildtype=release',
+ 'default_library=static'
+ ],
+)
+
+git = find_program('git', native: true, required: false)
+
+if not git.found()
+ add_project_arguments('-DVERSION="@0@"'.format(meson.project_version()), language: 'c')
+else
+ git_commit_hash = run_command([git.full_path(), 'describe', '--always', '--tags'], check: true).stdout().strip()
+ git_branch = run_command([git.full_path(), 'rev-parse', '--abbrev-ref', 'HEAD'], check: true).stdout().strip()
+ version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash, git_branch)
+ add_project_arguments('-DVERSION=@0@'.format(version), language: 'c')
+endif
+cc = meson.get_compiler('c')
+
+
+wayland_client = dependency('wayland-client')
+libhid = dependency('hidapi-hidraw')
+rt = cc.find_library('rt')
+
+
+
+src_files = files(
+ './src/error.c',
+ './src/hid/hid.c',
+ './src/keyboard/keyboard.c',
+ './src/main.c',
+)
+
+subdir('protocol')
+
+executable(
+ meson.project_name(),
+ src_files,
+ dependencies: [
+ client_protos,
+ wayland_client,
+ libhid,
+ rt,
+ ],
+)
+
diff --git a/rust/qmk-hid-com/src_c/protocol/meson.build b/rust/qmk-hid-com/src_c/protocol/meson.build
new file mode 100644
index 0000000..1bfe9e0
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/protocol/meson.build
@@ -0,0 +1,37 @@
+wayland_scanner = find_program('wayland-scanner')
+
+wayland_scanner_code = generator(
+ wayland_scanner,
+ output: '@BASENAME@-protocol.c',
+ arguments: ['private-code', '@INPUT@', '@OUTPUT@'],
+)
+
+wayland_scanner_client = generator(
+ wayland_scanner,
+ output: '@BASENAME@-client-protocol.h',
+ arguments: ['client-header', '@INPUT@', '@OUTPUT@'],
+)
+
+
+client_protocols = [
+ ['virtual-keyboard-unstable-v1.xml'],
+]
+client_protos_src = []
+client_protos_headers = []
+
+
+foreach p : client_protocols
+ xml = join_paths(p)
+ client_protos_src += wayland_scanner_code.process(xml)
+ client_protos_headers += wayland_scanner_client.process(xml)
+endforeach
+lib_client_protos = static_library(
+ 'client_protos',
+ client_protos_src + client_protos_headers,
+ dependencies: [wayland_client]
+)
+
+client_protos = declare_dependency(
+ link_with: lib_client_protos,
+ sources: client_protos_headers,
+)
diff --git a/rust/qmk-hid-com/src_c/protocol/virtual-keyboard-unstable-v1.xml b/rust/qmk-hid-com/src_c/protocol/virtual-keyboard-unstable-v1.xml
new file mode 100644
index 0000000..5095c91
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/protocol/virtual-keyboard-unstable-v1.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="virtual_keyboard_unstable_v1">
+ <copyright>
+ Copyright © 2008-2011 Kristian Høgsberg
+ Copyright © 2010-2013 Intel Corporation
+ Copyright © 2012-2013 Collabora, Ltd.
+ Copyright © 2018 Purism SPC
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+
+ <interface name="zwp_virtual_keyboard_v1" version="1">
+ <description summary="virtual keyboard">
+ The virtual keyboard provides an application with requests which emulate
+ the behaviour of a physical keyboard.
+
+ This interface can be used by clients on its own to provide raw input
+ events, or it can accompany the input method protocol.
+ </description>
+
+ <request name="keymap">
+ <description summary="keyboard mapping">
+ Provide a file descriptor to the compositor which can be
+ memory-mapped to provide a keyboard mapping description.
+
+ Format carries a value from the keymap_format enumeration.
+ </description>
+ <arg name="format" type="uint" summary="keymap format"/>
+ <arg name="fd" type="fd" summary="keymap file descriptor"/>
+ <arg name="size" type="uint" summary="keymap size, in bytes"/>
+ </request>
+
+ <enum name="error">
+ <entry name="no_keymap" value="0" summary="No keymap was set"/>
+ </enum>
+
+ <request name="key">
+ <description summary="key event">
+ A key was pressed or released.
+ The time argument is a timestamp with millisecond granularity, with an
+ undefined base. All requests regarding a single object must share the
+ same clock.
+
+ Keymap must be set before issuing this request.
+
+ State carries a value from the key_state enumeration.
+ </description>
+ <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+ <arg name="key" type="uint" summary="key that produced the event"/>
+ <arg name="state" type="uint" summary="physical state of the key"/>
+ </request>
+
+ <request name="modifiers">
+ <description summary="modifier and group state">
+ Notifies the compositor that the modifier and/or group state has
+ changed, and it should update state.
+
+ The client should use wl_keyboard.modifiers event to synchronize its
+ internal state with seat state.
+
+ Keymap must be set before issuing this request.
+ </description>
+ <arg name="mods_depressed" type="uint" summary="depressed modifiers"/>
+ <arg name="mods_latched" type="uint" summary="latched modifiers"/>
+ <arg name="mods_locked" type="uint" summary="locked modifiers"/>
+ <arg name="group" type="uint" summary="keyboard layout"/>
+ </request>
+
+ <request name="destroy" type="destructor" since="1">
+ <description summary="destroy the virtual keyboard keyboard object"/>
+ </request>
+ </interface>
+
+ <interface name="zwp_virtual_keyboard_manager_v1" version="1">
+ <description summary="virtual keyboard manager">
+ A virtual keyboard manager allows an application to provide keyboard
+ input events as if they came from a physical keyboard.
+ </description>
+
+ <enum name="error">
+ <entry name="unauthorized" value="0" summary="client not authorized to use the interface"/>
+ </enum>
+
+ <request name="create_virtual_keyboard">
+ <description summary="Create a new virtual keyboard">
+ Creates a new virtual keyboard associated to a seat.
+
+ If the compositor enables a keyboard to perform arbitrary actions, it
+ should present an error when an untrusted client requests a new
+ keyboard.
+ </description>
+ <arg name="seat" type="object" interface="wl_seat"/>
+ <arg name="id" type="new_id" interface="zwp_virtual_keyboard_v1"/>
+ </request>
+ </interface>
+</protocol>
diff --git a/rust/qmk-hid-com/src_c/src/error.c b/rust/qmk-hid-com/src_c/src/error.c
new file mode 100644
index 0000000..f970cfc
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/src/error.c
@@ -0,0 +1,20 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wayland-client.h>
+
+#include "error.h"
+
+__attribute__((noreturn)) __attribute__((format(printf, 1, 2))) void
+fail(const char *format, ...) {
+ va_list vas;
+
+ va_start(vas, format);
+ fprintf(stderr, "Error: ");
+ vfprintf(stderr, format, vas);
+ va_end(vas);
+
+ fprintf(stderr, "\n");
+
+ exit(EXIT_FAILURE);
+}
diff --git a/rust/qmk-hid-com/src_c/src/error.h b/rust/qmk-hid-com/src_c/src/error.h
new file mode 100644
index 0000000..e0d6aaf
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/src/error.h
@@ -0,0 +1 @@
+void fail(const char *format, ...);
diff --git a/rust/qmk-hid-com/src_c/src/hid/hid.c b/rust/qmk-hid-com/src_c/src/hid/hid.c
new file mode 100644
index 0000000..d468ba8
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/src/hid/hid.c
@@ -0,0 +1,83 @@
+#include <assert.h>
+#include <hidapi/hidapi.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "../error.h"
+#include "hid.h"
+
+static hid_device *find_device_by_usage(uint32_t expected_usage,
+ uint32_t expected_usage_page) {
+ struct hid_device_info *devs;
+ devs = hid_enumerate(0x0, 0x0);
+
+ hid_device *found_device = NULL;
+ bool found = false;
+
+ struct hid_device_info *cur_dev = devs;
+ for (; cur_dev; cur_dev = cur_dev->next) {
+ // printf("Checking device: %ls, %d (%d:%d) at %s ..\n",
+ // cur_dev->product_string, cur_dev->product_id, cur_dev->usage,
+ // cur_dev->usage_page, cur_dev->path);
+
+ if (cur_dev->usage == expected_usage &&
+ cur_dev->usage_page == expected_usage_page) {
+ found_device = hid_open_path(cur_dev->path);
+ found = true;
+
+ goto output;
+ }
+ }
+
+output:
+ hid_free_enumeration(devs);
+ if (!found_device) {
+ if (found) {
+ fail("Failed to open device usage (%d) and usage page (%d): %ls",
+ expected_usage, expected_usage_page, hid_error(found_device));
+ } else {
+ fail("Can't find device with usage (%d) and usage page (%d): %ls",
+ expected_usage, expected_usage_page, hid_error(found_device));
+ }
+ hid_exit();
+
+ return NULL;
+ } else {
+ return found_device;
+ }
+}
+
+uint32_t read_next(uint32_t usage, uint32_t usage_page) {
+ hid_device *handle;
+
+ if (hid_init()) {
+ fail("Failed to init hid");
+ }
+
+ handle = find_device_by_usage(usage, usage_page);
+
+ uint8_t buf[4];
+ int res = 0;
+ res = hid_read(handle, buf, sizeof(buf));
+ if (res < 0) {
+ fail("Failed to read 4 bytes from hid device: %ls", hid_error(handle));
+ } else if (res == 0) {
+ fail("Device did not send anything!");
+ }
+
+ hid_close(handle);
+ if (hid_exit()) {
+ fail("Failed to exit hid");
+ }
+
+ // Buf should only contain positive values.
+ assert(buf[0] >= 0 && buf[1] >= 0 && buf[2] >= 0 && buf[3] >= 0);
+
+ // Only lower Endian supported, TODO add the other one
+ uint32_t key_code =
+ (uint32_t)(buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24));
+
+ return key_code;
+}
diff --git a/rust/qmk-hid-com/src_c/src/hid/hid.h b/rust/qmk-hid-com/src_c/src/hid/hid.h
new file mode 100644
index 0000000..9ffb9d3
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/src/hid/hid.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include <stdint.h>
+
+uint32_t read_next(uint32_t usage, uint32_t usage_page);
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);
+}
diff --git a/rust/qmk-hid-com/src_c/src/keyboard/keyboard.h b/rust/qmk-hid-com/src_c/src/keyboard/keyboard.h
new file mode 100644
index 0000000..ac5d7bd
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/src/keyboard/keyboard.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include <stdint.h>
+
+struct qmk_unicode_type init_qmk_unicode();
+void destroy_qmk_unicode(struct qmk_unicode_type qmk_unicode_type);
+
+void type_keycode(struct qmk_unicode_type *qmk_unicode_type, uint32_t key_code);
+
+// Private
+struct qmk_unicode_type {
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct wl_seat *seat;
+ struct zwp_virtual_keyboard_manager_v1 *manager;
+ struct zwp_virtual_keyboard_v1 *keyboard;
+};
diff --git a/rust/qmk-hid-com/src_c/src/keyboard/virtual-keyboard-unstable-v1-client-protocol.h b/rust/qmk-hid-com/src_c/src/keyboard/virtual-keyboard-unstable-v1-client-protocol.h
new file mode 100644
index 0000000..81cac0b
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/src/keyboard/virtual-keyboard-unstable-v1-client-protocol.h
@@ -0,0 +1,280 @@
+/* Generated by wayland-scanner 1.23.1 */
+
+#ifndef VIRTUAL_KEYBOARD_UNSTABLE_V1_CLIENT_PROTOCOL_H
+#define VIRTUAL_KEYBOARD_UNSTABLE_V1_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_virtual_keyboard_unstable_v1 The virtual_keyboard_unstable_v1 protocol
+ * @section page_ifaces_virtual_keyboard_unstable_v1 Interfaces
+ * - @subpage page_iface_zwp_virtual_keyboard_v1 - virtual keyboard
+ * - @subpage page_iface_zwp_virtual_keyboard_manager_v1 - virtual keyboard manager
+ * @section page_copyright_virtual_keyboard_unstable_v1 Copyright
+ * <pre>
+ *
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2013 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ * Copyright © 2018 Purism SPC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * </pre>
+ */
+struct wl_seat;
+struct zwp_virtual_keyboard_manager_v1;
+struct zwp_virtual_keyboard_v1;
+
+#ifndef ZWP_VIRTUAL_KEYBOARD_V1_INTERFACE
+#define ZWP_VIRTUAL_KEYBOARD_V1_INTERFACE
+/**
+ * @page page_iface_zwp_virtual_keyboard_v1 zwp_virtual_keyboard_v1
+ * @section page_iface_zwp_virtual_keyboard_v1_desc Description
+ *
+ * The virtual keyboard provides an application with requests which emulate
+ * the behaviour of a physical keyboard.
+ *
+ * This interface can be used by clients on its own to provide raw input
+ * events, or it can accompany the input method protocol.
+ * @section page_iface_zwp_virtual_keyboard_v1_api API
+ * See @ref iface_zwp_virtual_keyboard_v1.
+ */
+/**
+ * @defgroup iface_zwp_virtual_keyboard_v1 The zwp_virtual_keyboard_v1 interface
+ *
+ * The virtual keyboard provides an application with requests which emulate
+ * the behaviour of a physical keyboard.
+ *
+ * This interface can be used by clients on its own to provide raw input
+ * events, or it can accompany the input method protocol.
+ */
+extern const struct wl_interface zwp_virtual_keyboard_v1_interface;
+#endif
+#ifndef ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_INTERFACE
+#define ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_INTERFACE
+/**
+ * @page page_iface_zwp_virtual_keyboard_manager_v1 zwp_virtual_keyboard_manager_v1
+ * @section page_iface_zwp_virtual_keyboard_manager_v1_desc Description
+ *
+ * A virtual keyboard manager allows an application to provide keyboard
+ * input events as if they came from a physical keyboard.
+ * @section page_iface_zwp_virtual_keyboard_manager_v1_api API
+ * See @ref iface_zwp_virtual_keyboard_manager_v1.
+ */
+/**
+ * @defgroup iface_zwp_virtual_keyboard_manager_v1 The zwp_virtual_keyboard_manager_v1 interface
+ *
+ * A virtual keyboard manager allows an application to provide keyboard
+ * input events as if they came from a physical keyboard.
+ */
+extern const struct wl_interface zwp_virtual_keyboard_manager_v1_interface;
+#endif
+
+#ifndef ZWP_VIRTUAL_KEYBOARD_V1_ERROR_ENUM
+#define ZWP_VIRTUAL_KEYBOARD_V1_ERROR_ENUM
+enum zwp_virtual_keyboard_v1_error {
+ /**
+ * No keymap was set
+ */
+ ZWP_VIRTUAL_KEYBOARD_V1_ERROR_NO_KEYMAP = 0,
+};
+#endif /* ZWP_VIRTUAL_KEYBOARD_V1_ERROR_ENUM */
+
+#define ZWP_VIRTUAL_KEYBOARD_V1_KEYMAP 0
+#define ZWP_VIRTUAL_KEYBOARD_V1_KEY 1
+#define ZWP_VIRTUAL_KEYBOARD_V1_MODIFIERS 2
+#define ZWP_VIRTUAL_KEYBOARD_V1_DESTROY 3
+
+
+/**
+ * @ingroup iface_zwp_virtual_keyboard_v1
+ */
+#define ZWP_VIRTUAL_KEYBOARD_V1_KEYMAP_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_virtual_keyboard_v1
+ */
+#define ZWP_VIRTUAL_KEYBOARD_V1_KEY_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_virtual_keyboard_v1
+ */
+#define ZWP_VIRTUAL_KEYBOARD_V1_MODIFIERS_SINCE_VERSION 1
+/**
+ * @ingroup iface_zwp_virtual_keyboard_v1
+ */
+#define ZWP_VIRTUAL_KEYBOARD_V1_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_virtual_keyboard_v1 */
+static inline void
+zwp_virtual_keyboard_v1_set_user_data(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_virtual_keyboard_v1, user_data);
+}
+
+/** @ingroup iface_zwp_virtual_keyboard_v1 */
+static inline void *
+zwp_virtual_keyboard_v1_get_user_data(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_virtual_keyboard_v1);
+}
+
+static inline uint32_t
+zwp_virtual_keyboard_v1_get_version(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1);
+}
+
+/**
+ * @ingroup iface_zwp_virtual_keyboard_v1
+ *
+ * Provide a file descriptor to the compositor which can be
+ * memory-mapped to provide a keyboard mapping description.
+ *
+ * Format carries a value from the keymap_format enumeration.
+ */
+static inline void
+zwp_virtual_keyboard_v1_keymap(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t format, int32_t fd, uint32_t size)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_v1,
+ ZWP_VIRTUAL_KEYBOARD_V1_KEYMAP, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1), 0, format, fd, size);
+}
+
+/**
+ * @ingroup iface_zwp_virtual_keyboard_v1
+ *
+ * A key was pressed or released.
+ * The time argument is a timestamp with millisecond granularity, with an
+ * undefined base. All requests regarding a single object must share the
+ * same clock.
+ *
+ * Keymap must be set before issuing this request.
+ *
+ * State carries a value from the key_state enumeration.
+ */
+static inline void
+zwp_virtual_keyboard_v1_key(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t time, uint32_t key, uint32_t state)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_v1,
+ ZWP_VIRTUAL_KEYBOARD_V1_KEY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1), 0, time, key, state);
+}
+
+/**
+ * @ingroup iface_zwp_virtual_keyboard_v1
+ *
+ * Notifies the compositor that the modifier and/or group state has
+ * changed, and it should update state.
+ *
+ * The client should use wl_keyboard.modifiers event to synchronize its
+ * internal state with seat state.
+ *
+ * Keymap must be set before issuing this request.
+ */
+static inline void
+zwp_virtual_keyboard_v1_modifiers(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_v1,
+ ZWP_VIRTUAL_KEYBOARD_V1_MODIFIERS, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1), 0, mods_depressed, mods_latched, mods_locked, group);
+}
+
+/**
+ * @ingroup iface_zwp_virtual_keyboard_v1
+ */
+static inline void
+zwp_virtual_keyboard_v1_destroy(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1)
+{
+ wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_v1,
+ ZWP_VIRTUAL_KEYBOARD_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_v1), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifndef ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_ERROR_ENUM
+#define ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_ERROR_ENUM
+enum zwp_virtual_keyboard_manager_v1_error {
+ /**
+ * client not authorized to use the interface
+ */
+ ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_ERROR_UNAUTHORIZED = 0,
+};
+#endif /* ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_ERROR_ENUM */
+
+#define ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_CREATE_VIRTUAL_KEYBOARD 0
+
+
+/**
+ * @ingroup iface_zwp_virtual_keyboard_manager_v1
+ */
+#define ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_CREATE_VIRTUAL_KEYBOARD_SINCE_VERSION 1
+
+/** @ingroup iface_zwp_virtual_keyboard_manager_v1 */
+static inline void
+zwp_virtual_keyboard_manager_v1_set_user_data(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) zwp_virtual_keyboard_manager_v1, user_data);
+}
+
+/** @ingroup iface_zwp_virtual_keyboard_manager_v1 */
+static inline void *
+zwp_virtual_keyboard_manager_v1_get_user_data(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) zwp_virtual_keyboard_manager_v1);
+}
+
+static inline uint32_t
+zwp_virtual_keyboard_manager_v1_get_version(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1)
+{
+ return wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_manager_v1);
+}
+
+/** @ingroup iface_zwp_virtual_keyboard_manager_v1 */
+static inline void
+zwp_virtual_keyboard_manager_v1_destroy(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1)
+{
+ wl_proxy_destroy((struct wl_proxy *) zwp_virtual_keyboard_manager_v1);
+}
+
+/**
+ * @ingroup iface_zwp_virtual_keyboard_manager_v1
+ *
+ * Creates a new virtual keyboard associated to a seat.
+ *
+ * If the compositor enables a keyboard to perform arbitrary actions, it
+ * should present an error when an untrusted client requests a new
+ * keyboard.
+ */
+static inline struct zwp_virtual_keyboard_v1 *
+zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(struct zwp_virtual_keyboard_manager_v1 *zwp_virtual_keyboard_manager_v1, struct wl_seat *seat)
+{
+ struct wl_proxy *id;
+
+ id = wl_proxy_marshal_flags((struct wl_proxy *) zwp_virtual_keyboard_manager_v1,
+ ZWP_VIRTUAL_KEYBOARD_MANAGER_V1_CREATE_VIRTUAL_KEYBOARD, &zwp_virtual_keyboard_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwp_virtual_keyboard_manager_v1), 0, seat, NULL);
+
+ return (struct zwp_virtual_keyboard_v1 *) id;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/rust/qmk-hid-com/src_c/src/main.c b/rust/qmk-hid-com/src_c/src/main.c
new file mode 100644
index 0000000..48d490e
--- /dev/null
+++ b/rust/qmk-hid-com/src_c/src/main.c
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+
+#include "error.h"
+#include "hid/hid.h"
+#include "keyboard/keyboard.h"
+
+int main(int argc, const char *argv[]) {
+ if (argc != 3) {
+ fail("Usage: %s <usage> <usage_page>", argv[0]);
+ }
+
+ char *ep;
+ uint32_t usage = (uint32_t)strtoul(argv[1], &ep, 0);
+ if (*ep != 0) {
+ fail("Invalid usage: %x", usage);
+ }
+
+ uint32_t usage_page = (uint32_t)strtoul(argv[2], &ep, 0);
+ if (*ep != 0) {
+ fail("Invalid usage: %x", usage_page);
+ }
+
+ uint32_t key_value = read_next(usage, usage_page);
+
+ struct qmk_unicode_type qmk_unicode_type = init_qmk_unicode();
+ type_keycode(&qmk_unicode_type, key_value);
+ destroy_qmk_unicode(qmk_unicode_type);
+}