From bbb5755b413198142d476d6a404654ddaaeb6de5 Mon Sep 17 00:00:00 2001 From: pentamassiv Date: Sat, 6 Jan 2024 16:45:50 +0100 Subject: [PATCH] test compilation --- Cargo.toml | 6 +- src/keycodes.rs | 33 ++++++- src/macos/macos_impl.rs | 212 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 236 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4a965dcd..66b2d404 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,11 @@ windows = { version = "0.51", features = [ [target.'cfg(target_os = "macos")'.dependencies] core-graphics = { version = "0.23", features = ["highsierra"] } -icrate = { version = "0.1.0", features = ["AppKit_all"] } +icrate = { version = "0.1", features = [ + "AppKit_all", +] } # AppKit_NSGraphicsContext +objc2 = { version = "0.5", features = ["relax-void-encoding"] } +foreign-types-shared = "0.3" [target.'cfg(target_os = "linux")'.dependencies] libc = "0.2" diff --git a/src/keycodes.rs b/src/keycodes.rs index 9e0a1c2f..c6da73a6 100644 --- a/src/keycodes.rs +++ b/src/keycodes.rs @@ -101,9 +101,13 @@ pub enum Key { /// backspace key Backspace, #[cfg(target_os = "linux")] - Begin, - #[cfg(target_os = "linux")] Break, + #[cfg(target_os = "linux")] + Begin, + #[cfg(target_os = "macos")] + BrightnessDown, + #[cfg(target_os = "macos")] + BrightnessUp, #[cfg(target_os = "windows")] BrowserBack, #[cfg(target_os = "windows")] @@ -127,6 +131,10 @@ pub enum Key { #[deprecated(since = "0.0.12", note = "now renamed to Meta")] /// command key on macOS (super key on Linux, windows key on Windows) Command, + #[cfg(target_os = "macos")] + ContrastUp, + #[cfg(target_os = "macos")] + ContrastDown, /// control key Control, #[cfg(target_os = "windows")] @@ -169,6 +177,8 @@ pub enum Key { Divide, /// down arrow key DownArrow, + #[cfg(target_os = "macos")] + Eject, /// end key End, #[cfg(target_os = "windows")] @@ -322,6 +332,12 @@ pub enum Key { IcoClear, #[cfg(target_os = "windows")] IcoHelp, + #[cfg(target_os = "macos")] + IlluminationDown, + #[cfg(target_os = "macos")] + IlluminationUp, + #[cfg(target_os = "macos")] + IlluminationToggle, #[cfg(target_os = "windows")] IMEOff, #[cfg(target_os = "windows")] @@ -345,6 +361,8 @@ pub enum Key { #[cfg(target_os = "macos")] /// Opens launchpad Launchpad, + #[cfg(target_os = "macos")] + LaunchPanel, #[cfg(target_os = "windows")] LButton, LControl, @@ -359,12 +377,13 @@ pub enum Key { LWin, #[cfg(target_os = "windows")] MButton, - #[cfg(any(target_os = "windows", target_os = "linux"))] + #[cfg(target_os = "macos")] + MediaFast, MediaNextTrack, - #[cfg(any(target_os = "windows", target_os = "linux"))] MediaPlayPause, - #[cfg(any(target_os = "windows", target_os = "linux"))] MediaPrevTrack, + #[cfg(target_os = "macos")] + MediaRewind, #[cfg(any(target_os = "windows", target_os = "linux"))] MediaStop, /// meta key (also known as "windows", "super", and "command") @@ -502,6 +521,8 @@ pub enum Key { Pause, #[cfg(target_os = "windows")] Play, + #[cfg(target_os = "macos")] + Power, #[cfg(any(target_os = "windows", target_os = "linux"))] Print, #[cfg(target_os = "windows")] @@ -558,6 +579,8 @@ pub enum Key { Undo, /// up arrow key UpArrow, + #[cfg(target_os = "macos")] + VidMirror, VolumeDown, VolumeMute, VolumeUp, diff --git a/src/macos/macos_impl.rs b/src/macos/macos_impl.rs index fa31faf9..7312b794 100644 --- a/src/macos/macos_impl.rs +++ b/src/macos/macos_impl.rs @@ -6,12 +6,16 @@ use std::{ use core_graphics::display::{CFIndex, CGDisplay, CGPoint}; use core_graphics::event::{ - CGEvent, CGEventTapLocation, CGEventType, CGKeyCode, CGMouseButton, EventField, KeyCode, - ScrollEventUnit, + CGEvent, CGEventRef, CGEventTapLocation, CGEventType, CGKeyCode, CGMouseButton, EventField, + KeyCode, ScrollEventUnit, }; use core_graphics::event_source::{CGEventSource, CGEventSourceStateID}; -use icrate::AppKit; +use foreign_types_shared::ForeignTypeRef as _; +use icrate::{AppKit, AppKit::NSEvent}; + +use icrate::Foundation::NSPoint; use log::{debug, error, info}; +use objc2::msg_send; use crate::{ Axis, Button, Coordinate, Direction, InputError, InputResult, Key, Keyboard, Mouse, @@ -337,19 +341,100 @@ impl Keyboard for Enigo { Ok(Some(())) } + #[allow(clippy::too_many_lines)] fn key(&mut self, key: Key, direction: Direction) -> InputResult<()> { debug!("\x1b[93mkey(key: {key:?}, direction: {direction:?})\x1b[0m"); // Nothing to do if key == Key::Unicode('\0') { return Ok(()); } + match key { + Key::VolumeUp => { + debug!("special case for handling the VolumeUp key"); + Enigo::special_keys(0, direction)?; + } + Key::VolumeDown => { + debug!("special case for handling the VolumeDown key"); + Enigo::special_keys(1, direction)?; + } + Key::BrightnessUp => { + debug!("special case for handling the BrightnessUp key"); + Enigo::special_keys(2, direction)?; + } + Key::BrightnessDown => { + debug!("special case for handling the BrightnessDown key"); + Enigo::special_keys(3, direction)?; + } + Key::Power => { + debug!("special case for handling the VolumeMute key"); + Enigo::special_keys(6, direction)?; + } + Key::VolumeMute => { + debug!("special case for handling the VolumeMute key"); + Enigo::special_keys(7, direction)?; + } - let Ok(keycode) = CGKeyCode::try_from(key) else { - return Err(InputError::InvalidInput( - "virtual keycodes on macOS have to fit into u16", - )); - }; - self.raw(keycode, direction)?; + Key::ContrastUp => { + debug!("special case for handling the VolumeUp key"); + Enigo::special_keys(11, direction)?; + } + Key::ContrastDown => { + debug!("special case for handling the VolumeDown key"); + Enigo::special_keys(12, direction)?; + } + Key::LaunchPanel => { + debug!("special case for handling the MediaPlayPause key"); + Enigo::special_keys(13, direction)?; + } + Key::Eject => { + debug!("special case for handling the MediaNextTrack key"); + Enigo::special_keys(14, direction)?; + } + Key::VidMirror => { + debug!("special case for handling the MediaPrevTrack key"); + Enigo::special_keys(15, direction)?; + } + Key::MediaPlayPause => { + debug!("special case for handling the MediaPlayPause key"); + Enigo::special_keys(16, direction)?; + } + Key::MediaNextTrack => { + debug!("special case for handling the MediaNextTrack key"); + Enigo::special_keys(17, direction)?; + } + Key::MediaPrevTrack => { + debug!("special case for handling the MediaPrevTrack key"); + Enigo::special_keys(18, direction)?; + } + Key::MediaFast => { + debug!("special case for handling the MediaNextTrack key"); + Enigo::special_keys(19, direction)?; + } + Key::MediaRewind => { + debug!("special case for handling the MediaPrevTrack key"); + Enigo::special_keys(20, direction)?; + } + Key::IlluminationUp => { + debug!("special case for handling the MediaPrevTrack key"); + Enigo::special_keys(21, direction)?; + } + Key::IlluminationDown => { + debug!("special case for handling the MediaNextTrack key"); + Enigo::special_keys(22, direction)?; + } + Key::IlluminationToggle => { + debug!("special case for handling the MediaPrevTrack key"); + Enigo::special_keys(23, direction)?; + } + _ => { + let Ok(keycode) = CGKeyCode::try_from(key) else { + return Err(InputError::InvalidInput( + "virtual keycodes on macOS have to fit into u16", + )); + }; + self.raw(keycode, direction)?; + } + } // TODO: The list of keys will contain the key and also the associated keycode. // They are a duplicate @@ -487,6 +572,99 @@ impl Enigo { debug!("nth_button_press: {nth_button_press}"); nth_button_press } + + fn special_keys(code: isize, direction: Direction) -> InputResult<()> { + if direction == Direction::Press || direction == Direction::Click { + let event = unsafe { + AppKit::NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2( + AppKit::NSEventTypeSystemDefined, // 14 + NSPoint::ZERO, + 0xa00, // NSEventModifierFlagCapsLock and NSEventModifierFlagOption + 0.0, + 0, + None, + 8, + (code << 16) | (0xa << 8), + -1 + ) + }; + + if let Some(event) = event { + let cg_event = unsafe { Self::ns_event_cg_event(&event).to_owned() }; + cg_event.post(CGEventTapLocation::HID); + } else { + return Err(InputError::Simulate( + "failed creating event to press special key", + )); + } + } + + if direction == Direction::Release || direction == Direction::Click { + let event = unsafe { + AppKit::NSEvent::otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2( + AppKit::NSEventTypeSystemDefined, // 14 + NSPoint::ZERO, + 0xb00, // NSEventModifierFlagCapsLock and NSEventModifierFlagOption + 0.0, + 0, + None, + 8, + (code << 16) | (0xb << 8), + -1 + ) + }; + + if let Some(event) = event { + let cg_event = unsafe { Self::ns_event_cg_event(&event).to_owned() }; + cg_event.post(CGEventTapLocation::HID); + } else { + return Err(InputError::Simulate( + "failed creating event to release special key", + )); + } + } + Ok(()) + /* + let event1 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xa00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xa << 8 as Int32))), data2: -1) + event1?.cgEvent?.post(tap: .cghidEventTap) + let event2 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xb00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xb << 8 as Int32))), data2: -1) + event2?.cgEvent?.post(tap: .cghidEventTap) + + + + // Simulate illumination down + let code = NX_KEYTYPE_ILLUMINATION_DOWN + let event1 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xa00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xa << 8 as Int32))), data2: -1) + event1?.cgEvent?.post(tap: .cghidEventTap) + let event2 = NSEvent.otherEvent(with: .systemDefined, location: NSPoint.zero, modifierFlags: NSEventModifierFlags(rawValue: 0xb00), timestamp: 0, windowNumber: 0, context: nil, subtype: 8, data1: (Int((code << 16 as Int32) | (0xb << 8 as Int32))), data2: -1) + event2?.cgEvent?.post(tap: .cghidEventTap) + + + + /* Mask of special keys that are posted as events */ + + #define NX_SPECIALKEY_POST_MASK \ + ((1 << NX_KEYTYPE_SOUND_UP) | (1 << NX_KEYTYPE_SOUND_DOWN) | \ + (1 << NX_POWER_KEY) | (1 << NX_KEYTYPE_MUTE) | \ + (1 << NX_KEYTYPE_BRIGHTNESS_UP) | (1 << NX_KEYTYPE_BRIGHTNESS_DOWN) | \ + (1 << NX_KEYTYPE_CONTRAST_UP) | (1 << NX_KEYTYPE_CONTRAST_UP) | \ + (1 << NX_KEYTYPE_LAUNCH_PANEL) | (1 << NX_KEYTYPE_EJECT) | \ + (1 << NX_KEYTYPE_VIDMIRROR) | (1 << NX_KEYTYPE_PLAY) | \ + (1 << NX_KEYTYPE_NEXT) | (1 << NX_KEYTYPE_PREVIOUS) | \ + (1 << NX_KEYTYPE_FAST) | (1 << NX_KEYTYPE_REWIND) | \ + (1 << NX_KEYTYPE_ILLUMINATION_UP) | \ + (1 << NX_KEYTYPE_ILLUMINATION_DOWN) | \ + (1 << NX_KEYTYPE_ILLUMINATION_TOGGLE) | 0) + + + + */ + } + + unsafe fn ns_event_cg_event(event: &NSEvent) -> &CGEventRef { + let ptr: *mut c_void = unsafe { msg_send![event, CGEvent] }; + unsafe { CGEventRef::from_ptr(ptr.cast()) } + } } /// Converts a `Key` to a `CGKeyCode` @@ -556,6 +734,22 @@ impl TryFrom for core_graphics::event::CGKeyCode { v } Key::Super | Key::Command | Key::Windows | Key::Meta => KeyCode::COMMAND, + Key::BrightnessDown + | Key::BrightnessUp + | Key::ContrastUp + | Key::ContrastDown + | Key::Eject + | Key::IlluminationDown + | Key::IlluminationUp + | Key::IlluminationToggle + | Key::LaunchPanel + | Key::MediaFast + | Key::MediaNextTrack + | Key::MediaPlayPause + | Key::MediaPrevTrack + | Key::MediaRewind + | Key::Power + | Key::VidMirror => return Err(()), }; Ok(key) }