Skip to content

Commit

Permalink
Auto merge of #436 - AsafFisher:master, r=jrmuizel
Browse files Browse the repository at this point in the history
  • Loading branch information
bors-servo authored May 26, 2021
2 parents ea68a18 + 532a321 commit f7e0b97
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 6 deletions.
1 change: 1 addition & 0 deletions core-foundation-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ pub mod string;
pub mod timezone;
pub mod url;
pub mod uuid;
pub mod mach_port;
20 changes: 20 additions & 0 deletions core-foundation-sys/src/mach_port.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pub use base::{CFAllocatorRef, CFIndex, CFTypeID};
use runloop::CFRunLoopSourceRef;
use std::os::raw::c_void;

#[repr(C)]
pub struct __CFMachPort(c_void);
pub type CFMachPortRef = *const __CFMachPort;

extern "C" {
/*
* CFMachPort.h
*/
pub fn CFMachPortCreateRunLoopSource(
allocator: CFAllocatorRef,
port: CFMachPortRef,
order: CFIndex,
) -> CFRunLoopSourceRef;

pub fn CFMachPortGetTypeID() -> CFTypeID;
}
1 change: 1 addition & 0 deletions core-foundation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,4 @@ pub mod propertylist;
pub mod runloop;
pub mod timezone;
pub mod uuid;
pub mod mach_port;
28 changes: 28 additions & 0 deletions core-foundation/src/mach_port.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use base::TCFType;
use core_foundation_sys::base::kCFAllocatorDefault;
use runloop::CFRunLoopSource;
pub use core_foundation_sys::mach_port::*;


declare_TCFType! {
/// An immutable numeric value.
CFMachPort, CFMachPortRef
}
impl_TCFType!(CFMachPort, CFMachPortRef, CFMachPortGetTypeID);
impl_CFTypeDescription!(CFMachPort);

impl CFMachPort {
pub fn create_runloop_source(
&self,
order: CFIndex,
) -> Result<CFRunLoopSource, ()> {
unsafe {
let runloop_source_ref = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, self.0, order);
if runloop_source_ref.is_null() {
Err(())
} else {
Ok(CFRunLoopSource::wrap_under_create_rule(runloop_source_ref))
}
}
}
}
157 changes: 151 additions & 6 deletions core-graphics/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#![allow(non_upper_case_globals)]

use core_foundation::base::{CFRelease, CFRetain, CFTypeID};
use geometry::CGPoint;
use core_foundation::{
base::{CFRelease, CFRetain, CFTypeID, TCFType},
mach_port::{CFMachPort, CFMachPortRef},
};
use event_source::CGEventSource;

use libc;

use foreign_types::ForeignType;
use geometry::CGPoint;
use libc::c_void;
use std::mem::ManuallyDrop;

pub type CGEventField = u32;
pub type CGKeyCode = u16;
Expand Down Expand Up @@ -384,6 +385,137 @@ pub enum CGEventTapLocation {
AnnotatedSession,
}

// The next three enums are taken from:
// [Ref](https://github.com/phracker/MacOSX-SDKs/blob/ef9fe35d5691b6dd383c8c46d867a499817a01b6/MacOSX10.15.sdk/System/Library/Frameworks/CoreGraphics.framework/Versions/A/Headers/CGEventTypes.h)
/* Constants that specify where a new event tap is inserted into the list of
active event taps. */
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventTapPlacement {
HeadInsertEventTap = 0,
TailAppendEventTap,
}

/* Constants that specify whether a new event tap is an active filter or a
passive listener. */
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum CGEventTapOptions {
Default = 0x00000000,
ListenOnly = 0x00000001,
}

pub type CGEventMask = u64;
/* Generate an event mask for a single type of event. */
macro_rules! CGEventMaskBit {
($eventType:expr) => {
1 << $eventType as CGEventMask
};
}

pub type CGEventTapProxy = *const c_void;
pub type CGEventTapCallBackFn<'tap_life> =
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>;
type CGEventTapCallBackInternal = unsafe extern "C" fn(
proxy: CGEventTapProxy,
etype: CGEventType,
event: ::sys::CGEventRef,
user_info: *const c_void,
) -> ::sys::CGEventRef;

#[no_mangle]
unsafe extern "C" fn cg_event_tap_callback_internal(
_proxy: CGEventTapProxy,
_etype: CGEventType,
_event: ::sys::CGEventRef,
_user_info: *const c_void,
) -> ::sys::CGEventRef {
let callback = _user_info as *mut CGEventTapCallBackFn;
let event = CGEvent::from_ptr(_event);
let new_event = (*callback)(_proxy, _etype, &event);
let event = match new_event {
Some(new_event) => new_event,
None => event,
};
ManuallyDrop::new(event).as_ptr()
}


/// ```no_run
///extern crate core_foundation;
///use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
///use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
///let current = CFRunLoop::get_current();
///match CGEventTap::new(
/// CGEventTapLocation::HID,
/// CGEventTapPlacement::HeadInsertEventTap,
/// CGEventTapOptions::Default,
/// vec![CGEventType::MouseMoved],
/// |_a, _b, d| {
/// println!("{:?}", d.location());
/// None
/// },
/// ) {
/// Ok(tap) => unsafe {
/// let loop_source = tap
/// .mach_port
/// .create_runloop_source(0)
/// .expect("Somethings is bad ");
/// current.add_source(&loop_source, kCFRunLoopCommonModes);
/// tap.enable();
/// CFRunLoop::run_current();
/// },
/// Err(_) => (assert!(false)),
/// }
/// ```
pub struct CGEventTap<'tap_life> {
pub mach_port: CFMachPort,
pub callback_ref:
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>,
}

impl<'tap_life> CGEventTap<'tap_life> {
pub fn new<F: Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>(
tap: CGEventTapLocation,
place: CGEventTapPlacement,
options: CGEventTapOptions,
events_of_interest: std::vec::Vec<CGEventType>,
callback: F,
) -> Result<CGEventTap<'tap_life>, ()> {
let event_mask: CGEventMask = events_of_interest
.iter()
.fold(CGEventType::Null as CGEventMask, |mask, &etype| {
mask | CGEventMaskBit!(etype)
});
let cb = Box::new(Box::new(callback) as CGEventTapCallBackFn);
let cbr = Box::into_raw(cb);
unsafe {
let event_tap_ref = CGEventTapCreate(
tap,
place,
options,
event_mask,
cg_event_tap_callback_internal,
cbr as *const c_void,
);

if !event_tap_ref.is_null() {
Ok(Self {
mach_port: (CFMachPort::wrap_under_create_rule(event_tap_ref)),
callback_ref: Box::from_raw(cbr),
})
} else {
Box::from_raw(cbr);
Err(())
}
}
}

pub fn enable(&self) {
unsafe { CGEventTapEnable(self.mach_port.as_concrete_TypeRef(), true) }
}
}

foreign_type! {
#[doc(hidden)]
type CType = ::sys::CGEvent;
Expand Down Expand Up @@ -666,4 +798,17 @@ extern {
/// fixed point number or integer, the value parameter is scaled as needed
/// and converted to the appropriate type.
fn CGEventSetDoubleValueField(event: ::sys::CGEventRef, field: CGEventField, value: f64);

// ::sys::CGEventTapRef is actually an CFMachPortRef
fn CGEventTapCreate(
tap: CGEventTapLocation,
place: CGEventTapPlacement,
options: CGEventTapOptions,
eventsOfInterest: CGEventMask,
callback: CGEventTapCallBackInternal,
userInfo: *const c_void,
) -> CFMachPortRef;

fn CGEventTapEnable(tap: CFMachPortRef, enable: bool);

}
2 changes: 2 additions & 0 deletions core-graphics/src/sys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub type CGGradientRef = *mut CGGradient;

#[cfg(target_os = "macos")]
mod macos {
pub enum CGEventTap {}
pub type CGEventTapRef = core_foundation::mach_port::CFMachPortRef;
pub enum CGEvent {}
pub type CGEventRef = *mut CGEvent;

Expand Down

0 comments on commit f7e0b97

Please sign in to comment.