如何通过Python/DBus在 KDE Plasma 6(Wayland)中获取活动窗口标题?

编程语言 2026-07-12

我在基于 CachyOS(Arch Linux)KDE Plasma 6(Wayland) 上进行一个语音转文本项目(Python)。我需要获取活动窗口的标题,以便对输入进行上下文感知的处理。

问题:

基于X11的标准解决方案(如 xdotoolxprop)在原生Wayland窗口上会失败,并抛出 BadWindow 错误:

XGetWindowProperty\[\_NET_ACTIVE_WINDOW\] failed (code=1)

xdo_get_active_window reported an error

X Error of failed request: BadWindow (invalid Window parameter)

我查阅过的内容:

我查看了StackOverflow上的若干现有解法,但它们要么过时,要么是X11特定:

我的尝试:

因为 qdbus 缺失,我尝试使用 dbus-send

dbus-send --session --print-reply --dest=org.kde.KWin /KWin org.kde.KWin.activeWindow

结果: Error org.freedesktop.DBus.Error.UnknownMethod: No such method 'activeWindow' in interface 'org.kde.KWin' at object path 'KWin'

环境:

  • 操作系统:CachyOS(基于Arch)
  • 桌面环境:KDE Plasma 6.3.5
  • Python 3.13.3

问题:

在Plasma 6/Wayland下,如何可靠地获取活动窗口标题(例如,使用 dbus-send 或某个Python库)?

解决方案

使用无障碍总线(AT-SPI)来绕过Wayland的安全限制

在Plasma 6(Wayland)上,对KWin的常规D-Bus查询由于增强的安全隔离,常返回空数据或受限数据。获取活动窗口标题最可靠的方法是通过无障碍技术服务提供者接口(AT-SPI)。

1.系统要求与设置

首先,确保无障碍总线处于活动状态。在像CachyOS这样的基于Arch的系统上,安装必要的组件:

sudo pacman -S orca at-spi2-core

(注:安装 orca 是确保所有KDE/Qt无障碍桥接和菜单选项解锁的最简单方法,即使你不使用语音输出。)

2.在 Plasma 6中启用无障碍功能

你必须让系统启动无障碍总线,并让Qt应用导出它们的元数据。

通过终端:

在KDE配置中启用ScreenReader桥

kwriteconfig6 --file kaccessrc --group ScreenReader --key Enabled true

将环境变量添加到 ~/.bashrc或 ~/.config/fish/config.fish中:

export QT_ACCESSIBILITY=1

通过图形界面: 前往 系统设置 > 无障碍 > 屏幕阅读器,勾选 启用屏幕阅读器

重要: 要使这些更改生效,必须登出并重新登录(或重启)。

3.静音(可选)

如果你不想让系统把一切都读成声音,可以运行Orca设置一次以禁用语音,但保持数据总线活动:

orca -s

前往 “Speech” 选项卡并取消勾选 “Enable speech”

4. Python实现

此脚本使用 GObject Introspection 监听 Atspi 总线。它遍历桌面上的子对象,找到具有 ACTIVEFOCUSED 状态的对象。

依赖项: sudo pacman -S python-gobject

try:
    gi.require_version('Atspi', '2.0')
    from gi.repository import Atspi
except Exception as e:
    print(f"Error: GObject-Introspection not found ({e})")
    exit(1)

def get_active_window_title_atspi():


    if Atspi.init() != 0:
        return "Atspi was not initialisiest"

    desktop = Atspi.get_desktop(0)

    for i in range(desktop.get_child_count()):
        app = desktop.get_child_at_index(i)
        if not app:
            continue

        for j in range(app.get_child_count()):
            window = app.get_child_at_index(j)
            if not window:
                continue

            state_set = window.get_state_set()
            states = state_set.get_states()

            if Atspi.StateType.ACTIVE in states or Atspi.StateType.FOCUSED in states:
                return f"App: {app.get_name()} | Titel: {window.get_name()}"

    return "no active window found by AT-SPI"



if __name__ == "__main__":
    print(get_active_window_title_atspi))

之所以有效:

尽管Wayland将应用彼此隔离,但它必须向无障碍总线广播窗口元数据,以便屏幕阅读器能够工作。作为一个“无障碍客户端”,你的Python脚本即使在KWin的标准D-Bus接口被锁定时,也能“看到”活动窗口的标题。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章