@@ -440,44 +440,75 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
440
440
}
441
441
442
442
/// ```no_run
443
- ///use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
444
- ///use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
445
- ///let current = CFRunLoop::get_current();
446
- ///match CGEventTap::new(
443
+ /// use core_foundation::runloop::{kCFRunLoopCommonModes, CFRunLoop};
444
+ /// use core_graphics::event::{CGEventTap, CGEventTapLocation, CGEventTapPlacement, CGEventTapOptions, CGEventType};
445
+ /// let current = CFRunLoop::get_current();
446
+ ///
447
+ /// CGEventTap::with(
447
448
/// CGEventTapLocation::HID,
448
449
/// CGEventTapPlacement::HeadInsertEventTap,
449
450
/// CGEventTapOptions::Default,
450
451
/// vec![CGEventType::MouseMoved],
451
- /// |_a, _b, d | {
452
- /// println!("{:?}", d .location());
452
+ /// |_proxy, _type, event | {
453
+ /// println!("{:?}", event .location());
453
454
/// None
454
455
/// },
455
- /// ) {
456
- /// Ok(tap) => unsafe {
456
+ /// |tap| {
457
457
/// let loop_source = tap
458
458
/// .mach_port()
459
459
/// .create_runloop_source(0)
460
460
/// .expect("Runloop source creation failed");
461
- /// current.add_source(&loop_source, kCFRunLoopCommonModes);
461
+ /// current.add_source(&loop_source, unsafe { kCFRunLoopCommonModes } );
462
462
/// tap.enable();
463
463
/// CFRunLoop::run_current();
464
464
/// },
465
- /// Err(_) => (assert!(false)),
466
- /// }
465
+ /// ).expect("Failed to install event tap");
467
466
/// ```
468
467
pub struct CGEventTap < ' tap_life > {
469
468
mach_port : CFMachPort ,
470
469
_callback : Box < CGEventTapCallBackFn < ' tap_life > > ,
471
470
}
472
471
473
- impl < ' tap_life > CGEventTap < ' tap_life > {
474
- pub fn new < F : Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' tap_life > (
472
+ impl CGEventTap < ' static > {
473
+ pub fn new < F : Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' static > (
475
474
tap : CGEventTapLocation ,
476
475
place : CGEventTapPlacement ,
477
476
options : CGEventTapOptions ,
478
477
events_of_interest : std:: vec:: Vec < CGEventType > ,
479
478
callback : F ,
480
- ) -> Result < CGEventTap < ' tap_life > , ( ) > {
479
+ ) -> Result < Self , ( ) > {
480
+ // SAFETY: callback is 'static so even if this object is forgotten it
481
+ // will be valid to call.
482
+ unsafe { Self :: new_unchecked ( tap, place, options, events_of_interest, callback) }
483
+ }
484
+ }
485
+
486
+ impl < ' tap_life > CGEventTap < ' tap_life > {
487
+ pub fn with < R > (
488
+ tap : CGEventTapLocation ,
489
+ place : CGEventTapPlacement ,
490
+ options : CGEventTapOptions ,
491
+ events_of_interest : std:: vec:: Vec < CGEventType > ,
492
+ callback : impl Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' tap_life ,
493
+ with_fn : impl FnOnce ( & Self ) -> R ,
494
+ ) -> Result < R , ( ) > {
495
+ // SAFETY: We are okay to bypass the 'static restriction because the
496
+ // event tap is dropped before returning. The callback therefore cannot
497
+ // be called after its lifetime expires.
498
+ let event_tap: Self =
499
+ unsafe { Self :: new_unchecked ( tap, place, options, events_of_interest, callback) ? } ;
500
+ Ok ( with_fn ( & event_tap) )
501
+ }
502
+
503
+ /// Caller is responsible for ensuring that this object is dropped before
504
+ /// `'tap_life` expires.
505
+ pub unsafe fn new_unchecked (
506
+ tap : CGEventTapLocation ,
507
+ place : CGEventTapPlacement ,
508
+ options : CGEventTapOptions ,
509
+ events_of_interest : std:: vec:: Vec < CGEventType > ,
510
+ callback : impl Fn ( CGEventTapProxy , CGEventType , & CGEvent ) -> Option < CGEvent > + ' tap_life ,
511
+ ) -> Result < Self , ( ) > {
481
512
let event_mask: CGEventMask = events_of_interest
482
513
. iter ( )
483
514
. fold ( CGEventType :: Null as CGEventMask , |mask, & etype| {
0 commit comments