Skip to content

Commit 15e9d94

Browse files
authored
Update cocoa (#172)
* Moving to objc2 ? * Fixing the listen_and_simulate test. * Fmt. * Forgot grab.
1 parent 1761a34 commit 15e9d94

File tree

9 files changed

+215
-237
lines changed

9 files changed

+215
-237
lines changed

Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,15 @@ wayland = ["input", "input-linux", "xkbcommon"]
2626
x11 = ["dep:x11"]
2727

2828
[target.'cfg(target_os = "macos")'.dependencies]
29-
cocoa = "0.26"
30-
core-graphics = {version = "0.24.0", features = ["highsierra"]}
29+
# cocoa = "0.26"
30+
# core-graphics = {version = "0.24.0", features = ["highsierra"]}
3131
core-foundation = {version = "0.10"}
3232
core-foundation-sys = {version = "0.8"}
3333
dispatch = "0.2"
34+
objc2-foundation = "0.3.1"
35+
objc2-core-graphics = "0.3.1"
36+
objc2-core-foundation = "0.3.1"
37+
objc2 = "0.6.1"
3438

3539

3640
[target.'cfg(all(target_family = "unix", not(target_os = "macos")))'.dependencies]

src/macos/common.rs

Lines changed: 50 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,27 @@
11
#![allow(clippy::upper_case_acronyms)]
22
use crate::macos::keyboard::Keyboard;
33
use crate::rdev::{Button, Event, EventType};
4-
use cocoa::base::id;
5-
use core_graphics::event::{CGEvent, CGEventFlags, CGEventTapLocation, CGEventType, EventField};
4+
use core::ptr::NonNull;
65
use lazy_static::lazy_static;
6+
use objc2_core_graphics::{CGEvent, CGEventField, CGEventFlags, CGEventType};
77
use std::convert::TryInto;
8-
use std::os::raw::c_void;
98
use std::sync::Mutex;
109
use std::time::SystemTime;
1110

1211
use crate::macos::keycodes::key_from_code;
1312

14-
pub type CFMachPortRef = *const c_void;
15-
pub type CFIndex = u64;
16-
pub type CFAllocatorRef = id;
17-
pub type CFRunLoopSourceRef = id;
18-
pub type CFRunLoopRef = id;
19-
pub type CFRunLoopMode = id;
20-
pub type CGEventTapProxy = id;
21-
pub type CGEventRef = CGEvent;
22-
23-
// https://developer.apple.com/documentation/coregraphics/cgeventtapplacement?language=objc
24-
pub type CGEventTapPlacement = u32;
25-
#[allow(non_upper_case_globals)]
26-
pub const kCGHeadInsertEventTap: u32 = 0;
27-
28-
// https://developer.apple.com/documentation/coregraphics/cgeventtapoptions?language=objc
29-
#[allow(non_upper_case_globals)]
30-
#[repr(u32)]
31-
pub enum CGEventTapOption {
32-
#[cfg(feature = "unstable_grab")]
33-
Default = 0,
34-
ListenOnly = 1,
35-
}
36-
3713
lazy_static! {
38-
pub static ref LAST_FLAGS: Mutex<CGEventFlags> = Mutex::new(CGEventFlags::CGEventFlagNull);
14+
pub static ref LAST_FLAGS: Mutex<CGEventFlags> = Mutex::new(CGEventFlags(0));
3915
pub static ref KEYBOARD_STATE: Mutex<Keyboard> = Mutex::new(Keyboard::new().unwrap());
4016
}
4117

42-
// https://developer.apple.com/documentation/coregraphics/cgeventmask?language=objc
43-
pub type CGEventMask = u64;
44-
#[allow(non_upper_case_globals)]
45-
pub const kCGEventMaskForAllEvents: u64 = (1 << CGEventType::LeftMouseDown as u64)
46-
+ (1 << CGEventType::LeftMouseUp as u64)
47-
+ (1 << CGEventType::RightMouseDown as u64)
48-
+ (1 << CGEventType::RightMouseUp as u64)
49-
+ (1 << CGEventType::MouseMoved as u64)
50-
+ (1 << CGEventType::LeftMouseDragged as u64)
51-
+ (1 << CGEventType::RightMouseDragged as u64)
52-
+ (1 << CGEventType::KeyDown as u64)
53-
+ (1 << CGEventType::KeyUp as u64)
54-
+ (1 << CGEventType::FlagsChanged as u64)
55-
+ (1 << CGEventType::ScrollWheel as u64);
56-
57-
#[cfg(target_os = "macos")]
58-
#[link(name = "Cocoa", kind = "framework")]
59-
unsafe extern "C" {
60-
#[allow(improper_ctypes)]
61-
pub fn CGEventTapCreate(
62-
tap: CGEventTapLocation,
63-
place: CGEventTapPlacement,
64-
options: CGEventTapOption,
65-
eventsOfInterest: CGEventMask,
66-
callback: QCallback,
67-
user_info: id,
68-
) -> CFMachPortRef;
69-
pub fn CFMachPortCreateRunLoopSource(
70-
allocator: CFAllocatorRef,
71-
tap: CFMachPortRef,
72-
order: CFIndex,
73-
) -> CFRunLoopSourceRef;
74-
pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFRunLoopMode);
75-
pub fn CFRunLoopGetCurrent() -> CFRunLoopRef;
76-
pub fn CGEventTapEnable(tap: CFMachPortRef, enable: bool);
77-
pub fn CFRunLoopRun();
78-
79-
pub static kCFRunLoopCommonModes: CFRunLoopMode;
80-
81-
}
82-
83-
// TODO Remove this, this was added as the coded
84-
// existed and worked, but clippy is complaining.
85-
// There's probably a better fix.
86-
#[allow(improper_ctypes_definitions)]
87-
pub type QCallback = unsafe extern "C" fn(
88-
proxy: CGEventTapProxy,
89-
_type: CGEventType,
90-
cg_event: CGEventRef,
91-
user_info: *mut c_void,
92-
) -> CGEventRef;
93-
9418
pub fn set_is_main_thread(b: bool) {
9519
KEYBOARD_STATE.lock().unwrap().set_is_main_thread(b);
9620
}
9721

9822
pub unsafe fn convert(
9923
_type: CGEventType,
100-
cg_event: &CGEvent,
24+
cg_event: NonNull<CGEvent>,
10125
keyboard_state: &mut Keyboard,
10226
) -> Option<Event> {
10327
unsafe {
@@ -107,81 +31,91 @@ pub unsafe fn convert(
10731
CGEventType::RightMouseDown => Some(EventType::ButtonPress(Button::Right)),
10832
CGEventType::RightMouseUp => Some(EventType::ButtonRelease(Button::Right)),
10933
CGEventType::MouseMoved => {
110-
let point = cg_event.location();
34+
let point = CGEvent::location(Some(cg_event.as_ref()));
35+
// let point = cg_event.location();
11136
Some(EventType::MouseMove {
11237
x: point.x,
11338
y: point.y,
11439
})
11540
}
11641
CGEventType::LeftMouseDragged => {
117-
let point = cg_event.location();
42+
let point = CGEvent::location(Some(cg_event.as_ref()));
11843
Some(EventType::MouseMove {
11944
x: point.x,
12045
y: point.y,
12146
})
12247
}
12348
CGEventType::RightMouseDragged => {
124-
let point = cg_event.location();
49+
let point = CGEvent::location(Some(cg_event.as_ref()));
12550
Some(EventType::MouseMove {
12651
x: point.x,
12752
y: point.y,
12853
})
12954
}
13055
CGEventType::KeyDown => {
131-
let code = cg_event.get_integer_value_field(EventField::KEYBOARD_EVENT_KEYCODE);
56+
let code = CGEvent::integer_value_field(
57+
Some(cg_event.as_ref()),
58+
CGEventField::KeyboardEventKeycode,
59+
);
13260
let key = key_from_code(code.try_into().ok()?);
13361
Some(EventType::KeyPress(key))
13462
}
13563
CGEventType::KeyUp => {
136-
let code = cg_event.get_integer_value_field(EventField::KEYBOARD_EVENT_KEYCODE);
64+
let code = CGEvent::integer_value_field(
65+
Some(cg_event.as_ref()),
66+
CGEventField::KeyboardEventKeycode,
67+
);
13768
let key = key_from_code(code.try_into().ok()?);
13869
Some(EventType::KeyRelease(key))
13970
}
14071
CGEventType::FlagsChanged => {
141-
let code = cg_event.get_integer_value_field(EventField::KEYBOARD_EVENT_KEYCODE);
72+
let code = CGEvent::integer_value_field(
73+
Some(cg_event.as_ref()),
74+
CGEventField::KeyboardEventKeycode,
75+
);
14276
let code = code.try_into().ok()?;
143-
let flags = cg_event.get_flags();
77+
let flags = CGEvent::flags(Some(cg_event.as_ref()));
14478
let key = key_from_code(code);
14579

14680
// Determine if this is a press or release based on flag changes
14781
let mut global_flags = LAST_FLAGS.lock().unwrap();
148-
if flags.contains(CGEventFlags::CGEventFlagShift)
149-
&& !global_flags.contains(CGEventFlags::CGEventFlagShift)
82+
if flags.contains(CGEventFlags::MaskShift)
83+
&& !global_flags.contains(CGEventFlags::MaskShift)
15084
{
15185
*global_flags = flags;
15286
Some(EventType::KeyPress(key))
153-
} else if !flags.contains(CGEventFlags::CGEventFlagShift)
154-
&& global_flags.contains(CGEventFlags::CGEventFlagShift)
87+
} else if !flags.contains(CGEventFlags::MaskShift)
88+
&& global_flags.contains(CGEventFlags::MaskShift)
15589
{
15690
*global_flags = flags;
15791
Some(EventType::KeyRelease(key))
158-
} else if flags.contains(CGEventFlags::CGEventFlagControl)
159-
&& !global_flags.contains(CGEventFlags::CGEventFlagControl)
92+
} else if flags.contains(CGEventFlags::MaskControl)
93+
&& !global_flags.contains(CGEventFlags::MaskControl)
16094
{
16195
*global_flags = flags;
16296
Some(EventType::KeyPress(key))
163-
} else if !flags.contains(CGEventFlags::CGEventFlagControl)
164-
&& global_flags.contains(CGEventFlags::CGEventFlagControl)
97+
} else if !flags.contains(CGEventFlags::MaskControl)
98+
&& global_flags.contains(CGEventFlags::MaskControl)
16599
{
166100
*global_flags = flags;
167101
Some(EventType::KeyRelease(key))
168-
} else if flags.contains(CGEventFlags::CGEventFlagAlternate)
169-
&& !global_flags.contains(CGEventFlags::CGEventFlagAlternate)
102+
} else if flags.contains(CGEventFlags::MaskAlternate)
103+
&& !global_flags.contains(CGEventFlags::MaskAlternate)
170104
{
171105
*global_flags = flags;
172106
Some(EventType::KeyPress(key))
173-
} else if !flags.contains(CGEventFlags::CGEventFlagAlternate)
174-
&& global_flags.contains(CGEventFlags::CGEventFlagAlternate)
107+
} else if !flags.contains(CGEventFlags::MaskAlternate)
108+
&& global_flags.contains(CGEventFlags::MaskAlternate)
175109
{
176110
*global_flags = flags;
177111
Some(EventType::KeyRelease(key))
178-
} else if flags.contains(CGEventFlags::CGEventFlagCommand)
179-
&& !global_flags.contains(CGEventFlags::CGEventFlagCommand)
112+
} else if flags.contains(CGEventFlags::MaskCommand)
113+
&& !global_flags.contains(CGEventFlags::MaskCommand)
180114
{
181115
*global_flags = flags;
182116
Some(EventType::KeyPress(key))
183-
} else if !flags.contains(CGEventFlags::CGEventFlagCommand)
184-
&& global_flags.contains(CGEventFlags::CGEventFlagCommand)
117+
} else if !flags.contains(CGEventFlags::MaskCommand)
118+
&& global_flags.contains(CGEventFlags::MaskCommand)
185119
{
186120
*global_flags = flags;
187121
Some(EventType::KeyRelease(key))
@@ -190,20 +124,26 @@ pub unsafe fn convert(
190124
}
191125
}
192126
CGEventType::ScrollWheel => {
193-
let delta_y = cg_event
194-
.get_integer_value_field(EventField::SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_1);
195-
let delta_x = cg_event
196-
.get_integer_value_field(EventField::SCROLL_WHEEL_EVENT_POINT_DELTA_AXIS_2);
127+
let delta_y = CGEvent::integer_value_field(
128+
Some(cg_event.as_ref()),
129+
CGEventField::ScrollWheelEventDeltaAxis1,
130+
);
131+
let delta_x = CGEvent::integer_value_field(
132+
Some(cg_event.as_ref()),
133+
CGEventField::ScrollWheelEventDeltaAxis2,
134+
);
197135
Some(EventType::Wheel { delta_x, delta_y })
198136
}
199137
_ => None,
200138
};
201139
if let Some(event_type) = option_type {
202140
let name = match event_type {
203141
EventType::KeyPress(_) => {
204-
let code =
205-
cg_event.get_integer_value_field(EventField::KEYBOARD_EVENT_KEYCODE) as u32;
206-
let flags = cg_event.get_flags();
142+
let code = CGEvent::integer_value_field(
143+
Some(cg_event.as_ref()),
144+
CGEventField::KeyboardEventKeycode,
145+
);
146+
let flags = CGEvent::flags(Some(cg_event.as_ref()));
207147
keyboard_state.create_string_for_key(code, flags)
208148
}
209149
_ => None,

src/macos/display.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
1+
use objc2_core_graphics::{CGDisplayPixelsHigh, CGDisplayPixelsWide, CGMainDisplayID};
2+
13
use crate::rdev::DisplayError;
2-
use core_graphics::display::CGDisplay;
34

45
pub fn display_size() -> Result<(u64, u64), DisplayError> {
5-
let main = CGDisplay::main();
6-
Ok((main.pixels_wide(), main.pixels_high()))
6+
unsafe {
7+
let main = CGMainDisplayID();
8+
Ok((
9+
CGDisplayPixelsWide(main)
10+
.try_into()
11+
.map_err(|_| DisplayError::ConversionError)?,
12+
CGDisplayPixelsHigh(main)
13+
.try_into()
14+
.map_err(|_| DisplayError::ConversionError)?,
15+
))
16+
}
717
}

src/macos/grab.rs

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,42 @@
11
#![allow(improper_ctypes_definitions)]
22
use crate::macos::common::*;
33
use crate::rdev::{Event, GrabError};
4-
use cocoa::base::nil;
5-
use cocoa::foundation::NSAutoreleasePool;
6-
use core_graphics::event::{CGEventTapLocation, CGEventType};
4+
use objc2_core_foundation::{CFMachPort, CFRunLoop, kCFRunLoopCommonModes};
5+
use objc2_core_graphics::{
6+
CGEvent, CGEventTapCallBack, CGEventTapLocation, CGEventTapOptions, CGEventTapPlacement,
7+
CGEventTapProxy, CGEventType, kCGEventMaskForAllEvents,
8+
};
9+
use objc2_foundation::NSAutoreleasePool;
710
use std::os::raw::c_void;
11+
use std::ptr::{NonNull, null_mut};
812

913
static mut GLOBAL_CALLBACK: Option<Box<dyn FnMut(Event) -> Option<Event>>> = None;
1014

1115
#[link(name = "Cocoa", kind = "framework")]
1216
unsafe extern "C" {}
1317

14-
unsafe extern "C" fn raw_callback(
18+
unsafe extern "C-unwind" fn raw_callback(
1519
_proxy: CGEventTapProxy,
1620
_type: CGEventType,
17-
cg_event: CGEventRef,
21+
cg_event: NonNull<CGEvent>,
1822
_user_info: *mut c_void,
19-
) -> CGEventRef {
23+
) -> *mut CGEvent {
2024
let opt = KEYBOARD_STATE.lock();
2125
if let Ok(mut keyboard) = opt {
2226
unsafe {
23-
if let Some(event) = convert(_type, &cg_event, &mut keyboard) {
27+
if let Some(event) = convert(_type, cg_event, &mut keyboard) {
2428
// Reborrowing the global callback pointer.
2529
// Totally UB. but not sure there's a great alternative.
2630
let ptr = &raw mut GLOBAL_CALLBACK;
2731
if let Some(callback) = &mut *ptr {
2832
if callback(event).is_none() {
29-
cg_event.set_type(CGEventType::Null);
33+
CGEvent::set_type(Some(cg_event.as_ref()), CGEventType::Null)
3034
}
3135
}
3236
}
3337
}
3438
}
35-
cg_event
39+
cg_event.as_ptr()
3640
}
3741

3842
pub fn grab<T>(callback: T) -> Result<(), GrabError>
@@ -41,28 +45,25 @@ where
4145
{
4246
unsafe {
4347
GLOBAL_CALLBACK = Some(Box::new(callback));
44-
let _pool = NSAutoreleasePool::new(nil);
45-
let tap = CGEventTapCreate(
46-
CGEventTapLocation::HID, // HID, Session, AnnotatedSession,
47-
kCGHeadInsertEventTap,
48-
CGEventTapOption::Default,
49-
kCGEventMaskForAllEvents,
50-
raw_callback,
51-
nil,
52-
);
53-
if tap.is_null() {
54-
return Err(GrabError::EventTapError);
55-
}
56-
let _loop = CFMachPortCreateRunLoopSource(nil, tap, 0);
57-
if _loop.is_null() {
58-
return Err(GrabError::LoopSourceError);
59-
}
48+
let _pool = NSAutoreleasePool::new();
49+
let callback: CGEventTapCallBack = Some(raw_callback);
50+
let tap = CGEvent::tap_create(
51+
CGEventTapLocation::HIDEventTap, // HID, Session, AnnotatedSession,
52+
CGEventTapPlacement::HeadInsertEventTap,
53+
CGEventTapOptions::Default,
54+
kCGEventMaskForAllEvents.into(),
55+
callback,
56+
null_mut(),
57+
)
58+
.ok_or(GrabError::EventTapError)?;
59+
let loop_ = CFMachPort::new_run_loop_source(None, Some(&tap), 0)
60+
.ok_or(GrabError::LoopSourceError)?;
6061

61-
let current_loop = CFRunLoopGetCurrent();
62-
CFRunLoopAddSource(current_loop, _loop, kCFRunLoopCommonModes);
62+
let current_loop = CFRunLoop::current().unwrap();
63+
current_loop.add_source(Some(&loop_), kCFRunLoopCommonModes);
6364

64-
CGEventTapEnable(tap, true);
65-
CFRunLoopRun();
65+
CGEvent::tap_enable(&tap, true);
66+
CFRunLoop::run();
6667
}
6768
Ok(())
6869
}

0 commit comments

Comments
 (0)