Skip "StatusIndicator" window in Auto-Type window list ()

Starting with macOS 12.2, when the audio recording indicator is shown, the
"Window Server" process injects a "StatusIndicator" window into the list of
active windows, which messes with Auto-Type's window title matching. This
window has an Alpha value of 1 (so technically, it is not invisible), and it
is always in front of all other windows. Hence, the only way to skip it is by
title and owner name.

Fixes 
This commit is contained in:
Janek Bevendorff 2022-03-12 21:08:01 +01:00 committed by GitHub
parent e6a6ba7d63
commit ed7acf358a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 13 deletions

View file

@ -23,7 +23,6 @@
#include <ApplicationServices/ApplicationServices.h> #include <ApplicationServices/ApplicationServices.h>
#define MAX_WINDOW_TITLE_LENGTH 1024
#define INVALID_KEYCODE 0xFFFF #define INVALID_KEYCODE 0xFFFF
AutoTypePlatformMac::AutoTypePlatformMac() AutoTypePlatformMac::AutoTypePlatformMac()
@ -60,7 +59,15 @@ QStringList AutoTypePlatformMac::windowTitles()
continue; continue;
} }
QString title = windowTitle(window); QString title = windowStringProperty(window, kCGWindowName);
QString owner = windowStringProperty(window, kCGWindowOwnerName);
// Audio recording injects a "StatusIndicator" window owned by the "Window Server" process
// into to list in macOS 12.2 (see: https://github.com/keepassxreboot/keepassxc/issues/7418).
if (title == "StatusIndicator" && owner == "Window Server") {
continue;
}
if (!title.isEmpty()) { if (!title.isEmpty()) {
list.append(title); list.append(title);
} }
@ -95,8 +102,16 @@ QString AutoTypePlatformMac::activeWindowTitle()
for (CFIndex i = 0; i < count; i++) { for (CFIndex i = 0; i < count; i++) {
CFDictionaryRef window = static_cast<CFDictionaryRef>(::CFArrayGetValueAtIndex(windowList, i)); CFDictionaryRef window = static_cast<CFDictionaryRef>(::CFArrayGetValueAtIndex(windowList, i));
if (windowLayer(window) == 0) { if (windowLayer(window) == 0) {
title = windowStringProperty(window, kCGWindowName);
QString owner = windowStringProperty(window, kCGWindowOwnerName);
// Audio recording injects a "StatusIndicator" window owned by the "Window Server" process
// into to list in macOS 12.2 (see: https://github.com/keepassxreboot/keepassxc/issues/7418).
if (title == "StatusIndicator" && owner == "Window Server") {
continue;
}
// First toplevel window in list (front to back order) // First toplevel window in list (front to back order)
title = windowTitle(window);
if (!title.isEmpty()) { if (!title.isEmpty()) {
break; break;
} }
@ -190,20 +205,20 @@ int AutoTypePlatformMac::windowLayer(CFDictionaryRef window)
} }
// //
// Get window title // Get window string property
// //
QString AutoTypePlatformMac::windowTitle(CFDictionaryRef window) QString AutoTypePlatformMac::windowStringProperty(CFDictionaryRef window, CFStringRef propertyRef)
{ {
char buffer[MAX_WINDOW_TITLE_LENGTH]; char buffer[1024];
QString title; QString value;
CFStringRef titleRef = static_cast<CFStringRef>(::CFDictionaryGetValue(window, kCGWindowName)); CFStringRef valueRef = static_cast<CFStringRef>(::CFDictionaryGetValue(window, propertyRef));
if (titleRef != nullptr if (valueRef != nullptr
&& ::CFStringGetCString(titleRef, buffer, MAX_WINDOW_TITLE_LENGTH, kCFStringEncodingUTF8)) { && ::CFStringGetCString(valueRef, buffer, 1024, kCFStringEncodingUTF8)) {
title = QString::fromUtf8(buffer); value = QString::fromUtf8(buffer);
} }
return title; return value;
} }
// //

View file

@ -49,7 +49,7 @@ public:
private: private:
static int windowLayer(CFDictionaryRef window); static int windowLayer(CFDictionaryRef window);
static QString windowTitle(CFDictionaryRef window); static QString windowStringProperty(CFDictionaryRef window, CFStringRef propertyRef);
}; };
class AutoTypeExecutorMac : public AutoTypeExecutor class AutoTypeExecutorMac : public AutoTypeExecutor