Event Tap strangeness

  • I'm trying to observe all mouse down and key down events with an
    event tap.

    Everything seems to work ok, but when I shut the event tap down, I'm
    seeing some bizarre event related behaviour in my app and other apps.

    These include:

    events disappearing (typically a click or key has no effect, until
    repeated).

    events being passed to the wrong app (e.g. command-D in a file dialog
    in my app instead creates a bookmark in Xcode sitting behind it).

    events delivery being delayed, or delivered twice. e.g. I hit F11 in
    my app, but when I quit the app seconds later, another F11 gets
    delivered (i.e. Desktop is revealed).

    I'm pretty sure that these are connected to the event tapping,
    although not how - they suddenly appeared after I rolled in the event
    tapping code. I don't get this for every event - it sometimes seems
    as though I get a single misdelivered event just after switching to a
    new application, although it's not quite that regular.

    I'm using kCGEventTapOptionListenOnly and returning the event
    unchanged. I'm pretty sure that its getting shut down correctly, as I
    don't see the callback function getting invoked after I stop tapping.

    Any suggestions would be great.

        cheers,
                m.

    CGEventRef MyEventTapCallback (
                                    CGEventTapProxy proxy,
                                    CGEventType type,
                                    CGEventRef event,
                                    void *refcon
                                    )
    {
        [[(CLSilverbackEventTapper *)refcon delegate] handleEvent:event];

        return event;
    }

    - (void) startTapping
    {
        NSLog(@"Installing event tap");

        if(mEventTap != NULL)
        {
            NSLog(@"WARNING: Event tap already exists");
            return;
        }

        CGEventMask eventsOfInterest = CGEventMaskBit
    (kCGEventLeftMouseDown) |
                            CGEventMaskBit(kCGEventRightMouseDown) |
                            CGEventMaskBit(kCGEventOtherMouseDown) |
                            CGEventMaskBit(kCGEventKeyDown);

        mEventTap = CGEventTapCreate (
                                      kCGSessionEventTap,
                                      kCGTailAppendEventTap,
                                      kCGEventTapOptionListenOnly,
                                      eventsOfInterest,
                                      MyEventTapCallback,
                                      self
                                      );

        if(mEventTap == NULL)
        {
            NSLog(@"WARNING: Could not create event tap");
            return;
        }

        mEventSrc = CFMachPortCreateRunLoopSource(NULL, mEventTap, 0);
        if(mEventSrc == NULL)
        {
            NSLog(@"No event run loop src?\n");
            return;
        }

        // Get the CFRunLoop primitive for the Carbon Main Event Loop,
    and add the new event souce
        // CFRunLoopAddSource((CFRunLoopRef) (GetCFRunLoopFromEventLoop
    (GetMainEventLoop())), mEventSrc, kCFRunLoopDefaultMode);
        CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventSrc,
    kCFRunLoopCommonModes);
    }

    - (void) stopTapping
    {
        NSLog(@"Removing event tap");

        if(mEventSrc)
        {
            // CFRunLoopRemoveSource((CFRunLoopRef)
    (GetCFRunLoopFromEventLoop(GetMainEventLoop())), mEventSrc,
    kCFRunLoopDefaultMode);
            CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventSrc,
    kCFRunLoopCommonModes);
            CFRelease(mEventSrc);
        }

        if(mEventTap != NULL)
        {
            CFRelease(mEventTap);
        }
    }
  • on 2008-02-12 8:13 AM, Martin Redington at <m.redington...> wrote:

    > I'm trying to observe all mouse down and key down events with an
    > event tap.
    >
    > Everything seems to work ok, but when I shut the event tap down, I'm
    > seeing some bizarre event related behaviour in my app and other apps.

    I've been using event taps extensively for the last few months, and I have
    not observed any of the behavior you describe. (Haven't tried it under
    10.5.2 yet, however.)

    Download my free Event Taps Testbench and see if you see similar behavior.
    <http://prefabsoftware.com/eventtapstestbench>.

    --

    Bill Cheeseman - <bill...>
    Quechee Software, Quechee, Vermont, USA
    www.quecheesoftware.com

    PreFab Software - www.prefabsoftware.com
  • The Event Taps Test Bench isn't giving me that behaviour, but it does
    seem to indicate that my event tap isn't being removed for some reason.

    The docs indicate that I should just need to call CFRelease to
    release and remove the tap, and I'm removing and releasing the run
    loop source beforehand, so I'm not sure what's happening there, but
    for some reason it's not being cleaned up properly.

    On 12 Feb 2008, at 14:14, Bill Cheeseman wrote:

    > on 2008-02-12 8:13 AM, Martin Redington at <m.redington...>
    > wrote:
    >
    >> I'm trying to observe all mouse down and key down events with an
    >> event tap.
    >>
    >> Everything seems to work ok, but when I shut the event tap down, I'm
    >> seeing some bizarre event related behaviour in my app and other apps.
    >
    > I've been using event taps extensively for the last few months, and
    > I have
    > not observed any of the behavior you describe. (Haven't tried it under
    > 10.5.2 yet, however.)
    >
    > Download my free Event Taps Testbench and see if you see similar
    > behavior.
    > <http://prefabsoftware.com/eventtapstestbench>.
    >
    > --
    >
    > Bill Cheeseman - <bill...>
    > Quechee Software, Quechee, Vermont, USA
    > www.quecheesoftware.com
    >
    > PreFab Software - www.prefabsoftware.com
    >
  • on 2008-02-12 11:43 AM, Martin Redington at <m.redington...> wrote:

    > The Event Taps Test Bench isn't giving me that behaviour, but it does
    > seem to indicate that my event tap isn't being removed for some reason.
    >
    > The docs indicate that I should just need to call CFRelease to
    > release and remove the tap, and I'm removing and releasing the run
    > loop source beforehand, so I'm not sure what's happening there, but
    > for some reason it's not being cleaned up properly.

    My memory is that CFRelease is not enough, but my code is at home and I
    can't check it until this evening.

    The quartz-dev list might get you more information.

    --

    Bill Cheeseman - <bill...>
    Quechee Software, Quechee, Vermont, USA
    www.quecheesoftware.com

    PreFab Software - www.prefabsoftware.com
  • At 08:55 -0800 12/02/08, <cocoa-dev-request...> wrote:
    > From: Martin Redington <m.redington...>
    > Precedence: list
    > MIME-Version: 1.0 (Apple Message framework v752.3)
    > To: Apple Cocoa-Dev Mailing List <cocoa-dev...>
    > Date: Tue, 12 Feb 2008 13:13:32 +0000
    > Message-ID: <890E357C-9C3A-4823-A2F3-B98CBE6E457B...>
    > Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed
    > Subject: Event Tap strangeness
    > Message: 4
    >
    >
    > I'm trying to observe all mouse down and key down events with an event tap.
    >
    > Everything seems to work ok, but when I shut the event tap down, I'm seeing some bizarre event related behaviour in my app and other apps.
    > ...
    > - (void) startTapping
    > {
    > NSLog(@"Installing event tap");
    >
    > if(mEventTap != NULL)
    > {
    > NSLog(@"WARNING: Event tap already exists");
    > return;
    > }
    >
    > CGEventMask eventsOfInterest = CGEventMaskBit(kCGEventLeftMouseDown) |
    > CGEventMaskBit(kCGEventRightMouseDown) |
    > CGEventMaskBit(kCGEventOtherMouseDown) |
    > CGEventMaskBit(kCGEventKeyDown);
    >
    > mEventTap = CGEventTapCreate (
    > kCGSessionEventTap,
    > kCGTailAppendEventTap,
    > kCGEventTapOptionListenOnly,
    > eventsOfInterest,
    > MyEventTapCallback,
    > self
    > );
    >
    > if(mEventTap == NULL)
    > {
    > NSLog(@"WARNING: Could not create event tap");
    > return;
    > }
    >
    >
    > mEventSrc = CFMachPortCreateRunLoopSource(NULL, mEventTap, 0);
    > if(mEventSrc == NULL)
    > {
    > NSLog(@"No event run loop src?\n");
    > return;
    > }
    >
    > // Get the CFRunLoop primitive for the Carbon Main Event Loop, and add the new event souce
    > // CFRunLoopAddSource((CFRunLoopRef) (GetCFRunLoopFromEventLoop(GetMainEventLoop())), mEventSrc, kCFRunLoopDefaultMode);
    > CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventSrc, kCFRunLoopCommonModes);
    > }
    >
    > - (void) stopTapping
    > {
    > NSLog(@"Removing event tap");
    >
    > if(mEventSrc)
    > {
    > // CFRunLoopRemoveSource((CFRunLoopRef) (GetCFRunLoopFromEventLoop(GetMainEventLoop())), mEventSrc, kCFRunLoopDefaultMode);
    > CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventSrc, kCFRunLoopCommonModes);
    > CFRelease(mEventSrc);
    > }
    >
    > if(mEventTap != NULL)
    > {
    > CFRelease(mEventTap);
    > }
    > }

    Not really a Cocoa problem, but anyway :-)

    I had similar problems (for similar code) until I twiddled the sequence of statements on both start and stop. Here's what I worked out, converted to your names (and condensed for clarity):

    - (void) startTapping {
        mEventTap = CGEventTapCreate (...args...);
        mEventSrc = CFMachPortCreateRunLoopSource(NULL, mEventTap, 0);
        CFRelease(mEventTap);
        CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventSrc, kCFRunLoopCommonModes);
        CFRelease(mEventSrc);
    }

    - (void) stopTapping {
            CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventSrc, kCFRunLoopCommonModes);
    }

    ...apparently this makes tap and source go away as soon as the source is removed from the event loop. If you over-retain and release them only after the source is removed, the tap clogs...

    HTH,
    --
    Rainer Brockerhoff  <rainer...>
    Belo Horizonte, Brazil
    "In the affairs of others even fools are wise
    In their own business even sages err."
    Weblog: http://www.brockerhoff.net/bb/viewtopic.php
  • Thanks Rainer,

        that seems to have done the trick!

    Its a bit weird that this doesn't clean up properly if you do the
    releases later, but your solution works for me.

        cheers,
                m.

    On 12 Feb 2008, at 17:50, Rainer Brockerhoff wrote:

    > At 08:55 -0800 12/02/08, <cocoa-dev-request...> wrote:
    >> From: Martin Redington <m.redington...>
    >> Precedence: list
    >> MIME-Version: 1.0 (Apple Message framework v752.3)
    >> To: Apple Cocoa-Dev Mailing List <cocoa-dev...>
    >> Date: Tue, 12 Feb 2008 13:13:32 +0000
    >> Message-ID: <890E357C-9C3A-4823-A2F3-B98CBE6E457B...>
    >> Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed
    >> Subject: Event Tap strangeness
    >> Message: 4
    >>
    >>
    >> I'm trying to observe all mouse down and key down events with an
    >> event tap.
    >>
    >> Everything seems to work ok, but when I shut the event tap down,
    >> I'm seeing some bizarre event related behaviour in my app and
    >> other apps.
    >> ...
    >> - (void) startTapping
    >> {
    >> NSLog(@"Installing event tap");
    >>
    >> if(mEventTap != NULL)
    >> {
    >> NSLog(@"WARNING: Event tap already exists");
    >> return;
    >> }
    >>
    >> CGEventMask eventsOfInterest = CGEventMaskBit
    >> (kCGEventLeftMouseDown) |
    >> CGEventMaskBit(kCGEventRightMouseDown) |
    >> CGEventMaskBit(kCGEventOtherMouseDown) |
    >> CGEventMaskBit(kCGEventKeyDown);
    >>
    >> mEventTap = CGEventTapCreate (
    >> kCGSessionEventTap,
    >> kCGTailAppendEventTap,
    >> kCGEventTapOptionListenOnly,
    >> eventsOfInterest,
    >> MyEventTapCallback,
    >> self
    >> );
    >>
    >> if(mEventTap == NULL)
    >> {
    >> NSLog(@"WARNING: Could not create event tap");
    >> return;
    >> }
    >>
    >>
    >> mEventSrc = CFMachPortCreateRunLoopSource(NULL, mEventTap, 0);
    >> if(mEventSrc == NULL)
    >> {
    >> NSLog(@"No event run loop src?\n");
    >> return;
    >> }
    >>
    >> // Get the CFRunLoop primitive for the Carbon Main Event Loop,
    >> and add the new event souce
    >> // CFRunLoopAddSource((CFRunLoopRef) (GetCFRunLoopFromEventLoop
    >> (GetMainEventLoop())), mEventSrc, kCFRunLoopDefaultMode);
    >> CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventSrc,
    >> kCFRunLoopCommonModes);
    >> }
    >>
    >> - (void) stopTapping
    >> {
    >> NSLog(@"Removing event tap");
    >>
    >> if(mEventSrc)
    >> {
    >> // CFRunLoopRemoveSource((CFRunLoopRef)
    >> (GetCFRunLoopFromEventLoop(GetMainEventLoop())), mEventSrc,
    >> kCFRunLoopDefaultMode);
    >> CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventSrc,
    >> kCFRunLoopCommonModes);
    >> CFRelease(mEventSrc);
    >> }
    >>
    >> if(mEventTap != NULL)
    >> {
    >> CFRelease(mEventTap);
    >> }
    >> }
    >
    > Not really a Cocoa problem, but anyway :-)
    >
    > I had similar problems (for similar code) until I twiddled the
    > sequence of statements on both start and stop. Here's what I worked
    > out, converted to your names (and condensed for clarity):
    >
    > - (void) startTapping {
    > mEventTap = CGEventTapCreate (...args...);
    > mEventSrc = CFMachPortCreateRunLoopSource(NULL, mEventTap, 0);
    > CFRelease(mEventTap);
    > CFRunLoopAddSource(CFRunLoopGetCurrent(), mEventSrc,
    > kCFRunLoopCommonModes);
    > CFRelease(mEventSrc);
    > }
    >
    > - (void) stopTapping {
    > CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mEventSrc,
    > kCFRunLoopCommonModes);
    > }
    >
    > ...apparently this makes tap and source go away as soon as the
    > source is removed from the event loop. If you over-retain and
    > release them only after the source is removed, the tap clogs...
    >
    > HTH,
    > --
    > Rainer Brockerhoff  <rainer...>
    > Belo Horizonte, Brazil
    > "In the affairs of others even fools are wise
    > In their own business even sages err."
    > Weblog: http://www.brockerhoff.net/bb/viewtopic.php
    >
  • At 18:12 +0000 12/02/08, Martin Redington wrote:
    > that seems to have done the trick!
    >
    > Its a bit weird that this doesn't clean up properly if you do the releases later, but your solution works for me.

    Yay. The rationale seems to be that, if you do it later, there's a time window where first the source lives a bit without a runloop to supply, then the tap lives a bit without a source to supply to. Of course I'm not sure if it's _really_ that way.

    --
    Rainer Brockerhoff  <rainer...>
    Belo Horizonte, Brazil
    "In the affairs of others even fools are wise
    In their own business even sages err."
    Weblog: http://www.brockerhoff.net/bb/viewtopic.php
  • on 2008-02-12 12:50 PM, Rainer Brockerhoff at <rainer...> wrote:

    > I had similar problems (for similar code) until I twiddled the sequence of
    > statements on both start and stop. Here's what I worked out,....

    Yeah, from memory that looks pretty much like what I do (but my code is
    wrapped in Objective-C methods).

    Also, my code does invalidate the event tap before releasing it, as the
    responsible Apple engineer indicated it should when this thread moved over
    to the quartz-dev list.

    --

    Bill Cheeseman - <bill...>
    Quechee Software, Quechee, Vermont, USA
    www.quecheesoftware.com

    PreFab Software - www.prefabsoftware.com
previous month february 2008 next month
MTWTFSS
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29    
Go to today
MindNode
MindNode offered a free license !