I just recently discovered the new CoreGraphics events API that are
in Tiger, and in particular I'm interested in event taps. So far
they're undocumented, but there was enough information in /System/
Library/Frameworks/ApplicationServices.framework/Frameworks/
CoreGraphics.framework/Headers/CGEvent.h for me to get the basic
jist of it.
So I tried throwing together a quick Carbon app that would make an
event tap that outputs a message when it's triggered (for say,
pressing the middle mouse button) but it doesn't work. If I set
the event tap to be a listener only, everything on my computer
behaves normally but no event is ever received by the tap. More
alarming though is when I set it not to be a listening-only tap.
As soon as I clicked a mouse button > 2, the entire system would
lock up. No keypresses or mouse events would be registered by
anything at all, though the cursor would still move around on the
screen. This problem persists until a few seconds after the
application terminates or the event tap is released. I've tried
making the function the event tap calls do various different minor
things like beeping or just doing nothing, but the UI lock still
occurs. Also, changing what events are being monitored seems to
have no effect - tapping any kind of event causes this to happen.
A listen-only event tap listens to events, but does not filter them.
Without the kCGEventTapOptionListenOnly option, the event tap acts as
a filter, which can effectively stall the flow of events through the
system unless it acts on and processes events promptly. At the very
low level that event taps operate at, the system guarantees that
events will be delivered sequentially. (We wouldn't want that
modifier key for your mouse click to arrive after the click, right?)
The symptoms you are describing are all indicative of the tapping
application not yet actually listening for events on the event tap's
CFMachPortRef. In your source code, nothing was done to actually
place the tap's CFMachPortRef in the Carbon MainEventLoop.
The CGEventTap code doesn't do this automatically, because there may
be many different kinds of run loops in applications. In general,
for fitering event tap applications, I recommend running the event
tap filter in it's own thread, with it's own CFRunLoop, rather than
in the main application thread. Trying to filter all the system's
events in the main application thread effectively throttles the flow
of events through the system to the rate at which your application
can process, draw, and fetch the next event.
So... what can I do? There's no documentation about these
functions so I can't check if I'm doing something wrong, and no one
else seems to have used them yet. I would have a hard time
believing that they're just broken.
So far, so good. You have an event tap port. Now you need to turn
it into a runloop source, and in this case, add it to the runloop
behind the Carbon main event loop. Note that I normally don't
recommend doing this, as it will throttle the flow of events to the
rate at which the main loop can process and draw. In this case, the
main event loop will just be servicing the CGEventTap, so we might be
able to get away with this.
eventSrc = CFMachPortCreateRunLoopSource(NULL, machPortRef, 0);
if ( eventSrc == NULL )
printf( "No event run loop src?\n" );
// Get the CFRunLoop primitive for the Carbon Main Event Loop,
and add the new event souce
CFRunLoopAddSource(GetCFRunLoopFromEventLoop(GetMainEventLoop
()), eventSrc, kCFRunLoopDefaultMode);
RunApplicationEventLoop();
if (machPortRef)
CFRelease(machPortRef);
if ( eventSrc )
CFRelease(eventSrc);
}
In a command line tool, faceless app, or daemon, you can do something
similar purely at the CoreFoundation level:
eventSrc = CFMachPortCreateRunLoopSource(NULL, eventPort, 0);
if ( eventSrc == NULL )
printf( "No event run loop src?\n" );
runLoop = CFRunLoopGetCurrent();
if ( runLoop == NULL )
printf( "No run loop?\n" );
CFRunLoopAddSource(runLoop, eventSrc, kCFRunLoopDefaultMode);
CFRunLoopRun();
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Quartz-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden