CGEventTapCreate fail on Mojave (10.14)

On MacOSX 10.14 (Mojave) the behavior changed, the following code runs on 10.13 but fail on 10.14.

The creation of "CGEventTapCreate" is failing (returning null) on Mojave but works before.


Any thoughts? Thanks in advance!


// alterkeys.c
// http://osxbook.com
//
// Complile using the following command line:
//     clang -Wall -o alterkeys alterkeys.c -framework ApplicationServices
//


#include <ApplicationServices/ApplicationServices.h>


// This callback will be invoked every time there is a keystroke.
//
CGEventRef
myCGEventCallback(CGEventTapProxy proxy, CGEventType type,
                  CGEventRef event, void *refcon)
{
    // Paranoid sanity check.
    if ((type != kCGEventKeyDown) && (type != kCGEventKeyUp))
        return event;


    // The incoming keycode.
    CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(
                                       event, kCGKeyboardEventKeycode);


    // Swap 'a' (keycode=0) and 'z' (keycode=6).
    if (keycode == (CGKeyCode)0)
        keycode = (CGKeyCode)6;
    else if (keycode == (CGKeyCode)6)
        keycode = (CGKeyCode)0;


    // Set the modified keycode field in the event.
    CGEventSetIntegerValueField(
        event, kCGKeyboardEventKeycode, (int64_t)keycode);


    // We must return the event for it to be useful.
    return event;
}


int
main(void)
{
    CGEventMask eventMask = CGEventMaskBit(kCGEventLeftMouseDown) |
                   CGEventMaskBit(kCGEventLeftMouseUp);
    CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0,
                                eventMask, myCGEventCallback, NULL);
    if (!eventTap) {
        fprintf(stderr, "failed to create event tap\n");
        exit(1);
    }


    // Create a run loop source.
    CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(
                        kCFAllocatorDefault, eventTap, 0);


    // Add to the current run loop.
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
                       kCFRunLoopCommonModes);


    // Enable the event tap.
    CGEventTapEnable(eventTap, true);


    // Set it all running.
    CFRunLoopRun();


    // In a real program, one would have arranged for cleaning up.


    exit(0);
}

Replies

Got this working after some fighting. Add this to your info.plist:


<key>NSAppleEventsUsageDescription</key>

<string></string>


Then go to your system preferences -> security -> privacy -> accessibility, and ensure your app is there and checked. If it's already there and this keeps happening, remove it and add it again. I have to do this every time I rebuild my app 😟

Thanks tsts123!


Do you know if there is a way to automatically add to the accessibility? Something like the first run, or during installation?

I just upgraded to Mojave (many reasons why it took this long but I'm there now) And I'm struggling with the same kind of problem, I've tried your workaround of editing my Info.plist but that hasn't worked for me. Does your application require running as root? In the past (like high sierra etc) the only way I could get CGEventTapCreate to succeed was to run my application as root. If your app doesn't require root how are you working around that???


Here is my Info.plist


<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plist version="1.0">

<dict>

<key>CFBundleDevelopmentRegion</key>

<string>English</string>

<key>CFBundleExecutable</key>

<string>MacPwdMgr</string>

<key>CFBundleIconFile</key>

<string>padlock</string>

<key>CFBundleIdentifier</key>

<string>com.xxxx.MacPwdMgr</string>

<key>CFBundleInfoDictionaryVersion</key>

<string>6.0</string>

<key>CFBundlePackageType</key>

<string>APPL</string>

<key>CFBundleSignature</key>

<string>????</string>

<key>NSAppleEventsUsageDescription</key>

<string></string>

<key>CFBundleURLTypes</key>

<array>

<dict>

<key>CFBundleURLSchemes</key>

<array>

<string>tel</string>

<string>sip</string>

</array>

</dict>

</array>

<key>CFBundleVersion</key>

<string>1.0</string>

<key>NSAppTransportSecurity</key>

<dict>

<key>NSAllowsArbitraryLoads</key>

<true/>

<key>NSExceptionDomains</key>

<dict>

<key>xxxx.com</key>

<dict>

<key>NSExceptionAllowsInsecureHTTPLoads</key>

<true/>

<key>NSIncludesSubdomains</key>

<true/>

</dict>

</dict>

</dict>

<key>NSAppleScriptEnabled</key>

<string>YES</string>

<key>NSMainNibFile</key>

<string>MainMenu</string>

<key>NSPrincipalClass</key>

<string>NSApplication</string>

<key>NSUIElement</key>

<string>1</string>

</dict>

</plist>

In the past I had to run as root (high sierra), but I guess I failed to try to run as myself once I made the above changes. Can't say if I needed the plist.info change or not but it does work now if I run it as myself and it's in the accessibility app list.


Thanks everyone!


I've created test sample and it works if you start it this way:

Code Block c
APP_PATH=./CmdLauncherOSX.app/Contents/MacOS/CmdLauncherOSX
#compile:
clang -Wall -o alterkeys alterkeys.c -framework ApplicationServices
#copy:
cp alterkeys $APP_PATH
#run:
open -a Terminal $APP_PATH


CmdLauncherOSX.app - test bundle created in XCode.

Working project on github: osx-cmd-launcher

Verified on macOS Mojave 10.14.6

This is failing for me on Ventura 13.4.1

I've posted https://stackoverflow.com/questions/76993541/cgeventtapcreate-returns-null-in-macos-ventura-13-4-1

I've also filed an issue https://github.com/0x8BADFOOD/osx-cmd-launcher/issues/1

What's most interesting is that a prior build of my app IS working. But any attempt to rebuild it and the rebuild will fail.

Please could an Apple engineer look into this. It's a clean testcase, and this failure is blocking an assistive technology I'm creating which is critical for myself and my users.

For those following at home, I’ll be helping p-i- in another context.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"