MacOS-先按最近使用的应用程序排序运行应用程序



使用Swift(或objective-C)我想获得当前在macOS上运行的应用程序的列表,按最近使用的顺序这将是cmd-tab在Mac上显示应用程序图标的顺序。

下面给了我应用程序,但不是按照我想要的顺序。

let apps = NSWorkspace.shared.runningApplications

.runningApps property的文档中,它说:

数组的顺序未指定,但它是稳定的,这意味着特定应用程序的相对顺序不会在多个应用程序之间发生变化调用运行应用程序。

有没有办法按所需顺序对应用程序进行排序?

编辑:

"brimstone"的答案中提出的方法似乎很有前景,但CGWindowListCopyWindowInfo仅在指定了CGWindowListOption.optionOnScreenOnly时才按从前到后的顺序返回窗口但是,在这种情况下,只返回当前空间中的窗口。然而,cmd-tab能够列出所有空间中的应用程序

有人知道其他办法吗?难道不应该有一种更直接/更简单的方法来做这件事吗?

所以我在看cmd选项卡,我想模仿这种行为的一种方法是通过窗口层次结构。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选项卡显示的顺序相同。但是,此方法也返回了一些作为菜单栏中项目的进程或后台进程,如SystemUIServerSpotlight

您可以从[NSWorkspace sharedWorkspace].notificationCenter订阅通知NSWorkspaceDidDeactivateApplicationNotification,并放入dictionary 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];

最新更新