如何使用 Swift 和 Cocoa 获得当前活动 window

How to get current active window using Swift and Cocoa

我目前正在开发一个 Safari 应用程序扩展,它由两部分组成:

此外,主机应用程序还提供了一个全局快捷方式,可以在状态栏中打开一个弹出窗口。 但是,我想检查哪个应用程序的 window 当前处于活动状态,因为如果 Safari window 当前处于活动状态,我不想打开弹出窗口。有什么方法可以使用 Swift 找出哪个应用程序的 window 当前处于活动状态?

感谢您的帮助。

因此,根据 Alexander 和 Wileke 的评论,我认为我找到了解决方案。

使用 NSWorkspace.shared.frontmostApplication 您可以检查 Safari 当前是否处于活动状态。 但正如 Wileke 指出的那样,这并不意味着它有一个活跃的 window。 因此,我们使用 CGWindowListCopyWindowInfo 先获取所有 windows 并通过比较 PID 来检查是否至少有一个属于 Safari

这样,我们可以有把握地说 Safari 当前必须有一个活动的 window 来接收按键事件。 这一定是真的,因为现在 Safari 在没有任何 windows 的情况下排在最前面,或者 Safari 作为 window 但不是同时排在最前面。

好吧,除非我错过了什么。 但目前它有效。

这是我想出的代码:

func safariIsActive() -> Bool {
        // Get the app that currently has the focus.
        let frontApp = NSWorkspace.shared.frontmostApplication!

        // Check if the front most app is Safari
        if frontApp.bundleIdentifier == "com.apple.Safari" {
            // If it is Safari, it still does not mean, that is receiving key events
            // (i.e., has a window at the front).
            // But what we can safely say is, that if Safari is the front most app
            // and it has at least one window, it has to be the window that
            // crrently receives key events.
            let safariPID = frontApp.processIdentifier

            // With this procedure, we get all available windows.
            let options = CGWindowListOption(arrayLiteral: CGWindowListOption.excludeDesktopElements, CGWindowListOption.optionOnScreenOnly)
            let windowListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
            let windowInfoList = windowListInfo as NSArray? as? [[String: AnyObject]]

            // Now that we have all available windows, we are going to check if at least one of them
            // is owned by Safari.
            for info in windowInfoList! {
                let windowPID = info["kCGWindowOwnerPID"] as! UInt32
                if  windowPID == safariPID {
                    return true
                }
            }
        }
        return false
    }