如何在Mac OS X上检测活动窗口是否已更改

时间:2018-11-07 09:24:13

标签: objective-c macos qt accessibility

我正在尝试创建一个程序来跟踪应用程序的聚焦窗口。我遇到了一些部分答案,但我认为它没有用。

这是Qt应用程序的Objective C ++部分,因此它可能与RunLoop有关,但我不确定。

void focusObserverCallback( AXObserverRef observer, AXUIElementRef element,
                             CFStringRef notificationName, void * contextData )
{
    // Never executes.
    qInfo("Focus changed.");
}

QString updateActiveWindow (void)
{
    NSRunningApplication* app = [[NSWorkspace sharedWorkspace]
                                  frontmostApplication];
    pid_t pid = [app processIdentifier];
    AXUIElementRef appElem = AXUIElementCreateApplication(pid);
    if (!appElem) {
      qInfo() << "!appElem";
      return nullptr;
    }

    // Get the accessibility element corresponding to the frontmost window
    // of the frontmost application.
    CFStringRef appName=nullptr;
    AXUIElementRef window = nullptr;
    if (AXUIElementCopyAttributeValue (appElem, kAXTitleAttribute, ((CFTypeRef*)&appName)) !=kAXErrorSuccess){
        if(appElem)
         CFRelease(appElem);
    }
    focusedAppName=toQString(appName);
    if (AXUIElementCopyAttributeValue (appElem, kAXFocusedWindowAttribute, (CFTypeRef*)&window) != kAXErrorSuccess) {
      if(appElem)
        CFRelease(appElem);
    }

    AXObserverRef observer = nullptr;
    if(AXObserverCreate(pid, focusObserverCallback, &observer) !=kAXErrorSuccess){
        qInfo("Failed to register observer");
    }

    AXObserverAddNotification(observer, window, kAXApplicationActivatedNotification, nullptr);

    CFRunLoopAddSource([[NSRunLoop currentRunLoop] getCFRunLoop],
            AXObserverGetRunLoopSource(observer),
            kCFRunLoopDefaultMode );

    // Finally, get the title of the frontmost window.
    CFStringRef title = nullptr;
    if(AXUIElementCopyAttributeValue(window, kAXTitleAttribute, (CFTypeRef*)&title)!=kAXErrorSuccess){
        qInfo("Problem Copying title");
    }
    focusedAppTitle= toQString(title);
    return toQString(title);
}

此代码的作用是,它运行一次即可获取最前面的应用程序最前面的窗口的名称和标题。那部分就像一个魅力。

问题是,它没有注册回调,并且当窗口失去焦点时也不会触发。我对Objective C完全陌生,因此可能还有其他问题(例如垃圾回收)。如果您可以提出一些建议,我将倍感荣幸。

1 个答案:

答案 0 :(得分:2)

应用程序被激活后将发送kAXApplicationActivatedNotification并成为最前面的应用程序。观察应用程序的kAXFocusedWindowChangedNotification,以观察应用程序的焦点窗口更改。