@@ -6,7 +6,7 @@ use bitflags::bitflags;
6
6
use core:: ffi:: { c_ulong, c_void} ;
7
7
use core_foundation:: {
8
8
base:: { CFRelease , CFRetain , CFTypeID , TCFType } ,
9
- mach_port:: { CFMachPort , CFMachPortRef } ,
9
+ mach_port:: { CFMachPort , CFMachPortInvalidate , CFMachPortRef } ,
10
10
} ;
11
11
use foreign_types:: { foreign_type, ForeignType } ;
12
12
use std:: mem:: ManuallyDrop ;
@@ -417,7 +417,7 @@ macro_rules! CGEventMaskBit {
417
417
}
418
418
419
419
pub type CGEventTapProxy = * const c_void ;
420
- pub type CGEventTapCallBackFn < ' tap_life > =
420
+ type CGEventTapCallBackFn < ' tap_life > =
421
421
Box < dyn Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' tap_life > ;
422
422
type CGEventTapCallBackInternal = unsafe extern "C" fn (
423
423
proxy : CGEventTapProxy ,
@@ -443,51 +443,81 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
443
443
}
444
444
445
445
/// ```no_run
446
- ///use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
447
- ///use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
448
- ///let current = CFRunLoop::get_current();
449
- ///match CGEventTap::new(
446
+ /// use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
447
+ /// use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
448
+ /// let current = CFRunLoop::get_current();
449
+ ///
450
+ /// CGEventTap::with(
450
451
/// CGEventTapLocation::HID,
451
452
/// CGEventTapPlacement::HeadInsertEventTap,
452
453
/// CGEventTapOptions::Default,
453
454
/// vec![CGEventType::MouseMoved],
454
- /// |_a, _b, d | {
455
- /// println!("{:?}", d .location());
455
+ /// |_proxy, _type, event | {
456
+ /// println!("{:?}", event .location());
456
457
/// None
457
458
/// },
458
- /// ) {
459
- /// Ok(tap) => unsafe {
459
+ /// |tap| {
460
460
/// let loop_source = tap
461
- /// .mach_port
461
+ /// .mach_port()
462
462
/// .create_runloop_source(0)
463
- /// .expect("Somethings is bad ");
464
- /// current.add_source(&loop_source, kCFRunLoopCommonModes);
463
+ /// .expect("Runloop source creation failed ");
464
+ /// current.add_source(&loop_source, unsafe { kCFRunLoopCommonModes } );
465
465
/// tap.enable();
466
466
/// CFRunLoop::run_current();
467
467
/// },
468
- /// Err(_) => (assert!(false)),
469
- /// }
468
+ /// ).expect("Failed to install event tap");
470
469
/// ```
471
470
pub struct CGEventTap < ' tap_life > {
472
- pub mach_port : CFMachPort ,
473
- pub callback_ref :
474
- Box < dyn Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' tap_life > ,
471
+ mach_port : CFMachPort ,
472
+ _callback : Box < CGEventTapCallBackFn < ' tap_life > > ,
475
473
}
476
474
477
- impl < ' tap_life > CGEventTap < ' tap_life > {
478
- pub fn new < F : Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' tap_life > (
475
+ impl CGEventTap < ' static > {
476
+ pub fn new < F : Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' static > (
479
477
tap : CGEventTapLocation ,
480
478
place : CGEventTapPlacement ,
481
479
options : CGEventTapOptions ,
482
480
events_of_interest : std:: vec:: Vec < CGEventType > ,
483
481
callback : F ,
484
- ) -> Result < CGEventTap < ' tap_life > , ( ) > {
482
+ ) -> Result < Self , ( ) > {
483
+ // SAFETY: callback is 'static so even if this object is forgotten it
484
+ // will be valid to call.
485
+ unsafe { Self :: new_unchecked ( tap, place, options, events_of_interest, callback) }
486
+ }
487
+ }
488
+
489
+ impl < ' tap_life > CGEventTap < ' tap_life > {
490
+ pub fn with < R > (
491
+ tap : CGEventTapLocation ,
492
+ place : CGEventTapPlacement ,
493
+ options : CGEventTapOptions ,
494
+ events_of_interest : std:: vec:: Vec < CGEventType > ,
495
+ callback : impl Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' tap_life ,
496
+ with_fn : impl FnOnce ( & Self ) -> R ,
497
+ ) -> Result < R , ( ) > {
498
+ // SAFETY: We are okay to bypass the 'static restriction because the
499
+ // event tap is dropped before returning. The callback therefore cannot
500
+ // be called after its lifetime expires.
501
+ let event_tap: Self =
502
+ unsafe { Self :: new_unchecked ( tap, place, options, events_of_interest, callback) ? } ;
503
+ Ok ( with_fn ( & event_tap) )
504
+ }
505
+
506
+ /// Caller is responsible for ensuring that this object is dropped before
507
+ /// `'tap_life` expires.
508
+ pub unsafe fn new_unchecked (
509
+ tap : CGEventTapLocation ,
510
+ place : CGEventTapPlacement ,
511
+ options : CGEventTapOptions ,
512
+ events_of_interest : std:: vec:: Vec < CGEventType > ,
513
+ callback : impl Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' tap_life ,
514
+ ) -> Result < Self , ( ) > {
485
515
let event_mask: CGEventMask = events_of_interest
486
516
. iter ( )
487
517
. fold ( CGEventType :: Null as CGEventMask , |mask, & etype| {
488
518
mask | CGEventMaskBit ! ( etype)
489
519
} ) ;
490
- let cb = Box :: new ( Box :: new ( callback) as CGEventTapCallBackFn ) ;
520
+ let cb: Box < CGEventTapCallBackFn > = Box :: new ( Box :: new ( callback) ) ;
491
521
let cbr = Box :: into_raw ( cb) ;
492
522
unsafe {
493
523
let event_tap_ref = CGEventTapCreate (
@@ -502,7 +532,7 @@ impl<'tap_life> CGEventTap<'tap_life> {
502
532
if !event_tap_ref. is_null ( ) {
503
533
Ok ( Self {
504
534
mach_port : ( CFMachPort :: wrap_under_create_rule ( event_tap_ref) ) ,
505
- callback_ref : Box :: from_raw ( cbr) ,
535
+ _callback : Box :: from_raw ( cbr) ,
506
536
} )
507
537
} else {
508
538
let _ = Box :: from_raw ( cbr) ;
@@ -511,11 +541,21 @@ impl<'tap_life> CGEventTap<'tap_life> {
511
541
}
512
542
}
513
543
544
+ pub fn mach_port ( & self ) -> & CFMachPort {
545
+ & self . mach_port
546
+ }
547
+
514
548
pub fn enable ( & self ) {
515
549
unsafe { CGEventTapEnable ( self . mach_port . as_concrete_TypeRef ( ) , true ) }
516
550
}
517
551
}
518
552
553
+ impl Drop for CGEventTap < ' _ > {
554
+ fn drop ( & mut self ) {
555
+ unsafe { CFMachPortInvalidate ( self . mach_port . as_CFTypeRef ( ) as * mut _ ) } ;
556
+ }
557
+ }
558
+
519
559
foreign_type ! {
520
560
#[ doc( hidden) ]
521
561
pub unsafe type CGEvent {
0 commit comments