You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过at-spi2向GNOME文件选择器对话框发送Ctrl-L按键

解决xdg-desktop-portal-gnome文件选择器的Ctrl-L快捷键发送问题

问题分析

你遇到的核心问题是:直接调用Atspi.generate_keyboard_event发送按键时,文件选择器对话框可能未获得焦点,且按键序列的发送逻辑不符合快捷键触发规则(Ctrl需要保持按住状态,再按下并释放L,最后释放Ctrl)。

修复步骤

  • 确保对话框获得焦点:找到对话框控件后,调用set_focus()方法激活它,让系统将输入焦点转移到对话框上。
  • 修正按键发送顺序:正确的Ctrl-L触发流程是:按下Ctrl键(持续按住)→ 按下并释放L键 → 释放Ctrl键。
  • 添加微小延迟:避免按键发送过快导致系统无法正确识别快捷键,可在按键操作间加入短暂休眠。

修改后的代码

import time
def search_chrome_filechooser():
    if not Atspi.is_initialized():
        err = Atspi.init()
        if err != 0:
            print("初始化错误:", err)
            return

    root = Atspi.get_desktop(0)
    app = search_widget(root, "xdg-desktop-portal-gnome", "application")
    if app is None:
        print("未找到xdg-desktop-portal-gnome进程")
        return
    dialog = search_widget(app, role_name="dialog")
    if dialog is None:
        print("未找到文件选择器对话框")
        if Atspi.is_initialized():
            Atspi.exit()
        return

    # 让对话框获得焦点
    if not dialog.set_focus():
        print("无法为对话框设置焦点")
        Atspi.exit()
        return

    # 发送Ctrl-L快捷键:先按住Ctrl,再按L,最后释放Ctrl
    Atspi.generate_keyboard_event(29, None, Atspi.KeySynthType.PRESS)
    time.sleep(0.05)  # 短暂延迟确保Ctrl被按住
    Atspi.generate_keyboard_event(38, None, Atspi.KeySynthType.PRESSRELEASE)
    time.sleep(0.05)
    Atspi.generate_keyboard_event(29, None, Atspi.KeySynthType.RELEASE)

    if Atspi.is_initialized():
        Atspi.exit()


def search_widget(root, name: str|None=None, role_name:str|None=None):
    widget = root
    if widget is None:
        return None
    if name is None and role_name is None:
        return None
    widget_name = widget.get_name()
    widget_role_name = widget.get_role_name()
    if name == widget_name and role_name is None:
        return widget
    elif name is None and role_name == widget_role_name:
        return widget
    elif name == widget_name and role_name == widget_role_name:
        return widget
    num = widget.get_child_count()
    for v in range(num):
        child = widget.get_child_at_index(v)
        if (result := search_widget(child, name, role_name)) is not None:
            return result

search_chrome_filechooser()

额外说明

  • 若不知道按键对应的键码,可使用xev工具查看:打开终端运行xev,按下对应按键后终端会输出键码信息。
  • 部分桌面环境可能需要开启无障碍权限,确保Python进程拥有控制界面元素的权限,可在GNOME设置的「无障碍」中开启相关选项。

内容的提问来源于stack exchange,提问作者KiYugadgeter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:56:30