hacker emblem Song Ziming's Blog

使用 xdotool 模拟用户交互

命令行下,对于一些常用而重复的命令,可以使用脚本来自动化;而对于图形界面程序,则可以使用 xdotool 来模拟用户的鼠标键盘输入。xdotool 是一个命令行工具,用户可以通过命令或者脚本模拟鼠标和键盘的动作,使用命令行控制图形界面。

安装

通常,发行版的软件源应该包含 xdotool,例如 Debian/Ubuntu 下可以通过 sudo apt-get install xdotool 来安装。如果系统软件源中没有,可以到 xdotool 官网下载源代码编译安装。xdotool 的依赖项只有 Xlib,因此编译过程应该很容易。

起步

下面通过一个简单的例子来测试 xdotool 的功能。首先打开图形界面下的终端模拟器,将鼠标移到某个菜单之上,但是不要点击。这时输入焦点应该还在命令行窗口,鼠标位置不动,输入下面的命令:

xdotool click 1

执行这条命灵之后,会发现鼠标悬停处的菜单神奇地打开了,就好像在那里点了左键一样。对 X11 来说,点击鼠标只是一个事件,它并不管这个事件来自鼠标、触摸板、触摸屏还是其他设备,或者是类似 xdotool 这样的软件。

上面的命令中,click 表示动作,1 表示鼠标左键,合法的取值有:

编号 含义
1 鼠标左键
2 鼠标中键
3 鼠标右键
4 滚轮向前
5 滚轮向后

进阶

下面考虑复杂一些的情况,如果用 xdotool 来完成自动化,那么需要移动指针到指定的地方。X 桌面坐标系原点位于左上角,x 轴正方向向右,y 轴正方向向下,以像素为单位。例如,本人屏幕分辨率为 1920x1080,那么左上角的坐标为 (0, 0),右上角的坐标为 (1920, 0)。

假设现在需要平铺所有的窗口(我用的是 GNOME 桌面),那么需要将鼠标移到屏幕左上角点击 “Activities” 按钮。使用 xdotool 可以这样实现:

xdotool mousemove 0 0 click 1

xdotool 支持多个命令连在一起,上面的例子中,首先将鼠标移到屏幕左上角,然后点击鼠标左键。

mousemove 指令将鼠标位置移动到指定处,mousemove_relative 以鼠标当前位置为初始,移动相应的距离。这两条指令经常带上 --sync 参数,表示一定要等到 X11 确认鼠标已经移动到了目标位置,才会继续执行。

需要注意的是,如果坐标包含负值,必须在坐标前加上两个减号。例如命令

xdotool mousemove_relative -10 -10

是不能正确执行的,应该使用这种方式:

xdotool mousemove_relative -- -10 -10

窗口

xdotool 最强大的一个功能,就是能够自动搜索窗口,确定该窗口的位置,并使用窗口的局部坐标。例如,寻找 Chrome 浏览器并激活其窗口,可以通过下面的命令实现:

xdotool search "Chrome" windowactivate

这个功能需要窗口管理器的支持,xdotool 会遍历所有窗口,一旦发现标题栏内容包含指定的关键词,就返回该窗口。如果没有符合规则的窗口,那么什么也不会发生。

这里需要指出的是,窗口的标题栏内容和程序名称没有必然的关系。xdotool 根据标题栏内容查找窗口,而非应用程序的名字。

找到了目标窗口,还不能立刻对窗口中的按钮进行操作,因为窗口可能为于屏幕的任何位置。不过,我们可以将鼠标移动到窗口的左上角:

xdotool search "Chrome" windowactivate --sync mousemove --window %1 0 0

--window X 表示后面的坐标是相对窗口 X 而言的,%1 表示 search 操作返回的第一个窗口。

除了将鼠标移动到窗口的左上角,另一个方案是将窗口移动到指定的位置。例如,将 Chrome 移动到 (50, 50) 处:

xdotool search "Chrome" windowactivate --sync windowmove 50 50

再进一步,还可以指定窗口的大小,例如将 Chrome 缩放到宽 640,高 480 的大小:

xdotool search "Chrome" windowsize 640 480

杂项

拖拽

拖拽动作可以分解为“按下鼠标-移动鼠标-释放鼠标”的步骤,下面的代码是一个简单的例子:

xdotool mousedown 1
sleep 0.5
xdotool mousemove_relative --sync 200 200
sleep 0.5
xdotool mouseup 1

按键与输入

与鼠标模拟相比,xdotool 的虚拟键盘要简单的多。例如,按下 F1 键只需要:

xdotool key F1

如果需要组合键,可以使用加号连接:

xdotool key ctrl+a

对于文本流的输入,xdotool 提供了一个 type 命令:

xdotool search "gedit" windowactivate --sync type "hello world"