@@ -443,44 +443,75 @@ unsafe extern "C" fn cg_event_tap_callback_internal(
443443}
444444
445445/// ```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(
450451/// CGEventTapLocation::HID,
451452/// CGEventTapPlacement::HeadInsertEventTap,
452453/// CGEventTapOptions::Default,
453454/// vec![CGEventType::MouseMoved],
454- /// |_a, _b, d | {
455- /// println!("{:?}", d .location());
455+ /// |_proxy, _type, event | {
456+ /// println!("{:?}", event .location());
456457/// None
457458/// },
458- /// ) {
459- /// Ok(tap) => unsafe {
459+ /// |tap| {
460460/// let loop_source = tap
461461/// .mach_port()
462462/// .create_runloop_source(0)
463463/// .expect("Runloop source creation failed");
464- /// current.add_source(&loop_source, kCFRunLoopCommonModes);
464+ /// current.add_source(&loop_source, unsafe { kCFRunLoopCommonModes } );
465465/// tap.enable();
466466/// CFRunLoop::run_current();
467467/// },
468- /// Err(_) => (assert!(false)),
469- /// }
468+ /// ).expect("Failed to install event tap");
470469/// ```
471470pub struct CGEventTap < ' tap_life > {
472471 mach_port : CFMachPort ,
473472 _callback : Box < CGEventTapCallBackFn < ' tap_life > > ,
474473}
475474
476- impl < ' tap_life > CGEventTap < ' tap_life > {
477- 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 > (
478477 tap : CGEventTapLocation ,
479478 place : CGEventTapPlacement ,
480479 options : CGEventTapOptions ,
481480 events_of_interest : std:: vec:: Vec < CGEventType > ,
482481 callback : F ,
483- ) -> 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 , ( ) > {
484515 let event_mask: CGEventMask = events_of_interest
485516 . iter ( )
486517 . fold ( CGEventType :: Null as CGEventMask , |mask, & etype| {
0 commit comments