You’re going to face two challenges here:
I’ll cover each in turn.
The API you’re using is part of AppKit and thus intended to be used by an AppKit app. Using it from a vanilla command-line tool may not work because it may rely on the AppKit machinery to be running.
If it is to work at all you’ll need to run the run loop. You wrote:
I have tried Runloop.main.run()
What behaviour did you see? Did that call return? Or did it just not deliver events?
However, my overall advice would be that you package this code into an app and run it from there. You can set
LSBackgroundOnly to prevent the app from showing any UI.
In this context TCC stands for “transparency, consent, control”, and it’s a name we use to cover the user authorisation stuff you’ll find in System Preferences > Security & Privacy > Privacy. One of the privileges there is Input Monitoring, and the global event monitor requires that you have this privilege.
TCC is tricky because of the concept of
responsibility. Normally when you use an API that requires a TCC privilege the system will display an alert asking the user to grant that. This can’t work if your ‘app’ is a command-line tool because there’s no way for the user to understand the context of that request. Likewise if you move this code to a background-only app.
To fix this the system tries to find the program responsible for your process. If you nest your tool, or your background-only app, within a standard app then the system will likely consider that app to be responsible for your process and use it to prompt for, and track, your TCC privileges.
For this to work properly you must sign your code with a stable signing identity. Without this the system has no ‘handle’ on which to hook these privileges.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"