diff --git a/src/linux/wayland/grab.rs b/src/linux/wayland/grab.rs index abcd4ee5..2bb49095 100644 --- a/src/linux/wayland/grab.rs +++ b/src/linux/wayland/grab.rs @@ -213,6 +213,18 @@ convert_keys!( KEY_F8, F8, KEY_F9, F9, KEY_F10, F10, + KEY_F13, F13, + KEY_F14, F14, + KEY_F15, F15, + KEY_F16, F16, + KEY_F17, F17, + KEY_F18, F18, + KEY_F19, F19, + KEY_F20, F20, + KEY_F21, F21, + KEY_F22, F22, + KEY_F23, F23, + KEY_F24, F24, KEY_NUMLOCK, NumLock, KEY_SCROLLLOCK, ScrollLock, KEY_KP7, Kp7, diff --git a/src/linux/wayland/keycodes.rs b/src/linux/wayland/keycodes.rs index 59a939dc..5666b1b2 100644 --- a/src/linux/wayland/keycodes.rs +++ b/src/linux/wayland/keycodes.rs @@ -73,6 +73,18 @@ decl_keycodes!( F10, 68, F11, 87, F12, 88, + F13, 183, + F14, 184, + F15, 185, + F16, 186, + F17, 187, + F18, 188, + F19, 189, + F20, 190, + F21, 191, + F22, 192, + F23, 193, + F24, 194, Home, 102, LeftArrow, 105, MetaLeft, 125, @@ -234,6 +246,18 @@ decl_keycodes_uinput!( Key::F8 , UKey::F8, Key::F9 , UKey::F9, Key::F10 , UKey::F10, + Key::F13 , UKey::F13, + Key::F14 , UKey::F14, + Key::F15 , UKey::F15, + Key::F16 , UKey::F16, + Key::F17 , UKey::F17, + Key::F18 , UKey::F18, + Key::F19 , UKey::F19, + Key::F20 , UKey::F20, + Key::F21 , UKey::F21, + Key::F22 , UKey::F22, + Key::F23 , UKey::F23, + Key::F24 , UKey::F24, Key::NumLock , UKey::NumLock, Key::ScrollLock , UKey::ScrollLock, Key::Kp7 , UKey::Kp7, @@ -281,6 +305,8 @@ decl_keycodes_uinput!( #[cfg(test)] mod test { use super::{UKey, code_from_key, key_from_code, key_from_ukey, ukey_from_key}; + use crate::Key; + #[test] fn test_reversible() { for code in 0..65636 { @@ -292,6 +318,31 @@ mod test { } } + #[test] + fn test_extended_function_key_mappings() { + let mappings = [ + (Key::F13, 183, UKey::F13), + (Key::F14, 184, UKey::F14), + (Key::F15, 185, UKey::F15), + (Key::F16, 186, UKey::F16), + (Key::F17, 187, UKey::F17), + (Key::F18, 188, UKey::F18), + (Key::F19, 189, UKey::F19), + (Key::F20, 190, UKey::F20), + (Key::F21, 191, UKey::F21), + (Key::F22, 192, UKey::F22), + (Key::F23, 193, UKey::F23), + (Key::F24, 194, UKey::F24), + ]; + + for (key, code, ukey) in mappings { + assert_eq!(code_from_key(key), Some(code)); + assert_eq!(key_from_code(code), key); + assert_eq!(ukey_from_key(key), Some(ukey)); + assert_eq!(key_from_ukey(ukey), key); + } + } + #[test] fn test_reversible_uinput() { for code in 0..u16::MAX { diff --git a/src/linux/x11/grab.rs b/src/linux/x11/grab.rs index d59144ce..1e331285 100644 --- a/src/linux/x11/grab.rs +++ b/src/linux/x11/grab.rs @@ -148,6 +148,18 @@ convert_keys!( KEY_F8, F8, KEY_F9, F9, KEY_F10, F10, + KEY_F13, F13, + KEY_F14, F14, + KEY_F15, F15, + KEY_F16, F16, + KEY_F17, F17, + KEY_F18, F18, + KEY_F19, F19, + KEY_F20, F20, + KEY_F21, F21, + KEY_F22, F22, + KEY_F23, F23, + KEY_F24, F24, KEY_NUMLOCK, NumLock, KEY_SCROLLLOCK, ScrollLock, KEY_KP7, Kp7, diff --git a/src/linux/x11/keycodes.rs b/src/linux/x11/keycodes.rs index 85adecf3..e44bc7e7 100644 --- a/src/linux/x11/keycodes.rs +++ b/src/linux/x11/keycodes.rs @@ -42,6 +42,18 @@ decl_keycodes!( F10, 76, F11, 95, F12, 96, + F13, 191, + F14, 192, + F15, 193, + F16, 194, + F17, 195, + F18, 196, + F19, 197, + F20, 198, + F21, 199, + F22, 200, + F23, 201, + F24, 202, F2, 68, F3, 69, F4, 70, @@ -136,6 +148,8 @@ decl_keycodes!( #[cfg(test)] mod test { use super::{code_from_key, key_from_code}; + use crate::Key; + #[test] fn test_reversible() { for code in 0..65636 { @@ -146,4 +160,27 @@ mod test { } } } + + #[test] + fn test_extended_function_key_mappings() { + let mappings = [ + (Key::F13, 191), + (Key::F14, 192), + (Key::F15, 193), + (Key::F16, 194), + (Key::F17, 195), + (Key::F18, 196), + (Key::F19, 197), + (Key::F20, 198), + (Key::F21, 199), + (Key::F22, 200), + (Key::F23, 201), + (Key::F24, 202), + ]; + + for (key, code) in mappings { + assert_eq!(code_from_key(key), Some(code)); + assert_eq!(key_from_code(code), key); + } + } } diff --git a/src/macos/common.rs b/src/macos/common.rs index f882ca6d..d4448669 100644 --- a/src/macos/common.rs +++ b/src/macos/common.rs @@ -8,7 +8,7 @@ use std::convert::TryInto; use std::sync::Mutex; use std::time::SystemTime; -use crate::macos::keycodes::key_from_code; +use crate::macos::keycodes::key_from_code_or_name; use super::keycodes::key_from_special_key; @@ -60,7 +60,9 @@ pub unsafe fn convert( Some(cg_event.as_ref()), CGEventField::KeyboardEventKeycode, ); - let key = key_from_code(code.try_into().ok()?); + let flags = CGEvent::flags(Some(cg_event.as_ref())); + let name = keyboard_state.create_string_for_key(code, flags); + let key = key_from_code_or_name(code.try_into().ok()?, name.as_deref()); Some(EventType::KeyPress(key)) } CGEventType::KeyUp => { @@ -68,7 +70,9 @@ pub unsafe fn convert( Some(cg_event.as_ref()), CGEventField::KeyboardEventKeycode, ); - let key = key_from_code(code.try_into().ok()?); + let flags = CGEvent::flags(Some(cg_event.as_ref())); + let name = keyboard_state.create_string_for_key(code, flags); + let key = key_from_code_or_name(code.try_into().ok()?, name.as_deref()); Some(EventType::KeyRelease(key)) } CGEventType::FlagsChanged => { @@ -78,7 +82,7 @@ pub unsafe fn convert( ); let code = code.try_into().ok()?; let flags = CGEvent::flags(Some(cg_event.as_ref())); - let key = key_from_code(code); + let key = key_from_code_or_name(code, None); // Determine if this is a press or release based on flag changes let mut global_flags = LAST_FLAGS.lock().unwrap(); diff --git a/src/macos/keycodes.rs b/src/macos/keycodes.rs index 2f102bb1..d773c510 100644 --- a/src/macos/keycodes.rs +++ b/src/macos/keycodes.rs @@ -17,6 +17,14 @@ const F1: CGKeyCode = 122; const F10: CGKeyCode = 109; const F11: CGKeyCode = 103; const F12: CGKeyCode = 111; +const F13: CGKeyCode = 105; +const F14: CGKeyCode = 107; +const F15: CGKeyCode = 113; +const F16: CGKeyCode = 106; +const F17: CGKeyCode = 64; +const F18: CGKeyCode = 79; +const F19: CGKeyCode = 80; +const F20: CGKeyCode = 90; const F2: CGKeyCode = 120; const F3: CGKeyCode = 99; const F4: CGKeyCode = 118; @@ -98,6 +106,14 @@ pub fn code_from_key(key: Key) -> Option { Key::F10 => Some(F10), Key::F11 => Some(F11), Key::F12 => Some(F12), + Key::F13 => Some(F13), + Key::F14 => Some(F14), + Key::F15 => Some(F15), + Key::F16 => Some(F16), + Key::F17 => Some(F17), + Key::F18 => Some(F18), + Key::F19 => Some(F19), + Key::F20 => Some(F20), Key::F2 => Some(F2), Key::F3 => Some(F3), Key::F4 => Some(F4), @@ -182,6 +198,14 @@ pub fn key_from_code(code: CGKeyCode) -> Key { F10 => Key::F10, F11 => Key::F11, F12 => Key::F12, + F13 => Key::F13, + F14 => Key::F14, + F15 => Key::F15, + F16 => Key::F16, + F17 => Key::F17, + F18 => Key::F18, + F19 => Key::F19, + F20 => Key::F20, F2 => Key::F2, F3 => Key::F3, F4 => Key::F4, @@ -252,6 +276,28 @@ pub fn key_from_code(code: CGKeyCode) -> Key { } } +pub fn key_from_code_or_name(code: CGKeyCode, name: Option<&str>) -> Key { + let key = key_from_code(code); + if !matches!(key, Key::Unknown(_)) { + return key; + } + + match name.and_then(extra_function_key_from_name) { + Some(key) => key, + None => key, + } +} + +fn extra_function_key_from_name(name: &str) -> Option { + match name.encode_utf16().next() { + Some(0xf718) => Some(Key::F21), + Some(0xf719) => Some(Key::F22), + Some(0xf71a) => Some(Key::F23), + Some(0xf71b) => Some(Key::F24), + _ => None, + } +} + //https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-308/IOHIDSystem/IOKit/hidsystem/ev_keymap.h // https://github.com/acidanthera/MacKernelSDK/blob/master/Headers/IOKit/hidsystem/ev_keymap.h @@ -330,7 +376,9 @@ pub fn key_from_special_key(code: u32) -> Option { #[cfg(test)] mod test { - use super::{code_from_key, key_from_code}; + use super::{code_from_key, key_from_code, key_from_code_or_name}; + use crate::Key; + #[test] fn test_reversible() { for code in 0..=65535 { @@ -341,4 +389,36 @@ mod test { } } } + + #[test] + fn test_extended_function_key_mappings() { + let mappings = [ + (Key::F13, 105), + (Key::F14, 107), + (Key::F15, 113), + (Key::F16, 106), + (Key::F17, 64), + (Key::F18, 79), + (Key::F19, 80), + (Key::F20, 90), + ]; + + for (key, code) in mappings { + assert_eq!(code_from_key(key), Some(code)); + assert_eq!(key_from_code(code), key); + } + + assert_eq!(code_from_key(Key::F21), None); + assert_eq!(code_from_key(Key::F22), None); + assert_eq!(code_from_key(Key::F23), None); + assert_eq!(code_from_key(Key::F24), None); + } + + #[test] + fn test_extended_function_key_name_fallback() { + assert_eq!(key_from_code_or_name(0x6c, Some("\u{f718}")), Key::F21); + assert_eq!(key_from_code_or_name(0x6e, Some("\u{f719}")), Key::F22); + assert_eq!(key_from_code_or_name(0x70, Some("\u{f71a}")), Key::F23); + assert_eq!(key_from_code_or_name(0x5e, Some("\u{f71b}")), Key::F24); + } }