使用Swift(或Objective-C)我想获取当前在macOS上运行的应用列表,按照最近的使用顺序。这将是cmd-tab
的顺序在Mac上显示应用程序图标。
以下内容为我提供了应用程序,但不是按照我想要的顺序。
let apps = NSWorkspace.shared.runningApplications
在documentation for the .runningApps property
中,它说:
数组的顺序未指定,但它是稳定的,这意味着 特定应用程序的相对顺序不会在多个方面发生变化 调用runningApplications。
有没有办法按所需顺序对应用进行排序/获取?
编辑:
'brimstone'在答案中建议的方法似乎很有希望,但CGWindowListCopyWindowInfo
只有在指定CGWindowListOption.optionOnScreenOnly
时才会以前后顺序返回窗口。但是,在这种情况下,只返回当前空格中的窗口。
cmd-tab
但是能够列出所有空间的应用。
有没有人知道其他任何方式?难道不应该有更直接/更简单的方法吗?
答案 0 :(得分:1)
所以我看着cmd-tab,我想到了一种模仿行为的方法是通过窗口层次结构。 CGWindowListOption
将按层次结构的顺序返回屏幕上的窗口列表 - 因此最新的应用程序将是第一个。这可以解决您订购runningApps
财产的问题。
let options = CGWindowListOption(arrayLiteral: CGWindowListOption.excludeDesktopElements, CGWindowListOption.optionOnScreenOnly)
let windowList = CGWindowListCopyWindowInfo(options, CGWindowID(0))
let windows = windowList as NSArray? as! [[String: AnyObject]]
然后,您可以遍历infoList
并检索所需的任何数据,例如每个应用程序的名称。
for window in windows {
let name = window[kCGWindowOwnerName as String]!
print(name)
}
如果您仍然需要NSRunningApplication
变量,则可以将窗口的所有者PID与应用程序的PID匹配。
let id = pid_t(window[kCGWindowOwnerPID as String]! as! Int)
let app = apps.filter { $0.processIdentifier == id } .first
app.hide() //Or whatever your desired action is
对我来说,这返回了我运行的所有应用程序,其顺序与CMD-Tab显示的顺序相同。但是,此方法还返回了一些进程,这些进程是菜单栏或后台进程中的项目,例如SystemUIServer
和Spotlight
。
答案 1 :(得分:1)
您可以从NSWorkspaceDidDeactivateApplicationNotification
订阅通知[NSWorkspace sharedWorkspace].notificationCenter
,并将其放入字典bundleId和时间戳,然后使用它对数组进行排序。缺点是应用程序在开始监听通知之前对使用的应用程序一无所知。
@property (strong) NSMutableDictionary *appActivity;
...
- (instancetype)init {
if (self = [super init]) {
self.appActivity = [NSMutableDictionary dictionary];
[self setupNotifications];
}
return self;
}
- (void)setupNotifications {
NSNotificationCenter *workspaceNotificationCenter = [NSWorkspace sharedWorkspace].notificationCenter;
[workspaceNotificationCenter addObserver:self selector:@selector(deactivateApp:) name:NSWorkspaceDidDeactivateApplicationNotification object:nil];
}
- (void)deactivateApp:(NSNotification *)notification {
NSRunningApplication *app = notification.userInfo[NSWorkspaceApplicationKey];
if (app.bundleIdentifier) {
self.appActivity[app.bundleIdentifier] = @([[NSDate date] timeIntervalSince1970]);
}
}
...
NSArray<NSRunningApplication *> *apps = [[NSWorkspace sharedWorkspace] runningApplications];
NSComparator sortByLastAccess = ^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
NSRunningApplication *item1 = obj1;
NSRunningApplication *item2 = obj2;
NSComparisonResult result = NSOrderedSame;
if (item1.bundleIdentifier && item2.bundleIdentifier) {
NSNumber *ts1 = self.appActivity[item1.bundleIdentifier];
NSNumber *ts2 = self.appActivity[item2.bundleIdentifier];
if (ts1 && ts2) {
result = [ts2 compare:ts1];
} else if (ts1) {
result = NSOrderedAscending;
} else if (ts2) {
result = NSOrderedDescending;
}
}
return result;
};
apps = [apps sortedArrayUsingComparator:sortByLastAccess];