From 3f886a1139f09b67e78173cb52e92105578e9e09 Mon Sep 17 00:00:00 2001 From: Jonathan <1808569+jonatino@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:58:23 -0400 Subject: [PATCH 1/5] add support for listening to "special keys" on macos (media keys etc) --- Cargo.toml | 8 +++--- src/macos/common.rs | 27 ++++++++++++++++++-- src/macos/grab.rs | 13 +++++++--- src/macos/keycodes.rs | 59 +++++++++++++++++++++++++++++++++++++++++++ src/rdev.rs | 9 +++++++ 5 files changed, 106 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6f378640..e6c2627e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,10 +22,10 @@ serialize = ["serde"] unstable_grab = ["evdev-rs", "epoll", "inotify"] [target.'cfg(target_os = "macos")'.dependencies] -cocoa = "0.22" -core-graphics = {version = "0.19.0", features = ["highsierra"]} -core-foundation = {version = "0.7"} -core-foundation-sys = {version = "0.7"} +cocoa = "0.26.0" +core-graphics = {version = "0.24.0", features = ["highsierra"] } +core-foundation = {version = "0.10.0" } +core-foundation-sys = {version = "0.8.7" } [target.'cfg(target_os = "linux")'.dependencies] diff --git a/src/macos/common.rs b/src/macos/common.rs index 6c837ab0..4302c2d3 100644 --- a/src/macos/common.rs +++ b/src/macos/common.rs @@ -9,7 +9,7 @@ use std::os::raw::c_void; use std::sync::Mutex; use std::time::SystemTime; -use crate::macos::keycodes::key_from_code; +use crate::macos::keycodes::{key_from_code, key_from_special_key}; pub type CFMachPortRef = *const c_void; pub type CFIndex = u64; @@ -135,7 +135,30 @@ pub unsafe fn convert( cg_event.get_integer_value_field(EventField::SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2); Some(EventType::Wheel { delta_x, delta_y }) } - _ => None, + o => { + // Core graphics doesnt support NX_SYSDEFINED yet + let int_type = o as u32; + + const NX_SYSDEFINED: u32 = 14; + + if int_type == NX_SYSDEFINED { + let data1 = cg_event.get_integer_value_field(149); + let key_flags = data1 & 0x0000ffff; + let key_pressed = ((key_flags & 0xff00) >> 8) == 0xa; + let _key_repeat = (key_flags & 0x1) == 0x1; + let key_code = (data1 & 0xffff0000) >> 16; + + let code = key_from_special_key(key_code.try_into().ok()?); + if key_pressed { + Some(EventType::KeyPress(code)) + } else { + Some(EventType::KeyRelease(code)) + } + } else { + println!("Unknown event type: {:?}", o as i32); + None + } + } }; if let Some(event_type) = option_type { let name = match event_type { diff --git a/src/macos/grab.rs b/src/macos/grab.rs index dd8de0fd..4807c63e 100644 --- a/src/macos/grab.rs +++ b/src/macos/grab.rs @@ -39,24 +39,29 @@ where unsafe { GLOBAL_CALLBACK = Some(Box::new(callback)); let _pool = NSAutoreleasePool::new(nil); + + // To capture media keys + const NX_SYSDEFINED: i64 = 14; + let tap = CGEventTapCreate( CGEventTapLocation::HID, // HID, Session, AnnotatedSession, kCGHeadInsertEventTap, CGEventTapOption::Default, - kCGEventMaskForAllEvents, + (1 << NX_SYSDEFINED) | kCGEventMaskForAllEvents, raw_callback, nil, ); if tap.is_null() { return Err(GrabError::EventTapError); } - let _loop = CFMachPortCreateRunLoopSource(nil, tap, 0); - if _loop.is_null() { + + let source = CFMachPortCreateRunLoopSource(nil, tap, 0); + if source.is_null() { return Err(GrabError::LoopSourceError); } let current_loop = CFRunLoopGetCurrent(); - CFRunLoopAddSource(current_loop, _loop, kCFRunLoopCommonModes); + CFRunLoopAddSource(current_loop, source, kCFRunLoopCommonModes); CGEventTapEnable(tap, true); CFRunLoopRun(); diff --git a/src/macos/keycodes.rs b/src/macos/keycodes.rs index eeb6f98e..f2dca6a8 100644 --- a/src/macos/keycodes.rs +++ b/src/macos/keycodes.rs @@ -251,6 +251,65 @@ pub fn key_from_code(code: CGKeyCode) -> Key { } } +//https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-308/IOHIDSystem/IOKit/hidsystem/ev_keymap.h + +/* + * Special keys currently known to and understood by the system. + * If new specialty keys are invented, extend this list as appropriate. + * The presence of these keys in a particular implementation is not + * guaranteed. + */ +const NX_NOSPECIALKEY: u32 = 0xFFFF; +const NX_KEYTYPE_SOUND_UP: u32 = 0; +const NX_KEYTYPE_SOUND_DOWN: u32 = 1; +const NX_KEYTYPE_BRIGHTNESS_UP: u32 = 2; +const NX_KEYTYPE_BRIGHTNESS_DOWN: u32 = 3; +const NX_KEYTYPE_CAPS_LOCK: u32 = 4; +const NX_KEYTYPE_HELP: u32 = 5; +const NX_POWER_KEY: u32 = 6; +const NX_KEYTYPE_MUTE: u32 = 7; +const NX_UP_ARROW_KEY: u32 = 8; +const NX_DOWN_ARROW_KEY: u32 = 9; +const NX_KEYTYPE_NUM_LOCK: u32 = 10; + +const NX_KEYTYPE_CONTRAST_UP: u32 = 11; +const NX_KEYTYPE_CONTRAST_DOWN: u32 = 12; +const NX_KEYTYPE_LAUNCH_PANEL: u32 = 13; +const NX_KEYTYPE_EJECT: u32 = 14; +const NX_KEYTYPE_VIDMIRROR: u32 = 15; + +const NX_KEYTYPE_PLAY: u32 = 16; +const NX_KEYTYPE_NEXT: u32 = 17; +const NX_KEYTYPE_PREVIOUS: u32 = 18; +const NX_KEYTYPE_FAST: u32 = 19; +const NX_KEYTYPE_REWIND: u32 = 20; + +const NX_KEYTYPE_ILLUMINATION_UP: u32 = 21; +const NX_KEYTYPE_ILLUMINATION_DOWN: u32 = 22; +const NX_KEYTYPE_ILLUMINATION_TOGGLE: u32 = 23; + +const NX_NUMSPECIALKEYS: u32 = 24; /* Maximum number of special keys */ +const NX_NUM_SCANNED_SPECIALKEYS: u32 = 24; /* First 24 special keys are */ +/* actively scanned in kernel */ + +pub fn key_from_special_key(code: u32) -> Key { + match code { + NX_KEYTYPE_SOUND_UP => Key::VolumeUp, + NX_KEYTYPE_SOUND_DOWN => Key::VolumeDown, + NX_KEYTYPE_MUTE => Key::VolumeMute, + NX_KEYTYPE_BRIGHTNESS_UP => Key::BrightnessUp, + NX_KEYTYPE_BRIGHTNESS_DOWN => Key::BrightnessDown, + NX_KEYTYPE_PLAY => Key::PlayPause, + NX_KEYTYPE_NEXT => Key::NextTrack, + NX_KEYTYPE_PREVIOUS => Key::PreviousTrack, + NX_KEYTYPE_CAPS_LOCK => Key::CapsLock, + NX_UP_ARROW_KEY => Key::UpArrow, + NX_DOWN_ARROW_KEY => Key::DownArrow, + NX_KEYTYPE_NUM_LOCK => Key::NumLock, + code => Key::UnknownSpecialKey(code.into()), + } +} + #[cfg(test)] mod test { use super::{code_from_key, key_from_code}; diff --git a/src/rdev.rs b/src/rdev.rs index 277be3b0..fa07d7f3 100644 --- a/src/rdev.rs +++ b/src/rdev.rs @@ -208,7 +208,16 @@ pub enum Key { Kp9, KpDelete, Function, + VolumeUp, + VolumeDown, + VolumeMute, + BrightnessUp, + BrightnessDown, + PreviousTrack, + PlayPause, + NextTrack, Unknown(u32), + UnknownSpecialKey(u32), } /// Standard mouse buttons From b3d58a814174e9faede2895a9d35afa9a0e17889 Mon Sep 17 00:00:00 2001 From: Jonathan <1808569+jonatino@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:03:44 -0400 Subject: [PATCH 2/5] add volume keycodes for windows --- src/windows/keycodes.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/windows/keycodes.rs b/src/windows/keycodes.rs index c3707f76..b5663c8c 100644 --- a/src/windows/keycodes.rs +++ b/src/windows/keycodes.rs @@ -132,7 +132,13 @@ decl_keycodes! { Kp7, 103, Kp8, 104, Kp9, 105, - KpDelete, 110 + KpDelete, 110, + VolumeMute: 173, + VolumeDown: 174, + VolumeUp: 175, + NextTrack: 176, + PreviousTrack: 177, + PlayPause: 179, } #[cfg(test)] From 3696f3091ae6beeae1cc1ff08d963310e70e37d6 Mon Sep 17 00:00:00 2001 From: Jonathan <1808569+jonatino@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:25:55 -0400 Subject: [PATCH 3/5] fix issue with special keys overlapping regular keys --- src/macos/common.rs | 21 ++++++++++++++++----- src/macos/keycodes.rs | 28 ++++++++++++++-------------- src/rdev.rs | 1 - 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/macos/common.rs b/src/macos/common.rs index 4302c2d3..75a8620d 100644 --- a/src/macos/common.rs +++ b/src/macos/common.rs @@ -142,20 +142,31 @@ pub unsafe fn convert( const NX_SYSDEFINED: u32 = 14; if int_type == NX_SYSDEFINED { + let subtype = cg_event.get_integer_value_field(99); let data1 = cg_event.get_integer_value_field(149); let key_flags = data1 & 0x0000ffff; let key_pressed = ((key_flags & 0xff00) >> 8) == 0xa; let _key_repeat = (key_flags & 0x1) == 0x1; let key_code = (data1 & 0xffff0000) >> 16; - let code = key_from_special_key(key_code.try_into().ok()?); - if key_pressed { - Some(EventType::KeyPress(code)) + // Mouse buttons like middle click/back/forward are subtype 7 + // Subtype 8 means keyboard event + if subtype != 8 { + return None; + } + + if let Some(code) = key_from_special_key(key_code.try_into().ok()?) { + if key_pressed { + Some(EventType::KeyPress(code)) + } else { + Some(EventType::KeyRelease(code)) + } } else { - Some(EventType::KeyRelease(code)) + // If we don't handle the key avoid creating an event since it can create duplicates with other keys + None } } else { - println!("Unknown event type: {:?}", o as i32); + //println!("Unknown event type: {:?}", o as i32); None } } diff --git a/src/macos/keycodes.rs b/src/macos/keycodes.rs index f2dca6a8..10bb4546 100644 --- a/src/macos/keycodes.rs +++ b/src/macos/keycodes.rs @@ -292,21 +292,21 @@ const NX_NUMSPECIALKEYS: u32 = 24; /* Maximum number of special keys */ const NX_NUM_SCANNED_SPECIALKEYS: u32 = 24; /* First 24 special keys are */ /* actively scanned in kernel */ -pub fn key_from_special_key(code: u32) -> Key { +pub fn key_from_special_key(code: u32) -> Option { match code { - NX_KEYTYPE_SOUND_UP => Key::VolumeUp, - NX_KEYTYPE_SOUND_DOWN => Key::VolumeDown, - NX_KEYTYPE_MUTE => Key::VolumeMute, - NX_KEYTYPE_BRIGHTNESS_UP => Key::BrightnessUp, - NX_KEYTYPE_BRIGHTNESS_DOWN => Key::BrightnessDown, - NX_KEYTYPE_PLAY => Key::PlayPause, - NX_KEYTYPE_NEXT => Key::NextTrack, - NX_KEYTYPE_PREVIOUS => Key::PreviousTrack, - NX_KEYTYPE_CAPS_LOCK => Key::CapsLock, - NX_UP_ARROW_KEY => Key::UpArrow, - NX_DOWN_ARROW_KEY => Key::DownArrow, - NX_KEYTYPE_NUM_LOCK => Key::NumLock, - code => Key::UnknownSpecialKey(code.into()), + NX_KEYTYPE_SOUND_UP => Some(Key::VolumeUp), + NX_KEYTYPE_SOUND_DOWN => Some(Key::VolumeDown), + NX_KEYTYPE_MUTE => Some(Key::VolumeMute), + NX_KEYTYPE_BRIGHTNESS_UP => Some(Key::BrightnessUp), + NX_KEYTYPE_BRIGHTNESS_DOWN => Some(Key::BrightnessDown), + NX_KEYTYPE_PLAY => Some(Key::PlayPause), + NX_KEYTYPE_NEXT => Some(Key::NextTrack), + NX_KEYTYPE_PREVIOUS => Some(Key::PreviousTrack), + NX_KEYTYPE_CAPS_LOCK => Some(Key::CapsLock), + NX_UP_ARROW_KEY => Some(Key::UpArrow), + NX_DOWN_ARROW_KEY => Some(Key::DownArrow), + NX_KEYTYPE_NUM_LOCK => Some(Key::NumLock), + _ => None, } } diff --git a/src/rdev.rs b/src/rdev.rs index fa07d7f3..a7737c7c 100644 --- a/src/rdev.rs +++ b/src/rdev.rs @@ -217,7 +217,6 @@ pub enum Key { PlayPause, NextTrack, Unknown(u32), - UnknownSpecialKey(u32), } /// Standard mouse buttons From 1042f0bb3d9a71ca64a394b6e1df4d50eb1e13b8 Mon Sep 17 00:00:00 2001 From: Jonathan <1808569+jonatino@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:35:06 -0400 Subject: [PATCH 4/5] Update keycodes.rs --- src/windows/keycodes.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/windows/keycodes.rs b/src/windows/keycodes.rs index b5663c8c..80b49c55 100644 --- a/src/windows/keycodes.rs +++ b/src/windows/keycodes.rs @@ -133,12 +133,12 @@ decl_keycodes! { Kp8, 104, Kp9, 105, KpDelete, 110, - VolumeMute: 173, - VolumeDown: 174, - VolumeUp: 175, - NextTrack: 176, - PreviousTrack: 177, - PlayPause: 179, + VolumeMute, 173, + VolumeDown, 174, + VolumeUp, 175, + NextTrack, 176, + PreviousTrack, 177, + PlayPause, 179, } #[cfg(test)] From dfd84f105fec2e738f85ed38f5eb4c319a4a515b Mon Sep 17 00:00:00 2001 From: Jonathan <1808569+jonatino@users.noreply.github.com> Date: Mon, 7 Oct 2024 16:36:48 -0400 Subject: [PATCH 5/5] Fix windows build --- src/windows/keycodes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows/keycodes.rs b/src/windows/keycodes.rs index 80b49c55..b3d1e1b9 100644 --- a/src/windows/keycodes.rs +++ b/src/windows/keycodes.rs @@ -138,7 +138,7 @@ decl_keycodes! { VolumeUp, 175, NextTrack, 176, PreviousTrack, 177, - PlayPause, 179, + PlayPause, 179 } #[cfg(test)]