如何使用 ScriptingBridge(或 AppleScript)确定具有活动键盘焦点的 window?

How do I determine the window with the active keyboard focus using ScriptingBridge (or AppleScript)?

从我能找到的所有 API 文档中,似乎正确的做法是检查系统事件返回的 "frontmost" window 或可访问性 API,就像这样(这里是 Python 中的例子,但这在 ObjC 或 swift 或 ruby 或其他什么中是相同的):

#!/usr/bin/env python
from ScriptingBridge import SBApplication
events = SBApplication.applicationWithBundleIdentifier_(
    "com.apple.systemevents")
for proc in events.applicationProcesses():
    if proc.frontmost():
        print(proc.name())

我从中得到的值与从 NSWorkspace.sharedWorkspace().frontmostApplication() 中得到的值相同。而且通常是正确的。除非提示对话框,尤其是来自系统的提示对话框 实际上 具有键盘焦点。例如,如果 Messages.app 想要我的 Jabber 帐户的密码,或者如果我的 iCloud 密码更改;这些对话框似乎来自 UserNotificationCenter 进程,即使它确实具有键盘焦点,它也不会以某种方式将自己报告为最前面的应用程序。

"UserNotificationCenter" 和 "UserNotificationCenter" 是后台应用程序(NSUIElement 键在 info.plist).

proc.frontmost() 在后台进程(无菜单且不在 Dock 中)上始终为 false

并且 NSWorkspace.sharedWorkspace().frontmostApplication() 不适用于后台应用程序。


要获取活动应用程序,请使用 NSWorkspace class

中的 activeApplication 方法

这是 AppleScript:

set pyScript to "from AppKit import NSWorkspace
activeApp = NSWorkspace.sharedWorkspace().activeApplication()
print activeApp['NSApplicationName'].encode('utf-8')
print activeApp['NSApplicationProcessIdentifier']"

set r to do shell script "/usr/bin/python -c " & quoted form of pyScript
set {localizedAppName, procID} to paragraphs of r -- procID is the unix id

使用未弃用的方法更新

set pyScript to "from AppKit import NSWorkspace
for app in NSWorkspace.sharedWorkspace().runningApplications():
        if app.isActive(): 
                print app.localizedName().encode('utf-8')
                print app.processIdentifier()
                break"

set r to do shell script "/usr/bin/python -c " & quoted form of pyScript
set {localizedAppName, procID} to paragraphs of r -- procID is the unix id

要从进程 ID 中获取前面的 window,请使用 procID 变量,如下所示:

tell application "System Events"
    tell (first process whose unix id = procID)
        log (get properties) -- properties of this process
        tell window 1 to if exists then log (get properties) -- properties of the front window of this process
    end tell
end tell