【问题标题】:Getting Previous Frontmost Application获取上一个最前面的应用程序
【发布时间】:2014-07-13 07:40:40
【问题描述】:

好吧,我被难住了,在这里。我正在编写一个小实用程序,它需要在我的程序启动之前知道最前面的应用程序是什么。我试过这个:

var thePreviousApp:NSRunningApplication = NSWorkspace.sharedWorkspace().frontmostApplication

override func awakeFromNib()
{
    thePreviousApp = NSWorkspace.sharedWorkspace().frontmostApplication
}

当我从 Xcode 运行时它可以工作(即将 thePreviousApp 设置为“Xcode”),但是当我从 Finder 或 Launchpad 运行二进制文件时,它返回我的程序的名称,而不是在我的程序启动之前位于最前面的程序。

对于它的价值,我可以通过将它放在 AppDelegate 中来获取上一个应用程序:

var thePreviousApp:NSRunningApplication = NSWorkspace.sharedWorkspace().frontmostApplication

 func applicationDidResignActive(notification: NSNotification!)
 {
    thePreviousApp = NSWorkspace.sharedWorkspace().frontmostApplication
 }

如果我启动程序,然后点击 command-tab 来激活之前的程序,然后再次点击 command tab 来激活我的程序,那么PreviousApp 就是正确的应用程序。

我还尝试让 runningApplications 数组是 NSWorkspace,然后遍历它们以检查哪个程序是“活动的”。再次,没有骰子。同样的问题。

任何建议将不胜感激。

谢谢, 汤姆

【问题讨论】:

    标签: objective-c cocoa swift


    【解决方案1】:

    我不知道你为什么要这样做,但我能想到的唯一方法是使用 NSWorkspace 通知 (NSWorkspaceDidDeactivateApplicationNotification)。

    您必须将您的一个对象注册为该通知的观察者,然后使用通知对象来获取已停用的应用程序。

    使用您的代码,您始终可以获得您的应用程序,因为 frontmostApplication() 不会在引发 applicationDidResignActive 通知的同一时刻更新。

    【讨论】:

    • 谢谢。我不应该感到惊讶。可能顺序是这样的: 1. NSWorkspaceDidDeactivateApplicationNotification 触发 2. 我的 AppDelegate 中的 applicationWillBecomeActive 触发 3. 我的应用程序变为活动并且最前面 4. 我的 AppDelegate 触发中的 applicationDidBecomeActive 所以当我将通知放入 applicationWillBecomeActive 时,没有活动的应用程序,因此我得到了零的回报。对吗?
    • 无论如何,事实证明 Swift 还没有真正的键值观察。您可以使用 willSet 和 didSet 函数非常轻松地设置适用于您自己的属性的内容。但是对于 NSWorkspace 通知等来说还不是那么容易。没关系。知道它仍在开发中,我选择使用 Swift,因为这个小项目不是关键任务。我相信完整的 KVO 即将推出。
    • @TomS。 KVO 与NSWorkspace 通知无关。 NSRunningApplication 仅在运行循环运行时更新自身。因此,没有理由期望它会在应用启动之前进行设置。
    【解决方案2】:

    对于那些想知道的人,这就是我最终所做的。我在 AppDelegate 中创建了一个名为 thePreviousApp 的属性。然后创建了一个观察者对象:

    import Foundation
    import Cocoa
    
    class theObserver: NSObject
    {
        override init() {
            super.init()
            NSWorkspace.sharedWorkspace().notificationCenter.addObserver(self, selector: "setPreviousApplication:", name: NSWorkspaceDidDeactivateApplicationNotification, object: nil)
        }
    
        func setPreviousApplication(notification: NSNotification!)
        {
            let theAppDelegate:AppDelegate=NSApplication.sharedApplication().delegate as AppDelegate
            theAppDelegate.thePreviousApp = notification.userInfo[NSWorkspaceApplicationKey] as NSRunningApplication
        }
    }
    

    此对象在 AppDelegate 中实例化。

    感谢 MrAsterico 的帮助。

    汤姆

    【讨论】:

      【解决方案3】:

      我找到了一种方法,可以在正确的 zPositions 中提供正在运行的应用程序窗口:

      让 windowNumbers = NSWindow.windowNumbersWithOptions( NSWindowNumberListAllSpaces | NSWindowNumberListAllApplications as NSWindowNumberListOptions )

      它将返回一个带有 windowNumbers 的数组,并且与 CGWindowListCopyWindowInfos 相比,现在它们的顺序从前到后是正确的。

      因为它们只是 windowId,您仍然需要在 CGWindowListCopyWindowInfos 数组/字典中进行查找以获取详细信息。

      但它有效!它会返回比明显可见的窗口更多的窗口,但您可以使用 windowName != "" 和其他过滤器(例如 size > 32x32(跳过菜单栏))很好地过滤它们

      【讨论】:

        【解决方案4】:

        我猜,一个想法是阅读最近使用过的 windows 列表。
        至少 zposition 应该是有序的,因为应用程序总是排在最前面(排在前面)。
        所以你的“最后一个”应用应该在列表旁边。

        您将从窗口列表中取出第二个程序,因为您的程序现在位于堆栈顶部。
        如果您从没有 gui 的情况下开始,例如。隐藏所有窗口,最后一个应用程序可能仍位于堆栈顶部。
        CGWindowListCopyWindowInfo 为您提供所有正在运行的应用程序的列表,甚至包括通知中心或桌面图像和菜单栏等隐藏应用程序。

        更新:runningApplications 列表是按随机顺序排列的,而不是按 zPositions 顺序排列的,所以这个想法行不通。

        【讨论】:

          猜你喜欢
          • 2014-02-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多