Detecting calls made to InstallEventHandler

I'm currently working on a method of detecting apps that might have global access to user keystrokes. Among the currently available APIs(CGEventTap, IOHIDManager) I've also encountered [NSEvent addGlobalMonitorForEventsMatchingMask:handler], which upon further inspection seems to call into InstallEventHandler( found in HIToolbox):

extern OSStatus 
InstallEventHandler(
  EventTargetRef         inTarget,
  EventHandlerUPP        inHandler,
  ItemCount              inNumTypes,
  const EventTypeSpec *  inList,
  void *                 inUserData,
  EventHandlerRef *      outRef)

An example of this would be(requires approving the binary in System Preferences -> Accesibility):

#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>

//Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/CarbonEvents.h
extern void RunApplicationEventLoop(void);

OSStatus globalKeyPress(EventHandlerCallRef nextHandler, EventRef theEvent, void *userData)
{
    NSEvent *anEvent = [NSEvent eventWithEventRef:theEvent];
    printf("%s", anEvent.characters.UTF8String);
    fflush(stdout);
    return CallNextEventHandler(nextHandler, theEvent);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        EventTypeSpec espec = {
            .eventClass = kEventClassKeyboard,
            .eventKind = kEventRawKeyUp
        };

        EventHandlerUPP handlerFunction = NewEventHandlerUPP(globalKeyPress);
        OSStatus err = InstallEventHandler(GetEventMonitorTarget(), handlerFunction, 1, &espec, NULL, NULL);
        if (err) {
            NSLog(@"InstallEventHandler: %d", err);
        }

        RunApplicationEventLoop();
    }
    return 0;
}

The documentation for GetEventMonitorTarget states that:

The event monitor target is a special event target used to
 *    monitor user input events across all processes. When an event
 *    handler is installed on the event monitor target, the Carbon
 *    Event Manager examines the EventTypeSpec for user input event
 *    types, such as mouse-down, mouse-up, key-down, and so forth. It
 *    then requests that the WindowServer make copies of any of these
 *    events that are sent to any process, and deliver them to the
 *    current process also...

I'm guessing that some process must be managing a global list of apps registered for these events.

How can I inspect the list(ideally by registering a callback, but polling is also fine) of processes which have installed one of these global event handlers?

Accepted Reply

How can I inspect the list … of processes which have installed one of these global event handlers?

There’s no API for this. The HIToolbox event monitor is implemented on top of the window server, and the window server has very few public APIs, none of which directly expose the state of the HIToolbox event monitor.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

How can I inspect the list … of processes which have installed one of these global event handlers?

There’s no API for this. The HIToolbox event monitor is implemented on top of the window server, and the window server has very few public APIs, none of which directly expose the state of the HIToolbox event monitor.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"