API: uia
UI Automation 模块,用于与 Windows 应用程序进行自动化交互。
基于 Microsoft UI Automation API,支持与大部分 Windows 应用程序的控件进行交互。
概述
UI Automation (UIA) 允许脚本直接操作应用程序的 UI 控件,而不是依赖坐标点击。这使得自动化更加可靠,不受窗口位置或大小变化的影响。
支持的控件类型
- Button - 按钮
- Edit - 文本输入框
- Text - 静态文本
- ComboBox - 下拉框
- List - 列表
- CheckBox - 复选框
- RadioButton - 单选按钮
- Tab - 标签页
- Menu - 菜单
- Window - 窗口
- ... 以及更多 Windows 标准控件
函数
fromForeground()
获取前台窗口的 UI Automation 根元素。
返回:
UIElement|nil- 根元素对象,失败返回 nil
示例:
local root = uia.fromForeground()
if root then
local info = root:getInfo()
print("Foreground window: " .. info.name)
endfromWindow(hwnd)
从窗口句柄获取 UI Automation 根元素。
参数:
hwnd(number) - 窗口句柄
返回:
UIElement|nil- 根元素对象,失败返回 nil
示例:
local hwnd, found = window.find("记事本")
if found then
local root = uia.fromWindow(hwnd)
if root then
print("记事本 UI 根元素获取成功")
end
endfromPoint(x, y)
从屏幕坐标获取 UI 元素。
参数:
x(number) - X 坐标y(number) - Y 坐标
返回:
UIElement|nil- 元素对象,失败返回 nil
示例:
local x, y = input.getMousePos()
local element = uia.fromPoint(x, y)
if element then
local info = element:getInfo()
print("Element: " .. info.name .. " (" .. info.controlType .. ")")
endfindByName(name)
在前台窗口中查找指定名称的元素。
参数:
name(string) - 元素名称
返回:
UIElement|nil- 找到的元素,未找到返回 nil
示例:
local fileMenu = uia.findByName("文件")
if fileMenu then
fileMenu:click()
endfindById(id)
在前台窗口中查找指定 Automation ID 的元素。
参数:
id(string) - Automation ID
返回:
UIElement|nil- 找到的元素,未找到返回 nil
findButton(name)
查找按钮控件。
参数:
name(string) - 按钮名称(支持部分匹配)
返回:
UIElement|nil- 找到的按钮,未找到返回 nil
示例:
local okBtn = uia.findButton("确定")
if okBtn then
okBtn:click()
endfindEdit(name)
查找编辑框控件。
参数:
name(string) - 编辑框名称(支持部分匹配,空字符串匹配任意编辑框)
返回:
UIElement|nil- 找到的编辑框,未找到返回 nil
示例:
local edit = uia.findEdit("")
if edit then
edit:setValue("Hello, UI Automation!")
endfindText(name)
查找文本控件。
参数:
name(string) - 文本名称(支持部分匹配)
返回:
UIElement|nil- 找到的文本元素,未找到返回 nil
findAll(name)
查找所有匹配指定名称的元素。
参数:
name(string) - 元素名称(可选,空字符串匹配所有)
返回:
UIElement|nil- 第一个匹配元素,未找到返回 nil
注意: 当前实现返回第一个匹配元素,完整实现将返回数组。
waitForName(name, timeout)
等待指定名称的元素出现。
参数:
name(string) - 元素名称timeout(number) - 超时时间(毫秒),默认 5000
返回:
UIElement|nil- 找到的元素,超时返回 nil
示例:
local dialog = uia.waitForName("对话框", 3000)
if dialog then
print("对话框已出现")
endonPropertyChanged(name, callback)
注册属性变更事件监听器。当指定元素的属性发生变化时触发回调。
参数:
name(string) - 要监听的元素名称callback(function) - 回调函数,接收参数(propertyName, value)
返回:
number|nil- 监听器 ID,失败返回 nil
示例:
local listenerId = uia.onPropertyChanged("编辑框", function(propertyName, value)
print(string.format("属性 %s 变更为: %s", propertyName, value))
end)
if listenerId then
print("监听器已注册,ID: " .. listenerId)
endonStructureChanged(name, callback)
注册结构变更事件监听器。当指定元素的子结构发生变化时触发回调。
参数:
name(string) - 要监听的元素名称callback(function) - 回调函数
返回:
number|nil- 监听器 ID,失败返回 nil
示例:
local listenerId = uia.onStructureChanged("列表框", function()
print("列表结构已变化")
end)removeEventListener(listenerId)
移除事件监听器。
参数:
listenerId(number) - 监听器 ID(由onPropertyChanged或onStructureChanged返回)
返回:
boolean- 是否成功移除
示例:
local listenerId = uia.onPropertyChanged("按钮", function(prop, val)
print("属性变化: " .. prop)
end)
-- 稍后移除监听器
if listenerId then
uia.removeEventListener(listenerId)
print("监听器已移除")
endUIElement 对象
方法
getInfo()
获取元素的完整信息。
返回:
table- 包含以下字段:name- 元素名称className- 类名automationId- Automation IDcontrolType- 控件类型bounds- 边界矩形isEnabled- 是否可用isVisible- 是否可见
示例:
local info = element:getInfo()
print(string.format("Name: %s, Type: %s", info.name, info.controlType))click()
点击元素。
返回:
boolean- 是否成功
示例:
element:click()rightClick()
右键点击元素。
返回:
boolean- 是否成功
doubleClick()
双击元素。
返回:
boolean- 是否成功
focus()
设置焦点到元素。
返回:
boolean- 是否成功
getValue()
获取元素的值(适用于编辑框等)。
返回:
string- 元素值
setValue(value)
设置元素的值。
参数:
value(string) - 要设置的值
返回:
boolean- 是否成功
示例:
local edit = uia.findEdit("")
edit:setValue("Hello World")getName()
获取元素名称。
返回:
string- 名称
getChildren()
获取所有子元素。
返回:
table- UIElement 数组
示例:
local children = root:getChildren()
for i, child in ipairs(children) do
local info = child:getInfo()
print(string.format("[%d] %s - %s", i, info.name, info.controlType))
endgetParent()
获取父元素。
返回:
UIElement|nil- 父元素
示例:
local parent = element:getParent()
if parent then
print("父元素: " .. parent:getName())
endexpand()
展开元素(适用于 Tree、ComboBox 等)。
返回:
boolean- 是否成功
collapse()
折叠元素。
返回:
boolean- 是否成功
isExpanded()
检查元素是否已展开。
返回:
boolean- 是否展开
示例:
local tree = uia.findByName("树形控件")
if tree then
if not tree:isExpanded() then
tree:expand()
end
endselectItem(item)
选择指定项(适用于 List、ComboBox 等)。
参数:
item(string) - 要选择的项名称
返回:
boolean- 是否成功
getSelection()
获取当前选中的项。
返回:
string- 选中的项名称
完整示例
-- 等待记事本窗口出现
print("等待记事本窗口...")
local hwnd, found = window.find("记事本")
if not found then
print("未找到记事本,尝试启动...")
process.start("notepad.exe")
util.sleep(1000)
hwnd, found = window.find("记事本")
end
if not found then
print("错误: 无法找到记事本窗口")
return
end
print("找到记事本窗口")
-- 激活窗口
window.activate(hwnd)
util.sleep(200)
-- 获取前台窗口的 UI Automation 根元素
local root = uia.fromForeground()
if not root then
print("错误: 无法获取 UI Automation 元素")
return
end
print("UI Automation 已初始化")
-- 获取所有子元素
print("\n=== 记事本 UI 元素 ===")
local children = root:getChildren()
for i, child in ipairs(children) do
local info = child:getInfo()
print(string.format("[%d] %s - %s (类型: %s, 可见: %s)",
i, info.name, info.className, info.controlType,
info.isVisible and "是" or "否"))
end
-- 查找编辑框
print("\n=== 查找编辑框 ===")
local edit = uia.findEdit("")
if edit then
-- 设置文本
edit:setValue("Hello from UI Automation!\n这是通过 Lua 脚本输入的文本。\n")
print("已设置文本")
-- 获取文本
local value = edit:getValue()
print("当前文本长度: " .. #value)
end
-- 查找关闭按钮
print("\n=== 查找关闭按钮 ===")
local closeButton = uia.findButton("关闭")
if closeButton then
print("找到关闭按钮")
-- closeButton:click() -- 取消注释可点击关闭按钮
end注意事项
- UI Automation 需要目标应用程序支持 UIA 接口,大部分现代 Windows 应用都支持
- 某些使用自定义绘制的应用可能不完全支持 UIA
- 如果 UIA 操作失败,可以降级使用坐标点击
- 使用
window.find()确保目标窗口在前台