diff --git a/pkgs/default.nix b/pkgs/default.nix index a9a2057..5c6bfd0 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -4,5 +4,6 @@ krunker = pkgs.callPackage ./krunker {}; ida-pro = pkgs.callPackage ./ida-pro {}; cartograph-cf = pkgs.callPackage ./cartograph-cf {}; + keyboard-state = pkgs.callPackage ./keyboard-state {}; }; } diff --git a/pkgs/keyboard-state/default.nix b/pkgs/keyboard-state/default.nix new file mode 100644 index 0000000..db9f213 --- /dev/null +++ b/pkgs/keyboard-state/default.nix @@ -0,0 +1,17 @@ +{ + rustPlatform, + pkg-config, + udev, +}: +rustPlatform.buildRustPackage { + pname = "keyboard-state"; + version = "0.1.0"; + + src = ./source; + cargoLock.lockFile = ./source/Cargo.lock; + + nativeBuildInputs = [pkg-config]; + buildInputs = [udev]; + + meta.mainProgram = "keyboard-state"; +} diff --git a/pkgs/keyboard-state/source/.gitignore b/pkgs/keyboard-state/source/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/pkgs/keyboard-state/source/.gitignore @@ -0,0 +1 @@ +/target diff --git a/pkgs/keyboard-state/source/Cargo.lock b/pkgs/keyboard-state/source/Cargo.lock new file mode 100644 index 0000000..df3b8bb --- /dev/null +++ b/pkgs/keyboard-state/source/Cargo.lock @@ -0,0 +1,185 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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", +] + +[[package]] +name = "keyboard-state" +version = "0.1.0" +dependencies = [ + "anyhow", + "enumflags2", + "hidapi", +] + +[[package]] +name = "libc" +version = "0.2.173" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8cfeafaffdbc32176b64fb251369d52ea9f0a8fbc6f8759edffef7b525d64bb" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[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_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[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_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[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_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/pkgs/keyboard-state/source/Cargo.toml b/pkgs/keyboard-state/source/Cargo.toml new file mode 100644 index 0000000..6d1773a --- /dev/null +++ b/pkgs/keyboard-state/source/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "keyboard-state" +version = "0.1.0" +edition = "2024" + +[dependencies] +anyhow = "1.0.98" +enumflags2 = "0.7.12" +hidapi = "2.6.3" diff --git a/pkgs/keyboard-state/source/src/main.rs b/pkgs/keyboard-state/source/src/main.rs new file mode 100644 index 0000000..76ea034 --- /dev/null +++ b/pkgs/keyboard-state/source/src/main.rs @@ -0,0 +1,95 @@ +use std::thread; +use std::time::Duration; + +use enumflags2::{BitFlag, bitflags}; +use hidapi::{HidApi, HidDevice, HidResult}; + +const VENDOR_ID: u16 = 0x594d; +const PRODUCT_ID: u16 = 0x0075; + +const USAGE_PAGE: u16 = 0xFF60; +const USAGE: u16 = 0x61; + +#[bitflags] +#[repr(u16)] +#[derive(Copy, Clone, Debug, PartialEq)] +enum Layer { + Base = 1 << 0, + Gaming = 1 << 1, + More = 1 << 2, + Extra = 1 << 3, +} + +fn main() -> anyhow::Result<()> { + let mut api = HidApi::new()?; + + let mut device: Option = None; + + loop { + match &device { + Some(d) => { + let mut data = [0u8; 32]; + if d.read(&mut data).is_err() { + eprintln!("Device disconnected. Searching for device..."); + device = None; + } else { + let layers = Layer::from_bits_truncate(u16::from_le_bytes([data[0], data[1]])); + + let short_layers: String = layers + .iter() + .map(|x| match x { + Layer::Base => "B", + Layer::Gaming => "G", + Layer::More => "m", + Layer::Extra => "e", + }) + .collect(); + + let long_layers: String = layers + .iter() + .map(|x| match x { + Layer::Base => "Base", + Layer::Gaming => "Gaming", + Layer::More => "more", + Layer::Extra => "extra", + }) + .flat_map(|elem| [", ", elem]) + .skip(1) + .collect(); + + println!( + r#"{{"text":"{short_layers}", "alt": "none", "tooltip": "{long_layers}", "class": "none"}}"# + ); + } + } + None => { + api.reset_devices()?; + api.add_devices(VENDOR_ID, PRODUCT_ID)?; + println!( + r#"{{"text":"N/A", "alt": "Unknown keyboard state", "tooltip": "none", "class": "none"}}"# + ); + + match api.device_list().find(|device| { + device.vendor_id() == VENDOR_ID + && device.product_id() == PRODUCT_ID + && device.usage_page() == USAGE_PAGE + && device.usage() == USAGE + }) { + Some(d) => match api.open_path(d.path()) { + Ok(d) => { + eprintln!("Device connected"); + device = Some(d) + } + Err(e) => { + eprintln!("Error connecting to device: {e}"); + thread::sleep(Duration::from_secs(2)); + } + }, + None => { + thread::sleep(Duration::from_secs(2)); + } + } + } + } + } +}