From 20906651f6ccbddace23856b7d226590185e7c85 Mon Sep 17 00:00:00 2001 From: Psych3r Date: Sun, 10 Dec 2023 01:52:56 +0200 Subject: [PATCH] feat(macos): add limited macOS support (#652) Some notable bits of missing functionality are: - missing mouse functionality (input and output) - missing unicode functionality --- Cargo.lock | 20 + Cargo.toml | 5 +- README.md | 20 +- docs/config.adoc | 31 +- example_tcp_client/src/main.rs | 4 +- parser/src/cfg/defcfg.rs | 24 +- parser/src/cfg/mod.rs | 4 + parser/src/cfg/tests.rs | 10 +- parser/src/keys/linux.rs | 2 +- parser/src/keys/macos.rs | 2018 ++++++++++++++++++++++++++++++++ parser/src/keys/mod.rs | 15 + src/kanata/macos.rs | 75 ++ src/kanata/mod.rs | 11 +- src/main.rs | 10 + src/oskbd/macos.rs | 228 ++++ src/oskbd/mod.rs | 6 + 16 files changed, 2463 insertions(+), 20 deletions(-) create mode 100644 parser/src/keys/macos.rs create mode 100644 src/kanata/macos.rs create mode 100644 src/oskbd/macos.rs diff --git a/Cargo.lock b/Cargo.lock index bdad7e9e9..39a53ddcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,6 +104,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -363,6 +364,15 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "kanata" version = "1.5.0-prerelease-3" @@ -377,6 +387,7 @@ dependencies = [ "kanata-interception", "kanata-keyberon", "kanata-parser", + "karabiner-driverkit", "log", "miette", "mio", @@ -441,6 +452,15 @@ dependencies = [ "thiserror", ] +[[package]] +name = "karabiner-driverkit" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f1032243b23de4466cf25488e0f6082d9f8f6092e71641a2baefaffbf7b6768" +dependencies = [ + "cc", +] + [[package]] name = "lazy_static" version = "1.4.0" diff --git a/Cargo.toml b/Cargo.toml index ab43ba051..d7840ff45 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,10 @@ is-terminal = "=0.4.7" # Otherwise any changes to the local files will not reflect in the compiled # binary. kanata-keyberon = { path = "keyberon" } -kanata-parser = { path = "parser" } +kanata-parser = { path = "parser" } + +[target.'cfg(target_os = "macos")'.dependencies] +karabiner-driverkit = "0.1.0" [target.'cfg(target_os = "linux")'.dependencies] evdev = "=0.12.0" diff --git a/README.md b/README.md index 5e607153a..567dbba6a 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ ## What does this do? -This is a software keyboard remapper for Linux and Windows. A short summary of +This is a cross-platform software keyboard remapper for Linux, macOS and Windows. A short summary of the features: - multiple layers of key functionality @@ -76,7 +76,7 @@ Using `cargo install`: cargo install kanata - # On Linux, this may not work without `sudo`, see below + # On Linux and macOS, this may not work without `sudo`, see below kanata --cfg Build and run yourself in Linux: @@ -96,6 +96,22 @@ Build and run yourself in Windows. cargo build # --release optional, not really perf sensitive target\debug\kanata --cfg +Build and run yourself in macOS: + +First, install the [Karabiner VirtualHiDDevice Driver](https://github.com/pqrs-org/Karabiner-DriverKit-VirtualHIDDevice/blob/main/dist/Karabiner-DriverKit-VirtualHIDDevice-3.1.0.pkg). + +To activate it: + +`/Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager activate` + + + git clone https://github.com/jtroo/kanata && cd kanata + cargo build # --release optional, not really perf sensitive + + # sudo is needed to gain permission to intercept the keyboard + + sudo target/debug/kanata --cfg + The full configuration guide is [found here](./docs/config.adoc). Sample configuration files are found in [cfg_samples](./cfg_samples). The diff --git a/docs/config.adoc b/docs/config.adoc index 6736ea9f2..c38c5e7ec 100644 --- a/docs/config.adoc +++ b/docs/config.adoc @@ -170,11 +170,12 @@ that are not allowed in `defsrc` by default, at least according to the symbol shown. You can use `deflocalkeys` to define additional key names that can be used in `defsrc`, `deflayer` and anywhere else in the configuration. -There are three variants of deflocalkeys: +There are four variants of deflocalkeys: - `deflocalkeys-win` - `deflocalkeys-wintercept` - `deflocalkeys-linux` +- `deflocalkeys-macos` Only one of each deflocalkeys-* variant is allowed. The variants that are not @@ -201,6 +202,10 @@ Please contribute to the document if you are able! ì 13 ) +(deflocalkeys-macos + ì 13 +) + (defsrc grv 1 2 3 4 5 6 7 8 9 0 - ì bspc ) @@ -637,6 +642,30 @@ This configuration item does not affect Wayland or no-desktop environments. ) ---- +[[macos-only-macos-dev-names-include]] +=== macOS only: macos-dev-names-include +<> + +This option defines a list of device names that should be included. +By default, kanata will try to detect which input devices are keyboards and try +to intercept them all. However, you may specify exact keyboard devices to intercept +using the `macos-dev-names-include` configuration. +Device names that do not exist in the list will be ignored. +This option is parsed identically to `linux-dev`. + +Use `kanata -l` or `kanata --list` to list the available keyboards. + +.Example: +[source] +---- +(defcfg + macos-dev-names-include ( + "Device name 1" + "Device name 2" + ) +) +---- + [[windows-only-windows-altgr]] === Windows only: windows-altgr <> diff --git a/example_tcp_client/src/main.rs b/example_tcp_client/src/main.rs index 0090d24a8..6b98438ec 100644 --- a/example_tcp_client/src/main.rs +++ b/example_tcp_client/src/main.rs @@ -33,9 +33,7 @@ fn main() { ) .expect("connect to kanata"); log::info!("successfully connected"); - let writer_stream = kanata_conn - .try_clone() - .expect("clone writer"); + let writer_stream = kanata_conn.try_clone().expect("clone writer"); let reader_stream = kanata_conn; std::thread::spawn(move || write_to_kanata(writer_stream)); read_from_kanata(reader_stream); diff --git a/parser/src/cfg/defcfg.rs b/parser/src/cfg/defcfg.rs index 24465786c..09a02b3e9 100644 --- a/parser/src/cfg/defcfg.rs +++ b/parser/src/cfg/defcfg.rs @@ -39,6 +39,8 @@ pub struct CfgOptions { target_os = "unknown" ))] pub windows_interception_mouse_hwid: Option<[u8; HWID_ARR_SZ]>, + #[cfg(any(target_os = "macos", target_os = "unknown"))] + pub macos_dev_names_include: Option>, } impl Default for CfgOptions { @@ -77,6 +79,8 @@ impl Default for CfgOptions { target_os = "unknown" ))] windows_interception_mouse_hwid: None, + #[cfg(any(target_os = "macos", target_os = "unknown"))] + macos_dev_names_include: None, } } } @@ -117,7 +121,7 @@ pub fn parse_defcfg(expr: &[SExpr]) -> Result { "linux-dev" => { #[cfg(any(target_os = "linux", target_os = "unknown"))] { - cfg.linux_dev = parse_linux_dev(val)?; + cfg.linux_dev = parse_dev(val)?; if cfg.linux_dev.is_empty() { bail_expr!( val, @@ -129,7 +133,7 @@ pub fn parse_defcfg(expr: &[SExpr]) -> Result { "linux-dev-names-include" => { #[cfg(any(target_os = "linux", target_os = "unknown"))] { - let dev_names = parse_linux_dev(val)?; + let dev_names = parse_dev(val)?; if dev_names.is_empty() { log::warn!("linux-dev-names-include is empty"); } @@ -139,7 +143,7 @@ pub fn parse_defcfg(expr: &[SExpr]) -> Result { "linux-dev-names-exclude" => { #[cfg(any(target_os = "linux", target_os = "unknown"))] { - cfg.linux_dev_names_exclude = Some(parse_linux_dev(val)?); + cfg.linux_dev_names_exclude = Some(parse_dev(val)?); } } "linux-unicode-u-code" => { @@ -238,6 +242,16 @@ pub fn parse_defcfg(expr: &[SExpr]) -> Result { cfg.windows_interception_mouse_hwid = Some(hwid_slice?); } } + "macos-dev-names-include" => { + #[cfg(any(target_os = "macos", target_os = "unknown"))] + { + let dev_names = parse_dev(val)?; + if dev_names.is_empty() { + log::warn!("macos-dev-names-include is empty"); + } + cfg.macos_dev_names_include = Some(dev_names); + } + } "process-unmapped-keys" => { cfg.process_unmapped_keys = parse_defcfg_val_bool(val, label)? @@ -348,8 +362,8 @@ pub fn parse_colon_separated_text(paths: &str) -> Vec { all_paths } -#[cfg(any(target_os = "linux", target_os = "unknown"))] -pub fn parse_linux_dev(val: &SExpr) -> Result> { +#[cfg(any(target_os = "linux", target_os = "macos", target_os = "unknown"))] +pub fn parse_dev(val: &SExpr) -> Result> { Ok(match val { SExpr::Atom(a) => { let devs = parse_colon_separated_text(a.t.trim_matches('"')); diff --git a/parser/src/cfg/mod.rs b/parser/src/cfg/mod.rs index a57c6edf6..7850f877d 100644 --- a/parser/src/cfg/mod.rs +++ b/parser/src/cfg/mod.rs @@ -263,6 +263,8 @@ fn parse_cfg( const DEF_LOCAL_KEYS: &str = "deflocalkeys-win"; #[cfg(all(feature = "interception_driver", target_os = "windows"))] const DEF_LOCAL_KEYS: &str = "deflocalkeys-wintercept"; +#[cfg(target_os = "macos")] +const DEF_LOCAL_KEYS: &str = "deflocalkeys-macos"; #[cfg(any(target_os = "linux", target_os = "unknown"))] const DEF_LOCAL_KEYS: &str = "deflocalkeys-linux"; @@ -402,6 +404,7 @@ pub fn parse_cfg_raw_string( "deflocalkeys-win", "deflocalkeys-wintercept", "deflocalkeys-linux", + "deflocalkeys-macos", ] { if let Some(result) = root_exprs .iter() @@ -633,6 +636,7 @@ fn error_on_unknown_top_level_atoms(exprs: &[Spanned>]) -> Result<()> | "defsrc" | "deflayer" | "defoverrides" + | "deflocalkeys-macos" | "deflocalkeys-linux" | "deflocalkeys-win" | "deflocalkeys-wintercept" diff --git a/parser/src/cfg/tests.rs b/parser/src/cfg/tests.rs index 14a5787a5..7f01be181 100644 --- a/parser/src/cfg/tests.rs +++ b/parser/src/cfg/tests.rs @@ -1211,10 +1211,10 @@ fn parse_device_paths() { #[test] #[cfg(any(target_os = "linux", target_os = "unknown"))] -fn test_parse_linux_dev() { +fn test_parse_dev() { // The old colon separated devices format assert_eq!( - parse_linux_dev(&SExpr::Atom(Spanned { + parse_dev(&SExpr::Atom(Spanned { t: "\"Keyboard2:Input Device 1:pci-0000\\:00\\:14.0-usb-0\\:1\\:1.0-event\"" .to_string(), span: Span::default(), @@ -1226,7 +1226,7 @@ fn test_parse_linux_dev() { "pci-0000:00:14.0-usb-0:1:1.0-event" ] ); - parse_linux_dev(&SExpr::Atom(Spanned { + parse_dev(&SExpr::Atom(Spanned { t: "\"\"".to_string(), span: Span::default(), })) @@ -1234,7 +1234,7 @@ fn test_parse_linux_dev() { // The new device list format assert_eq!( - parse_linux_dev(&SExpr::List(Spanned { + parse_dev(&SExpr::List(Spanned { t: vec![ SExpr::Atom(Spanned { t: "Keyboard2".to_string(), @@ -1263,7 +1263,7 @@ fn test_parse_linux_dev() { r"backslashes\do\not\escape\:\anything" ] ); - parse_linux_dev(&SExpr::List(Spanned { + parse_dev(&SExpr::List(Spanned { t: vec![ SExpr::Atom(Spanned { t: "Device1".to_string(), diff --git a/parser/src/keys/linux.rs b/parser/src/keys/linux.rs index 117b8aa30..43ae238a0 100644 --- a/parser/src/keys/linux.rs +++ b/parser/src/keys/linux.rs @@ -1,11 +1,11 @@ // This file is taken from the original ktrl project's keys.rs file with modifications. use super::OsCode; + impl OsCode { pub(super) const fn as_u16_linux(self) -> u16 { self as u16 } - pub(super) const fn from_u16_linux(code: u16) -> Option { match code { 0 => Some(OsCode::KEY_RESERVED), diff --git a/parser/src/keys/macos.rs b/parser/src/keys/macos.rs new file mode 100644 index 000000000..b747dc321 --- /dev/null +++ b/parser/src/keys/macos.rs @@ -0,0 +1,2018 @@ +use super::OsCode; + +// because the parser can't handle oscode u16 values > 767 +// and macos has fucked up key coding (page and code) +pub struct PageCode { + pub page: u32, + pub code: u32, +} + +impl TryFrom for PageCode { + type Error = &'static str; + fn try_from(item: OsCode) -> Result { + match item { + OsCode::KEY_RESERVED => Ok(PageCode { + page: 0xFF, + code: 0xFF, + }), + OsCode::KEY_A => Ok(PageCode { + page: 0x07, + code: 0x04, + }), + OsCode::KEY_B => Ok(PageCode { + page: 0x07, + code: 0x05, + }), + OsCode::KEY_C => Ok(PageCode { + page: 0x07, + code: 0x06, + }), + OsCode::KEY_D => Ok(PageCode { + page: 0x07, + code: 0x07, + }), + OsCode::KEY_E => Ok(PageCode { + page: 0x07, + code: 0x08, + }), + OsCode::KEY_F => Ok(PageCode { + page: 0x07, + code: 0x09, + }), + OsCode::KEY_G => Ok(PageCode { + page: 0x07, + code: 0x0A, + }), + OsCode::KEY_H => Ok(PageCode { + page: 0x07, + code: 0x0B, + }), + OsCode::KEY_I => Ok(PageCode { + page: 0x07, + code: 0x0C, + }), + OsCode::KEY_J => Ok(PageCode { + page: 0x07, + code: 0x0D, + }), + OsCode::KEY_K => Ok(PageCode { + page: 0x07, + code: 0x0E, + }), + OsCode::KEY_L => Ok(PageCode { + page: 0x07, + code: 0x0F, + }), + OsCode::KEY_M => Ok(PageCode { + page: 0x07, + code: 0x10, + }), + OsCode::KEY_N => Ok(PageCode { + page: 0x07, + code: 0x11, + }), + OsCode::KEY_O => Ok(PageCode { + page: 0x07, + code: 0x12, + }), + OsCode::KEY_P => Ok(PageCode { + page: 0x07, + code: 0x13, + }), + OsCode::KEY_Q => Ok(PageCode { + page: 0x07, + code: 0x14, + }), + OsCode::KEY_R => Ok(PageCode { + page: 0x07, + code: 0x15, + }), + OsCode::KEY_S => Ok(PageCode { + page: 0x07, + code: 0x16, + }), + OsCode::KEY_T => Ok(PageCode { + page: 0x07, + code: 0x17, + }), + OsCode::KEY_U => Ok(PageCode { + page: 0x07, + code: 0x18, + }), + OsCode::KEY_V => Ok(PageCode { + page: 0x07, + code: 0x19, + }), + OsCode::KEY_W => Ok(PageCode { + page: 0x07, + code: 0x1A, + }), + OsCode::KEY_X => Ok(PageCode { + page: 0x07, + code: 0x1B, + }), + OsCode::KEY_Y => Ok(PageCode { + page: 0x07, + code: 0x1C, + }), + OsCode::KEY_Z => Ok(PageCode { + page: 0x07, + code: 0x1D, + }), + OsCode::KEY_1 => Ok(PageCode { + page: 0x07, + code: 0x1E, + }), + OsCode::KEY_2 => Ok(PageCode { + page: 0x07, + code: 0x1F, + }), + OsCode::KEY_3 => Ok(PageCode { + page: 0x07, + code: 0x20, + }), + OsCode::KEY_4 => Ok(PageCode { + page: 0x07, + code: 0x21, + }), + OsCode::KEY_5 => Ok(PageCode { + page: 0x07, + code: 0x22, + }), + OsCode::KEY_6 => Ok(PageCode { + page: 0x07, + code: 0x23, + }), + OsCode::KEY_7 => Ok(PageCode { + page: 0x07, + code: 0x24, + }), + OsCode::KEY_8 => Ok(PageCode { + page: 0x07, + code: 0x25, + }), + OsCode::KEY_9 => Ok(PageCode { + page: 0x07, + code: 0x26, + }), + OsCode::KEY_0 => Ok(PageCode { + page: 0x07, + code: 0x27, + }), + OsCode::KEY_ENTER => Ok(PageCode { + page: 0x07, + code: 0x28, + }), + OsCode::KEY_ESC => Ok(PageCode { + page: 0x07, + code: 0x29, + }), + OsCode::KEY_BACKSPACE => Ok(PageCode { + page: 0x07, + code: 0x2A, + }), + OsCode::KEY_TAB => Ok(PageCode { + page: 0x07, + code: 0x2B, + }), + OsCode::KEY_SPACE => Ok(PageCode { + page: 0x07, + code: 0x2C, + }), + OsCode::KEY_MINUS => Ok(PageCode { + page: 0x07, + code: 0x2D, + }), + OsCode::KEY_EQUAL => Ok(PageCode { + page: 0x07, + code: 0x2E, + }), + OsCode::KEY_LEFTBRACE => Ok(PageCode { + page: 0x07, + code: 0x2F, + }), + OsCode::KEY_RIGHTBRACE => Ok(PageCode { + page: 0x07, + code: 0x30, + }), + OsCode::KEY_BACKSLASH => Ok(PageCode { + page: 0x07, + code: 0x31, + }), + // KeyboardNonUSPound => 0x0732, todo + OsCode::KEY_SEMICOLON => Ok(PageCode { + page: 0x07, + code: 0x33, + }), + OsCode::KEY_APOSTROPHE => Ok(PageCode { + page: 0x07, + code: 0x34, + }), + OsCode::KEY_GRAVE => Ok(PageCode { + page: 0x07, + code: 0x35, + }), + OsCode::KEY_COMMA => Ok(PageCode { + page: 0x07, + code: 0x36, + }), + OsCode::KEY_DOT => Ok(PageCode { + page: 0x07, + code: 0x37, + }), + OsCode::KEY_SLASH => Ok(PageCode { + page: 0x07, + code: 0x38, + }), + OsCode::KEY_CAPSLOCK => Ok(PageCode { + page: 0x07, + code: 0x39, + }), + OsCode::KEY_F1 => Ok(PageCode { + page: 0x07, + code: 0x3A, + }), + OsCode::KEY_F2 => Ok(PageCode { + page: 0x07, + code: 0x3B, + }), + OsCode::KEY_F3 => Ok(PageCode { + page: 0x07, + code: 0x3C, + }), + OsCode::KEY_F4 => Ok(PageCode { + page: 0x07, + code: 0x3D, + }), + OsCode::KEY_F5 => Ok(PageCode { + page: 0x07, + code: 0x3E, + }), + OsCode::KEY_F6 => Ok(PageCode { + page: 0x07, + code: 0x3F, + }), + OsCode::KEY_F7 => Ok(PageCode { + page: 0x07, + code: 0x40, + }), + OsCode::KEY_F8 => Ok(PageCode { + page: 0x07, + code: 0x41, + }), + OsCode::KEY_F9 => Ok(PageCode { + page: 0x07, + code: 0x42, + }), + OsCode::KEY_F10 => Ok(PageCode { + page: 0x07, + code: 0x43, + }), + OsCode::KEY_F11 => Ok(PageCode { + page: 0x07, + code: 0x44, + }), + OsCode::KEY_F12 => Ok(PageCode { + page: 0x07, + code: 0x45, + }), + OsCode::KEY_PRINT => Ok(PageCode { + page: 0x07, + code: 0x46, + }), + OsCode::KEY_SCROLLLOCK => Ok(PageCode { + page: 0x07, + code: 0x47, + }), + OsCode::KEY_PAUSE => Ok(PageCode { + page: 0x07, + code: 0x48, + }), + OsCode::KEY_INSERT => Ok(PageCode { + page: 0x07, + code: 0x49, + }), + OsCode::KEY_HOME => Ok(PageCode { + page: 0x07, + code: 0x4A, + }), + OsCode::KEY_PAGEUP => Ok(PageCode { + page: 0x07, + code: 0x4B, + }), + OsCode::KEY_DELETE => Ok(PageCode { + page: 0x07, + code: 0x4C, + }), + OsCode::KEY_END => Ok(PageCode { + page: 0x07, + code: 0x4D, + }), + OsCode::KEY_PAGEDOWN => Ok(PageCode { + page: 0x07, + code: 0x4E, + }), + OsCode::KEY_RIGHT => Ok(PageCode { + page: 0x07, + code: 0x4F, + }), + OsCode::KEY_LEFT => Ok(PageCode { + page: 0x07, + code: 0x50, + }), + OsCode::KEY_DOWN => Ok(PageCode { + page: 0x07, + code: 0x51, + }), + OsCode::KEY_UP => Ok(PageCode { + page: 0x07, + code: 0x52, + }), + OsCode::KEY_NUMLOCK => Ok(PageCode { + page: 0x07, + code: 0x53, + }), + OsCode::KEY_KPSLASH => Ok(PageCode { + page: 0x07, + code: 0x54, + }), + OsCode::KEY_KPASTERISK => Ok(PageCode { + page: 0x07, + code: 0x55, + }), + OsCode::KEY_KPMINUS => Ok(PageCode { + page: 0x07, + code: 0x56, + }), + OsCode::KEY_KPPLUS => Ok(PageCode { + page: 0x07, + code: 0x57, + }), + OsCode::KEY_KPENTER => Ok(PageCode { + page: 0x07, + code: 0x58, + }), + OsCode::KEY_KP1 => Ok(PageCode { + page: 0x07, + code: 0x59, + }), + OsCode::KEY_KP2 => Ok(PageCode { + page: 0x07, + code: 0x5A, + }), + OsCode::KEY_KP3 => Ok(PageCode { + page: 0x07, + code: 0x5B, + }), + OsCode::KEY_KP4 => Ok(PageCode { + page: 0x07, + code: 0x5C, + }), + OsCode::KEY_KP5 => Ok(PageCode { + page: 0x07, + code: 0x5D, + }), + OsCode::KEY_KP6 => Ok(PageCode { + page: 0x07, + code: 0x5E, + }), + OsCode::KEY_KP7 => Ok(PageCode { + page: 0x07, + code: 0x5F, + }), + OsCode::KEY_KP8 => Ok(PageCode { + page: 0x07, + code: 0x60, + }), + OsCode::KEY_KP9 => Ok(PageCode { + page: 0x07, + code: 0x61, + }), + OsCode::KEY_KP0 => Ok(PageCode { + page: 0x07, + code: 0x62, + }), + OsCode::KEY_KPDOT => Ok(PageCode { + page: 0x07, + code: 0x63, + }), + OsCode::KEY_102ND => Ok(PageCode { + page: 0x07, + code: 0x64, + }), //KeyboardNonUSBackslash + // KeyboardApplication => 0x0765, todo + OsCode::KEY_POWER => Ok(PageCode { + page: 0x07, + code: 0x66, + }), + OsCode::KEY_KPEQUAL => Ok(PageCode { + page: 0x07, + code: 0x67, + }), + OsCode::KEY_F13 => Ok(PageCode { + page: 0x07, + code: 0x68, + }), + OsCode::KEY_F14 => Ok(PageCode { + page: 0x07, + code: 0x69, + }), + OsCode::KEY_F15 => Ok(PageCode { + page: 0x07, + code: 0x6A, + }), + OsCode::KEY_F16 => Ok(PageCode { + page: 0x07, + code: 0x6B, + }), + OsCode::KEY_F17 => Ok(PageCode { + page: 0x07, + code: 0x6C, + }), + OsCode::KEY_F18 => Ok(PageCode { + page: 0x07, + code: 0x6D, + }), + OsCode::KEY_F19 => Ok(PageCode { + page: 0x07, + code: 0x6E, + }), + OsCode::KEY_F20 => Ok(PageCode { + page: 0x07, + code: 0x6F, + }), + OsCode::KEY_F21 => Ok(PageCode { + page: 0x07, + code: 0x70, + }), + OsCode::KEY_F22 => Ok(PageCode { + page: 0x07, + code: 0x71, + }), + OsCode::KEY_F23 => Ok(PageCode { + page: 0x07, + code: 0x72, + }), + OsCode::KEY_F24 => Ok(PageCode { + page: 0x07, + code: 0x73, + }), + // KeyboardExecute => 0x0774, todo + OsCode::KEY_HELP => Ok(PageCode { + page: 0x07, + code: 0x75, + }), + OsCode::KEY_MENU => Ok(PageCode { + page: 0x07, + code: 0x76, + }), + OsCode::KEY_SELECT => Ok(PageCode { + page: 0x07, + code: 0x77, + }), + OsCode::KEY_STOP => Ok(PageCode { + page: 0x07, + code: 0x78, + }), + OsCode::KEY_AGAIN => Ok(PageCode { + page: 0x07, + code: 0x79, + }), + OsCode::KEY_UNDO => Ok(PageCode { + page: 0x07, + code: 0x7A, + }), + OsCode::KEY_CUT => Ok(PageCode { + page: 0x07, + code: 0x7B, + }), + OsCode::KEY_COPY => Ok(PageCode { + page: 0x07, + code: 0x7C, + }), + OsCode::KEY_PASTE => Ok(PageCode { + page: 0x07, + code: 0x7D, + }), + OsCode::KEY_FIND => Ok(PageCode { + page: 0x07, + code: 0x7E, + }), + OsCode::KEY_MUTE => Ok(PageCode { + page: 0x0C, + code: 0xE2, + }), // 0x077f + OsCode::KEY_VOLUMEUP => Ok(PageCode { + page: 0x0C, + code: 0xE9, + }), // 0x0780 + OsCode::KEY_VOLUMEDOWN => Ok(PageCode { + page: 0x0C, + code: 0xEA, + }), // 0x0781 + //KeyboardLockingCapsLock => 82, todo + //KeyboardLockingNumLock => 83, todo + //KeyboardLockingScrollLock => 84, todo + OsCode::KEY_KPCOMMA => Ok(PageCode { + page: 0x07, + code: 0x85, + }), + OsCode::KEY_ALTERASE => Ok(PageCode { + page: 0x07, + code: 0x99, + }), + OsCode::KEY_CANCEL => Ok(PageCode { + page: 0x07, + code: 0x9B, + }), + OsCode::KEY_CLEAR => Ok(PageCode { + page: 0x07, + code: 0x9C, + }), + OsCode::KEY_LEFTCTRL => Ok(PageCode { + page: 0x07, + code: 0xE0, + }), + OsCode::KEY_LEFTSHIFT => Ok(PageCode { + page: 0x07, + code: 0xE1, + }), + OsCode::KEY_LEFTALT => Ok(PageCode { + page: 0x07, + code: 0xE2, + }), + OsCode::KEY_LEFTMETA => Ok(PageCode { + page: 0x07, + code: 0xE3, + }), + OsCode::KEY_RIGHTCTRL => Ok(PageCode { + page: 0x07, + code: 0xE4, + }), + OsCode::KEY_RIGHTSHIFT => Ok(PageCode { + page: 0x07, + code: 0xE5, + }), + OsCode::KEY_RIGHTALT => Ok(PageCode { + page: 0x07, + code: 0xE6, + }), + OsCode::KEY_RIGHTMETA => Ok(PageCode { + page: 0x07, + code: 0xE7, + }), + // ?? + //OsCode::KEY_POWER => Ok( PageCode { page: 0x0C, code: 0x30 } ), + OsCode::KEY_SLEEP => Ok(PageCode { + page: 0x0C, + code: 0x32, + }), + OsCode::KEY_FORWARD => Ok(PageCode { + page: 0x0C, + code: 0xB3, + }), + OsCode::KEY_REWIND => Ok(PageCode { + page: 0x0C, + code: 0xB4, + }), + OsCode::KEY_NEXTSONG => Ok(PageCode { + page: 0x0C, + code: 0xB5, + }), + OsCode::KEY_PREVIOUSSONG => Ok(PageCode { + page: 0x0C, + code: 0xB6, + }), + OsCode::KEY_PLAYPAUSE => Ok(PageCode { + page: 0x0C, + code: 0xCD, + }), + OsCode::KEY_FN => Ok(PageCode { + page: 0xFF, + code: 0x03, + }), + OsCode::KEY_BRIGHTNESSUP => Ok(PageCode { + page: 0x0C, + code: 0x6F, + }), + OsCode::KEY_BRIGHTNESSDOWN => Ok(PageCode { + page: 0x0C, + code: 0x70, + }), + // OsCode::KEY_BRIGHTNESSUP => Ok( PageCode { page: 0x0C, code: 0x04 } ), + // OsCode::KEY_BRIGHTNESSDOWN => Ok( PageCode { page: 0x0C, code: 0x05 } ), + // OsCode::KEY_KBDILLUMTOGGLE => Ok( PageCode { page: 0x0C, code: 0x07 } ), + // OsCode::KEY_KBDILLUMUP => Ok( PageCode { page: 0x0C, code: 0x08 } ), + // OsCode::KEY_KBDILLUMDOWN => Ok( PageCode { page: 0x0C, code: 0x09 } ), + OsCode::KEY_KBDILLUMTOGGLE => Ok(PageCode { + page: 0xFF, + code: 0x07, + }), + OsCode::KEY_KBDILLUMUP => Ok(PageCode { + page: 0xFF, + code: 0x08, + }), + OsCode::KEY_KBDILLUMDOWN => Ok(PageCode { + page: 0xFF, + code: 0x09, + }), + // ?? + OsCode::KEY_DASHBOARD => Ok(PageCode { + page: 0xFF, + code: 0x02, + }), + OsCode::KEY_SEARCH => Ok(PageCode { + page: 0xFF, + code: 0x01, + }), + // OsCode::KEY_FN_ESC => 0x07, + // OsCode::KEY_FN_F1 => 0x07, + // OsCode::KEY_FN_F2 => 0x07, + // OsCode::KEY_FN_F3 => 0x07, + // OsCode::KEY_FN_F4 => 0x07, + // OsCode::KEY_FN_F5 => 0x07, + // OsCode::KEY_FN_F6 => 0x07, + // OsCode::KEY_FN_F7 => 0x07, + // OsCode::KEY_FN_F8 => 0x07, + // OsCode::KEY_FN_F9 => 0x07, + // OsCode::KEY_FN_F10 => 0x07, + // OsCode::KEY_FN_F11 => 0x07, + // OsCode::KEY_FN_F12 => 0x07, + // OsCode::KEY_FN_1 => 0x07, + // OsCode::KEY_FN_2 => 0x07, + // OsCode::KEY_FN_D => 0x07, + // OsCode::KEY_FN_E => 0x07, + // OsCode::KEY_FN_F => 0x07, + // OsCode::KEY_FN_S => 0x07, + // OsCode::KEY_FN_B => 0x07, + // osc => Err(&format!("OsCode {} not mapped!", osc.as_u16())), + _ => Err("OsCode unrecognized!"), + } + } +} + +impl TryFrom for OsCode { + type Error = &'static str; + fn try_from(item: PageCode) -> Result { + match item { + PageCode { + page: 0xFF, + code: 0xFF, + } => Ok(OsCode::KEY_RESERVED), + PageCode { + page: 0x07, + code: 0x04, + } => Ok(OsCode::KEY_A), + PageCode { + page: 0x07, + code: 0x05, + } => Ok(OsCode::KEY_B), + PageCode { + page: 0x07, + code: 0x06, + } => Ok(OsCode::KEY_C), + PageCode { + page: 0x07, + code: 0x07, + } => Ok(OsCode::KEY_D), + PageCode { + page: 0x07, + code: 0x08, + } => Ok(OsCode::KEY_E), + PageCode { + page: 0x07, + code: 0x09, + } => Ok(OsCode::KEY_F), + PageCode { + page: 0x07, + code: 0x0A, + } => Ok(OsCode::KEY_G), + PageCode { + page: 0x07, + code: 0x0B, + } => Ok(OsCode::KEY_H), + PageCode { + page: 0x07, + code: 0x0C, + } => Ok(OsCode::KEY_I), + PageCode { + page: 0x07, + code: 0x0D, + } => Ok(OsCode::KEY_J), + PageCode { + page: 0x07, + code: 0x0E, + } => Ok(OsCode::KEY_K), + PageCode { + page: 0x07, + code: 0x0F, + } => Ok(OsCode::KEY_L), + PageCode { + page: 0x07, + code: 0x10, + } => Ok(OsCode::KEY_M), + PageCode { + page: 0x07, + code: 0x11, + } => Ok(OsCode::KEY_N), + PageCode { + page: 0x07, + code: 0x12, + } => Ok(OsCode::KEY_O), + PageCode { + page: 0x07, + code: 0x13, + } => Ok(OsCode::KEY_P), + PageCode { + page: 0x07, + code: 0x14, + } => Ok(OsCode::KEY_Q), + PageCode { + page: 0x07, + code: 0x15, + } => Ok(OsCode::KEY_R), + PageCode { + page: 0x07, + code: 0x16, + } => Ok(OsCode::KEY_S), + PageCode { + page: 0x07, + code: 0x17, + } => Ok(OsCode::KEY_T), + PageCode { + page: 0x07, + code: 0x18, + } => Ok(OsCode::KEY_U), + PageCode { + page: 0x07, + code: 0x19, + } => Ok(OsCode::KEY_V), + PageCode { + page: 0x07, + code: 0x1A, + } => Ok(OsCode::KEY_W), + PageCode { + page: 0x07, + code: 0x1B, + } => Ok(OsCode::KEY_X), + PageCode { + page: 0x07, + code: 0x1C, + } => Ok(OsCode::KEY_Y), + PageCode { + page: 0x07, + code: 0x1D, + } => Ok(OsCode::KEY_Z), + PageCode { + page: 0x07, + code: 0x1E, + } => Ok(OsCode::KEY_1), + PageCode { + page: 0x07, + code: 0x1F, + } => Ok(OsCode::KEY_2), + PageCode { + page: 0x07, + code: 0x20, + } => Ok(OsCode::KEY_3), + PageCode { + page: 0x07, + code: 0x21, + } => Ok(OsCode::KEY_4), + PageCode { + page: 0x07, + code: 0x22, + } => Ok(OsCode::KEY_5), + PageCode { + page: 0x07, + code: 0x23, + } => Ok(OsCode::KEY_6), + PageCode { + page: 0x07, + code: 0x24, + } => Ok(OsCode::KEY_7), + PageCode { + page: 0x07, + code: 0x25, + } => Ok(OsCode::KEY_8), + PageCode { + page: 0x07, + code: 0x26, + } => Ok(OsCode::KEY_9), + PageCode { + page: 0x07, + code: 0x27, + } => Ok(OsCode::KEY_0), + PageCode { + page: 0x07, + code: 0x28, + } => Ok(OsCode::KEY_ENTER), + PageCode { + page: 0x07, + code: 0x29, + } => Ok(OsCode::KEY_ESC), + PageCode { + page: 0x07, + code: 0x2A, + } => Ok(OsCode::KEY_BACKSPACE), + PageCode { + page: 0x07, + code: 0x2B, + } => Ok(OsCode::KEY_TAB), + PageCode { + page: 0x07, + code: 0x2C, + } => Ok(OsCode::KEY_SPACE), + PageCode { + page: 0x07, + code: 0x2D, + } => Ok(OsCode::KEY_MINUS), + PageCode { + page: 0x07, + code: 0x2E, + } => Ok(OsCode::KEY_EQUAL), + PageCode { + page: 0x07, + code: 0x2F, + } => Ok(OsCode::KEY_LEFTBRACE), + PageCode { + page: 0x07, + code: 0x30, + } => Ok(OsCode::KEY_RIGHTBRACE), + PageCode { + page: 0x07, + code: 0x31, + } => Ok(OsCode::KEY_BACKSLASH), + PageCode { + page: 0x07, + code: 0x33, + } => Ok(OsCode::KEY_SEMICOLON), + PageCode { + page: 0x07, + code: 0x34, + } => Ok(OsCode::KEY_APOSTROPHE), + PageCode { + page: 0x07, + code: 0x35, + } => Ok(OsCode::KEY_GRAVE), + PageCode { + page: 0x07, + code: 0x36, + } => Ok(OsCode::KEY_COMMA), + PageCode { + page: 0x07, + code: 0x37, + } => Ok(OsCode::KEY_DOT), + PageCode { + page: 0x07, + code: 0x38, + } => Ok(OsCode::KEY_SLASH), + PageCode { + page: 0x07, + code: 0x39, + } => Ok(OsCode::KEY_CAPSLOCK), + PageCode { + page: 0x07, + code: 0x3A, + } => Ok(OsCode::KEY_F1), + PageCode { + page: 0x07, + code: 0x3B, + } => Ok(OsCode::KEY_F2), + PageCode { + page: 0x07, + code: 0x3C, + } => Ok(OsCode::KEY_F3), + PageCode { + page: 0x07, + code: 0x3D, + } => Ok(OsCode::KEY_F4), + PageCode { + page: 0x07, + code: 0x3E, + } => Ok(OsCode::KEY_F5), + PageCode { + page: 0x07, + code: 0x3F, + } => Ok(OsCode::KEY_F6), + PageCode { + page: 0x07, + code: 0x40, + } => Ok(OsCode::KEY_F7), + PageCode { + page: 0x07, + code: 0x41, + } => Ok(OsCode::KEY_F8), + PageCode { + page: 0x07, + code: 0x42, + } => Ok(OsCode::KEY_F9), + PageCode { + page: 0x07, + code: 0x43, + } => Ok(OsCode::KEY_F10), + PageCode { + page: 0x07, + code: 0x44, + } => Ok(OsCode::KEY_F11), + PageCode { + page: 0x07, + code: 0x45, + } => Ok(OsCode::KEY_F12), + PageCode { + page: 0x07, + code: 0x46, + } => Ok(OsCode::KEY_PRINT), + PageCode { + page: 0x07, + code: 0x47, + } => Ok(OsCode::KEY_SCROLLLOCK), + PageCode { + page: 0x07, + code: 0x48, + } => Ok(OsCode::KEY_PAUSE), + PageCode { + page: 0x07, + code: 0x49, + } => Ok(OsCode::KEY_INSERT), + PageCode { + page: 0x07, + code: 0x4A, + } => Ok(OsCode::KEY_HOME), + PageCode { + page: 0x07, + code: 0x4B, + } => Ok(OsCode::KEY_PAGEUP), + PageCode { + page: 0x07, + code: 0x4C, + } => Ok(OsCode::KEY_DELETE), + PageCode { + page: 0x07, + code: 0x4D, + } => Ok(OsCode::KEY_END), + PageCode { + page: 0x07, + code: 0x4E, + } => Ok(OsCode::KEY_PAGEDOWN), + PageCode { + page: 0x07, + code: 0x4F, + } => Ok(OsCode::KEY_RIGHT), + PageCode { + page: 0x07, + code: 0x50, + } => Ok(OsCode::KEY_LEFT), + PageCode { + page: 0x07, + code: 0x51, + } => Ok(OsCode::KEY_DOWN), + PageCode { + page: 0x07, + code: 0x52, + } => Ok(OsCode::KEY_UP), + PageCode { + page: 0x07, + code: 0x53, + } => Ok(OsCode::KEY_NUMLOCK), + PageCode { + page: 0x07, + code: 0x54, + } => Ok(OsCode::KEY_KPSLASH), + PageCode { + page: 0x07, + code: 0x55, + } => Ok(OsCode::KEY_KPASTERISK), + PageCode { + page: 0x07, + code: 0x56, + } => Ok(OsCode::KEY_KPMINUS), + PageCode { + page: 0x07, + code: 0x57, + } => Ok(OsCode::KEY_KPPLUS), + PageCode { + page: 0x07, + code: 0x58, + } => Ok(OsCode::KEY_KPENTER), + PageCode { + page: 0x07, + code: 0x59, + } => Ok(OsCode::KEY_KP1), + PageCode { + page: 0x07, + code: 0x5A, + } => Ok(OsCode::KEY_KP2), + PageCode { + page: 0x07, + code: 0x5B, + } => Ok(OsCode::KEY_KP3), + PageCode { + page: 0x07, + code: 0x5C, + } => Ok(OsCode::KEY_KP4), + PageCode { + page: 0x07, + code: 0x5D, + } => Ok(OsCode::KEY_KP5), + PageCode { + page: 0x07, + code: 0x5E, + } => Ok(OsCode::KEY_KP6), + PageCode { + page: 0x07, + code: 0x5F, + } => Ok(OsCode::KEY_KP7), + PageCode { + page: 0x07, + code: 0x60, + } => Ok(OsCode::KEY_KP8), + PageCode { + page: 0x07, + code: 0x61, + } => Ok(OsCode::KEY_KP9), + PageCode { + page: 0x07, + code: 0x62, + } => Ok(OsCode::KEY_KP0), + PageCode { + page: 0x07, + code: 0x63, + } => Ok(OsCode::KEY_KPDOT), + PageCode { + page: 0x07, + code: 0x64, + } => Ok(OsCode::KEY_102ND), + PageCode { + page: 0x07, + code: 0x66, + } => Ok(OsCode::KEY_POWER), + PageCode { + page: 0x07, + code: 0x67, + } => Ok(OsCode::KEY_KPEQUAL), + PageCode { + page: 0x07, + code: 0x68, + } => Ok(OsCode::KEY_F13), + PageCode { + page: 0x07, + code: 0x69, + } => Ok(OsCode::KEY_F14), + PageCode { + page: 0x07, + code: 0x6A, + } => Ok(OsCode::KEY_F15), + PageCode { + page: 0x07, + code: 0x6B, + } => Ok(OsCode::KEY_F16), + PageCode { + page: 0x07, + code: 0x6C, + } => Ok(OsCode::KEY_F17), + PageCode { + page: 0x07, + code: 0x6D, + } => Ok(OsCode::KEY_F18), + PageCode { + page: 0x07, + code: 0x6E, + } => Ok(OsCode::KEY_F19), + PageCode { + page: 0x07, + code: 0x6F, + } => Ok(OsCode::KEY_F20), + PageCode { + page: 0x07, + code: 0x70, + } => Ok(OsCode::KEY_F21), + PageCode { + page: 0x07, + code: 0x71, + } => Ok(OsCode::KEY_F22), + PageCode { + page: 0x07, + code: 0x72, + } => Ok(OsCode::KEY_F23), + PageCode { + page: 0x07, + code: 0x73, + } => Ok(OsCode::KEY_F24), + PageCode { + page: 0x07, + code: 0x75, + } => Ok(OsCode::KEY_HELP), + PageCode { + page: 0x07, + code: 0x76, + } => Ok(OsCode::KEY_MENU), + PageCode { + page: 0x07, + code: 0x77, + } => Ok(OsCode::KEY_SELECT), + PageCode { + page: 0x07, + code: 0x78, + } => Ok(OsCode::KEY_STOP), + PageCode { + page: 0x07, + code: 0x79, + } => Ok(OsCode::KEY_AGAIN), + PageCode { + page: 0x07, + code: 0x7A, + } => Ok(OsCode::KEY_UNDO), + PageCode { + page: 0x07, + code: 0x7B, + } => Ok(OsCode::KEY_CUT), + PageCode { + page: 0x07, + code: 0x7C, + } => Ok(OsCode::KEY_COPY), + PageCode { + page: 0x07, + code: 0x7D, + } => Ok(OsCode::KEY_PASTE), + PageCode { + page: 0x07, + code: 0x7E, + } => Ok(OsCode::KEY_FIND), + PageCode { + page: 0x0C, + code: 0xE2, + } => Ok(OsCode::KEY_MUTE), + PageCode { + page: 0x0C, + code: 0xE9, + } => Ok(OsCode::KEY_VOLUMEUP), + PageCode { + page: 0x0C, + code: 0xEA, + } => Ok(OsCode::KEY_VOLUMEDOWN), + PageCode { + page: 0x07, + code: 0x85, + } => Ok(OsCode::KEY_KPCOMMA), + PageCode { + page: 0x07, + code: 0x99, + } => Ok(OsCode::KEY_ALTERASE), + PageCode { + page: 0x07, + code: 0x9B, + } => Ok(OsCode::KEY_CANCEL), + PageCode { + page: 0x07, + code: 0x9C, + } => Ok(OsCode::KEY_CLEAR), + PageCode { + page: 0x07, + code: 0xE0, + } => Ok(OsCode::KEY_LEFTCTRL), + PageCode { + page: 0x07, + code: 0xE1, + } => Ok(OsCode::KEY_LEFTSHIFT), + PageCode { + page: 0x07, + code: 0xE2, + } => Ok(OsCode::KEY_LEFTALT), + PageCode { + page: 0x07, + code: 0xE3, + } => Ok(OsCode::KEY_LEFTMETA), + PageCode { + page: 0x07, + code: 0xE4, + } => Ok(OsCode::KEY_RIGHTCTRL), + PageCode { + page: 0x07, + code: 0xE5, + } => Ok(OsCode::KEY_RIGHTSHIFT), + PageCode { + page: 0x07, + code: 0xE6, + } => Ok(OsCode::KEY_RIGHTALT), + PageCode { + page: 0x07, + code: 0xE7, + } => Ok(OsCode::KEY_RIGHTMETA), + PageCode { + page: 0x0C, + code: 0x32, + } => Ok(OsCode::KEY_SLEEP), + PageCode { + page: 0x0C, + code: 0xB3, + } => Ok(OsCode::KEY_FORWARD), + PageCode { + page: 0x0C, + code: 0xB4, + } => Ok(OsCode::KEY_REWIND), + PageCode { + page: 0x0C, + code: 0xB5, + } => Ok(OsCode::KEY_NEXTSONG), + PageCode { + page: 0x0C, + code: 0xB6, + } => Ok(OsCode::KEY_PREVIOUSSONG), + PageCode { + page: 0x0C, + code: 0xCD, + } => Ok(OsCode::KEY_PLAYPAUSE), + PageCode { + page: 0xFF, + code: 0x03, + } => Ok(OsCode::KEY_FN), + PageCode { + page: 0x0C, + code: 0x6F, + } => Ok(OsCode::KEY_BRIGHTNESSUP), + PageCode { + page: 0x0C, + code: 0x70, + } => Ok(OsCode::KEY_BRIGHTNESSDOWN), + PageCode { + page: 0xFF, + code: 0x07, + } => Ok(OsCode::KEY_KBDILLUMTOGGLE), + PageCode { + page: 0xFF, + code: 0x08, + } => Ok(OsCode::KEY_KBDILLUMUP), + PageCode { + page: 0xFF, + code: 0x09, + } => Ok(OsCode::KEY_KBDILLUMDOWN), + PageCode { + page: 0xFF, + code: 0x02, + } => Ok(OsCode::KEY_DASHBOARD), + PageCode { + page: 0xFF, + code: 0x01, + } => Ok(OsCode::KEY_SEARCH), + _ => Err("PageCode unrecognized!"), + } + } +} + +impl OsCode { + pub(super) const fn as_u16_macos(self) -> u16 { + self as u16 + } + pub(super) const fn from_u16_macos(code: u16) -> Option { + match code { + 0 => Some(OsCode::KEY_RESERVED), + 1 => Some(OsCode::KEY_ESC), + 2 => Some(OsCode::KEY_1), + 3 => Some(OsCode::KEY_2), + 4 => Some(OsCode::KEY_3), + 5 => Some(OsCode::KEY_4), + 6 => Some(OsCode::KEY_5), + 7 => Some(OsCode::KEY_6), + 8 => Some(OsCode::KEY_7), + 9 => Some(OsCode::KEY_8), + 10 => Some(OsCode::KEY_9), + 11 => Some(OsCode::KEY_0), + 12 => Some(OsCode::KEY_MINUS), + 13 => Some(OsCode::KEY_EQUAL), + 14 => Some(OsCode::KEY_BACKSPACE), + 15 => Some(OsCode::KEY_TAB), + 16 => Some(OsCode::KEY_Q), + 17 => Some(OsCode::KEY_W), + 18 => Some(OsCode::KEY_E), + 19 => Some(OsCode::KEY_R), + 20 => Some(OsCode::KEY_T), + 21 => Some(OsCode::KEY_Y), + 22 => Some(OsCode::KEY_U), + 23 => Some(OsCode::KEY_I), + 24 => Some(OsCode::KEY_O), + 25 => Some(OsCode::KEY_P), + 26 => Some(OsCode::KEY_LEFTBRACE), + 27 => Some(OsCode::KEY_RIGHTBRACE), + 28 => Some(OsCode::KEY_ENTER), + 29 => Some(OsCode::KEY_LEFTCTRL), + 30 => Some(OsCode::KEY_A), + 31 => Some(OsCode::KEY_S), + 32 => Some(OsCode::KEY_D), + 33 => Some(OsCode::KEY_F), + 34 => Some(OsCode::KEY_G), + 35 => Some(OsCode::KEY_H), + 36 => Some(OsCode::KEY_J), + 37 => Some(OsCode::KEY_K), + 38 => Some(OsCode::KEY_L), + 39 => Some(OsCode::KEY_SEMICOLON), + 40 => Some(OsCode::KEY_APOSTROPHE), + 41 => Some(OsCode::KEY_GRAVE), + 42 => Some(OsCode::KEY_LEFTSHIFT), + 43 => Some(OsCode::KEY_BACKSLASH), + 44 => Some(OsCode::KEY_Z), + 45 => Some(OsCode::KEY_X), + 46 => Some(OsCode::KEY_C), + 47 => Some(OsCode::KEY_V), + 48 => Some(OsCode::KEY_B), + 49 => Some(OsCode::KEY_N), + 50 => Some(OsCode::KEY_M), + 51 => Some(OsCode::KEY_COMMA), + 52 => Some(OsCode::KEY_DOT), + 53 => Some(OsCode::KEY_SLASH), + 54 => Some(OsCode::KEY_RIGHTSHIFT), + 55 => Some(OsCode::KEY_KPASTERISK), + 56 => Some(OsCode::KEY_LEFTALT), + 57 => Some(OsCode::KEY_SPACE), + 58 => Some(OsCode::KEY_CAPSLOCK), + 59 => Some(OsCode::KEY_F1), + 60 => Some(OsCode::KEY_F2), + 61 => Some(OsCode::KEY_F3), + 62 => Some(OsCode::KEY_F4), + 63 => Some(OsCode::KEY_F5), + 64 => Some(OsCode::KEY_F6), + 65 => Some(OsCode::KEY_F7), + 66 => Some(OsCode::KEY_F8), + 67 => Some(OsCode::KEY_F9), + 68 => Some(OsCode::KEY_F10), + 69 => Some(OsCode::KEY_NUMLOCK), + 70 => Some(OsCode::KEY_SCROLLLOCK), + 71 => Some(OsCode::KEY_KP7), + 72 => Some(OsCode::KEY_KP8), + 73 => Some(OsCode::KEY_KP9), + 74 => Some(OsCode::KEY_KPMINUS), + 75 => Some(OsCode::KEY_KP4), + 76 => Some(OsCode::KEY_KP5), + 77 => Some(OsCode::KEY_KP6), + 78 => Some(OsCode::KEY_KPPLUS), + 79 => Some(OsCode::KEY_KP1), + 80 => Some(OsCode::KEY_KP2), + 81 => Some(OsCode::KEY_KP3), + 82 => Some(OsCode::KEY_KP0), + 83 => Some(OsCode::KEY_KPDOT), + 84 => Some(OsCode::KEY_84), + 85 => Some(OsCode::KEY_ZENKAKUHANKAKU), + 86 => Some(OsCode::KEY_102ND), + 87 => Some(OsCode::KEY_F11), + 88 => Some(OsCode::KEY_F12), + 89 => Some(OsCode::KEY_RO), + 90 => Some(OsCode::KEY_KATAKANA), + 91 => Some(OsCode::KEY_HIRAGANA), + 92 => Some(OsCode::KEY_HENKAN), + 93 => Some(OsCode::KEY_KATAKANAHIRAGANA), + 94 => Some(OsCode::KEY_MUHENKAN), + 95 => Some(OsCode::KEY_KPJPCOMMA), + 96 => Some(OsCode::KEY_KPENTER), + 97 => Some(OsCode::KEY_RIGHTCTRL), + 98 => Some(OsCode::KEY_KPSLASH), + 99 => Some(OsCode::KEY_SYSRQ), + 100 => Some(OsCode::KEY_RIGHTALT), + 101 => Some(OsCode::KEY_LINEFEED), + 102 => Some(OsCode::KEY_HOME), + 103 => Some(OsCode::KEY_UP), + 104 => Some(OsCode::KEY_PAGEUP), + 105 => Some(OsCode::KEY_LEFT), + 106 => Some(OsCode::KEY_RIGHT), + 107 => Some(OsCode::KEY_END), + 108 => Some(OsCode::KEY_DOWN), + 109 => Some(OsCode::KEY_PAGEDOWN), + 110 => Some(OsCode::KEY_INSERT), + 111 => Some(OsCode::KEY_DELETE), + 112 => Some(OsCode::KEY_MACRO), + 113 => Some(OsCode::KEY_MUTE), + 114 => Some(OsCode::KEY_VOLUMEDOWN), + 115 => Some(OsCode::KEY_VOLUMEUP), + 116 => Some(OsCode::KEY_POWER), + 117 => Some(OsCode::KEY_KPEQUAL), + 118 => Some(OsCode::KEY_KPPLUSMINUS), + 119 => Some(OsCode::KEY_PAUSE), + 120 => Some(OsCode::KEY_SCALE), + 121 => Some(OsCode::KEY_KPCOMMA), + 122 => Some(OsCode::KEY_HANGEUL), + 123 => Some(OsCode::KEY_HANJA), + 124 => Some(OsCode::KEY_YEN), + 125 => Some(OsCode::KEY_LEFTMETA), + 126 => Some(OsCode::KEY_RIGHTMETA), + 127 => Some(OsCode::KEY_COMPOSE), + 128 => Some(OsCode::KEY_STOP), + 129 => Some(OsCode::KEY_AGAIN), + 130 => Some(OsCode::KEY_PROPS), + 131 => Some(OsCode::KEY_UNDO), + 132 => Some(OsCode::KEY_FRONT), + 133 => Some(OsCode::KEY_COPY), + 134 => Some(OsCode::KEY_OPEN), + 135 => Some(OsCode::KEY_PASTE), + 136 => Some(OsCode::KEY_FIND), + 137 => Some(OsCode::KEY_CUT), + 138 => Some(OsCode::KEY_HELP), + 139 => Some(OsCode::KEY_MENU), + 140 => Some(OsCode::KEY_CALC), + 141 => Some(OsCode::KEY_SETUP), + 142 => Some(OsCode::KEY_SLEEP), + 143 => Some(OsCode::KEY_WAKEUP), + 144 => Some(OsCode::KEY_FILE), + 145 => Some(OsCode::KEY_SENDFILE), + 146 => Some(OsCode::KEY_DELETEFILE), + 147 => Some(OsCode::KEY_XFER), + 148 => Some(OsCode::KEY_PROG1), + 149 => Some(OsCode::KEY_PROG2), + 150 => Some(OsCode::KEY_WWW), + 151 => Some(OsCode::KEY_MSDOS), + 152 => Some(OsCode::KEY_COFFEE), + 153 => Some(OsCode::KEY_ROTATE_DISPLAY), + 154 => Some(OsCode::KEY_CYCLEWINDOWS), + 155 => Some(OsCode::KEY_MAIL), + 156 => Some(OsCode::KEY_BOOKMARKS), + 157 => Some(OsCode::KEY_COMPUTER), + 158 => Some(OsCode::KEY_BACK), + 159 => Some(OsCode::KEY_FORWARD), + 160 => Some(OsCode::KEY_CLOSECD), + 161 => Some(OsCode::KEY_EJECTCD), + 162 => Some(OsCode::KEY_EJECTCLOSECD), + 163 => Some(OsCode::KEY_NEXTSONG), + 164 => Some(OsCode::KEY_PLAYPAUSE), + 165 => Some(OsCode::KEY_PREVIOUSSONG), + 166 => Some(OsCode::KEY_STOPCD), + 167 => Some(OsCode::KEY_RECORD), + 168 => Some(OsCode::KEY_REWIND), + 169 => Some(OsCode::KEY_PHONE), + 170 => Some(OsCode::KEY_ISO), + 171 => Some(OsCode::KEY_CONFIG), + 172 => Some(OsCode::KEY_HOMEPAGE), + 173 => Some(OsCode::KEY_REFRESH), + 174 => Some(OsCode::KEY_EXIT), + 175 => Some(OsCode::KEY_MOVE), + 176 => Some(OsCode::KEY_EDIT), + 177 => Some(OsCode::KEY_SCROLLUP), + 178 => Some(OsCode::KEY_SCROLLDOWN), + 179 => Some(OsCode::KEY_KPLEFTPAREN), + 180 => Some(OsCode::KEY_KPRIGHTPAREN), + 181 => Some(OsCode::KEY_NEW), + 182 => Some(OsCode::KEY_REDO), + 183 => Some(OsCode::KEY_F13), + 184 => Some(OsCode::KEY_F14), + 185 => Some(OsCode::KEY_F15), + 186 => Some(OsCode::KEY_F16), + 187 => Some(OsCode::KEY_F17), + 188 => Some(OsCode::KEY_F18), + 189 => Some(OsCode::KEY_F19), + 190 => Some(OsCode::KEY_F20), + 191 => Some(OsCode::KEY_F21), + 192 => Some(OsCode::KEY_F22), + 193 => Some(OsCode::KEY_F23), + 194 => Some(OsCode::KEY_F24), + 195 => Some(OsCode::KEY_195), + 196 => Some(OsCode::KEY_196), + 197 => Some(OsCode::KEY_197), + 198 => Some(OsCode::KEY_198), + 199 => Some(OsCode::KEY_199), + 200 => Some(OsCode::KEY_PLAYCD), + 201 => Some(OsCode::KEY_PAUSECD), + 202 => Some(OsCode::KEY_PROG3), + 203 => Some(OsCode::KEY_PROG4), + 204 => Some(OsCode::KEY_DASHBOARD), + 205 => Some(OsCode::KEY_SUSPEND), + 206 => Some(OsCode::KEY_CLOSE), + 207 => Some(OsCode::KEY_PLAY), + 208 => Some(OsCode::KEY_FASTFORWARD), + 209 => Some(OsCode::KEY_BASSBOOST), + 210 => Some(OsCode::KEY_PRINT), + 211 => Some(OsCode::KEY_HP), + 212 => Some(OsCode::KEY_CAMERA), + 213 => Some(OsCode::KEY_SOUND), + 214 => Some(OsCode::KEY_QUESTION), + 215 => Some(OsCode::KEY_EMAIL), + 216 => Some(OsCode::KEY_CHAT), + 217 => Some(OsCode::KEY_SEARCH), + 218 => Some(OsCode::KEY_CONNECT), + 219 => Some(OsCode::KEY_FINANCE), + 220 => Some(OsCode::KEY_SPORT), + 221 => Some(OsCode::KEY_SHOP), + 222 => Some(OsCode::KEY_ALTERASE), + 223 => Some(OsCode::KEY_CANCEL), + 224 => Some(OsCode::KEY_BRIGHTNESSDOWN), + 225 => Some(OsCode::KEY_BRIGHTNESSUP), + 226 => Some(OsCode::KEY_MEDIA), + 227 => Some(OsCode::KEY_SWITCHVIDEOMODE), + 228 => Some(OsCode::KEY_KBDILLUMTOGGLE), + 229 => Some(OsCode::KEY_KBDILLUMDOWN), + 230 => Some(OsCode::KEY_KBDILLUMUP), + 231 => Some(OsCode::KEY_SEND), + 232 => Some(OsCode::KEY_REPLY), + 233 => Some(OsCode::KEY_FORWARDMAIL), + 234 => Some(OsCode::KEY_SAVE), + 235 => Some(OsCode::KEY_DOCUMENTS), + 236 => Some(OsCode::KEY_BATTERY), + 237 => Some(OsCode::KEY_BLUETOOTH), + 238 => Some(OsCode::KEY_WLAN), + 239 => Some(OsCode::KEY_UWB), + 240 => Some(OsCode::KEY_UNKNOWN), + 241 => Some(OsCode::KEY_VIDEO_NEXT), + 242 => Some(OsCode::KEY_VIDEO_PREV), + 243 => Some(OsCode::KEY_BRIGHTNESS_CYCLE), + 244 => Some(OsCode::KEY_BRIGHTNESS_AUTO), + 245 => Some(OsCode::KEY_DISPLAY_OFF), + 246 => Some(OsCode::KEY_WWAN), + 247 => Some(OsCode::KEY_RFKILL), + 248 => Some(OsCode::KEY_MICMUTE), + 249 => Some(OsCode::KEY_249), + 250 => Some(OsCode::KEY_250), + 251 => Some(OsCode::KEY_251), + 252 => Some(OsCode::KEY_252), + 253 => Some(OsCode::KEY_253), + 254 => Some(OsCode::KEY_254), + 255 => Some(OsCode::KEY_255), + 256 => Some(OsCode::BTN_0), + 257 => Some(OsCode::BTN_1), + 258 => Some(OsCode::BTN_2), + 259 => Some(OsCode::BTN_3), + 260 => Some(OsCode::BTN_4), + 261 => Some(OsCode::BTN_5), + 262 => Some(OsCode::BTN_6), + 263 => Some(OsCode::BTN_7), + 264 => Some(OsCode::BTN_8), + 265 => Some(OsCode::BTN_9), + 266 => Some(OsCode::KEY_266), + 267 => Some(OsCode::KEY_267), + 268 => Some(OsCode::KEY_268), + 269 => Some(OsCode::KEY_269), + 270 => Some(OsCode::KEY_270), + 271 => Some(OsCode::KEY_271), + 272 => Some(OsCode::BTN_LEFT), + 273 => Some(OsCode::BTN_RIGHT), + 274 => Some(OsCode::BTN_MIDDLE), + 275 => Some(OsCode::BTN_SIDE), + 276 => Some(OsCode::BTN_EXTRA), + 277 => Some(OsCode::BTN_FORWARD), + 278 => Some(OsCode::BTN_BACK), + 279 => Some(OsCode::BTN_TASK), + 280 => Some(OsCode::KEY_280), + 281 => Some(OsCode::KEY_281), + 282 => Some(OsCode::KEY_282), + 283 => Some(OsCode::KEY_283), + 284 => Some(OsCode::KEY_284), + 285 => Some(OsCode::KEY_285), + 286 => Some(OsCode::KEY_286), + 287 => Some(OsCode::KEY_287), + 288 => Some(OsCode::BTN_TRIGGER), + 289 => Some(OsCode::BTN_THUMB), + 290 => Some(OsCode::BTN_THUMB2), + 291 => Some(OsCode::BTN_TOP), + 292 => Some(OsCode::BTN_TOP2), + 293 => Some(OsCode::BTN_PINKIE), + 294 => Some(OsCode::BTN_BASE), + 295 => Some(OsCode::BTN_BASE2), + 296 => Some(OsCode::BTN_BASE3), + 297 => Some(OsCode::BTN_BASE4), + 298 => Some(OsCode::BTN_BASE5), + 299 => Some(OsCode::BTN_BASE6), + 300 => Some(OsCode::KEY_300), + 301 => Some(OsCode::KEY_301), + 302 => Some(OsCode::KEY_302), + 303 => Some(OsCode::BTN_DEAD), + 304 => Some(OsCode::BTN_SOUTH), + 305 => Some(OsCode::BTN_EAST), + 306 => Some(OsCode::BTN_C), + 307 => Some(OsCode::BTN_NORTH), + 308 => Some(OsCode::BTN_WEST), + 309 => Some(OsCode::BTN_Z), + 310 => Some(OsCode::BTN_TL), + 311 => Some(OsCode::BTN_TR), + 312 => Some(OsCode::BTN_TL2), + 313 => Some(OsCode::BTN_TR2), + 314 => Some(OsCode::BTN_SELECT), + 315 => Some(OsCode::BTN_START), + 316 => Some(OsCode::BTN_MODE), + 317 => Some(OsCode::BTN_THUMBL), + 318 => Some(OsCode::BTN_THUMBR), + 319 => Some(OsCode::KEY_319), + 320 => Some(OsCode::BTN_TOOL_PEN), + 321 => Some(OsCode::BTN_TOOL_RUBBER), + 322 => Some(OsCode::BTN_TOOL_BRUSH), + 323 => Some(OsCode::BTN_TOOL_PENCIL), + 324 => Some(OsCode::BTN_TOOL_AIRBRUSH), + 325 => Some(OsCode::BTN_TOOL_FINGER), + 326 => Some(OsCode::BTN_TOOL_MOUSE), + 327 => Some(OsCode::BTN_TOOL_LENS), + 328 => Some(OsCode::BTN_TOOL_QUINTTAP), + 329 => Some(OsCode::BTN_STYLUS3), + 330 => Some(OsCode::BTN_TOUCH), + 331 => Some(OsCode::BTN_STYLUS), + 332 => Some(OsCode::BTN_STYLUS2), + 333 => Some(OsCode::BTN_TOOL_DOUBLETAP), + 334 => Some(OsCode::BTN_TOOL_TRIPLETAP), + 335 => Some(OsCode::BTN_TOOL_QUADTAP), + 336 => Some(OsCode::BTN_GEAR_DOWN), + 337 => Some(OsCode::BTN_GEAR_UP), + 338 => Some(OsCode::KEY_338), + 339 => Some(OsCode::KEY_339), + 340 => Some(OsCode::KEY_340), + 341 => Some(OsCode::KEY_341), + 342 => Some(OsCode::KEY_342), + 343 => Some(OsCode::KEY_343), + 344 => Some(OsCode::KEY_344), + 345 => Some(OsCode::KEY_345), + 346 => Some(OsCode::KEY_346), + 347 => Some(OsCode::KEY_347), + 348 => Some(OsCode::KEY_348), + 349 => Some(OsCode::KEY_349), + 350 => Some(OsCode::KEY_350), + 351 => Some(OsCode::KEY_351), + 352 => Some(OsCode::KEY_OK), + 353 => Some(OsCode::KEY_SELECT), + 354 => Some(OsCode::KEY_GOTO), + 355 => Some(OsCode::KEY_CLEAR), + 356 => Some(OsCode::KEY_POWER2), + 357 => Some(OsCode::KEY_OPTION), + 358 => Some(OsCode::KEY_INFO), + 359 => Some(OsCode::KEY_TIME), + 360 => Some(OsCode::KEY_VENDOR), + 361 => Some(OsCode::KEY_ARCHIVE), + 362 => Some(OsCode::KEY_PROGRAM), + 363 => Some(OsCode::KEY_CHANNEL), + 364 => Some(OsCode::KEY_FAVORITES), + 365 => Some(OsCode::KEY_EPG), + 366 => Some(OsCode::KEY_PVR), + 367 => Some(OsCode::KEY_MHP), + 368 => Some(OsCode::KEY_LANGUAGE), + 369 => Some(OsCode::KEY_TITLE), + 370 => Some(OsCode::KEY_SUBTITLE), + 371 => Some(OsCode::KEY_ANGLE), + 372 => Some(OsCode::KEY_FULL_SCREEN), + 373 => Some(OsCode::KEY_MODE), + 374 => Some(OsCode::KEY_KEYBOARD), + 375 => Some(OsCode::KEY_ASPECT_RATIO), + 376 => Some(OsCode::KEY_PC), + 377 => Some(OsCode::KEY_TV), + 378 => Some(OsCode::KEY_TV2), + 379 => Some(OsCode::KEY_VCR), + 380 => Some(OsCode::KEY_VCR2), + 381 => Some(OsCode::KEY_SAT), + 382 => Some(OsCode::KEY_SAT2), + 383 => Some(OsCode::KEY_CD), + 384 => Some(OsCode::KEY_TAPE), + 385 => Some(OsCode::KEY_RADIO), + 386 => Some(OsCode::KEY_TUNER), + 387 => Some(OsCode::KEY_PLAYER), + 388 => Some(OsCode::KEY_TEXT), + 389 => Some(OsCode::KEY_DVD), + 390 => Some(OsCode::KEY_AUX), + 391 => Some(OsCode::KEY_MP3), + 392 => Some(OsCode::KEY_AUDIO), + 393 => Some(OsCode::KEY_VIDEO), + 394 => Some(OsCode::KEY_DIRECTORY), + 395 => Some(OsCode::KEY_LIST), + 396 => Some(OsCode::KEY_MEMO), + 397 => Some(OsCode::KEY_CALENDAR), + 398 => Some(OsCode::KEY_RED), + 399 => Some(OsCode::KEY_GREEN), + 400 => Some(OsCode::KEY_YELLOW), + 401 => Some(OsCode::KEY_BLUE), + 402 => Some(OsCode::KEY_CHANNELUP), + 403 => Some(OsCode::KEY_CHANNELDOWN), + 404 => Some(OsCode::KEY_FIRST), + 405 => Some(OsCode::KEY_LAST), + 406 => Some(OsCode::KEY_AB), + 407 => Some(OsCode::KEY_NEXT), + 408 => Some(OsCode::KEY_RESTART), + 409 => Some(OsCode::KEY_SLOW), + 410 => Some(OsCode::KEY_SHUFFLE), + 411 => Some(OsCode::KEY_BREAK), + 412 => Some(OsCode::KEY_PREVIOUS), + 413 => Some(OsCode::KEY_DIGITS), + 414 => Some(OsCode::KEY_TEEN), + 415 => Some(OsCode::KEY_TWEN), + 416 => Some(OsCode::KEY_VIDEOPHONE), + 417 => Some(OsCode::KEY_GAMES), + 418 => Some(OsCode::KEY_ZOOMIN), + 419 => Some(OsCode::KEY_ZOOMOUT), + 420 => Some(OsCode::KEY_ZOOMRESET), + 421 => Some(OsCode::KEY_WORDPROCESSOR), + 422 => Some(OsCode::KEY_EDITOR), + 423 => Some(OsCode::KEY_SPREADSHEET), + 424 => Some(OsCode::KEY_GRAPHICSEDITOR), + 425 => Some(OsCode::KEY_PRESENTATION), + 426 => Some(OsCode::KEY_DATABASE), + 427 => Some(OsCode::KEY_NEWS), + 428 => Some(OsCode::KEY_VOICEMAIL), + 429 => Some(OsCode::KEY_ADDRESSBOOK), + 430 => Some(OsCode::KEY_MESSENGER), + 431 => Some(OsCode::KEY_DISPLAYTOGGLE), + 432 => Some(OsCode::KEY_SPELLCHECK), + 433 => Some(OsCode::KEY_LOGOFF), + 434 => Some(OsCode::KEY_DOLLAR), + 435 => Some(OsCode::KEY_EURO), + 436 => Some(OsCode::KEY_FRAMEBACK), + 437 => Some(OsCode::KEY_FRAMEFORWARD), + 438 => Some(OsCode::KEY_CONTEXT_MENU), + 439 => Some(OsCode::KEY_MEDIA_REPEAT), + 440 => Some(OsCode::KEY_10CHANNELSUP), + 441 => Some(OsCode::KEY_10CHANNELSDOWN), + 442 => Some(OsCode::KEY_IMAGES), + 443 => Some(OsCode::KEY_443), + 444 => Some(OsCode::KEY_444), + 445 => Some(OsCode::KEY_445), + 446 => Some(OsCode::KEY_446), + 447 => Some(OsCode::KEY_447), + 448 => Some(OsCode::KEY_DEL_EOL), + 449 => Some(OsCode::KEY_DEL_EOS), + 450 => Some(OsCode::KEY_INS_LINE), + 451 => Some(OsCode::KEY_DEL_LINE), + 452 => Some(OsCode::KEY_452), + 453 => Some(OsCode::KEY_453), + 454 => Some(OsCode::KEY_454), + 455 => Some(OsCode::KEY_455), + 456 => Some(OsCode::KEY_456), + 457 => Some(OsCode::KEY_457), + 458 => Some(OsCode::KEY_458), + 459 => Some(OsCode::KEY_459), + 460 => Some(OsCode::KEY_460), + 461 => Some(OsCode::KEY_461), + 462 => Some(OsCode::KEY_462), + 463 => Some(OsCode::KEY_463), + 464 => Some(OsCode::KEY_FN), + 465 => Some(OsCode::KEY_FN_ESC), + 466 => Some(OsCode::KEY_FN_F1), + 467 => Some(OsCode::KEY_FN_F2), + 468 => Some(OsCode::KEY_FN_F3), + 469 => Some(OsCode::KEY_FN_F4), + 470 => Some(OsCode::KEY_FN_F5), + 471 => Some(OsCode::KEY_FN_F6), + 472 => Some(OsCode::KEY_FN_F7), + 473 => Some(OsCode::KEY_FN_F8), + 474 => Some(OsCode::KEY_FN_F9), + 475 => Some(OsCode::KEY_FN_F10), + 476 => Some(OsCode::KEY_FN_F11), + 477 => Some(OsCode::KEY_FN_F12), + 478 => Some(OsCode::KEY_FN_1), + 479 => Some(OsCode::KEY_FN_2), + 480 => Some(OsCode::KEY_FN_D), + 481 => Some(OsCode::KEY_FN_E), + 482 => Some(OsCode::KEY_FN_F), + 483 => Some(OsCode::KEY_FN_S), + 484 => Some(OsCode::KEY_FN_B), + 485 => Some(OsCode::KEY_485), + 486 => Some(OsCode::KEY_486), + 487 => Some(OsCode::KEY_487), + 488 => Some(OsCode::KEY_488), + 489 => Some(OsCode::KEY_489), + 490 => Some(OsCode::KEY_490), + 491 => Some(OsCode::KEY_491), + 492 => Some(OsCode::KEY_492), + 493 => Some(OsCode::KEY_493), + 494 => Some(OsCode::KEY_494), + 495 => Some(OsCode::KEY_495), + 496 => Some(OsCode::KEY_496), + 497 => Some(OsCode::KEY_BRL_DOT1), + 498 => Some(OsCode::KEY_BRL_DOT2), + 499 => Some(OsCode::KEY_BRL_DOT3), + 500 => Some(OsCode::KEY_BRL_DOT4), + 501 => Some(OsCode::KEY_BRL_DOT5), + 502 => Some(OsCode::KEY_BRL_DOT6), + 503 => Some(OsCode::KEY_BRL_DOT7), + 504 => Some(OsCode::KEY_BRL_DOT8), + 505 => Some(OsCode::KEY_BRL_DOT9), + 506 => Some(OsCode::KEY_BRL_DOT10), + 507 => Some(OsCode::KEY_507), + 508 => Some(OsCode::KEY_508), + 509 => Some(OsCode::KEY_509), + 510 => Some(OsCode::KEY_510), + 511 => Some(OsCode::KEY_511), + 512 => Some(OsCode::KEY_NUMERIC_0), + 513 => Some(OsCode::KEY_NUMERIC_1), + 514 => Some(OsCode::KEY_NUMERIC_2), + 515 => Some(OsCode::KEY_NUMERIC_3), + 516 => Some(OsCode::KEY_NUMERIC_4), + 517 => Some(OsCode::KEY_NUMERIC_5), + 518 => Some(OsCode::KEY_NUMERIC_6), + 519 => Some(OsCode::KEY_NUMERIC_7), + 520 => Some(OsCode::KEY_NUMERIC_8), + 521 => Some(OsCode::KEY_NUMERIC_9), + 522 => Some(OsCode::KEY_NUMERIC_STAR), + 523 => Some(OsCode::KEY_NUMERIC_POUND), + 524 => Some(OsCode::KEY_NUMERIC_A), + 525 => Some(OsCode::KEY_NUMERIC_B), + 526 => Some(OsCode::KEY_NUMERIC_C), + 527 => Some(OsCode::KEY_NUMERIC_D), + 528 => Some(OsCode::KEY_CAMERA_FOCUS), + 529 => Some(OsCode::KEY_WPS_BUTTON), + 530 => Some(OsCode::KEY_TOUCHPAD_TOGGLE), + 531 => Some(OsCode::KEY_TOUCHPAD_ON), + 532 => Some(OsCode::KEY_TOUCHPAD_OFF), + 533 => Some(OsCode::KEY_CAMERA_ZOOMIN), + 534 => Some(OsCode::KEY_CAMERA_ZOOMOUT), + 535 => Some(OsCode::KEY_CAMERA_UP), + 536 => Some(OsCode::KEY_CAMERA_DOWN), + 537 => Some(OsCode::KEY_CAMERA_LEFT), + 538 => Some(OsCode::KEY_CAMERA_RIGHT), + 539 => Some(OsCode::KEY_ATTENDANT_ON), + 540 => Some(OsCode::KEY_ATTENDANT_OFF), + 541 => Some(OsCode::KEY_ATTENDANT_TOGGLE), + 542 => Some(OsCode::KEY_LIGHTS_TOGGLE), + 543 => Some(OsCode::KEY_543), + 544 => Some(OsCode::BTN_DPAD_UP), + 545 => Some(OsCode::BTN_DPAD_DOWN), + 546 => Some(OsCode::BTN_DPAD_LEFT), + 547 => Some(OsCode::BTN_DPAD_RIGHT), + 548 => Some(OsCode::KEY_548), + 549 => Some(OsCode::KEY_549), + 550 => Some(OsCode::KEY_550), + 551 => Some(OsCode::KEY_551), + 552 => Some(OsCode::KEY_552), + 553 => Some(OsCode::KEY_553), + 554 => Some(OsCode::KEY_554), + 555 => Some(OsCode::KEY_555), + 556 => Some(OsCode::KEY_556), + 557 => Some(OsCode::KEY_557), + 558 => Some(OsCode::KEY_558), + 559 => Some(OsCode::KEY_559), + 560 => Some(OsCode::KEY_ALS_TOGGLE), + 561 => Some(OsCode::KEY_ROTATE_LOCK_TOGGLE), + 562 => Some(OsCode::KEY_562), + 563 => Some(OsCode::KEY_563), + 564 => Some(OsCode::KEY_564), + 565 => Some(OsCode::KEY_565), + 566 => Some(OsCode::KEY_566), + 567 => Some(OsCode::KEY_567), + 568 => Some(OsCode::KEY_568), + 569 => Some(OsCode::KEY_569), + 570 => Some(OsCode::KEY_570), + 571 => Some(OsCode::KEY_571), + 572 => Some(OsCode::KEY_572), + 573 => Some(OsCode::KEY_573), + 574 => Some(OsCode::KEY_574), + 575 => Some(OsCode::KEY_575), + 576 => Some(OsCode::KEY_BUTTONCONFIG), + 577 => Some(OsCode::KEY_TASKMANAGER), + 578 => Some(OsCode::KEY_JOURNAL), + 579 => Some(OsCode::KEY_CONTROLPANEL), + 580 => Some(OsCode::KEY_APPSELECT), + 581 => Some(OsCode::KEY_SCREENSAVER), + 582 => Some(OsCode::KEY_VOICECOMMAND), + 583 => Some(OsCode::KEY_ASSISTANT), + 584 => Some(OsCode::KEY_KBD_LAYOUT_NEXT), + 585 => Some(OsCode::KEY_585), + 586 => Some(OsCode::KEY_586), + 587 => Some(OsCode::KEY_587), + 588 => Some(OsCode::KEY_588), + 589 => Some(OsCode::KEY_589), + 590 => Some(OsCode::KEY_590), + 591 => Some(OsCode::KEY_591), + 592 => Some(OsCode::KEY_BRIGHTNESS_MIN), + 593 => Some(OsCode::KEY_BRIGHTNESS_MAX), + 594 => Some(OsCode::KEY_594), + 595 => Some(OsCode::KEY_595), + 596 => Some(OsCode::KEY_596), + 597 => Some(OsCode::KEY_597), + 598 => Some(OsCode::KEY_598), + 599 => Some(OsCode::KEY_599), + 600 => Some(OsCode::KEY_600), + 601 => Some(OsCode::KEY_601), + 602 => Some(OsCode::KEY_602), + 603 => Some(OsCode::KEY_603), + 604 => Some(OsCode::KEY_604), + 605 => Some(OsCode::KEY_605), + 606 => Some(OsCode::KEY_606), + 607 => Some(OsCode::KEY_607), + 608 => Some(OsCode::KEY_KBDINPUTASSIST_PREV), + 609 => Some(OsCode::KEY_KBDINPUTASSIST_NEXT), + 610 => Some(OsCode::KEY_KBDINPUTASSIST_PREVGROUP), + 611 => Some(OsCode::KEY_KBDINPUTASSIST_NEXTGROUP), + 612 => Some(OsCode::KEY_KBDINPUTASSIST_ACCEPT), + 613 => Some(OsCode::KEY_KBDINPUTASSIST_CANCEL), + 614 => Some(OsCode::KEY_RIGHT_UP), + 615 => Some(OsCode::KEY_RIGHT_DOWN), + 616 => Some(OsCode::KEY_LEFT_UP), + 617 => Some(OsCode::KEY_LEFT_DOWN), + 618 => Some(OsCode::KEY_ROOT_MENU), + 619 => Some(OsCode::KEY_MEDIA_TOP_MENU), + 620 => Some(OsCode::KEY_NUMERIC_11), + 621 => Some(OsCode::KEY_NUMERIC_12), + 622 => Some(OsCode::KEY_AUDIO_DESC), + 623 => Some(OsCode::KEY_3D_MODE), + 624 => Some(OsCode::KEY_NEXT_FAVORITE), + 625 => Some(OsCode::KEY_STOP_RECORD), + 626 => Some(OsCode::KEY_PAUSE_RECORD), + 627 => Some(OsCode::KEY_VOD), + 628 => Some(OsCode::KEY_UNMUTE), + 629 => Some(OsCode::KEY_FASTREVERSE), + 630 => Some(OsCode::KEY_SLOWREVERSE), + 631 => Some(OsCode::KEY_DATA), + 632 => Some(OsCode::KEY_ONSCREEN_KEYBOARD), + 633 => Some(OsCode::KEY_633), + 634 => Some(OsCode::KEY_634), + 635 => Some(OsCode::KEY_635), + 636 => Some(OsCode::KEY_636), + 637 => Some(OsCode::KEY_637), + 638 => Some(OsCode::KEY_638), + 639 => Some(OsCode::KEY_639), + 640 => Some(OsCode::KEY_640), + 641 => Some(OsCode::KEY_641), + 642 => Some(OsCode::KEY_642), + 643 => Some(OsCode::KEY_643), + 644 => Some(OsCode::KEY_644), + 645 => Some(OsCode::KEY_645), + 646 => Some(OsCode::KEY_646), + 647 => Some(OsCode::KEY_647), + 648 => Some(OsCode::KEY_648), + 649 => Some(OsCode::KEY_649), + 650 => Some(OsCode::KEY_650), + 651 => Some(OsCode::KEY_651), + 652 => Some(OsCode::KEY_652), + 653 => Some(OsCode::KEY_653), + 654 => Some(OsCode::KEY_654), + 655 => Some(OsCode::KEY_655), + 656 => Some(OsCode::KEY_656), + 657 => Some(OsCode::KEY_657), + 658 => Some(OsCode::KEY_658), + 659 => Some(OsCode::KEY_659), + 660 => Some(OsCode::KEY_660), + 661 => Some(OsCode::KEY_661), + 662 => Some(OsCode::KEY_662), + 663 => Some(OsCode::KEY_663), + 664 => Some(OsCode::KEY_664), + 665 => Some(OsCode::KEY_665), + 666 => Some(OsCode::KEY_666), + 667 => Some(OsCode::KEY_667), + 668 => Some(OsCode::KEY_668), + 669 => Some(OsCode::KEY_669), + 670 => Some(OsCode::KEY_670), + 671 => Some(OsCode::KEY_671), + 672 => Some(OsCode::KEY_672), + 673 => Some(OsCode::KEY_673), + 674 => Some(OsCode::KEY_674), + 675 => Some(OsCode::KEY_675), + 676 => Some(OsCode::KEY_676), + 677 => Some(OsCode::KEY_677), + 678 => Some(OsCode::KEY_678), + 679 => Some(OsCode::KEY_679), + 680 => Some(OsCode::KEY_680), + 681 => Some(OsCode::KEY_681), + 682 => Some(OsCode::KEY_682), + 683 => Some(OsCode::KEY_683), + 684 => Some(OsCode::KEY_684), + 685 => Some(OsCode::KEY_685), + 686 => Some(OsCode::KEY_686), + 687 => Some(OsCode::KEY_687), + 688 => Some(OsCode::KEY_688), + 689 => Some(OsCode::KEY_689), + 690 => Some(OsCode::KEY_690), + 691 => Some(OsCode::KEY_691), + 692 => Some(OsCode::KEY_692), + 693 => Some(OsCode::KEY_693), + 694 => Some(OsCode::KEY_694), + 695 => Some(OsCode::KEY_695), + 696 => Some(OsCode::KEY_696), + 697 => Some(OsCode::KEY_697), + 698 => Some(OsCode::KEY_698), + 699 => Some(OsCode::KEY_699), + 700 => Some(OsCode::KEY_700), + 701 => Some(OsCode::KEY_701), + 702 => Some(OsCode::KEY_702), + 703 => Some(OsCode::KEY_703), + 704 => Some(OsCode::BTN_TRIGGER_HAPPY1), + 705 => Some(OsCode::BTN_TRIGGER_HAPPY2), + 706 => Some(OsCode::BTN_TRIGGER_HAPPY3), + 707 => Some(OsCode::BTN_TRIGGER_HAPPY4), + 708 => Some(OsCode::BTN_TRIGGER_HAPPY5), + 709 => Some(OsCode::BTN_TRIGGER_HAPPY6), + 710 => Some(OsCode::BTN_TRIGGER_HAPPY7), + 711 => Some(OsCode::BTN_TRIGGER_HAPPY8), + 712 => Some(OsCode::BTN_TRIGGER_HAPPY9), + 713 => Some(OsCode::BTN_TRIGGER_HAPPY10), + 714 => Some(OsCode::BTN_TRIGGER_HAPPY11), + 715 => Some(OsCode::BTN_TRIGGER_HAPPY12), + 716 => Some(OsCode::BTN_TRIGGER_HAPPY13), + 717 => Some(OsCode::BTN_TRIGGER_HAPPY14), + 718 => Some(OsCode::BTN_TRIGGER_HAPPY15), + 719 => Some(OsCode::BTN_TRIGGER_HAPPY16), + 720 => Some(OsCode::BTN_TRIGGER_HAPPY17), + 721 => Some(OsCode::BTN_TRIGGER_HAPPY18), + 722 => Some(OsCode::BTN_TRIGGER_HAPPY19), + 723 => Some(OsCode::BTN_TRIGGER_HAPPY20), + 724 => Some(OsCode::BTN_TRIGGER_HAPPY21), + 725 => Some(OsCode::BTN_TRIGGER_HAPPY22), + 726 => Some(OsCode::BTN_TRIGGER_HAPPY23), + 727 => Some(OsCode::BTN_TRIGGER_HAPPY24), + 728 => Some(OsCode::BTN_TRIGGER_HAPPY25), + 729 => Some(OsCode::BTN_TRIGGER_HAPPY26), + 730 => Some(OsCode::BTN_TRIGGER_HAPPY27), + 731 => Some(OsCode::BTN_TRIGGER_HAPPY28), + 732 => Some(OsCode::BTN_TRIGGER_HAPPY29), + 733 => Some(OsCode::BTN_TRIGGER_HAPPY30), + 734 => Some(OsCode::BTN_TRIGGER_HAPPY31), + 735 => Some(OsCode::BTN_TRIGGER_HAPPY32), + 736 => Some(OsCode::BTN_TRIGGER_HAPPY33), + 737 => Some(OsCode::BTN_TRIGGER_HAPPY34), + 738 => Some(OsCode::BTN_TRIGGER_HAPPY35), + 739 => Some(OsCode::BTN_TRIGGER_HAPPY36), + 740 => Some(OsCode::BTN_TRIGGER_HAPPY37), + 741 => Some(OsCode::BTN_TRIGGER_HAPPY38), + 742 => Some(OsCode::BTN_TRIGGER_HAPPY39), + 743 => Some(OsCode::BTN_TRIGGER_HAPPY40), + 744 => Some(OsCode::BTN_MAX), + 767 => Some(OsCode::KEY_MAX), + _ => None, + } + } +} diff --git a/parser/src/keys/mod.rs b/parser/src/keys/mod.rs index 351f32352..97f66986e 100644 --- a/parser/src/keys/mod.rs +++ b/parser/src/keys/mod.rs @@ -7,8 +7,12 @@ use rustc_hash::FxHashMap as HashMap; #[cfg(any(target_os = "linux", target_os = "unknown"))] mod linux; +#[cfg(any(target_os = "macos", target_os = "unknown"))] +mod macos; #[cfg(any(target_os = "windows", target_os = "unknown"))] mod windows; +#[cfg(any(target_os = "macos", target_os = "unknown"))] +pub use macos::PageCode; mod mappings; pub use mappings::*; @@ -18,6 +22,7 @@ pub use mappings::*; pub enum Platform { Win, Linux, + Macos, } #[cfg(target_os = "unknown")] @@ -29,6 +34,7 @@ impl OsCode { return match *OSCODE_MAPPING_VARIANT.lock() { Platform::Win => self.as_u16_windows(), Platform::Linux => self.as_u16_linux(), + Platform::Macos => self.as_u16_macos(), }; #[cfg(target_os = "linux")] @@ -36,6 +42,9 @@ impl OsCode { #[cfg(target_os = "windows")] return self.as_u16_windows(); + + #[cfg(target_os = "macos")] + return self.as_u16_macos(); } pub fn from_u16(code: u16) -> Option { @@ -43,6 +52,7 @@ impl OsCode { return match *OSCODE_MAPPING_VARIANT.lock() { Platform::Win => OsCode::from_u16_windows(code), Platform::Linux => OsCode::from_u16_linux(code), + Platform::Macos => OsCode::from_u16_macos(code), }; #[cfg(target_os = "linux")] @@ -50,6 +60,9 @@ impl OsCode { #[cfg(target_os = "windows")] return OsCode::from_u16_windows(code); + + #[cfg(target_os = "macos")] + return OsCode::from_u16_macos(code); } } @@ -254,6 +267,8 @@ pub fn str_to_oscode(s: &str) -> Option { "f22" => OsCode::KEY_F22, "f23" => OsCode::KEY_F23, "f24" => OsCode::KEY_F24, + #[cfg(any(target_os = "macos", target_os = "unknown"))] + "fn" => OsCode::KEY_FN, #[cfg(target_os = "windows")] "kana" | "katakana" | "katakanahiragana" => OsCode::KEY_HANGEUL, #[cfg(any(target_os = "linux", target_os = "unknown"))] diff --git a/src/kanata/macos.rs b/src/kanata/macos.rs new file mode 100644 index 000000000..a9e97051f --- /dev/null +++ b/src/kanata/macos.rs @@ -0,0 +1,75 @@ +use super::*; +use anyhow::{anyhow, bail, Result}; +use log::info; +use parking_lot::Mutex; +use std::convert::TryFrom; +use std::sync::mpsc::SyncSender as Sender; +use std::sync::Arc; + +static PRESSED_KEYS: Lazy>> = Lazy::new(|| Mutex::new(HashSet::default())); + +impl Kanata { + /// Enter an infinite loop that listens for OS key events and sends them to the processing thread. + pub fn event_loop(kanata: Arc>, tx: Sender) -> Result<()> { + info!("entering the event loop"); + + let k = kanata.lock(); + let mut kb = match KbdIn::new(k.include_names.clone()) { + Ok(kbd_in) => kbd_in, + Err(e) => bail!("failed to open keyboard device(s): {}", e), + }; + drop(k); + + loop { + let event = kb.read().map_err(|e| anyhow!("failed read: {}", e))?; + + let mut key_event = match KeyEvent::try_from(event) { + Ok(ev) => ev, + _ => { + // Pass-through unrecognized keys + log::debug!("{event:?} is unrecognized!"); + let mut kanata = kanata.lock(); + kanata + .kbd_out + .write(event.clone()) + .map_err(|e| anyhow!("failed write: {}", e))?; + continue; + } + }; + + check_for_exit(&key_event); + + if !MAPPED_KEYS.lock().contains(&key_event.code) { + log::debug!("{key_event:?} is not mapped"); + let mut kanata = kanata.lock(); + kanata + .kbd_out + .write(event.clone()) + .map_err(|e| anyhow!("failed write: {}", e))?; + continue; + } + + log::debug!("sending {key_event:?} to processing loop"); + + match key_event.value { + KeyValue::Release => { + PRESSED_KEYS.lock().remove(&key_event.code); + } + KeyValue::Press => { + let mut pressed_keys = PRESSED_KEYS.lock(); + if pressed_keys.contains(&key_event.code) { + key_event.value = KeyValue::Repeat; + } else { + pressed_keys.insert(key_event.code); + } + } + _ => {} + } + tx.try_send(key_event)?; + } + } + + pub fn check_release_non_physical_shift(&mut self) -> Result<()> { + Ok(()) + } +} diff --git a/src/kanata/mod.rs b/src/kanata/mod.rs index 2c157f7b5..ff56cdc02 100644 --- a/src/kanata/mod.rs +++ b/src/kanata/mod.rs @@ -39,6 +39,11 @@ mod linux; #[cfg(target_os = "linux")] pub use linux::*; +#[cfg(target_os = "macos")] +mod macos; +#[cfg(target_os = "macos")] +pub use macos::*; + mod caps_word; pub use caps_word::*; @@ -121,8 +126,8 @@ pub struct Kanata { #[cfg(target_os = "linux")] /// Tracks the Linux user configuration to continue or abort if no devices are found. continue_if_no_devices: bool, - #[cfg(target_os = "linux")] - /// Tracks the Linux user configuration for device names (instead of paths) that should be + #[cfg(any(target_os = "linux", target_os = "macos"))] + /// Tracks the Linux/Macos user configuration for device names (instead of paths) that should be /// included for interception and processing by kanata. pub include_names: Option>, #[cfg(target_os = "linux")] @@ -319,6 +324,8 @@ impl Kanata { live_reload_requested: false, overrides: cfg.overrides, override_states: OverrideStates::new(), + #[cfg(target_os = "macos")] + include_names: cfg.items.macos_dev_names_include, #[cfg(target_os = "linux")] kbd_in_paths: cfg.items.linux_dev, #[cfg(target_os = "linux")] diff --git a/src/main.rs b/src/main.rs index d986d2977..3eac3dd5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -90,6 +90,10 @@ kanata.kbd in the current working directory and #[arg(short, long, verbatim_doc_comment)] symlink_path: Option, + #[cfg_attr(target_os = "macos", doc = "List the keyboards available for grabbing")] + #[arg(short, long)] + list: bool, + /// Enable debug logging. #[arg(short, long)] debug: bool, @@ -108,6 +112,12 @@ kanata.kbd in the current working directory and fn cli_init() -> Result { let args = Args::parse(); + #[cfg(target_os = "macos")] + if args.list { + karabiner_driverkit::list_keyboards(); + std::process::exit(0); + } + let cfg_paths = args.cfg.unwrap_or_else(default_cfg); let log_lvl = match (args.debug, args.trace) { diff --git a/src/oskbd/macos.rs b/src/oskbd/macos.rs new file mode 100644 index 000000000..40962e521 --- /dev/null +++ b/src/oskbd/macos.rs @@ -0,0 +1,228 @@ +//! Contains the input/output code for keyboards on Macos. +use super::*; +use crate::kanata::CalculatedMouseMove; +use crate::oskbd::KeyEvent; +use anyhow::anyhow; +use kanata_parser::custom_action::*; +use kanata_parser::keys::*; +use karabiner_driverkit::*; +use std::convert::TryFrom; +use std::io; + +pub const HI_RES_SCROLL_UNITS_IN_LO_RES: u16 = 120; + +#[derive(Debug, Clone, Copy)] +pub struct InputEvent { + value: u64, + page: u32, + code: u32, +} + +impl InputEvent { + pub fn new(event: DKEvent) -> Self { + InputEvent { + value: event.value, + page: event.page, + code: event.code, + } + } +} + +impl From for DKEvent { + fn from(event: InputEvent) -> Self { + Self { + value: event.value, + page: event.page, + code: event.code, + } + } +} + +pub struct KbdIn {} + +impl Drop for KbdIn { + fn drop(&mut self) { + release(); + } +} + +impl KbdIn { + pub fn new(include_names: Option>) -> Result { + if !driver_activated() { + return Err(anyhow!( + "Karabiner-VirtualHIDDevice driver is not activated." + )); + } + + let device_names = if include_names.is_some() { + validate_and_register_devices(include_names.unwrap()) + } else { + vec![] + }; + + if !device_names.is_empty() || register_device("") { + if grab() { + Ok(Self {}) + } else { + Err(anyhow!("grab failed")) + } + } else { + Err(anyhow!("Couldn't register any device")) + } + } + + pub fn read(&mut self) -> Result { + let mut event = DKEvent { + value: 0, + page: 0, + code: 0, + }; + + wait_key(&mut event); + + Ok(InputEvent::new(event)) + } +} + +fn validate_and_register_devices(include_names: Vec) -> Vec { + include_names + .iter() + .filter_map(|dev| match device_matches(dev) { + true => Some(dev.to_string()), + false => { + log::warn!("Not a valid device name '{dev}'"); + None + } + }) + .filter_map(|dev| { + if register_device(&dev) { + Some(dev.to_string()) + } else { + log::warn!("Couldn't register device '{dev}'"); + None + } + }) + .collect() +} + +impl TryFrom for KeyEvent { + type Error = (); + + fn try_from(item: InputEvent) -> Result { + if let Ok(oscode) = OsCode::try_from(PageCode { + page: item.page, + code: item.code, + }) { + Ok(KeyEvent { + code: oscode, + value: if item.value == 1 { + KeyValue::Press + } else { + KeyValue::Release + }, + }) + } else { + Err(()) + } + } +} + +impl TryFrom for InputEvent { + type Error = (); + + fn try_from(item: KeyEvent) -> Result { + if let Ok(pagecode) = PageCode::try_from(item.code) { + let val = match item.value { + KeyValue::Press => 1, + _ => 0, + }; + Ok(InputEvent { + value: val, + page: pagecode.page, + code: pagecode.code, + }) + } else { + Err(()) + } + } +} + +pub struct KbdOut {} + +impl KbdOut { + pub fn new() -> Result { + Ok(KbdOut {}) + } + + pub fn write(&mut self, event: InputEvent) -> Result<(), io::Error> { + let mut devent = event.into(); + log::debug!("Attempting to write {event:?} {devent:?}"); + let _sent = send_key(&mut devent); + Ok(()) + } + + pub fn write_key(&mut self, key: OsCode, value: KeyValue) -> Result<(), io::Error> { + if let Ok(event) = InputEvent::try_from(KeyEvent { value, code: key }) { + self.write(event) + } else { + log::debug!("couldn't write unrecognized {key:?}"); + Err(io::Error::new( + io::ErrorKind::NotFound, + "OsCode not recognized!", + )) + } + } + + pub fn write_code(&mut self, code: u32, value: KeyValue) -> Result<(), io::Error> { + if let Ok(event) = InputEvent::try_from(KeyEvent { + value, + code: OsCode::from_u16(code as u16).unwrap(), + }) { + self.write(event) + } else { + log::debug!("couldn't write unrecognized OsCode {code}"); + Err(io::Error::new( + io::ErrorKind::NotFound, + "OsCode not recognized!", + )) + } + } + + pub fn press_key(&mut self, key: OsCode) -> Result<(), io::Error> { + self.write_key(key, KeyValue::Press) + } + + pub fn release_key(&mut self, key: OsCode) -> Result<(), io::Error> { + self.write_key(key, KeyValue::Release) + } + + /// Send using C-S-u + + spc + pub fn send_unicode(&mut self, c: char) -> Result<(), io::Error> { + log::error!("Unable to send unicode {c}, unsupported functionality"); + todo!() + } + + pub fn scroll(&mut self, _direction: MWheelDirection, _distance: u16) -> Result<(), io::Error> { + panic!("Mouse is not supported yet on Macos") + } + + pub fn click_btn(&mut self, _btn: Btn) -> Result<(), io::Error> { + panic!("Mouse is not supported yet on Macos") + } + + pub fn release_btn(&mut self, _btn: Btn) -> Result<(), io::Error> { + panic!("Mouse is not supported yet on Macos") + } + + pub fn move_mouse(&mut self, _mv: CalculatedMouseMove) -> Result<(), io::Error> { + panic!("Mouse is not supported yet on Macos") + } + + pub fn move_mouse_many(&mut self, _moves: &[CalculatedMouseMove]) -> Result<(), io::Error> { + panic!("Mouse is not supported yet on Macos") + } + + pub fn set_mouse(&mut self, _x: u16, _y: u16) -> Result<(), io::Error> { + panic!("Mouse is not supported yet on Macos") + } +} diff --git a/src/oskbd/mod.rs b/src/oskbd/mod.rs index 05664ac1c..406a25a67 100644 --- a/src/oskbd/mod.rs +++ b/src/oskbd/mod.rs @@ -10,6 +10,11 @@ mod windows; #[cfg(target_os = "windows")] pub use windows::*; +#[cfg(target_os = "macos")] +mod macos; +#[cfg(target_os = "macos")] +pub use macos::*; + // ------------------ KeyValue -------------------- #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -55,6 +60,7 @@ pub struct KeyEvent { } #[cfg(not(all(feature = "interception_driver", target_os = "windows")))] +#[cfg(not(target_os = "macos"))] impl KeyEvent { pub fn new(code: OsCode, value: KeyValue) -> Self { Self { code, value }