Skip to content

Commit 7e4d907

Browse files
authored
Allow dropping event from CGEventTap callback (#724)
1 parent 548b65c commit 7e4d907

File tree

1 file changed

+36
-22
lines changed

1 file changed

+36
-22
lines changed

core-graphics/src/event.rs

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use core_foundation::{
99
mach_port::{CFMachPort, CFMachPortInvalidate, CFMachPortRef},
1010
};
1111
use foreign_types::{foreign_type, ForeignType};
12-
use std::mem::ManuallyDrop;
12+
use std::{mem::ManuallyDrop, ptr};
1313

1414
pub type CGEventField = u32;
1515
pub type CGKeyCode = u16;
@@ -503,8 +503,21 @@ macro_rules! CGEventMaskBit {
503503
}
504504

505505
pub type CGEventTapProxy = *const c_void;
506-
type CGEventTapCallBackFn<'tap_life> =
507-
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life>;
506+
507+
/// What the system should do with the event passed to the callback.
508+
///
509+
/// This value is ignored if [`CGEventTapOptions::ListenOnly`] is specified.
510+
pub enum CallbackResult {
511+
/// Pass the event unchanged to other consumers.
512+
Keep,
513+
/// Drop the event so it is not passed to later consumers.
514+
Drop,
515+
/// Replace the event with a different one.
516+
Replace(CGEvent),
517+
}
518+
519+
type CGEventTapCallbackFn<'tap_life> =
520+
Box<dyn Fn(CGEventTapProxy, CGEventType, &CGEvent) -> CallbackResult + 'tap_life>;
508521
type CGEventTapCallBackInternal = unsafe extern "C" fn(
509522
proxy: CGEventTapProxy,
510523
etype: CGEventType,
@@ -513,24 +526,25 @@ type CGEventTapCallBackInternal = unsafe extern "C" fn(
513526
) -> crate::sys::CGEventRef;
514527

515528
unsafe extern "C" fn cg_event_tap_callback_internal(
516-
_proxy: CGEventTapProxy,
517-
_etype: CGEventType,
518-
_event: crate::sys::CGEventRef,
519-
_user_info: *const c_void,
529+
proxy: CGEventTapProxy,
530+
etype: CGEventType,
531+
event: crate::sys::CGEventRef,
532+
user_info: *const c_void,
520533
) -> crate::sys::CGEventRef {
521-
let callback = _user_info as *mut CGEventTapCallBackFn;
522-
let event = CGEvent::from_ptr(_event);
523-
let new_event = (*callback)(_proxy, _etype, &event);
524-
let event = match new_event {
525-
Some(new_event) => new_event,
526-
None => event,
527-
};
528-
ManuallyDrop::new(event).as_ptr()
534+
let callback = user_info as *mut CGEventTapCallbackFn;
535+
let event = ManuallyDrop::new(CGEvent::from_ptr(event));
536+
let response = (*callback)(proxy, etype, &event);
537+
use CallbackResult::*;
538+
match response {
539+
Keep => event.as_ptr(),
540+
Drop => ptr::null_mut(),
541+
Replace(new_event) => ManuallyDrop::new(new_event).as_ptr(),
542+
}
529543
}
530544

531545
/// ```no_run
532546
/// use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
533-
/// use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
547+
/// use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType, CallbackResult};
534548
/// let current = CFRunLoop::get_current();
535549
///
536550
/// CGEventTap::with(
@@ -540,7 +554,7 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
540554
/// vec![CGEventType::MouseMoved],
541555
/// |_proxy, _type, event| {
542556
/// println!("{:?}", event.location());
543-
/// None
557+
/// CallbackResult::Keep
544558
/// },
545559
/// |tap| {
546560
/// let loop_source = tap
@@ -555,11 +569,11 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
555569
/// ```
556570
pub struct CGEventTap<'tap_life> {
557571
mach_port: CFMachPort,
558-
_callback: Box<CGEventTapCallBackFn<'tap_life>>,
572+
_callback: Box<CGEventTapCallbackFn<'tap_life>>,
559573
}
560574

561575
impl CGEventTap<'static> {
562-
pub fn new<F: Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'static>(
576+
pub fn new<F: Fn(CGEventTapProxy, CGEventType, &CGEvent) -> CallbackResult + 'static>(
563577
tap: CGEventTapLocation,
564578
place: CGEventTapPlacement,
565579
options: CGEventTapOptions,
@@ -578,7 +592,7 @@ impl<'tap_life> CGEventTap<'tap_life> {
578592
place: CGEventTapPlacement,
579593
options: CGEventTapOptions,
580594
events_of_interest: std::vec::Vec<CGEventType>,
581-
callback: impl Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life,
595+
callback: impl Fn(CGEventTapProxy, CGEventType, &CGEvent) -> CallbackResult + 'tap_life,
582596
with_fn: impl FnOnce(&Self) -> R,
583597
) -> Result<R, ()> {
584598
// SAFETY: We are okay to bypass the 'static restriction because the
@@ -596,14 +610,14 @@ impl<'tap_life> CGEventTap<'tap_life> {
596610
place: CGEventTapPlacement,
597611
options: CGEventTapOptions,
598612
events_of_interest: std::vec::Vec<CGEventType>,
599-
callback: impl Fn(CGEventTapProxy, CGEventType, &CGEvent) -> Option<CGEvent> + 'tap_life,
613+
callback: impl Fn(CGEventTapProxy, CGEventType, &CGEvent) -> CallbackResult + 'tap_life,
600614
) -> Result<Self, ()> {
601615
let event_mask: CGEventMask = events_of_interest
602616
.iter()
603617
.fold(CGEventType::Null as CGEventMask, |mask, &etype| {
604618
mask | CGEventMaskBit!(etype)
605619
});
606-
let cb: Box<CGEventTapCallBackFn> = Box::new(Box::new(callback));
620+
let cb: Box<CGEventTapCallbackFn> = Box::new(Box::new(callback));
607621
let cbr = Box::into_raw(cb);
608622
unsafe {
609623
let event_tap_ref = CGEventTapCreate(

0 commit comments

Comments
 (0)