如何使用 Swift 和 Cocoa 获取当前活动窗口

adu*_*dur 5 macos cocoa swift safari-app-extension

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

  • 仅限主机状态栏的应用程序
  • Safari 扩展

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

感谢您的帮助。

adu*_*dur 6

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

NSWorkspace.shared.frontmostApplication可以检查 Safari 当前是否处于活动状态。但正如怀勒克指出的那样,这并不意味着它有一个活动窗口。因此,我们CGWindowListCopyWindowInfo首先获取所有窗口,然后通过比较 PID 来检查其中至少一个窗口是否属于 Safari。

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

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

这是我想出的代码:

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
    }
Run Code Online (Sandbox Code Playgroud)