如何获取Mac OSX上的窗口标题列表?

Phi*_*ent 17 api macos objective-c

我想获取当前正在运行的应用程序的窗口标题列表.

在Windows上我有EnumWndProc和GetWindowText.

在Linux上我有XGetWindowProperty和XFetchName.

什么是Native Mac等价物?

out*_*tis 12

一些可能有用的参考:

CGSGetWindowProperty没有正式记录,但我相信你可以的一个项目使用NSWindowList()如下(经过充分测试):

OSErr err;
CGSValue titleValue;
char *title;
CGSConnection connection = _CGSDefaultConnection();
int windowCount, *windows, i;

NSCountWindows(&windowCount);
windows = malloc(windowCount * sizeof(*windows));
if (windows) {
    NSWindowList(windowCount, windows);
    for (i=0; i < windowCount; ++i) {
        err = CGSGetWindowProperty(connection, windows[i], 
                    CGSCreateCStringNoCopy("kCGSWindowTitle"), 
                    &titleValue);
        title = CGSCStringValue(titleValue);
    }
    free(windows);
}
Run Code Online (Sandbox Code Playgroud)

在AppleScript中,它非常简单:

tell application "System Events" to get the title of every window of every process
Run Code Online (Sandbox Code Playgroud)

您可以使用NSAppleScript从应用程序中调用applescript,或使用appscript作为ObjC-AppleScript桥.使用Leopard,您可以使用Scripting Bridge(更多未经测试的代码):

SystemEventsApplication *systemEvents = [SBApplication applicationWithBundleIdentifier:@"com.apple.systemevents"];
SBElementArray *processes = [systemEvents processes];
for (SystemEventsProcess* process in processes) {
    NSArray *titles = [[process windows] arrayByApplyingSelector:@selector(title)];
}
Run Code Online (Sandbox Code Playgroud)

如果你不关心可读性,你甚至可以在一个长时间的通话中尝试它.

SystemEventsApplication *systemEvents = [SBApplication applicationWithBundleIdentifier:@"com.apple.systemevents"];
NSArray *titles = [[[systemEvents processes] 
                     arrayByApplyingSelector:@selector(windows)] 
               arrayByApplyingSelector:@selector(arrayByApplyingSelector:) 
               withObject:@selector(title)];
Run Code Online (Sandbox Code Playgroud)

编译器会抱怨这@selector(title)是错误的类型,但它应该工作.手动一些代表团,你可以把电话转为[[[systemEvents processes] windows] title].

  • 示例辅助功能API代码:http://developer.apple.com/mac/library/samplecode/UIElementInspector/index.html (3认同)
  • 请注意,AppleScript使用的是可访问性界面,这些界面是公共的并且具有C等价物(请参阅http://developer.apple.com/mac/library/documentation/Accessibility/Reference/AccessibilityLowlevel/).CGS*API不仅没有记录,它们可能随时更改.(因此,只有在您愿意提前测试并且经常在新操作系统版本上进行测试且没有其他选择时才使用它们.) (2认同)

Ale*_*ing 8

浮动的CGSPrivate.h标题与OS X 10.8不直接兼容,因为CGSGetWindowProperty()不再存在(嗯,确实如此,但你不能再链接到它).所以将这两行添加到CGSPrivate.h文件中 - 我在搜索Google几个小时之后继续自己想出来 - 让它工作:

extern CGSConnection CGSDefaultConnectionForThread(void);
extern CGError CGSCopyWindowProperty(const CGSConnection cid, NSInteger wid, CFStringRef key, CFStringRef *output);
Run Code Online (Sandbox Code Playgroud)

调整outis的代码,这是一种迭代每个窗口标题的方法.我在山狮上使用clang 4.2进行了测试:

CFStringRef titleValue;
CGSConnection connection = CGSDefaultConnectionForThread();
NSInteger windowCount, *windows;

NSCountWindows(&windowCount);
windows = (NSInteger*) malloc(windowCount * sizeof(NSInteger));
if (windows) {
    NSWindowList(windowCount, windows);
    for (int i = 0; i < windowCount; ++i)
    {
        CGSCopyWindowProperty(connection, windows[i], CFSTR("kCGSWindowTitle"), &titleValue);

        if(!titleValue) //Not every window has a title
            continue;

        //Do something with titleValue here
    }
    free(windows);
}
Run Code Online (Sandbox Code Playgroud)

我发现的其他一些东西包括以下内容:

  1. 没有窗口标题超过127个字节.
  2. 窗口标题使用kCFStringEncodingMacRoman进行编码

所以,如果你想把它作为一个C字符串,写下这样的东西:

char *cTitle[127] = {0};
CFStringGetCString(titleValue,cTitle,127,kCFStringEncodingMacRoman);
Run Code Online (Sandbox Code Playgroud)

就个人而言,我建议这样做,因为Accessibility API总是很痛苦,需要额外的权限.

希望这有助于某人!干杯!