summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--flake.nix12
-rw-r--r--package.nix2
-rw-r--r--rust/format/output6
-rw-r--r--rust/format/output26
-rw-r--r--rust/qmk-hid-com/.gitignore3
-rw-r--r--rust/qmk-hid-com/Cargo.lock357
-rw-r--r--rust/qmk-hid-com/Cargo.toml26
-rw-r--r--rust/qmk-hid-com/contrib/lib/udev/rules.d/099-allow-hid.rules1
-rw-r--r--rust/qmk-hid-com/package.nix25
-rw-r--r--rust/qmk-hid-com/src/cli.rs40
-rw-r--r--rust/qmk-hid-com/src/hid/mod.rs44
-rw-r--r--rust/qmk-hid-com/src/main.rs107
-rw-r--r--rust/qmk-hid-com/src/search.rs51
-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
-rw-r--r--src/keymaps/soispha/config.h3
-rw-r--r--src/keymaps/soispha/hid/hid.c47
-rw-r--r--src/keymaps/soispha/hid/hid.h9
-rw-r--r--src/keymaps/soispha/keymap.c9
-rw-r--r--src/keymaps/soispha/layout/keymap.h2
-rw-r--r--src/keymaps/soispha/layout/layout.h1
-rw-r--r--src/keymaps/soispha/macros.h2
-rw-r--r--src/keymaps/soispha/rules.mk8
33 files changed, 1531 insertions, 18 deletions
diff --git a/flake.nix b/flake.nix
index 33ff880..4e472d3 100644
--- a/flake.nix
+++ b/flake.nix
@@ -54,6 +54,18 @@
formatter = treefmtEval.config.build.wrapper;
devShells.default = pkgs.mkShell {
+ nativeBuildInputs = [
+ pkgs.pkg-config
+
+ pkgs.wayland-scanner
+ pkgs.meson
+ pkgs.ninja
+ ];
+ buildInputs = [
+ pkgs.libudev-zero
+ pkgs.kdePackages.wayland.dev
+ pkgs.hidapi
+ ];
packages = with pkgs; [
format_layer
diff --git a/package.nix b/package.nix
index b5607a5..7db364e 100644
--- a/package.nix
+++ b/package.nix
@@ -30,7 +30,7 @@
'';
# NOTE: Change this _EVERY_ time you actually use a new keymap. <2024-12-29>
- version = "25";
+ version = "26";
in
stdenv.mkDerivation
{
diff --git a/rust/format/output b/rust/format/output
deleted file mode 100644
index 95f3cdd..0000000
--- a/rust/format/output
+++ /dev/null
@@ -1,6 +0,0 @@
-KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, RV_SPAWN_NHEKO, RV_SPAWN_NEORG_FIREFOX, RV_SPAWN_KEEPASSXC, RV_SPAWN_SIGNAL, KK_TP, KK_TP,
-KK_TP, RV_SCREEN_SHOT, RV_PAUSE, RV_TOGGLE_MUSIC, RV_RUN, KK_TP, KK_TP, KK_TP, RV_TOGGLE_FLOAT, RV_TOGGLE_FULLSCREEN, RV_ZOOM_VIEW, KK_TP, RV_EXIT, KK_TP,
-KK_TP, KK_TP, KK_TP, RV_MOVE_VIEW_PREVIOUS_TAG, RV_MOVE_PREVIOUS_TAG, RV_MOVE_OUTPUT_NEXT, KK_TP, KK_TP, RV_VIEW_CLOSE, RV_VIEW_NEXT, RV_SWAP_NEXT, RV_SWAP_PREV, RV_VIEW_PREV, KK_TP,
-KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, RV_SEND_OUTPUT, KK_TP, KK_TP, KK_TP, KK_TP,
-KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP,
-KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP
diff --git a/rust/format/output2 b/rust/format/output2
deleted file mode 100644
index edc3a82..0000000
--- a/rust/format/output2
+++ /dev/null
@@ -1,6 +0,0 @@
-KC_EQL, KC_1, KC_2, KC_3, KC_4, KC_5, KC_LEFT, KC_RGHT, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,
-KC_DEL, KC_Q, KC_W, KC_E, KC_R, KC_T, TG(SYMB), TG(SYMB), KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLS,
-KC_BSPC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_HYPR, KC_MEH, KC_H, KC_J, KC_K, KC_L, LT(MDIA,KC_SCLN), LGUI_T(KC_QUOT),
-KC_LSFT, LCTL_T(KC_Z), KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, RCTL_T(KC_SLSH), KC_RSFT,
-LT(SYMB,KC_GRV), WEBUSB_PAIR, A(KC_LSFT), KC_LEFT, KC_RGHT, LALT_T(KC_APP), RCTL_T(KC_ESC), KC_UP, KC_DOWN, KC_LBRC, KC_RBRC, MO(SYMB),
-KC_SPC, KC_BSPC, KC_LGUI, KC_LALT, KC_TAB, KC_ENT
diff --git a/rust/qmk-hid-com/.gitignore b/rust/qmk-hid-com/.gitignore
new file mode 100644
index 0000000..ed14267
--- /dev/null
+++ b/rust/qmk-hid-com/.gitignore
@@ -0,0 +1,3 @@
+# build
+/target
+/result
diff --git a/rust/qmk-hid-com/Cargo.lock b/rust/qmk-hid-com/Cargo.lock
new file mode 100644
index 0000000..e763b63
--- /dev/null
+++ b/rust/qmk-hid-com/Cargo.lock
@@ -0,0 +1,357 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "anstream"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
+
+[[package]]
+name = "cc"
+version = "1.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d6dbb628b8f8555f86d0323c2eb39e3ec81901f4b83e091db8a6a76d316a333"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "hidapi"
+version = "2.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "libc",
+ "pkg-config",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+
+[[package]]
+name = "libc"
+version = "0.2.169"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "qmk-hid-com"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "clap",
+ "hidapi",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/rust/qmk-hid-com/Cargo.toml b/rust/qmk-hid-com/Cargo.toml
new file mode 100644
index 0000000..20cc11f
--- /dev/null
+++ b/rust/qmk-hid-com/Cargo.toml
@@ -0,0 +1,26 @@
+# Qmk Hid Com - A small middelware between a qmk keyboard and a wayland virtual
+# keyboard. For unicode input
+#
+# Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Qmk Hid Com.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+[package]
+name = "qmk-hid-com"
+description = "A small middelware between a qmk keyboard and a wayland virtual keyboard. For unicode input"
+version = "0.1.0"
+edition = "2021"
+license = "AGPL-3.0-or-later"
+homepage = ""
+repository = "https://git.foss-syndicate.org/bpeetz/tools/qmk-hid-com"
+
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[dependencies]
+anyhow = "1.0.95"
+clap = { version = "4.5.23", features = ["derive"] }
+hidapi = "2.6.3"
diff --git a/rust/qmk-hid-com/contrib/lib/udev/rules.d/099-allow-hid.rules b/rust/qmk-hid-com/contrib/lib/udev/rules.d/099-allow-hid.rules
new file mode 100644
index 0000000..c4fc74b
--- /dev/null
+++ b/rust/qmk-hid-com/contrib/lib/udev/rules.d/099-allow-hid.rules
@@ -0,0 +1 @@
+KERNEL=="hidraw4", SUBSYSTEM=="hidraw", ATTRS{idProduct}=="1969", ATTRS{idVendor}=="3297", TAG+="uaccess"
diff --git a/rust/qmk-hid-com/package.nix b/rust/qmk-hid-com/package.nix
new file mode 100644
index 0000000..157e92e
--- /dev/null
+++ b/rust/qmk-hid-com/package.nix
@@ -0,0 +1,25 @@
+{
+ rustPlatform,
+ lib,
+}:
+rustPlatform.buildRustPackage {
+ pname = "qmk-hid-com";
+ version = "1.0.0";
+
+ src = lib.cleanSourceWith {
+ src = lib.cleanSource ./.;
+ filter = name: type:
+ (type == "directory")
+ || (builtins.elem (builtins.baseNameOf name) [
+ "Cargo.toml"
+ "Cargo.lock"
+ ])
+ || (lib.strings.hasSuffix ".rs" (builtins.baseNameOf name));
+ };
+
+ doCheck = true;
+
+ cargoLock = {
+ lockFile = ./Cargo.lock;
+ };
+}
diff --git a/rust/qmk-hid-com/src/cli.rs b/rust/qmk-hid-com/src/cli.rs
new file mode 100644
index 0000000..afef1a9
--- /dev/null
+++ b/rust/qmk-hid-com/src/cli.rs
@@ -0,0 +1,40 @@
+use clap::{command, Parser, Subcommand};
+
+#[derive(Parser, Debug)]
+pub struct CliArgs {
+ #[clap(subcommand)]
+ pub command: Command,
+}
+#[derive(Clone, Debug, Subcommand)]
+pub enum Command {
+ /// List all devices, where the manufacturer string contains the search key
+ Search {
+ /// The part that must be contained in the manufacturer name
+ vendor_name: String,
+ },
+
+ /// Talk to the device specified by the [`vendor_id`] and [`product_id`].
+ Send {
+ usage_page: u16,
+ usage_id: u16,
+ message: u8,
+ },
+
+ /// Talk to the device specified by the [`vendor_id`] and [`product_id`].
+ Monitor { usage_page: u16, usage_id: u16 },
+
+ Inform {
+ #[command(subcommand)]
+ command: Inform,
+ },
+
+ ArrInform { values: Vec<u8> },
+}
+
+#[derive(Subcommand, Clone, Debug)]
+pub enum Inform {
+ Hex { val: String },
+ Dec { val: i64 },
+ Bin { val: String },
+ Char { val: char },
+}
diff --git a/rust/qmk-hid-com/src/hid/mod.rs b/rust/qmk-hid-com/src/hid/mod.rs
new file mode 100644
index 0000000..b80c835
--- /dev/null
+++ b/rust/qmk-hid-com/src/hid/mod.rs
@@ -0,0 +1,44 @@
+use hidapi::{HidApi, HidDevice};
+
+fn find_device(api: &HidApi, usage_id: u16, usage_page: u16) -> anyhow::Result<HidDevice> {
+ Ok({
+ let devs = api
+ .device_list()
+ .filter(|dev| dev.usage() == usage_id && dev.usage_page() == usage_page)
+ .collect::<Vec<_>>();
+
+ assert_eq!(
+ devs.len(),
+ 1,
+ "Only one device should have such a usage:usage_page value"
+ );
+
+ api.open(devs[0].vendor_id(), devs[0].product_id())?
+ })
+}
+
+pub fn monitor(api: &HidApi, usage_id: u16, usage_page: u16) -> anyhow::Result<()> {
+ let device = find_device(api, usage_id, usage_page)?;
+
+ loop {
+ // Read data from device
+ let mut buf = [0u8; 4];
+ let res = device.read(&mut buf[..]).unwrap();
+
+ let value = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]);
+
+ println!("Read: {:?} ({} bytes) -> {value:x}", &buf[..res], res);
+ }
+}
+pub fn send(api: &HidApi, usage_id: u16, usage_page: u16, message: u8) -> anyhow::Result<()> {
+ let device = find_device(api, usage_id, usage_page)?;
+
+ // Write data to device
+ let mut buf = [0u8; 33];
+ buf[1] = message;
+
+ let res = device.write(&buf)?;
+ println!("Wrote: {:#?} byte(s)", res);
+
+ Ok(())
+}
diff --git a/rust/qmk-hid-com/src/main.rs b/rust/qmk-hid-com/src/main.rs
new file mode 100644
index 0000000..ebaa91b
--- /dev/null
+++ b/rust/qmk-hid-com/src/main.rs
@@ -0,0 +1,107 @@
+// Qmk Hid Com - A small middelware between a qmk keyboard and a wayland virtual
+// keyboard. For unicode input
+//
+// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+// SPDX-License-Identifier: AGPL-3.0-or-later
+//
+// This file is part of Qmk Hid Com.
+//
+// You should have received a copy of the License along with this program.
+// If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+use clap::Parser;
+use cli::{CliArgs, Command, Inform};
+
+mod cli;
+mod hid;
+mod search;
+
+fn main() -> anyhow::Result<()> {
+ let args = CliArgs::parse();
+ let api = hidapi::HidApi::new().unwrap();
+
+ match args.command {
+ Command::Search { vendor_name } => search::search(&api, vendor_name),
+ Command::Monitor {
+ usage_id,
+ usage_page,
+ } => hid::monitor(&api, usage_id, usage_page),
+ Command::Send {
+ usage_id,
+ usage_page,
+ message,
+ } => hid::send(&api, usage_id, usage_page, message),
+
+ Command::Inform { command } => {
+ let (decimal, _) = match command {
+ Inform::Hex { val } => (i64::from_str_radix(&val.to_lowercase(), 16)?, val),
+ Inform::Dec { val } => (val, val.to_string()),
+ Inform::Bin { val } => (i64::from_str_radix(&val.to_lowercase(), 2)?, val),
+ Inform::Char { val } => ((val as u32) as i64, val.to_string()),
+ };
+
+ let character = char::from_u32(decimal as u32).unwrap();
+
+ let binary = {
+ decimal
+ .to_ne_bytes()
+ .map(|sm| format!("{:<08b}", sm))
+ .join(" ")
+ };
+
+ let split = {
+ let first;
+ let second;
+ let third;
+ let fourth;
+
+ if cfg!(target_endian = "big") {
+ let decimal: u32 = decimal as u32;
+ let decimal = decimal.to_be();
+
+ dbg!(decimal
+ .to_be_bytes()
+ .map(|sm| format!("{:<08b}", sm))
+ .join(" "));
+
+ fourth = decimal as u8;
+ third = (decimal >> 8) as u8;
+ second = (decimal >> 16) as u8;
+ first = (decimal >> 24) as u8;
+ } else {
+ first = decimal as u8;
+ second = (decimal >> 8) as u8;
+ third = (decimal >> 16) as u8;
+ fourth = (decimal >> 24) as u8;
+ }
+ [first, second, third, fourth]
+ };
+
+ println!(
+ "dec: {}, hex: {:x}, char: {:#?}, bin: {}, split: {:?}/[{}] ({})",
+ decimal,
+ decimal,
+ character,
+ binary,
+ split,
+ split
+ .iter()
+ .map(|val| format!("{:x}", val))
+ .collect::<Vec<_>>()
+ .join(", "),
+ i32::from_ne_bytes(split)
+ );
+ Ok(())
+ }
+ Command::ArrInform { values } => {
+ assert_eq!(values.len(), 4);
+ let arr = [values[0], values[1], values[2], values[3]];
+
+ let output = u32::from_le_bytes(arr);
+
+ println!("{:?} -> {output}", arr);
+
+ Ok(())
+ }
+ }
+}
diff --git a/rust/qmk-hid-com/src/search.rs b/rust/qmk-hid-com/src/search.rs
new file mode 100644
index 0000000..3c954ba
--- /dev/null
+++ b/rust/qmk-hid-com/src/search.rs
@@ -0,0 +1,51 @@
+use hidapi::HidApi;
+
+pub fn search(api: &HidApi, vendor_name: String) -> anyhow::Result<()> {
+ for device in api.device_list() {
+ if let Some(string) = device.manufacturer_string() {
+ if string.to_lowercase().contains(&vendor_name.to_lowercase()) {
+ println!(
+ "Device matches: {} (VID) - {} (PID) {}:{} - at {} by {} via {:#?}",
+ device.vendor_id(),
+ device.product_id(),
+ device.usage_page(),
+ device.usage(),
+ device.path().to_str()?,
+ string,
+ device.bus_type(),
+ );
+
+ println!(
+ " {} (Interface {}):",
+ match device.product_string() {
+ Some(s) => s,
+ _ => "<COULD NOT FETCH>",
+ },
+ device.interface_number()
+ );
+ let mut descriptor = vec![0u8; 2048];
+ match device
+ .open_device(api)
+ .and_then(|dev| dev.get_report_descriptor(&mut descriptor))
+ {
+ Ok(length) => {
+ println!(" {} (descriptor)", {
+ &descriptor[..length]
+ .iter()
+ .map(|val| val.to_string())
+ .collect::<String>()
+ })
+ }
+ Err(err) => println!(" Failed to retrieve descriptor ({:?})", err),
+ }
+ println!();
+ }
+ } else {
+ eprintln!(
+ "Device without manufacturer string ({})",
+ device.product_id()
+ );
+ }
+ }
+ Ok(())
+}
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);
+}
diff --git a/src/keymaps/soispha/config.h b/src/keymaps/soispha/config.h
index 2b1d36a..9cc7cc5 100644
--- a/src/keymaps/soispha/config.h
+++ b/src/keymaps/soispha/config.h
@@ -23,7 +23,8 @@
#define USB_SUSPEND_WAKEUP_DELAY 0
#define LAYER_STATE_16BIT
-#define UNICODE_SELECTED_MODES UNICODE_MODE_LINUX
+#define RAW_USAGE_PAGE 0xFF61 // 65377
+#define RAW_USAGE_ID 0x6A // 106
#define MOUSEKEY_DELAY 0
#define MOUSEKEY_INTERVAL 20
diff --git a/src/keymaps/soispha/hid/hid.c b/src/keymaps/soispha/hid/hid.c
new file mode 100644
index 0000000..73b7370
--- /dev/null
+++ b/src/keymaps/soispha/hid/hid.c
@@ -0,0 +1,47 @@
+#include "hid.h"
+#include "raw_hid.h"
+#include <stdint.h>
+#include <string.h>
+
+void hid_send(uint32_t hex) {
+ uint8_t length = 32;
+
+ uint8_t response[length];
+ memset(response, 0, length);
+
+ uint8_t first, second, third, fourth;
+
+ uint8_t n = 1;
+ if (*(char *)&n == 1) {
+ // Little endian
+ first = (uint8_t)hex;
+ second = (uint8_t)(hex >> 8);
+ third = (uint8_t)(hex >> 16);
+ fourth = (uint8_t)(hex >> 24);
+ } else {
+ // Big endian
+ fourth = (uint8_t)hex;
+ third = (uint8_t)(hex << 8);
+ second = (uint8_t)(hex << 16);
+ first = (uint8_t)(hex << 24);
+ }
+
+ response[0] = first;
+ response[1] = second;
+ response[2] = third;
+ response[3] = fourth;
+
+ raw_hid_send(response, length);
+}
+
+// `data` is a pointer to the buffer containing the received HID report
+// `length` is the length of the report - always `RAW_EPSIZE`
+void raw_hid_receive(uint8_t *data, uint8_t length) {
+ uint8_t response[length];
+ memset(response, 0, length);
+ response[0] = 'B';
+
+ if (data[0] == 'A') {
+ raw_hid_send(response, length);
+ }
+}
diff --git a/src/keymaps/soispha/hid/hid.h b/src/keymaps/soispha/hid/hid.h
new file mode 100644
index 0000000..6ee0eda
--- /dev/null
+++ b/src/keymaps/soispha/hid/hid.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <stdint.h>
+
+#define UK(c) (UK_UNICODE | (c))
+
+
+
+void hid_send(uint32_t hex);
diff --git a/src/keymaps/soispha/keymap.c b/src/keymaps/soispha/keymap.c
index 9391212..2b6c16f 100644
--- a/src/keymaps/soispha/keymap.c
+++ b/src/keymaps/soispha/keymap.c
@@ -13,6 +13,9 @@
#include "layout/layout.h"
#include "macros.h"
#include "version.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include "hid/hid.h"
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
@@ -21,6 +24,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
SEND_STRING(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION
" (rev: " QMK_GIT_HASH ")");
}
+ return false;
break;
case ST_MACRO_0:
if (record->event.pressed) {
@@ -77,6 +81,11 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
return false;
}
+
+ if (keycode >= UK_UNICODE && keycode <= UK_UNICODE_MAX) {
+ hid_send(QK_UNICODE_GET_CODE_POINT(keycode));
+ }
+
return true;
}
diff --git a/src/keymaps/soispha/layout/keymap.h b/src/keymaps/soispha/layout/keymap.h
index d4b183a..f61ac0f 100644
--- a/src/keymaps/soispha/layout/keymap.h
+++ b/src/keymaps/soispha/layout/keymap.h
@@ -83,7 +83,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[9] = LAYOUT_moonlander( // Special characters
KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP,
KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP,
- KK_TP, UC(0x201C), KK_TP, KK_TP, UC(0x201D), KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP,
+ KK_TP, UK(0x201C), KK_TP, KK_TP, UK(0x201D), KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP,
KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP,
KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP,
KK_TP, KK_TP, KK_TP, KK_TP, KK_TP, KK_TP
diff --git a/src/keymaps/soispha/layout/layout.h b/src/keymaps/soispha/layout/layout.h
index 4acb7f5..6b0c709 100644
--- a/src/keymaps/soispha/layout/layout.h
+++ b/src/keymaps/soispha/layout/layout.h
@@ -13,6 +13,7 @@
#pragma once
#include QMK_KEYBOARD_H
#include "../macros.h"
+#include "../hid/hid.h"
#define KK_TP KC_TRANSPARENT
diff --git a/src/keymaps/soispha/macros.h b/src/keymaps/soispha/macros.h
index e337830..ff03175 100644
--- a/src/keymaps/soispha/macros.h
+++ b/src/keymaps/soispha/macros.h
@@ -15,6 +15,8 @@ enum custom_keycodes {
ST_MACRO_6,
ST_MACRO_7,
VERSION_NUMBER,
+ UK_UNICODE = 0x8000,
+ UK_UNICODE_MAX = 0xFFFF,
};
enum tap_dance_codes {
diff --git a/src/keymaps/soispha/rules.mk b/src/keymaps/soispha/rules.mk
index c04c2d7..27610b4 100644
--- a/src/keymaps/soispha/rules.mk
+++ b/src/keymaps/soispha/rules.mk
@@ -24,8 +24,10 @@ SEND_STRING_ENABLE = yes
SPACE_CADET_ENABLE = no
SWAP_HANDS_ENABLE = yes
TAP_DANCE_ENABLE = yes
+UNICODE_ENABLE = no
-UNICODE_COMMON = yes
-UNICODE_ENABLE = yes
+RAW_ENABLE = yes
-SRC += rgb.c
+# LTO_ENABLE = yes
+
+SRC += rgb.c hid/hid.c