From 34f60f1c4d0d8f2a726768000dcd5f92bdc9aae5 Mon Sep 17 00:00:00 2001 From: Nicolas Patry Date: Mon, 23 Jun 2025 13:59:00 +0200 Subject: [PATCH] Supporting media keys on macos. Co-Authored-By: Jonathan <1808569+jonatino@users.noreply.github.com> --- src/macos/common.rs | 38 +++++++++++++++++++++- src/macos/keycodes.rs | 76 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/src/macos/common.rs b/src/macos/common.rs index d15ad27..3a20322 100644 --- a/src/macos/common.rs +++ b/src/macos/common.rs @@ -10,6 +10,8 @@ use std::time::SystemTime; use crate::macos::keycodes::key_from_code; +use super::keycodes::key_from_special_key; + lazy_static! { pub static ref LAST_FLAGS: Mutex = Mutex::new(CGEventFlags(0)); pub static ref KEYBOARD_STATE: Mutex = Mutex::new(Keyboard::new().unwrap()); @@ -53,6 +55,7 @@ pub unsafe fn convert( }) } CGEventType::KeyDown => { + println!("Received {cg_event:?}"); let code = CGEvent::integer_value_field( Some(cg_event.as_ref()), CGEventField::KeyboardEventKeycode, @@ -134,7 +137,40 @@ pub unsafe fn convert( ); Some(EventType::Wheel { delta_x, delta_y }) } - _ => None, + CGEventType(14) => { + // Core graphics doesnt support NX_SYSDEFINED yet + + let subtype = + CGEvent::integer_value_field(Some(cg_event.as_ref()), CGEventField(99)); + let data1 = + CGEvent::integer_value_field(Some(cg_event.as_ref()), CGEventField(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; + + // Mouse buttons like middle click/back/forward are subtype 7 + // Subtype 8 means keyboard event + if subtype != 8 { + return None; + } + + println!("Received {key_code:?}"); + 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 { + // If we don't handle the key avoid creating an event since it can create duplicates with other keys + None + } + } + _ev => { + println!("Received {_ev:?}"); + None + } }; if let Some(event_type) = option_type { let name = match event_type { diff --git a/src/macos/keycodes.rs b/src/macos/keycodes.rs index 95769eb..2f102bb 100644 --- a/src/macos/keycodes.rs +++ b/src/macos/keycodes.rs @@ -252,6 +252,82 @@ pub fn key_from_code(code: CGKeyCode) -> Key { } } +//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 + +/* + * 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. + */ + +#[allow(unused)] +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; +#[allow(unused)] +const NX_KEYTYPE_HELP: u32 = 5; +#[allow(unused)] +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; + +#[allow(unused)] +const NX_KEYTYPE_CONTRAST_UP: u32 = 11; +#[allow(unused)] +const NX_KEYTYPE_CONTRAST_DOWN: u32 = 12; +#[allow(unused)] +const NX_KEYTYPE_LAUNCH_PANEL: u32 = 13; +#[allow(unused)] +const NX_KEYTYPE_EJECT: u32 = 14; +#[allow(unused)] +const NX_KEYTYPE_VIDMIRROR: u32 = 15; + +const NX_KEYTYPE_PLAY: u32 = 16; +const NX_KEYTYPE_NEXT: u32 = 17; +const NX_KEYTYPE_PREVIOUS: u32 = 18; +#[allow(unused)] +const NX_KEYTYPE_FAST: u32 = 19; +#[allow(unused)] +const NX_KEYTYPE_REWIND: u32 = 20; + +#[allow(unused)] +const NX_KEYTYPE_ILLUMINATION_UP: u32 = 21; +#[allow(unused)] +const NX_KEYTYPE_ILLUMINATION_DOWN: u32 = 22; +#[allow(unused)] +const NX_KEYTYPE_ILLUMINATION_TOGGLE: u32 = 23; + +#[allow(unused)] +const NX_NUMSPECIALKEYS: u32 = 24; /* Maximum number of special keys */ +#[allow(unused)] +const NX_NUM_SCANNED_SPECIALKEYS: u32 = 24; /* First 24 special keys are */ +/* actively scanned in kernel */ + +pub fn key_from_special_key(code: u32) -> Option { + match code { + 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, + } +} + #[cfg(test)] mod test { use super::{code_from_key, key_from_code};