Problem with event tap permission in Sequoia

I have a Mac app with a background-only helper app that needs to have Accessibility permission in order to use an event tap that can modify events. This has worked OK through Sonoma, but in the Sequoia beta it is failing to create the tap. C code to test the ability to create the event tap:

static CGEventRef  _Nullable DummyTap(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *userInfo)
{
	return NULL;
}

static bool	CanFilterEvents( void )
{
	CFMachPortRef thePort = CGEventTapCreate(
		kCGSessionEventTap,
		kCGTailAppendEventTap,
		kCGEventTapOptionDefault,	// active filter, not passive listener
		CGEventMaskBit(kCGEventKeyDown),
		DummyTap,
		NULL );
	bool madeTap = (thePort != NULL);
	if (madeTap)
	{
		CFMachPortInvalidate( thePort );
		CFRelease( thePort );
	}
	
	return madeTap;
}

So, on Sequoia, CanFilterEvents returns false in spite of Accessibility permission being granted in System Settings. CGPreflightPostEventAccess also returns false, but AXIsProcessTrusted returns true.

I tried making a non-background-only test app, and when that has Accessibility permission, CanFilterEvents, CGPreflightPostEventAccess, and AXIsProcessTrusted all return true. Suggestions on what to try next?

Answered by DTS Engineer in 793915022

I tried making a non-background-only test app, and when that has Accessibility permission, CanFilterEvents, CGPreflightPostEventAccess, and AXIsProcessTrusted all return true. Suggestions on what to try next?

First off, please file a bug report on this and post the feedback number here. If something that used to work stops working then a bug is always warranted.

As for what you do "now", there are few things:

  1. How exactly is your "background-only helper app" setup? Is it an app bundle that marked as "faceless" with LSUIElement set? Or is it a standalone executable? My general recommendation is that the "default" should be to bundle ALL executables, even if you won't actually be calling/using that executable as an "app". For example, I even think it's a good idea to bundle "command line" executables that simply perform specific tasks and then exit. As far as the system is concerned, any executable will work fine inside an app bundle and, in my experience, the bundle structure is far less likely to have issues.

  2. How are you launching your helper app? In particular, "direct execution" (Process, NSTask, fork/exec, posix_spawn...) is NOT equivalent to having "the system" launch the app (NSWorkspace). There's a long history of "nonsensical" API failures like this occurring because an internal framework change ended up breaking a complicated chain of "details" that were allowing the direct execution case to work.

  3. What have you actually granted permission to? If you haven't authorized your main app, that would be worth trying as well.

  4. What happens if you transition your test app into "accessory"? Or transition your real app into "regular", then back to "accessory"? Our API history obscures this, but apps can freely transition in/out of app types using setActivationPolicy(_:)->.accessory/.regular. What LSUIElement basically does is tell LaunchServices not to create a dock icon during early launch the "set" your app into NSApplication.ActivationPolicy.accessory once it's actual up and running.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

I tried making a non-background-only test app, and when that has Accessibility permission, CanFilterEvents, CGPreflightPostEventAccess, and AXIsProcessTrusted all return true. Suggestions on what to try next?

First off, please file a bug report on this and post the feedback number here. If something that used to work stops working then a bug is always warranted.

As for what you do "now", there are few things:

  1. How exactly is your "background-only helper app" setup? Is it an app bundle that marked as "faceless" with LSUIElement set? Or is it a standalone executable? My general recommendation is that the "default" should be to bundle ALL executables, even if you won't actually be calling/using that executable as an "app". For example, I even think it's a good idea to bundle "command line" executables that simply perform specific tasks and then exit. As far as the system is concerned, any executable will work fine inside an app bundle and, in my experience, the bundle structure is far less likely to have issues.

  2. How are you launching your helper app? In particular, "direct execution" (Process, NSTask, fork/exec, posix_spawn...) is NOT equivalent to having "the system" launch the app (NSWorkspace). There's a long history of "nonsensical" API failures like this occurring because an internal framework change ended up breaking a complicated chain of "details" that were allowing the direct execution case to work.

  3. What have you actually granted permission to? If you haven't authorized your main app, that would be worth trying as well.

  4. What happens if you transition your test app into "accessory"? Or transition your real app into "regular", then back to "accessory"? Our API history obscures this, but apps can freely transition in/out of app types using setActivationPolicy(_:)->.accessory/.regular. What LSUIElement basically does is tell LaunchServices not to create a dock icon during early launch the "set" your app into NSApplication.ActivationPolicy.accessory once it's actual up and running.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

After more fooling around with deleting builds, deleting the copy from the App Store, and so forth, the problem no longer reproduces. So, that's good, I guess, but I'm not in the position of being able to file a useful bug report.

But to answer your questions:

  1. The helper is an app bundle with LSBackgroundOnly set true in its Info.plist.
  2. I launch it using NSWorkspace.
  3. I granted permission to the helper, not the main app.
  4. Since the helper is background only, not a LSUIElement, I'm not sure that what you're saying there is relevant.
Problem with event tap permission in Sequoia
 
 
Q