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

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 #7418
This commit is contained in:
Janek Bevendorff 2022-03-12 21:07:36 +01:00 committed by GitHub
parent 4bc32d37ac
commit e07d143c9b
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