@@ -440,44 +440,75 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
440440}
441441
442442/// ```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(
447448/// CGEventTapLocation::HID,
448449/// CGEventTapPlacement::HeadInsertEventTap,
449450/// CGEventTapOptions::Default,
450451/// vec![CGEventType::MouseMoved],
451- /// |_a, _b, d | {
452- /// println!("{:?}", d .location());
452+ /// |_proxy, _type, event | {
453+ /// println!("{:?}", event .location());
453454/// None
454455/// },
455- /// ) {
456- /// Ok(tap) => unsafe {
456+ /// |tap| {
457457/// let loop_source = tap
458458/// .mach_port()
459459/// .create_runloop_source(0)
460460/// .expect("Runloop source creation failed");
461- /// current.add_source(&loop_source, kCFRunLoopCommonModes);
461+ /// current.add_source(&loop_source, unsafe { kCFRunLoopCommonModes } );
462462/// tap.enable();
463463/// CFRunLoop::run_current();
464464/// },
465- /// Err(_) => (assert!(false)),
466- /// }
465+ /// ).expect("Failed to install event tap");
467466/// ```
468467pub struct CGEventTap < ' tap_life > {
469468 mach_port : CFMachPort ,
470469 _callback : Box < CGEventTapCallBackFn < ' tap_life > > ,
471470}
472471
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 > (
475474 tap : CGEventTapLocation ,
476475 place : CGEventTapPlacement ,
477476 options : CGEventTapOptions ,
478477 events_of_interest : std:: vec:: Vec < CGEventType > ,
479478 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 , ( ) > {
481512 let event_mask: CGEventMask = events_of_interest
482513 . iter ( )
483514 . fold ( CGEventType :: Null as CGEventMask , |mask, & etype| {
0 commit comments