How I can send Ctrl-l key input to the GNOME file chooser dialog with at-spi2?

122 Views Asked by At

I want to control chromium file chooser dialog without any human intervention on Linux.

I am trying to achieve it with at-spi2 and python. (at-spi2 python binding that made by gobject-intropection)

I would like to show an textbox to enter the file path directly with Ctrl-L.
But I have no idea how to send Ctrl-L to the file chooser dialog box.


Edit

I thought it only happens in Chromium, But actually it happens not only chromium but also all of others like zenity.


Now I know the dialog box do not belong under the chromium, actually it is controlled by xdg-desktop-portal-gnome.

How I can do it?

My environment is ArchLinux and Gnome 45, Chromium 122.0.6261.94 (Official Build)

The following code is I tried send keyboard input with generate_keyboard_event, but nothing to happen...

def search_chrome_filechooser():
    if not Atspi.is_initialized():
        err = Atspi.init()
        if err != 0:
            print("Something Error:", err)
            return

    root = Atspi.get_desktop(0)
    app = search_widget(root, "xdg-desktop-portal-gnome", "application")
    if app == None:
        print("app not found")
        return
    dialog = search_widget(app, role_name="dialog")
    if dialog is None:
        print("file chooser dialog not found")
        if Atspi.is_initialized():
            Atspi.exit()
        return


    Atspi.generate_keyboard_event(29, None, Atspi.KeySynthType.PRESS)
    Atspi.generate_keyboard_event(38, None, Atspi.KeySynthType.PRESSRELEASE)
    if Atspi.is_initialized():
        Atspi.exit()


def search_widget(root, name: str|None=None, role_name:str|None=None):
    widget = root
    if widget == None:
        return None
    if name == None and role_name == None:
        return
    widget_name = widget.get_name()
    widget_role_name = widget.get_role_name()
    if name == widget_name and role_name == None:
        return widget
    elif name == 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)) != None:
            return result

search_chrome_filechooser()
1

There are 1 best solutions below

5
Philippe On

This is the script which works when File Chooser has focus, I'm on Ubuntu/Gnome/Wayland:

from pyatspi import Atspi

def send_ctrl_l():
    if not Atspi.is_initialized():
        Atspi.init()

    # Ensure these key codes are correct for your system
    ctrl_key_code = 29  # Key code for 'Ctrl'
    l_key_code = 38     # Key code for 'L'
    
    # Press 'Ctrl'
    Atspi.generate_keyboard_event(ctrl_key_code, None, Atspi.KeySynthType.PRESS)

    # Press and release 'L'
    Atspi.generate_keyboard_event(l_key_code, None, Atspi.KeySynthType.PRESSRELEASE)

    # Release 'Ctrl'
    Atspi.generate_keyboard_event(ctrl_key_code, None, Atspi.KeySynthType.RELEASE)

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

To move focus, try this :

xdotool windowfocus --sync $(xdotool search -all --name "Open File"); python test.py

My xdotool version

$ xdotool -v
xdotool version 3.20160805.1

$ uname -a
Linux ubuntu 6.5.0-26-generic #26~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue Mar 12 10:22:43 UTC 2 x86_64 x86_64 x86_64 GNU/Linux