I am using CGEventTapCreateForPSN
to trap and filter keys for my application. I'm not interested in intercepting events for other applications. I'm pretty sure an event tap is too heavy handed for my purpose, but I've been unable to find a better way, and using the event tap works.
Specifically, this code does what I want.
GetCurrentProcess(&psn);
CFMachPortRef eventTap = CGEventTapCreateForPSN(
&psn,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventKeyDown)
| CGEventMaskBit(kCGEventKeyUp),
eventCallback,
userInfo);
And my callback is handled nicely, with the events being intercepted from the current application only.
Unfortunately, all the methods to get the current ProcessSerialNumber
have been deprecated as of 10.9. There is an old standard way of getting the ProcessSerialNumber
to pass to other routines in the same process, with this initialization...
ProcessSerialNumber psn = { 0, kCurrentProcess };
but that does not work when calling CGEventTapCreateForPSN
. The header file docs indicates as much, and the following code snippet returns NULL
as confirmation.
ProcessSerialNumber psn = { 0, kCurrentProcess };
CFMachPortRef eventTap = CGEventTapCreateForPSN(
&psn,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventKeyDown)
| CGEventMaskBit(kCGEventKeyUp),
eventCallback,
userInfo);
I can use CGEventTapCreate
but it taps the entire host, and I would then need to filter anything not directed to my application, and the CGEventTapProxy
is opaque, and I don't know how to use it to determine if its my app or not.
I have verified that the deprecated code still works, but Apple can decide to remove it at any time. So, does anyone have an idea how I should proceed for calling CGEventTapCreateForPSN
in Mavericks and beyond?
Thanks!
UPDATE
In 10.11 (I think that was El Capitan), a new function was added. While it has zero documentation, it has almost the exact same signature as CGEventTapCreateForPSN
.
CFMachPortRef CGEventTapCreateForPSN(
void *processSerialNumber,
CGEventTapPlacement place,
CGEventTapOptions options,
CGEventMask eventsOfInterest,
CGEventTapCallBack callback,
void *userInfo);
CFMachPortRef CGEventTapCreateForPid(
pid_t pid,
CGEventTapPlacement place,
CGEventTapOptions options,
CGEventMask eventsOfInterest,
CGEventTapCallBack callback,
void *userInfo);
Thus, the deprecated function is not needed since the PID can be used as the first parameter.
I think you should subclass NSApplication and override
- (void)sendEvent:(NSEvent *)theEvent
method for this purpose. From docs:Also:
Thus, you can intercept all the events passed though your application and call custom NSApplicationDelegate-inherited protocol methods.
I'm not sure if this approach solves the problem but you still make a try.
Another way is to subclass
NSApplication
and overridenextEventMatchingMask:untilDate:inMode:dequeue:
. This sees mouse events that are not seen by overridingsendEvent:
, e.g., when tracking a scroll bar. I'm not sure if it matters for keyboard events, which the question was about, but it might be of interest to others who stumble on this question.