如何在 Mac 中使用 Python 获取活动窗口标题?

9

我正在尝试编写Python脚本,使用Mac OS中的Python打印活动窗口的标题。

以下是我的代码:

from AppKit import NSWorkspace
active_app_name = NSWorkspace.sharedWorkspace().frontmostApplication().localizedName()
print active_app_name

这段代码只会输出应用程序的名称,例如Google Chrome或Firefox,但不会输出窗口的标题。如何获取窗口的标题?


2
可能是使用Python在Mac OS X中查找当前活动窗口的重复问题。 - kenorb
4个回答

8

以下是使用Python和Quartz API在Mac OS X上找到活动应用程序名称和窗口标题的方法。

首先,我们需要根据需要添加导入:

if sys.platform == "darwin":
    import applescript
    from AppKit import NSWorkspace
    from Quartz import (
        CGWindowListCopyWindowInfo,
        kCGWindowListOptionOnScreenOnly,
        kCGNullWindowID
    )

然后,我们可以通过以下代码获取活动应用程序名称和窗口标题:

def getActiveInfo(event_window_num):
    try:
        if sys.platform == "darwin":
            app = NSWorkspace.sharedWorkspace().frontmostApplication()
            active_app_name = app.localizedName()

            options = kCGWindowListOptionOnScreenOnly
            windowList = CGWindowListCopyWindowInfo(options, kCGNullWindowID)
            windowTitle = 'Unknown'
            for window in windowList:
                windowNumber = window['kCGWindowNumber']
                ownerName = window['kCGWindowOwnerName']
                # geometry = window['kCGWindowBounds']
                windowTitle = window.get('kCGWindowName', u'Unknown')
                if windowTitle and (
                                event_window_num == windowNumber
                        or ownerName == active_app_name
                ):
                    # log.debug(
                    #     'ownerName=%s, windowName=%s, x=%s, y=%s, '
                    #     'width=%s, height=%s'
                    #     % (window['kCGWindowOwnerName'],
                    #        window.get('kCGWindowName', u'Unknown'),
                    #        geometry['X'],
                    #        geometry['Y'],
                    #        geometry['Width'],
                    #        geometry['Height']))
                    break

            return _review_active_info(active_app_name, windowTitle)
        if sys.platform == "win32":
            (active_app_name, windowTitle) = _getActiveInfo_Win32()
            return _review_active_info(active_app_name, windowTitle)
    except:
        log.error('Unexpected error: %s' % sys.exc_info()[0])
        log.error('error line number: %s' % sys.exc_traceback.tb_lineno)
    return 'Unknown', 'Unknown'

你能给一个完整的shell示例吗?我不明白event_window_num参数是用来干什么的。还有_review_active_info()函数。 - Yehosef
@Yehosef,event_window_num参数来自于鼠标事件或键盘事件捕获,我认为你可以安全地忽略这个参数。_review_active_info也是我的应用程序中的自定义函数,仅用于验证我们获取的app_name和window_title,你也可以忽略此方法。获取活动app_name和window_title的核心部分在示例代码中显示。 - Jake W
很不幸,我刚开始就遇到了一个错误:import applescript : ImportError: No module named applescript - mivk

4

NSWorkspace.sharedWorkspace().activeApplication()无法获得应用程序标题的访问权限。

但是,您可以通过其PID找到当前窗口的标题:

例如:

from AppKit import NSWorkspace
pid = NSWorkspace.sharedWorkspace().activeApplication()['NSApplicationProcessIdentifier']

然后使用下面的代码(存储在kCGWindowOwnerPID中)找到正确的窗口,如下所示:

这是一个完整的shell示例,基于@JakeW的脚本

#!/usr/bin/python
# Prints list of windows in the current workspace.
import sys
if sys.platform == "darwin":
    from AppKit import NSWorkspace
    from Quartz import (
        CGWindowListCopyWindowInfo,
        kCGWindowListOptionOnScreenOnly,
        kCGNullWindowID
    )

if sys.platform == "darwin":
    curr_app = NSWorkspace.sharedWorkspace().frontmostApplication()
    curr_pid = NSWorkspace.sharedWorkspace().activeApplication()['NSApplicationProcessIdentifier']
    curr_app_name = curr_app.localizedName()
    options = kCGWindowListOptionOnScreenOnly
    windowList = CGWindowListCopyWindowInfo(options, kCGNullWindowID)
    for window in windowList:
        pid = window['kCGWindowOwnerPID']
        windowNumber = window['kCGWindowNumber']
        ownerName = window['kCGWindowOwnerName']
        geometry = window['kCGWindowBounds']
        windowTitle = window.get('kCGWindowName', u'Unknown')
        if curr_pid == pid:
            print("%s - %s (PID: %d, WID: %d): %s" % (ownerName, windowTitle.encode('ascii','ignore'), pid, windowNumber, geometry))
elif sys.platform == "win32":
    (active_app_name, windowTitle) = _getActiveInfo_Win32()

它会列出当前活动窗口的详细信息,包括其标题。

这将列出活动应用程序的所有窗口,而不仅仅是活动窗口。例如,在 Chrome 中打开开发者工具时会在单独的窗口中显示,你无法区分哪个是活动窗口。 - sivann
你需要在 curr_pid == pid: 后添加一个 break,并且检查 windowTitle 是否存在。 - sivann
这个可行,Jake W的得票更高的答案不可行。 - jason

2

我尝试了@kenorb的代码,但不幸的是,它只能获取应用程序名称,而无法获取标题内容。

最后,我找到了一种使用AppleScript实现此功能的方法: 您可以在此处找到答案: MacOSX:获取最前面窗口的标题

首先创建一个名为GetNameAndTitleOfActiveWindow.scpt的appleScript

global frontApp, frontAppName, windowTitle

set windowTitle to ""
tell application "System Events"
    set frontApp to first application process whose frontmost is true
    set frontAppName to name of frontApp
    tell process frontAppName
        tell (1st window whose value of attribute "AXMain" is true)
            set windowTitle to value of attribute "AXTitle"
        end tell
    end tell
end tell

return {frontAppName, windowTitle}

您可以先在Mac终端中进行测试:

osascript GetNameAndTitleOfActiveWindow.scpt

然后用Python编写:

title = subprocess.check_output(['osascript', 'GetNameAndTitleOfActiveWindow.scpt'])

1

4
这篇回答写得很好,但没有回答提问者关于窗口标题的问题。你能否更新你的回答,告诉我们如何获取窗口标题? - Samuel Jaeschke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接