LuaTouch 文档 首页 iOS 文档 安卓文档 开发者登录

前言

本页是 LuaTouch 安卓版 API 文档:目录、模块划分与 API 签名与 iOS 文档保持一致, 正文已按安卓端引擎的实际实现逐条核对(2026-09-15)。
条目标注 已支持 android支持 表示安卓端可用; iOS 不支持 表示安卓特有 API。

安卓端与 iOS 端共用同一套 Lua 脚本写法(全局函数、无模块前缀),差异主要在底层实现与个别平台限定的 API。

脚本约定

  • 坐标均为物理像素,示例以安卓测试机 720×1280 为准(iOS 文档示例为 1242×2208,数值不同、写法相同)
  • API 名称、参数、返回值语义与 iOS 对齐;若某个 API 在安卓端行为不同(返回值、权限、坐标单位等),会在该条目正文里单独说明
  • 老版安卓脚本使用的旧名(startApp、setClipboard、getClipboard、getWidth、getHeight、saveScreenshot、keepSurface、injectKeycode、injectKeyEvent、pressReleaseKeycode、keepScreenCapture)已于 2026-09-15 全部移除,请迁移到对应新名:appLaunch、imeSetClipText、imeGetClipText、getScreenSize、screenshot、keepCapture/releaseCapture、key/keyRaw/keyMeta
  • 安卓端另有双名 execute_shell_command(与 executeShellCommand 同一实现,安卓特有,供老脚本兼容)
  • 安卓端以下 API 已停用(注册被注释,Lua 面为 nil):srcUi、logUi/logUi_An/logUi_Dn、downloadFileUi、updateFloatingWindowPositionUi、saveScreenshotWithLeptonica、getLuaFilesDirectory、getEngineFilesDirectory、updateScript

下载项

官方安装包与配套工具,地址由管理端统一维护,点击链接即可下载。

加载中…

script 模块(脚本控制)

print(...) 已支持 android支持

打印日志(输出到引擎/Lua 日志文件,用于调试)。

  • 参数:任意多个值(字符串/数字/布尔等)
  • 返回:无
print("hello", 123, true)   -- 日志输出

require 保护与模块隔离 已支持 android支持

为被 require 引用的模块提供两件防护(对齐 iOS 端,需引擎最新版):

  • been_require(全局布尔):模块被别人 require 时引擎自动置 true;主脚本直接运行时为 false/nil。用于拒绝被人当库引用
  • table.deep_copy(t):深拷贝一张表——递归复制嵌套表、防循环引用、保留 metatable;函数等其它类型原样共享(Lua 无法复制函数)
  • .luc 加密模块同样适用(require 优先找 .luc,标志在装载路径上统一设置)

拒绝被引用(禁止白嫖):

if been_require then return end   -- 只想当主脚本跑,被 require 直接退出

环境隔离(防全局被污染/被顺走)——模块开头把全局环境深拷贝一份给自己;要留逃生门就在切换前先抓真全局的引用:

local realG = _G                     -- ★真逃生门:必须在切换前抓引用(upvalue)
local _ENV = table.deep_copy(_ENV)   -- 这行之后是自己的世界
t = 20                -- 写进自己的私有副本,外面看不见(改的是副本)
print(t)              -- 读的是"拷贝那一刻"的快照值
print(_G.t)           -- 注意:模块内 _G 也被换成了副本(防环机制把
                      -- _ENV 的自引用 _G 换成副本自己),不是真全局!
print(realG.t)        -- 真·逃生门:实时读真全局;realG.t = v 实时写回
local M = {}
function M.get_t() return t end   -- 导出函数:返回副本里的 t
return M              -- 隔离后 return 是唯一对外出口

隔离的边界要记清(可类比 Java 的访问控制:return=public、local=private、_ENV 隔离=私有静态区、been_require=final):

  • 引擎 API(tap/httpGet/print…)照常调用——函数是共享引用,行为不变
  • 普通全局变量按快照隔离:拷贝之后外部改了看不见,自己写的也出不去
  • 模块内 _G 也被换成了私有副本(_G.t ≡ 自己副本里的 t);要实时读写真全局,只能切换前 local realG = _G 抓引用,之后走 realG.xxx
  • 依赖「全局变量跨脚本传参」(globalSet / 主脚本设值子脚本读)的模块不要开隔离,否则设置的全局出不去

wsLog(...) 已支持 android支持

向中控推送日志({"type":"log"} 消息,中控 UI 实时可见);同时写入本地引擎日志。用法与 print 一致,多参数以 tab 分隔。需引擎 v1.10.1016+。

  • 参数:任意多个值(字符串/数字/布尔等)
  • 返回:boolean — true=已推送到中控;false=中控未连接(不报错,仅写本地日志)
wsLog("开始找图", pageNum)      -- 中控实时可见
local ok = wsLog("步骤1完成")   -- ok=true 已推送 / false 中控未连接

sleep(ms) 已支持 android支持

休眠指定毫秒数(暂停/停止脚本时立即响应,不等满时长)。

  • 参数:ms {int} 休眠毫秒数
  • 返回:无
sleep(1000)   -- 等 1 秒

LUA_CODE 已支持 android支持

全局配置集合变量:主 App 启动引擎时把控制面板参数集合(pass 字段,key 用 Pass_ 前缀)作为 JSON 字符串传入,引擎开启脚本时写入全局 LUA_CODE。

  • 类型:string(JSON 字符串),全局只读,脚本内直接读取
  • 内容:控制面板全部参数,key 为 Pass_ 前缀,与 NSUserDefaults 一致
  • 来源:主 App 控制面板输入框(引擎模式/账号/密码/序号/设备编号/luacode)→ 重启引擎生效
  • 取值:用 jsonToTable() 解析成表后按 key 取字段
-- LUA_CODE 内容示例:
-- {"Pass_mode":"root","Pass_account":"test","Pass_password":"test",
--  "Pass_seq":"1","Pass_device":"cs1","Pass_luacode":""}

-- 解析成表取字段(用于账号/授权校验、设备绑定等)
local cfg = jsonToTable(LUA_CODE)
if cfg and cfg.Pass_account == "test" then
    print("账号匹配: " .. cfg.Pass_account)
end

exitScript() 已支持 android支持

终止当前脚本(不重启)。调用后脚本立即停止执行。

  • 参数:无
  • 返回:无
exitScript()   -- 立即退出脚本

restartScript() 已支持 android支持

终止当前脚本并重新执行同一脚本文件(从头开始)。

  • 参数:无
  • 返回:无
restartScript()   -- 重启脚本

installScript(zipPath) 已支持 android支持

解压脚本项目包到工作目录:先清空工作目录的 res/、config/、libs/、scripts/ 四个目录,再把 zip 内对应目录解压到工作目录(等同安装一个脚本包;带 zip-slip 防护)。⚠️ 测试用的临时文件不要放这四个目录,会被清掉。

  • 参数:zipPath — 脚本包 zip 的完整路径(如 /data/local/tmp/com.luatouch.app/models/script.zip)
  • 返回:boolean 是否解压成功
local ok = installScript("/data/local/tmp/com.luatouch.app/models/script.zip")
-- zip 内 res/  → 工作目录 res/
--         config/ → 工作目录 config/
--         libs/   → 工作目录 libs/
--         scripts/→ 工作目录 scripts/
if ok then print("install ok") end

executeShellCommand(cmd) 安卓特有

执行系统 Shell 命令并返回输出。安卓端真实执行(引擎为 shell uid,权限内命令均可执行);iOS 端同名函数为空壳(不执行、恒返回 nil)。另有双名 execute_shell_command(同一实现,供老脚本兼容)。

  • cmd {string} 命令字符串;缺参/非字符串返回 nil, 错误信息
  • 返回:string 命令执行结果(stdout 输出)
local out = executeShellCommand("ls /data/local/tmp")   -- 返回目录列表
print(out)

getStartMode() 已支持 android支持

获取当前启动模式(START_MODE,int),由各启动入口在启动时设置:悬浮球点「开始」= 0、HTTP 10010 远程启动 = 1(可扩展其他模式);restartScript 重跑不重置(保留当前值)。

  • 参数:无
  • 返回:int 当前 START_MODE 值(当前版本恒为 0,预留字段)
local mode = getStartMode()
print("START_MODE =", mode)

Thread.newThread(callback) 已支持 android支持

创建子线程并立即开始执行 callback(独立 pthread + 独立 lua_State,与主脚本 真并行)。返回 thread userdata 用于后续 stopThread() 控制。

  • 参数:callback {function} 子线程入口函数
  • 返回:thread userdata;创建失败返回 nil + 错误消息

数据共享(globalSet / globalGet):每个线程(含主线程)的全局变量默认本线程私有 (标准 Lua 语义,线程之间互不可见)。跨线程共享走 C 层共享区,就两个公开 API:

  • globalSet("名", 值) —— 发布/覆盖:把值写进共享区。支持路径形式 globalSet("cfg", "ip", "1.2.3.4")(= 共享区的 cfg.ip,多层路径依次传分量); 值传 nil = 删除该路径。表/函数都能发(表逐字段入库,函数以字节码跨线程加载,取回可直接调用)
  • globalGet("名") / globalGet("cfg", "ip") —— 读取:返回共享区里的 深拷贝实体(表可正常 pairs / 索引 / #,每次读取是独立副本,改它不影响共享区); 不存在返回 nil
  • 快照语义(最重要):发布是"拷一份进共享区"——发布之后本线程再改自己的变量, 共享区不会自动跟着变,要让别人看到必须重新 globalSet 一次

重要约束:

  • 回调不能依赖闭包 upvalue(子线程通过字节码加载回调,upvalue 不跨线程传递); 数据一律用 globalSet / globalGet 传
  • 子线程里先 globalGet 取到本地再循环使用,要最新值时再取一次 (别在循环里反复取大表,每次都是深拷贝)
  • 子线程不响应主脚本的暂停/恢复;只有 stopThread() 或主脚本结束/停止时强停
-- 主脚本:发布共享数据(子线程看不到普通全局变量,必须 globalSet)
config = { count = 0, stop = false }
globalSet("config", config)            -- 整表发布(逐字段入库)

function worker()
    while true do
        local cfg = globalGet("config")          -- 取共享区副本
        if cfg and cfg.stop then break end
        print("worker tick, count=" .. tostring(cfg and cfg.count))
        sleep(1000)
    end
    print("worker exit")
end

local t = Thread.newThread(worker)
-- 主脚本继续干别的事...
sleep(5000)
config.stop = true
globalSet("config", config)            -- ★ 改完必须重新发布,子线程才看得到

thread:stopThread() 已支持 android支持

强制终止该子线程(置独立停止标志,线程内 sleep 立即响应,hook 强停)。只影响该线程, 不影响主脚本与其他子线程。主脚本结束/停止时引擎会自动强停所有子线程,无需手动清理。

  • 参数:无(thread 为 Thread.newThread 的返回值)
  • 返回:无
local t = Thread.newThread(worker)
sleep(3000)
t:stopThread()   -- 单独停掉 worker,主脚本继续跑

app 模块

appCurrentPackage() 已支持 android支持

获取当前前台应用的 Bundle Identifier。

  • 参数:无
  • 返回:string 前台应用的包名;无前台应用时返回 nil
-- 获取当前前台 App 的包名
local bid = appCurrentPackage()
print(bid)   -- 例如 "com.apple.mobilesafari"

appLaunch(packageName) 已支持 android支持

通过 Bundle Identifier 启动应用。

  • packageName {string} 应用包名
  • 返回:bool 是否启动成功
local ok = appLaunch("com.apple.mobilesafari")
if ok then print("已启动") end

appForceStop(packageName) 已支持 android支持

关闭指定应用(系统级终止进程)。

  • packageName {string} 应用包名
  • 返回:bool 是否成功终止
appForceStop("com.example.app")

appGetList(includeSystemApps) 已支持 android支持

获取已安装应用列表。

  • includeSystemApps {bool} 是否包含系统应用
  • 返回:table 应用信息数组,每个元素是下表结构
字段名类型说明
PackageNamestring应用的 Bundle Identifier
AppNamestring应用显示名称
VersionNamestring版本号(安卓版为 versionName)
VersionCodestring构建号(安卓版为 versionCode)
IsSystemAppbool是否为系统应用
local list = appGetList(true)
for _, a in ipairs(list) do
    print(a.PackageName, a.AppName, a.VersionName)
end

appGetBundlePath(packageName) 已支持 android支持

获取应用安装包(.app)路径。

  • packageName {string} 应用包名
  • 返回:string 路径;未找到返回 nil
local path = appGetBundlePath("com.auto.go")

appGetDataPath(packageName) 已支持 android支持

获取应用数据目录路径。

  • packageName {string} 应用包名
  • 返回:string 数据目录路径;未找到返回 nil
local data = appGetDataPath("com.auto.go")

appSelfPackage() 已支持 android支持

获取当前脚本/宿主自身的包名。

  • 参数:无
  • 返回:string 当前应用包名;获取失败返回 nil
local pkg = appSelfPackage()

appGetVersion(packageName) 已支持 android支持

通过包名获取应用版本号(安卓版为 versionName)。

  • packageName {string} 应用包名
  • 返回:string 版本号;未找到返回 nil
local ver = appGetVersion("com.tencent.xin")

appUninstall(packageName) 已支持 android支持

卸载应用。

  • packageName {string} 应用包名
  • 返回:bool 是否成功
appUninstall("com.example.app")

appInstall(path) 已支持 android支持

后台静默安装 APK 文件。

  • path {string} APK 文件路径
  • 返回:bool 是否成功
appInstall("/data/local/tmp/com.luatouch.app/app.apk")

appClear(packageName) 已支持 android支持

清除应用数据(删除数据容器内容)。

  • packageName {string} 应用包名
  • 返回:bool 是否成功
appClear("com.example.app")

appOpenUrl(url) 已支持 android支持

使用系统默认方式打开 URL。若未带 http:// 或 https:// 前缀,会自动补上 http://。

  • url {string} 网址或 URL Scheme
  • 返回:bool 是否成功
appOpenUrl("https://example.com")

appGetPackageName() 已支持 android支持

获取宿主 App(LuaTouch)包名。与 appSelfPackage() 的区别: appSelfPackage() 返回引擎宿主(com.luatouch.core),本函数返回主 App(com.luatouch.app)。

  • 参数:无
  • 返回:string 主 App 包名(com.luatouch.app)
print(appGetPackageName()) -- com.luatouch.app
print(appSelfPackage())   -- com.luatouch.core

device 模块

deviceGet() 已支持 android支持

一次获取设备信息(本引擎便利封装)。只含「变量 + 下方函数拿不到」的信息;内存用 deviceGetTotalMem、屏幕用 deviceGetDisplayInfo。

  • 参数:无
  • 返回:table,字段见下表(取不到时字段缺失)
字段类型说明
Modelstring设备机型标识(如 TAS-AL00)
Releasestring系统版本(如 "14.6")
Serialstring设备序列号
Buildstring系统构建号(如 18F72)
SystemNamestring系统名称(如 "iOS")
DeviceNamestring用户设置的设备名
ArchstringCPU 架构(如 arm64)
Is64Bitbool是否 64 位
CpuCountintCPU 核数
local d = deviceGet()
print(d.Model, d.Release, d.Serial)
print(d.Arch, d.Is64Bit, d.CpuCount)

deviceGetDisplayInfo() 已支持 android支持

获取主屏幕的分辨率信息(多返回值)。

  • 参数:无
  • 返回:width {int} 逻辑宽度,height {int} 逻辑高度,scale {number} 缩放因子,rotation {int} 旋转角度(0/90/180/270)
local w, h, scale, rot = deviceGetDisplayInfo()
print(w, h, scale, rot)   -- 例如 390 844 2.0 0

deviceVpnStatus() 已支持 android支持

获取 VPN 状态(存在 utun 网络接口即视为开启)。

  • 参数:无
  • 返回:bool
if deviceVpnStatus() then
    print("VPN 已开启")
end

deviceSetVPNEnabled(enabled) 已支持 android支持

设置 VPN 开关状态。

  • enabled {bool} 是否打开
  • 返回:false
deviceSetVPNEnabled(true)   -- 恒 false

deviceSetWiFiEnabled(enabled) 已支持 android支持

设置 WiFi 开关状态。

  • enabled {bool} 是否打开
  • 返回:false
deviceSetWiFiEnabled(true)   -- 恒 false

deviceGetBattery() 已支持 android支持

获取当前电量百分比。

  • 参数:无
  • 返回:int 0~100;读取失败返回 -1
local level = deviceGetBattery()
print("电量 " .. level .. "%")

deviceGetBatteryStatus() 已支持 android支持

获取电池状态。

  • 参数:无
  • 返回:int 0 未知,1 未充电,2 充电中,3 已充满
local st = deviceGetBatteryStatus()
if st == 2 then print("充电中") end

deviceIsScreenOn() 已支持 android支持

判断屏幕是否点亮(未锁屏即视为点亮)。

  • 参数:无
  • 返回:bool
if deviceIsScreenOn() then print("屏幕亮着") end

deviceIsScreenUnlock() 已支持 android支持

判断屏幕是否已解锁(未处于锁屏状态)。

  • 参数:无
  • 返回:bool
if deviceIsScreenUnlock() then print("已解锁") end

deviceGetBrightness() 已支持 android支持

获取当前屏幕亮度。

  • 参数:无
  • 返回:int 0~255
local b = deviceGetBrightness()
print("亮度 " .. b)

deviceGetTotalMem() 已支持 android支持

获取设备总内存。

  • 参数:无
  • 返回:int 总内存,单位 KB;失败返回 0
print(deviceGetTotalMem() .. " KB")

deviceGetAvailMem() 已支持 android支持

获取设备当前可用内存(free + inactive,host_statistics64)。

  • 参数:无
  • 返回:int 单位 KB;失败返回 0
print(deviceGetAvailMem() .. " KB")

deviceWakeUp() 已支持 android支持

唤醒设备(点亮屏幕)。

  • 参数:无
  • 返回:bool 是否成功调用
deviceWakeUp()

deviceKeepScreenOn() 已支持 android支持

保持屏幕常亮(关闭自动锁屏)。

  • 参数:无
  • 返回:bool 是否成功调用
deviceKeepScreenOn()

deviceGetIp() 已支持 android支持

获取设备局域网 IPv4 地址(优先私有网段,跳过自分配地址)。

  • 参数:无
  • 返回:string 如 "192.168.31.169";取不到返回 nil
local ip = deviceGetIp()
print(ip)

deviceGetWifiMac() 已支持 android支持

获取 Wi‑Fi 网卡 MAC 地址(en0,回退 en1)。

  • 参数:无
  • 返回:string 如 "aa:bb:cc:dd:ee:ff";取不到返回 nil
local mac = deviceGetWifiMac()
print(mac)

deviceReboot() 已支持 android支持

重启设备(root 直接 reboot(RB_AUTOBOOT),调用后设备立即重启)。

  • 参数:无
  • 返回:bool(正常不会返回)
-- 慎用:立即重启设备
deviceReboot()

getPlatform() 已支持 android支持

获取运行平台标识。iOS 版恒返回 "ios"(跨平台脚本兼容用,安卓版返回 "android")。

  • 参数:无
  • 返回:string 平台标识,iOS 上恒为 "ios"
if getPlatform() == "ios" then
    print("当前运行在 iOS")
end

file 模块

deleteFile(path) 已支持 android支持

删除文件或空目录(目录用 rmdir,文件用 remove)。

  • path {string} 文件或空目录路径
  • 返回:bool 是否删除成功
deleteFile("/data/local/tmp/com.luatouch.app/tmp.txt")

moveFile(src, dst) 已支持 android支持

移动或重命名文件(rename)。

  • src {string} 源路径
  • dst {string} 目标路径
  • 返回:bool 是否成功
moveFile("/tmp/a.txt", "/data/local/tmp/com.luatouch.app/a.txt")

unzipFile(zip, dest) 已支持 android支持

解压 zip 文件到目标目录。

  • zip {string} zip 文件路径
  • dest {string} 解压目标目录(不存在会自动创建)
  • 返回:bool 是否成功
unzipFile("/data/local/tmp/com.luatouch.app/app.zip", "/data/local/tmp/com.luatouch.app/extract")

readFileAsBase64(path) 已支持 android支持

读取文件内容并编码为 Base64(双返回值)。

  • path {string} 文件路径
  • 返回:string Base64 内容;失败返回 nil + 错误信息
local b64, err = readFileAsBase64("/tmp/img.png")
if b64 then
    print("base64 length", #b64)
end

base64Encode(str) 已支持 android支持

将字符串编码为 Base64(标准字母表 A-Z a-z 0-9 + /,= 填充)。

  • str {string} 原始内容
  • 返回:string Base64 编码结果
local b64 = base64Encode("hello")
print(b64)          -- aGVsbG8=

base64Decode(str) 已支持 android支持

将 Base64 字符串解码为原始内容(自动忽略换行/空白/= 填充,容错宽松)。

  • str {string} Base64 内容
  • 返回:string 解码结果
local raw = base64Decode("aGVsbG8=")
print(raw)          -- hello

http 模块

httpGet(url, timeout?) 已支持 android支持

HTTP GET 请求。支持 HTTP/HTTPS,默认超时 30 秒。

  • url {string} 完整 URL(如 http://192.168.1.1:8080/api)
  • timeout {number} 可选,超时秒数,默认 30
  • 返回:int HTTP 状态码(200/404…,负值为错误码见下表)+ string 响应体
local code, body = httpGet("http://example.com/api")
print(code, body)

httpPost(url, data, contentType?, timeout?) 已支持 android支持

HTTP POST 请求。支持 HTTP/HTTPS,默认超时 30 秒。

  • url {string} 完整 URL
  • data {string} 请求体(POST 数据)
  • contentType {string} 可选,Content-Type;默认 application/x-www-form-urlencoded
  • timeout {number} 可选,超时秒数,默认 30
  • 返回:int 状态码 + string 响应体
local code, body = httpPost("http://example.com/api",
    "name=test&id=1", "application/x-www-form-urlencoded")

downloadFile(url, path, timeout?) 已支持 android支持

HTTP 下载文件到本地(流式写盘,父目录自动创建)。支持 HTTP/HTTPS,默认超时 60 秒。

  • url {string} 完整 URL
  • path {string} 保存路径(绝对路径)
  • timeout {number} 可选,超时秒数,默认 60
  • 返回:boolean 是否成功 + string 错误信息(成功为空串)
local ok, err = downloadFile("http://example.com/file.zip",
    "/data/local/tmp/com.luatouch.app/downloads/file.zip")

tableToJson(table) 已支持 android支持

Lua 表序列化为 JSON 字符串。数组(连续数字键)输出数组,否则输出对象。

  • table {table} 要序列化的表
  • 返回:string JSON 字符串;参数非表返回错误串
local json = tableToJson({ name = "test", id = 1 })
print(json)   -- {"id":1,"name":"test"}

jsonToTable(str) 已支持 android支持

JSON 字符串解析为 Lua 表。

  • str {string} JSON 字符串
  • 返回:table 解析结果;解析失败返回 nil
local t = jsonToTable('{"name":"test","id":1}')
print(t.name, t.id)

HTTP 错误码 说明

码含义
-1参数错误(url 为空 / POST 无数据)
-2URL 解析失败
-4socket 创建失败
-5DNS 解析失败
-6连接失败
-7发送失败
-8无响应(超过 timeout 秒)

ime 模块

imeInputText(text) 已支持 android支持

向当前焦点控件输入文本(支持中文、英文、数字)。

  • text {string} 要输入的文本(支持中文/英文/数字)
  • 返回:bool 是否注入成功
imeInputText("Hello, World!")
imeInputText("你好世界")

imePasteText() 已支持 android支持

模拟 Command+V,把剪贴板内容粘贴到当前焦点。

  • 参数:无
  • 返回:bool 是否注入成功
imeSetClipText("要粘贴的内容")
imePasteText()

imeGetClipText() 已支持 android支持

获取剪贴板文本内容。

  • 参数:无
  • 返回:string 剪贴板文本;失败返回 nil
local text = imeGetClipText()
print(text)

imeSetClipText(text) 已支持 android支持

设置剪贴板文本内容。

  • text {string} 要写入剪贴板的文本
  • 返回:bool 是否设置成功
imeSetClipText("要复制的内容")

touch 模块

tap(x, y, tip?, barrel?, radius?) 已支持 android支持

在指定位置点击一下。

  • x {number} 横坐标(物理像素,0~屏幕宽)
  • y {number} 纵坐标(物理像素,0~屏幕高)
  • tip {number} 可选,指尖压力 0~1,默认 1
  • barrel {number} 可选,笔身压力 0~1,默认 0
  • radius {number} 可选,触摸半径,默认 0.04
  • 返回:无
tap(360, 640)   -- 点击屏幕中心(720x1280)

swipe(x1, y1, x2, y2, ms?, tip?, barrel?, radius?) 已支持 android支持

从起点滑动到终点(20 步插值)。

  • x1, y1 {number} 起点坐标
  • x2, y2 {number} 终点坐标
  • ms {int} 可选,滑动时长毫秒,默认 300(最小 50)
  • tip {number} 可选,指尖压力 0~1,默认 1
  • barrel {number} 可选,笔身压力 0~1,默认 0
  • radius {number} 可选,触摸半径,默认 0.04
  • 返回:无
swipe(621, 1600, 621, 400, 500)   -- 从下往上滑

key(name) 已支持 android支持

按命名按键(按下 → 保持约 40ms → 自动抬起)。

  • name {string} 键名,仅支持下列 6 个:home / home2 / lock(锁屏)/ volup / voldown / mute
  • 返回:bool 是否支持该键名(true=已注入;false=键名未知,不注入任何按键)
键名对应 HID说明
homepage 0x0C, usage 0x40回到主屏(Consumer Home/Menu)
home2page 0x0C, usage 0x0223回主屏的另一种实现(Consumer AC Home),部分场景比 home 更有效
lockpage 0x0C, usage 0x30锁屏 / 电源键
voluppage 0x0C, usage 0xE9音量 +
voldownpage 0x0C, usage 0xEA音量 −
mutepage 0x0C, usage 0xE2静音开关
key("home")       -- 回到主屏
key("volup")      -- 音量+
key("lock")       -- 锁屏
if not key("back") then print("key 不认识 back,需要用 keyRaw") end

keyRaw(page, usage) 已支持 android支持

按 HID 原始键码(按下 → 保持约 40ms → 自动抬起),用于 key() 未内置的按键。

  • page {int} HID 用法页(如 0x0C 消费类、0x07 键盘)
  • usage {int} 用法码
  • 返回:无
keyRaw(0x0C, 0x40)    -- Consumer Home

keyMeta(name, repeat?, meta?) 已支持 android支持

带修饰键的按键(键名范围同 key();修饰键只支持 Shift)。

  • name {string} 键名(同 key)
  • repeat {int} 可选,重复次数,默认 1
  • meta {int} 可选,修饰键位掩码:0x1 = Shift,默认 0
  • 返回:无
keyMeta("home", 2)       -- 按 home 两次
keyMeta("home", 1, 0x1)  -- Shift + home

touchDown(idx, x, y, tip?, barrel?, radius?) 已支持 android支持

多指触摸:第 idx 根手指按下。手指索引范围 0~9,按下 / 移动 / 抬起必须用同一个 idx 成对出现(自己保证配对,不做手势识别)。

  • idx {int} 手指索引(0~9)
  • x, y {number} 按下位置
  • tip {number} 可选,指尖压力 0~1,默认 1
  • barrel {number} 可选,笔身压力 0~1,默认 0
  • radius {number} 可选,触摸半径,默认 0.04
  • 返回:无
touchDown(0, 100, 300)   -- 第一根手指按下

touchMove(idx, x, y, tip?, barrel?, radius?) 已支持 android支持

多指触摸:移动第 idx 根手指到新位置。按规范应先 touchDown 同一 idx;idx 超出 0~9 会被忽略。

  • idx {int} 手指索引(0~9)
  • x, y {number} 新位置
  • tip {number} 可选,指尖压力 0~1,默认 1
  • barrel {number} 可选,笔身压力 0~1,默认 0
  • radius {number} 可选,触摸半径,默认 0.04
  • 返回:无
touchDown(0, 200, 400)
touchMove(0, 400, 400)   -- 保持按住并拖动
touchUp(0)

touchUp(idx) 已支持 android支持

多指触摸:抬起第 idx 根手指(必须与对应 touchDown 的 idx 一致,抬起位置用的是按下时记录的坐标)。若该 idx 当前并未按下,则不发送任何事件、静默返回;idx 超出 0~9 同样被忽略。

  • idx {int} 手指索引(0~9)
  • 返回:无
touchUp(0)               -- 第一根手指抬起

color 模块

keepCapture() / releaseCapture() 已支持 android支持

图色渲染帧冻结控制:图色函数读取的是后台持续更新的缓存帧。

  • keepCapture():冻结当前画面,期间所有图色函数查的是同一帧
  • releaseCapture():恢复实时画面
  • 参数:无;返回:无
  • 用途:画面静止时连续多次图色查找(循环找点)保证同一画面
keepCapture()                     -- 冻结当前帧
for i = 1, 10 do
    local x, y = findMultiColors(0, 0, 0, 0, "359bed-101010",
        "45|76|ffffff-101010|93|114|ffffff-101010|33|146|ffffff-101010|-9|432|359bed-101010|58|447|359bed-101010",
        0, 0.9)
    if x ~= -1 and y ~= -1 then print(x, y) end
end
releaseCapture()                  -- 恢复实时画面

⚠️ 注意:每次开启脚本(悬浮球「开始」)会自动恢复实时渲染,不会因上次脚本忘记释放而永久冻结;但脚本内 keep 后建议主动 release。安卓实现为图像帧层开关(keepCapture() = 停止实时更新、一直保存当前帧;releaseCapture() = 恢复实时渲染)。

颜色格式 已支持 android支持

颜色统一为 6 位十六进制 RGB,格式 目标-容差(分隔符 - 或 | 均可):

  • 目标 {string} 6 位目标颜色,如 ffffff
  • 容差 {string} 6 位容差值(R/G/B 各一字节),如 323232 表示每通道允许 ±0x32
findColor(0, 0, 720, 1280, "ffffff-323232", 0, 0, 0)
-- 多点偏移组:x|y|目标-容差
detectsMultiColors("620|389|ffffff-323232,100|200|000000-101010")

getPixel(x, y) 已支持 android支持

获取指定像素点的 RGB 分量(多返回值)。

  • x, y {int} 屏幕像素坐标
  • 返回:r, g, b(0~255);越界返回 nil
local r, g, b = getPixel(100, 200)
print(r, g, b)

getRGB(x, y) 已支持 android支持

获取指定像素点的打包颜色值。

  • x, y {int} 屏幕像素坐标
  • 返回:int 颜色 0xAARRGGBB;失败返回 0
local c = getRGB(100, 200)
print(string.format("%08X", c))

getScreenSize() 已支持 android支持

获取屏幕尺寸(多返回值)。

  • 参数:无
  • 返回:w, h(像素);无屏幕缓存返回 nil
local w, h = getScreenSize()

findColor(x1, y1, x2, y2, color, d1?, d2?, d3?) 已支持 android支持

在矩形区域内查找第一个匹配颜色的点(8 方向扫描)。

  • x1, y1, x2, y2 {int} 搜索区域(自动归一化)
  • color {string} 目标-容差,如 ffffff-323232
  • d1, d2, d3 {int} 可选,扫描方向(0/1),决定起扫边与主轴;全 0 = 左上→右下
  • 返回:x, y 命中坐标;未找到返回 -1, -1
local x, y = findColor(0, 0, 720, 1280, "ff0000-101010")
if x >= 0 then
    print("found at", x, y)
end

isColor(x, y, color) 已支持 android支持

判定指定像素点颜色是否匹配(单点快速判定:直读渲染源目标像素,不建目标面、不整帧拷贝;keepCapture 冻结期 / 50ms 去重窗口内直接读缓存帧零成本返回)。

  • x, y {int} 屏幕像素坐标
  • color {string} RRGGBB 或 RRGGBB-容差;纯 6 位串自动按容差 000000 处理
  • 返回:boolean true 命中 / false 不命中
if isColor(102, 86, "D33422-101010") then
    print("是目标颜色")
end

findMultiColors(x1, y1, x2, y2, firstColor, offsetColors, d1?, d2?, d3?) 已支持 android支持

首点 + 相对偏移多点匹配(可精确识别图标/按钮)。

  • x1, y1, x2, y2 {int} 搜索区域
  • firstColor {string} 首点颜色(目标-容差)
  • offsetColors {string} 偏移点组,x|y|目标-容差 逗号分隔(偏移相对首点)
  • d1, d2, d3 {int} 可选,扫描方向
  • 返回:x, y 首点命中坐标;未找到返回 -1, -1
local x, y = findMultiColors(0, 0, 720, 1280,
    "ffffff-323232",
    "620|391|ffffff-323232,100|200|000000-101010")

tableFindMultiColors(x1, y1, x2, y2, firstColor, offsetColors, d1?, d2?, d3?) 已支持 android支持

与 findMultiColors 同参数,但返回区域内所有匹配点的集合(而非第一个点)。

  • x1, y1, x2, y2 {int} 搜索区域
  • firstColor {string} 首点颜色(目标-容差)
  • offsetColors {string} 偏移点组,x|y|目标-容差 逗号分隔(偏移相对首点)
  • d1, d2, d3 {int} 可选,扫描方向
  • 返回:table 所有匹配点集合 {{x=,y=},...};无匹配返回空表 {}
local pts = tableFindMultiColors(0, 0, 720, 1280,
    "ffffff-323232",
    "620|391|ffffff-323232,100|200|000000-101010")
for i, p in ipairs(pts) do
    print(i, p.x, p.y)
end

findPic(x1, y1, x2, y2, files, deltaColor?, sim?, dir?) 已支持 android支持

区域找图(模板匹配):在屏幕区域内查找模板图片,返回其左上角坐标。支持透明图/异形图(模板四角同色且占比 ≥30% 时该色判为背景,匹配时只比前景像素——兼容大漠涂抹异形图用法与 PNG 真透明)、每通道偏色、多模板(| 分隔,返回最先命中的)。

  • x1, y1, x2, y2 {int} 搜索区域;x2/y2 为 0 时取整屏,坐标写反自动交换
  • files {string} 模板图片路径,多图用 | 分隔(如 a.png|b.png);相对路径以脚本工作目录 res/ 为基准;支持 png/jpg
  • deltaColor {string} 可选,偏色 RRGGBB(如 "101010"),匹配时每通道允许 ±该值;"000000" = 无偏色
  • sim {number} 可选,相似度 0.1~1.0(默认 0.9),1.0 = 逐像素完全一致
  • dir {int} 可选,扫描方向:0 从左上(默认)/ 1 从右上 / 2 从左下 / 3 从右下
  • 返回:x, y 命中模板的左上角坐标;未找到返回 -1, -1

模板图可用「图色助手 → 裁剪画笔涂抹」制作:涂抹掉不要的部分(涂抹色需一致且占比 ≥30%、四角为涂抹色,工具会自动补涂)。

-- 全屏找 btn.png,相似度 0.9,无偏色
local x, y = findPic(0, 0, 0, 0, "btn.png", "000000", 0.9, 0)
if x ~= -1 then
    tap(x + 20, y + 10)  -- 点模板内相对位置
end

-- 多模板:返回最先命中的那个(透明图/异形图直接可用)
x, y = findPic(0, 0, 0, 0, "btn2.jpg|btn3.png", "000000", 0.9, 0)
print(x, y)

findPicEx(x1, y1, x2, y2, files, deltaColor?, sim?, dir?) 已支持 android支持

区域找图(多图全部命中):与 findPic 同参数,但返回区域内所有模板命中结果的集合(而非第一个),结果按扫描方向排序,上限 1800 个。

  • 参数与 findPic 完全一致
  • 返回:table 每项 {index=模板序号, name=文件名, x=, y=};无匹配返回空表 {}
local t = findPicEx(0, 0, 0, 0, "a.png|b.png", "000000", 0.9, 0)
for i, v in ipairs(t) do
    print(i, v.name, v.x, v.y)
end
-- 无匹配时 t 为空表

getColorCountInRegion(x1, y1, x2, y2, colorStr, sim?) 已支持 android支持

统计区域内符合颜色条件的像素数量。

  • x1, y1 {int} 区域左上角坐标
  • x2, y2 {int} 区域右下角坐标;为 0 时取屏幕最大宽/高
  • colorStr {string} 颜色字符串,多颜色用 | 分隔,每组 RRGGBB 或 RRGGBB-容差,如 FFFFFF|CCCCCC-101010
  • sim {number} 可选,相似度 0.1~1.0(默认 0.9);未带容差的颜色用它换算容差 (1-sim)*255
  • 返回:int 匹配像素总数(任一颜色命中即计 1)
local count = getColorCountInRegion(0, 0, 0, 0, "FFFFFF", 0.9)
print(count)

detectsMultiColors(colors) 已支持 android支持

多点同屏判定:给定一组绝对坐标点,判断是否全部匹配(常用于区域校验)。

  • colors {string} x|y|目标-容差 逗号分隔;首点可带第 4 字段 extra 指定偏移搜索范围(默认 0)
  • 返回:bool 全部匹配返回 1,否则 0
local ok = detectsMultiColors("620|389|ffffff-323232,100|200|000000-101010")
if ok == 1 then
    print("all colors match")
end

screenshot(path) 已支持 android支持

截取全屏并保存为 PNG 文件。

  • path {string} 保存路径
  • 返回:bool 是否保存成功
screenshot("/data/local/tmp/com.luatouch.app/screen.png")

cv 模块(对象式 OpenCV,206 个函数)

用法与 Mat 对象 已支持 android支持

cv 模块为对象式 API:cv.snapshot() 等函数返回 Mat 对象,处理函数一律「Mat 进、Mat 出」。旧的 12 个 cv_xxx 全局函数已废弃,由本模块取代。

  • 双写法:每个成员同时注册全小写与首字母大写两个名字(cv.snapshot = cv.Snapshot),任选其一。
  • Mat 对象方法(6 个):mat:release() 主动释放 / mat:empty() 是否为空 / mat:size() 尺寸 / mat:type() 类型 / mat:clone() 深拷贝 / mat:origin() 截屏原点偏移。空 Mat 一律以 nil 表示。
  • 常量传参:OpenCV 常量可直接传名字字符串(如 "TM_SQDIFF_NORMED"、"CV_32F")或数字值。
  • 点集参数:所有接受点集的函数(arclength / contourarea / approxpolydp / convexhull / perspectivetransform 等)同时支持字段式 {{x=10,y=20},...} 与数组式 {{10,20},...},也可混用 Point 指针;引擎版本 1.0.5 起两端一致。
  • 字节序:屏幕帧是 RGBA;要 imwrite / base64 输出图片前先 cv.tobgr(mat),否则红蓝颠倒。
  • 找纯色块:matchtemplate/findimage 默认 TM_CCOEFF_NORMED,纯色无纹理模板必然失效,须显式传 "TM_SQDIFF_NORMED"。
  • 释放:Mat 走 GC 自动回收,高频循环建议手动 mat:release();OCR 实例(ocr/ppocr)按需创建且不自动释放,用完记得 ocr_close / ppocr_release。
  • 所有函数的坐标均为 Mat 像素坐标;带 origin 的 Mat(roi/crop 产物)findimage 等返回绝对坐标。

创建与生命周期 已支持 android支持

  • snapshot([x1,y1,x2,y2]) — 截当前屏幕帧为 Mat(无参全屏,有参区域)
  • new(w,h[,ch[,fill]]) — 新建空 Mat(CV_8UC1~4,可指定填充值)
  • eye(n) / ones(rows,cols) / zeros(rows,cols) — 单位阵 / 全 1 / 全 0
  • clone(m) — 深拷贝(新内存)
  • copyto(src[,dst[,mask]]) — 拷贝(可带掩码)
  • setto(m,value[,mask]) — 区域赋值
  • convertto(m,type[,alpha[,beta]]) — 元素类型转换(可缩放)
  • reshape(m,ch,rows) — 改变形状
  • roi(m,x,y,w,h) / crop(m,x,y,w,h) — 截取子区域(新 Mat,origin 累计偏移)
  • release(m) — 主动释放(裸指针的释放见下方「指针与辅助类型」)

属性与像素读写 已支持 android支持

  • empty(m) / getsize(m) / gettype(m) / getorigin(m) — 空 / 尺寸 / 类型 / 截屏原点
  • getpixel(m,x,y) / setpixel(m,x,y,value) — 单像素读写(value 为 {b,g,r} 表)
  • seqcount(m) — 序列元素个数(点集/结果序列长度)
  • gettextsize(text,font,scale,thickness) — 计算文字绘制尺寸

指针与辅助类型 已支持 android支持

分配/读写原生标量与 Point 指针(供需要输出参数的接口使用)。指针必须用 cv.deletePtr 释放——忘记释放由 GC 兜底不泄漏,但释放后再读写会明确报错;类型严格校验(int 指针传给 getDouble 会报错)。拼写为全小写/首字母大写双名(cv.newpoint = cv.NewPoint)。

  • newInt(v) / getInt(p) / setInt(p,v) — 整型指针分配 / 读 / 写
  • newDouble / getDouble / setDouble、newFloat / getFloat / setFloat、newLong / getLong / setLong、newByte / getByte / setByte — 与 Int 完全同构(双精度 / 单精度 / 长整 / 字节指针)
  • newPoint(x,y) / getPoint(p) / setPoint(p,x,y) — Point 指针;getPoint 返回 {x=,y=} 表
  • newPoint2f(x,y) / getPoint2f(p) / setPoint2f(p,x,y) — 浮点坐标 Point(返回同样为 {x=,y=} 表)
  • deletePtr(p) — 释放指针;ptrtype(p) — 返回类型名与是否已释放(调试用)
local p = cv.newInt(5)
print(cv.getInt(p))      -- 5
cv.setInt(p, 8)
print(cv.getInt(p))      -- 8
cv.deletePtr(p)

local pt = cv.newPoint(100, 200)
local pos = cv.getPoint(pt)   -- {x=100, y=200}
cv.setPoint(pt, 500, 500)
print(cv.ptrtype(pt))         -- point   false(未释放)
cv.deletePtr(pt)

算术与数学 已支持 android支持

  • add / subtract / multiply / divide — 四则(带饱和/缩放语义)
  • addweighted(m1,a,m2,b,gamma) — 加权和;scaleadd(m1,a,m2) — 缩放加
  • absdiff(m1,m2) — 绝对差;min/max(m1,m2) — 逐元素最值;compare(m1,m2,op) — 比较
  • bitwiseand / bitwisenot / bitwiseor / bitwisexor — 位运算(可带掩码)
  • sqrt / pow / exp / log — 逐元素数学
  • convertscaleabs(m[,alpha[,beta]]) — 缩放+偏移后取绝对值,输出 CV_8U(增强对比/边缘可视化的常用前处理)
  • gemm(a,b,alpha,c,beta) — 广义矩阵乘(注意第 5 参才是 beta,第 4 参可省略矩阵)
  • invert(m[,method]) / determinant(m) / trace(m) — 求逆 / 行列式 / 迹
  • solve(a,b[,method]) / solvecubic / solvepoly / solvey — 线性方程组 / 多项式求根
  • setidentity(m[,s]) — 原地置单位阵
  • sort(m[,flags]) / sortidx(m[,flags]) — 排序 / 排序索引
  • magnitude(x,y) / carttopolar / polartocart — 幅值与极坐标互换;phasecorrelate — 相位相关

统计 已支持 android支持

  • mean(m[,mask]) / meanstddev(m[,mask]) — 均值 / 均值与标准差
  • sumelems(m) — 元素求和;countnonzero(m) — 非零个数
  • minmaxidx(m[,mask]) — 最小最大值与位置(注意 idx[0]=行 y、idx[1]=列 x,不是线性下标)
  • minmaxloc(m[,mask]) — 最小最大值与位置
  • findnonzero(m) — 非零元素坐标表(N×2 CV_32S)
  • norm(m[,normType[,mask]]) / normalize(m[,alpha,beta,normType]) — 范数 / 归一化
  • psnr(a,b) — 峰值信噪比;calchist / comparehist — 直方图统计与比对
  • kmeans(data,K,...) — K 均值聚类;reduce / reduceargmax / reduceargmin — 按行/列压缩与最值位置
  • integral(m) — 积分图;batchdistance(a,b[,dtype,normType,K]) — 点集距离矩阵(注意硬断言:K=0 必须 noArray,CV_8U 只能配 CV_32S)
  • checkrange(m[,min,max]) — 值域检查(返回 bool + 首个越界位置)

滤波与增强 已支持 android支持

  • blur / gaussianblur / medianblur / bilateralfilter / boxfilter — 常规滤波
  • filter2d / sepfilter2d(m,kernel,...) — 自定义(可分离)卷积
  • sobel / scharr / laplacian / spatialgradient — 梯度与边缘算子
  • sharpen(m[,strength]) — USM 锐化;clahe(m[,clipLimit]) — 限对比度自适应直方图均衡
  • equalizehist(m) — 全局直方图均衡;lut(m,table) — 查表变换
  • denoise([h,hColor,templateWindowSize,searchWindowSize]) — 非局部均值去噪
  • detailenhance([sigma_s,sigma_r]) — 细节增强(只支持 8 位 3 通道)
  • inpaint(m,mask,radius,method) — 修复(去水印/遮挡)
  • colordeviation(m,"RRGGBB-RRGGBB") — 颜色偏差二值化(目标色-容差)
  • getgaussiankernel / createhanningwindow — 生成核 / 窗函数

形态学 已支持 android支持

  • erode / dilate(m,kernel[,iter]) — 腐蚀 / 膨胀
  • morphologyex(m,op,kernel[,iter]) — 开闭/梯度/顶帽/黑帽
  • getstructuringelement(shape,ksize) — 生成结构元

几何变换 已支持 android支持

  • resize(m,w,h[,interp]) — 缩放;rotate(m,code) / rot90(m,k) / flip(m,code) — 旋转 / 翻转
  • transpose(m) — 转置
  • warpaffine(m,M,dsize) / warpperspective(m,M,dsize) — 仿射 / 透视变换
  • getaffinetransform / invertaffinetransform / getperspectivetransform — 变换矩阵求解
  • perspectivetransform(pts, m[,ox,oy]) — 点集透视/仿射变换(pts 点集支持字段式/数组式(见上方「点集参数」),m 为 3x3 矩阵,配合 getperspectivetransform 用;返回点集 Mat)
  • clipline(w,h,p1,p2) — 线段裁剪到矩形内(p1/p2 可为 {x,y} 表或 Point 指针;返回 bool 与裁剪后坐标)
  • getrotationmatrix2d(center,angle,scale) — 旋转矩阵;remap(m,map1,map2) — 重映射
  • getrectsubpix / borderinterpolate / copymakeborder — 子像素取块 / 边界推算 / 加边
  • pyrdown / pyrup(m) — 金字塔降/升采样;tile(m,nx,ny) / repeat_(m,nx,ny) — 平铺复制

阈值 / 边缘 / 轮廓 / 特征 已支持 android支持

  • threshold(m,thresh,maxval,type) / adaptivethreshold(...) — 二值化
  • inrange(m,lower,upper) — 区间掩码;canny(m,t1,t2) — Canny 边缘
  • findcontours(m[,mode,method]) / drawcontours — 轮廓提取与绘制
  • contourarea / arclength / moments(m[,binaryImage]) — 面积 / 周长 / 矩
  • boundingrect / boxpoints / minarearect / minenclosingcircle — 外接框与最小包围
  • fitellipse / fitline / approxpolydp / convexhull / convexitydefects / iscontourconvex / pointpolygontest / matchshapes — 拟合与形状匹配(convexityDefects 需下标版凸包:convexhull(...,returnPoints=false))
  • connectedcomponentswithstats(m[,conn,ltype]) — 连通域(⚠️ 6 參重载第 6 参是 ltype=CV_32S,别传 CCL_DEFAULT)
  • goodfeaturestrack / cornersubpix — 角点;houghlines / houghlinesp / houghcircles — 霍夫直线/圆
  • distancetransform / watershed — 距离变换 / 分水岭

色彩与通道 已支持 android支持

  • cvtcolor(m,code) — 色彩空间转换;togray(m) — 转灰度;tobgr(m) — RGBA→BGR(存图前必做)
  • split(m) / merge(mats) — 通道拆分 / 合并
  • mixchannels / extractchannel / insertchannel — 通道混合 / 抽取 / 插入
  • applycolormap(m,code) — 伪彩色映射

绘图 已支持 android支持

  • circle(m,center,radius,color[,thickness]) — 圆;line / arrowedline — 直线 / 箭头线
  • rectangle(m,pt1,pt2,color[,thickness]) — 矩形;polylines / fillpoly — 折线 / 多边形填充
  • ellipse(m,center,axes,angle,...) — 椭圆;puttext(m,text,org,font,scale,color) — 文字

图像 IO 已支持 android支持

  • imread(path[,flags]) / imwrite(m,path) — 读 / 写图像文件
  • imencode(m,ext) / imdecode(buf,flags) — 内存编解码;imdecodeb64(b64) — base64 解码为 Mat
  • tobase64(m[,ext]) — Mat → base64(PNG/JPG);saveimage(m,path) — 保存

模板匹配 / 找图 已支持 android支持

  • matchtemplate(img,tmpl[,method]) — 模板匹配(结果为相似度图)
  • findimage(src,tmpl[,method,sim]) — 找图,返回 {x,y,w,h,sim} 或 nil(绝对坐标)
  • findimageall(src,tmpl[,method,sim,maxCount]) — 找全部命中(按相似度降序)
  • 默认 TM_CCOEFF_NORMED;纯色/无纹理模板必须显式传 "TM_SQDIFF_NORMED",否则必然找不到

完整示例(可直接跑):

-- ══ 模板匹配 / 找图 完整测试 ══
-- 1) 准备:截全屏当大图,区域帧直接当模板(也可 cv.imread 读本地图片文件)
local src  = cv.snapshot()
local tmpl = cv.snapshot(100, 200, 259, 439)     -- (l,t,r,b) 区域帧

-- 2) 找一个:默认 TM_CCOEFF_NORMED、sim≥0.8,返回 {x,y,w,h,sim}(绝对坐标)或 nil
local r = cv.findimage(src, tmpl)
if r then
    print(string.format("命中 (%d,%d) %dx%d sim=%.3f", r.x, r.y, r.w, r.h, r.sim))
    tap(math.floor(r.x + r.w/2), math.floor(r.y + r.h/2))   -- 点命中中心
else
    print("未命中(相似度未达 0.8)")
end

-- 3) 显式传方法与阈值
local r2 = cv.findimage(src, tmpl, "TM_CCOEFF_NORMED", 0.9)

-- 4) 找全部:sim≥0.7 最多 10 个,结果按相似度降序
local all = cv.findimageall(src, tmpl, "TM_CCOEFF_NORMED", 0.7, 10)
for i, m in ipairs(all) do
    print(string.format("第%d个 (%d,%d) %dx%d sim=%.3f", i, m.x, m.y, m.w, m.h, m.sim))
end

-- 5) 纯色/无纹理模板(纯色图标、色块)必须 TM_SQDIFF_NORMED,且 sim 阈值放低
local r3 = cv.findimage(src, tmpl, "TM_SQDIFF_NORMED", 0.1)
if r3 then print("SQDIFF 命中", r3.x, r3.y, string.format("%.3f", r3.sim)) end

-- 6) 只要相似度图自己分析:matchtemplate 出 CV_32F 单通道 Mat,配 newDouble/newPoint 指针取峰值
local res = cv.matchtemplate(src, tmpl, "TM_CCOEFF_NORMED")
local mnV, mxV = cv.newDouble(0), cv.newDouble(0)
local mnP, mxP = cv.newPoint(0, 0), cv.newPoint(0, 0)
cv.minmaxloc(res, mnV, mxV, mnP, mxP)
local pos = cv.getPoint(mxP)
print("最高相似度", cv.getDouble(mxV), "@", pos.x, pos.y)
cv.deletePtr(mnV); cv.deletePtr(mxV); cv.deletePtr(mnP); cv.deletePtr(mxP)

其他 已支持 android支持

  • randu / randn(m,low,high) — 均匀/正态随机填充;setrngseed(seed) — 随机种子
  • getnumthreads() / setnumthreads(n) — 计算线程数
  • hconcat / vconcat(mats) — 水平 / 垂直拼接

yolo 模块(YOLO11/v8 目标检测,ncnn)

yolo_init(param, bin, conf?, nms?, input_size?, names_txt?) 已支持 android支持

初始化 YOLO 检测器(ncnn 推理,4 线程 + fp16)。模型须用 yolo export format=ncnn 导出(输入名 in0、输出名 out0),如 yolo11n.ncnn.param + yolo11n.ncnn.bin。

  • param, bin {string} ncnn 模型两件套的绝对路径
  • conf {number} 置信度阈值,默认 0.25(低于该分数的框丢弃;嫌误检多就调高,如 0.5)
  • nms {number} NMS IoU 阈值,默认 0.45
  • input_size {int} 推理输入边长,默认 640(32 的倍数,范围 32~1280)
  • names_txt {string} 可选,类别名文件(每行一个,按序号对应);不传则 label 为 "cls<编号>"
  • 返回:bool;失败返回 false + 错误串(code=1 路径空 / 2 param 加载失败 / 3 bin 加载失败)
  • 中途可重复调用 yolo_init 换阈值(会重载模型,几百毫秒)
local M = "/data/local/tmp/com.luatouch.app/models/yolo/"
local ok = yolo_init(M .. "yolo11n.ncnn.param", M .. "yolo11n.ncnn.bin", 0.5)

yolo_detect_image(mat) 已支持 android支持

对一个 cv Mat(如 cv.snapshot() 的返回)做目标检测。

  • 返回:{width=, height=, count=, dets={...}}
  • 每个 det:{x=, y=, w=, h=, rate=, cls=, label=} — 坐标为 Mat 像素坐标,rate 为置信度,cls 为类别编号,label 为类别名(无 names_txt 时为 "cls<编号>")
  • 未初始化返回 nil + 提示
local m = cv.snapshot()
local r = yolo_detect_image(m)
for i = 1, r.count do
    local d = r.dets[i]
    print(string.format("[cls%d] rate=%.2f x=%d y=%d w=%d h=%d", d.cls, d.rate, d.x, d.y, d.w, d.h))
end

yolo_detect_file(path) 已支持 android支持

直接读图像文件做检测,返回表结构与 yolo_detect_image 一致。

  • path {string} 图像文件路径
  • 返回:同 yolo_detect_image;读图失败返回 nil + 提示

yolo_close() 已支持 android支持

释放检测器(模型内存)。脚本结束不自动释放,长期驻留脚本建议不用时 close。

  • 返回:无

tessocr 模块

ocr_init(dataDir, language) 已支持 android支持

初始化文字识别引擎,加载语言数据。

  • dataDir {string} 语言数据目录,如 /data/local/tmp/com.luatouch.app/models/tessdata
  • language {string} 识别语言,如 eng(英文)
  • 返回:bool 是否初始化成功
local ok = ocr_init("/data/local/tmp/com.luatouch.app/models/tessdata", "eng")

ocr_set_param(param, value) 已支持 android支持

设置识别参数(需先 ocr_init)。底层引擎为 Tesseract 5.5.0(静态库、仅 LSTM 识别引擎),参数名沿用 Tesseract 官方变量名。

  • param {string} 参数名,见下方参数表,如 tessedit_char_whitelist(字符白名单)
  • value {string} 参数值,必须用字符串传入:布尔写 "1" / "0"(也接受 true / false / T / F / Y / N),数值写 "7"、"0.7" 这类字符串
  • 返回:bool 参数名存在即返回 true;未 ocr_init 时返回 false, "OCR not initialized"

返回值只代表“参数名存在”,不等于一定生效:

  • 参数名写错、或该变量在当前 Tesseract 版本里不存在 → 返回 false
  • 表中标注「初始化前」的参数必须在 ocr_init 之前设定,而本接口要求先 ocr_init,所以这类参数会返回 true 但实际不生效
  • 重新执行 ocr_init(例如换语言)会重置全部参数,需要重新设置

可直接使用的参数

参数名类型默认说明
tessedit_char_whiteliststring空只识别白名单内的字符,固定字符集场景可明显提高准确率
tessedit_char_blackliststring空禁止输出指定字符(与白名单互斥使用)
page_seg_modeint6页面分割模式;本引擎的专用别名,等价于 tessedit_pageseg_mode
tessedit_pageseg_modeint6同上:0=方向/脚本检测,3=全自动,6=整块文本,7=单行,8=单词,10=单字符,11=稀疏文本
preserve_interword_spacesbool0保留词间多个空格,适合列表、对齐文本
user_defined_dpiint0指定输入图像 DPI,0 表示自动判断
textord_tabfind_find_tablesbool1表格检测;纯文字截图可设 0,略快
invert_thresholddouble0.7反色判定阈值(tessedit_do_invert 的替代参数)
tessedit_do_invertbool1尝试反色图像;Tesseract 已标记废弃,6.0 版将移除
tessedit_write_imagesbool0保存预处理后的图像,排查识别不准时使用

初始化前才能设定的参数(本接口设置不会生效)

参数名默认说明
load_system_dawg1加载系统词典(关闭后不再把字符纠正成词典词)
load_freq_dawg1加载高频词词典
load_punc_dawg1加载标点词典
tessedit_ocr_engine_mode3识别引擎选择;本构建仅含 LSTM 引擎

当前版本不存在的参数名(写了会返回 false)

  • tessedit_do_orientation:5.5.0 无此变量,方向检测由页面分割模式(page_seg_mode)控制
  • tessedit_do_blur_detection:5.5.0 无此变量
  • tessedit_use_opencl:Tesseract 5 已移除 OpenCL 支持
-- 只识别数字和字母
ocr_set_param("tessedit_char_whitelist", "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")

-- 单行文本 + 保留词间空格
ocr_set_param("page_seg_mode", "7")
ocr_set_param("preserve_interword_spaces", "1")

-- 纯文字截图关掉表格检测
ocr_set_param("textord_tabfind_find_tables", "0")

-- 用返回值判断参数名是否有效
print(ocr_set_param("tessedit_do_orientation", "0"))   -- false:本版本没有这个参数

ocr_from_file(path) 已支持 android支持

识别指定图片文件中的文字。

  • path {string} 图片路径
  • 返回:string 识别出的文字;失败返回 nil, errMsg
local text = ocr_from_file("/data/local/tmp/com.luatouch.app/screen.png")

ocr_from_image(mat) 已支持 android支持

识别 cv Mat 图像中的文字(Mat 来自 cv.snapshot / cv.imread 等)。

  • mat {cv.Mat} 待识别图像(必填)
  • 返回:string 识别出的文字;失败返回 nil, errMsg
local img = cv.snapshot(0, 0, 374, 811)   -- 截取屏幕区域为 Mat
local text, err = ocr_from_image(img)
if text then print("识别:", text) end
img:release()   -- 可选:GC 也会自动回收,高频循环建议手动释放

ocr_from_pixels(data, w, h, bpp) 已支持 android支持

识别原始像素数据中的文字。

  • data {string} 二进制像素数据(raw 字节串)
  • w, h {int} 图像宽高
  • bpp {int} 每像素字节数
  • 返回:string 识别出的文字;失败返回 nil, errMsg
local text = ocr_from_pixels(rawdata, 720, 1280, 4)

ocr_set_rectangle(left, top, w, h) 已支持 android支持

限定识别区域(相对当前图像/像素数据的坐标),只识别该区域内的文字。

  • left, top {int} 区域左上角
  • w, h {int} 区域宽高
  • 返回:bool 设置成功;失败返回 false, errMsg
ocr_set_rectangle(100, 200, 200, 100)

ocr_clear() 已支持 android支持

清除识别状态(区域限制、临时数据等)。

  • 参数:无
  • 返回:无
ocr_clear()

ocr_close() 已支持 android支持

释放识别引擎资源。

  • 参数:无
  • 返回:无
ocr_close()

ocr 模块(点阵字库识别/找字)

点阵字库 OCR(移植自 OP 插件,大漠同语义):用字库文件里每个字的 0/1 点阵,与屏幕按颜色二值化后的点阵逐位比对。与 tessocr / ppocr 的 AI 识别不同—— 只认识字库里有的字,但速度极快(毫秒级)、结果精确可控,适合游戏内固定字体的文字 (金币数量、按钮文字、菜单项、伤害数字等)。

字库文件:用「AutoGo图色助手」的字库制作导出(OP 文本格式,每行 名字$颜色$h,w,bit$HEX),放 <数据目录>/res/ 下(与 findPic 模板同基准)。 GBK / UTF-8 编码都认(GBK 自动转 UTF-8,脚本里可直接用中文比对)。

⚠️ 字库必须与目标画面同源同尺寸:字库是在哪张截图上取的,识别就得用同一分辨率、 同一字体渲染的画面(换分辨率 / 换设备 / 换窗口大小 = 字的像素尺寸变了 → 必须重取字库, 否则简单字勉强能中、笔画复杂的字必挂)。

匹配规则:sim 0.1~1.0,默认 1.0(精确:一个像素都不许错); sim<1 时按 有效相似度 = 0.5 + sim/2 放宽容差(如 sim=0.8 → 允许 10% 像素差异)。 建议优先用 1.0,识别不到再降(越低假阳性越多)。 区域必须完整包住文字:返回坐标是字形的左上角,区域边界把字窗口切掉一部分的 字会被直接跳过(下边界多留一个字高)。

ocrSetDict(idx, path) 已支持 android支持

载入字库文件到 idx 号槽位(0~99)。重复载入同槽 = 整槽覆盖。

  • idx {number} 槽位号 0~99
  • path {string} 字库文件路径;相对路径以 <数据目录>/res/ 为基准
  • 返回:number 载入的字数;失败返回 -1
  • 字库槽全局共用:主脚本与所有子线程看到的是同一份
local n = ocrSetDict(0, "opdict.txt")     -- 实际读 <数据目录>/res/opdict.txt
print("载入 " .. n .. " 个字")

ocrUseDict(idx) 已支持 android支持

切换当前使用的字库槽位(后续 ocr/findStr 都用它)。

  • idx {number} 槽位号 0~99
  • 返回:number 该槽字数;槽空返回 0
ocrSetDict(0, "dict_main.txt")   -- 主字库(菜单/按钮)
ocrSetDict(1, "dict_num.txt")    -- 数字字库(伤害/金币)
ocrUseDict(1)                    -- 切到数字字库做识别

ocrGetNowDict() 已支持 android支持

返回当前使用的槽位号(number)。

ocrGetDictCount(idx) 已支持 android支持

返回 idx 号槽的字数;该槽未载入返回 -1。

ocr(x1, y1, x2, y2, color?, sim?) 已支持 android支持

识别区域内所有字库字,按阅读顺序(|Δy|<9 视为同一行,行内按 x)拼接成字符串返回。

  • x1, y1, x2, y2 {number} 识别区域;x2/y2 ≤ 0 表示取到帧右下角
  • color {string} 可选,颜色串(同 findColor 格式):"RRGGBB[-偏色]", '|' 分隔多组;默认 "FFFFFF-323232"。必须与做字库时用的颜色口径一致
  • sim {number} 可选,相似度 0.1~1.0,默认 1.0
  • 返回:string 拼接后的识别文本(无命中返回空串)
ocrSetDict(0, "opdict.txt")
local s = ocr(200, 310, 480, 360, "FFFFFF-323232", 1.0)
print(s)          -- 例:雷电游戏中心

ocrEx(x1, y1, x2, y2, color?, sim?) 已支持 android支持

同 ocr,但返回逐字结果(含每个字的坐标)。

  • 参数同 ocr
  • 返回:table {{index=结果序号, name=字符, x=, y=}, ...}, index 从 0 起(阅读序),x/y = 字形左上角(屏幕绝对坐标)
local hits = ocrEx(0, 0, 0, 0, "FFFFFF-323232", 1.0)
for i, h in ipairs(hits) do
    print(h.index, h.name, h.x, h.y)
end

findStr(x1, y1, x2, y2, strs, color?, sim?) 已支持 android支持

在区域内找字库里指定的词,返回第一个命中的词。

  • strs {string} 目标词,'|' 分隔多词,如 "确定|取消"; 词名必须与字库里的一致
  • 返回:3 个值 —— idx 命中的词序号(0 = 第一个词,无命中 -1)、 x / y 该词首个命中字形的左上角(无命中 -1,-1)
local idx, x, y = findStr(0, 0, 0, 0, "确定|取消", "FFFFFF-323232", 1.0)
if idx == 0 then
    print("找到 确定 @ " .. x .. "," .. y)      -- 点它: tap(x + 10, y + 10)
elseif idx == 1 then
    print("找到 取消 @ " .. x .. "," .. y)
end

findStrEx(x1, y1, x2, y2, strs, color?, sim?) 已支持 android支持

同 findStr,但返回全部命中。

  • 参数同 findStr
  • 返回:table {{index=词序号, name=词名, x=, y=}, ...}(无命中空表)
local all = findStrEx(0, 0, 0, 0, "雷|闪电|中心", "FFFFFF-323232", 1.0)
for i, h in ipairs(all) do
    print("词" .. h.index .. " [" .. h.name .. "] @ " .. h.x .. "," .. h.y)
end

ppocr 模块

ppocr_create() 已支持 android支持

创建文字识别器实例。

  • 参数:无
  • 返回:bool 创建成功;失败返回 false, errMsg
local ok = ppocr_create()

ppocr_init(det.param, det.bin, rec.param?, rec.bin?, cls.param?, cls.bin?) 已支持 android支持

加载识别模型(检测模型必填,识别/分类模型可选)。

  • det.param, det.bin {string} 文本检测模型文件路径
  • rec.param, rec.bin {string} 可选,文字识别模型文件路径
  • cls.param, cls.bin {string} 可选,方向分类模型文件路径
  • 返回:bool 加载成功;失败返回 false, errMsg
local M = "/data/local/tmp/com.luatouch.app/models/ch/"
local ok = ppocr_init(
    M .. "PP_OCRv5_mobile_det.ncnn.param", M .. "PP_OCRv5_mobile_det.ncnn.bin",
    M .. "PP_OCRv5_mobile_rec.ncnn.param", M .. "PP_OCRv5_mobile_rec.ncnn.bin")

ppocr_set_param(name, value) 已支持 android支持

设置识别参数。底层引擎为自研 PP-OCRv5(ncnn 推理),只支持下表列出的 8 个参数名,不沿用 PaddleOCR 官方配置文件里的字段名。

  • name {string} 参数名,见下方参数表
  • value {string} 参数值,必须用字符串传入:数值写 "0.45"、"960",布尔用 "1" / "0"
  • 返回:bool 仅在未先调用 ppocr_create 时返回 false, "PPOcr not created";其余情况一律返回 true

返回值不能用来判断参数是否生效(与 ocr_set_param 不同):

  • 参数名不在下表内(拼错、或用了 PaddleOCR 的字段名如 det_db_thresh、rec_img_h、num_threads)→ 静默忽略,仍然返回 true
  • 本接口可重复调用、后设覆盖先设;参数在 ppocr_create 之后即可设置,不必等 ppocr_init,且 ppocr_init 不会重置已设参数
  • 执行 ppocr_release 后再 ppocr_create 会得到全新实例,全部参数恢复默认值
  • 线程数不可调:检测固定用 ncnn 大核数、识别固定单线程

可用参数表

参数名类型默认说明
target_sizeint640检测阶段输入图最长边的缩放上限(超过则等比缩小后再送模型)。调大:小字更清晰但变慢;调小:更快,小字可能漏检
box_threshfloat0.6候选文本框的平均得分阈值(0~1),低于该值的框被丢弃。调低:框更多(含噪声);调高:框更少更干净
thresholdfloat0.3检测概率图的二值化阈值。调低:文字区域更连片(易粘连);调高:更严格(易断裂)
min_size_basefloat3.0最小框尺寸基准,实际最小边 ≈ min_size_base × 缩放比,用于过滤极小噪点框。调大:滤掉小字
max_candidatesint1000单张图最多处理的候选轮廓数,超出直接截断。密集文本可调大
enlarge_ratiofloat1.95文本框向外扩张比例,保证文字边缘被完整裁入。过大易把相邻文字并进同一行
post_process_modeint0后处理方式:0=按比例扩张矩形(快);1=DBNet unclip(按轮廓面积/周长扩张,更贴合文字形状,稍慢)
target_heightint48识别阶段文字行统一缩放到的高度。调大:小字/笔画复杂字符更准但更慢;调小:更快
ppocr_create()
ppocr_init(M .. "PP_OCRv5_mobile_det.ncnn.param", M .. "PP_OCRv5_mobile_det.ncnn.bin",
           M .. "PP_OCRv5_mobile_rec.ncnn.param", M .. "PP_OCRv5_mobile_rec.ncnn.bin")

-- 小字场景:加大检测分辨率、放宽候选框阈值
ppocr_set_param("target_size", "960")
ppocr_set_param("box_thresh", "0.4")

-- 密集文本:提高候选上限
ppocr_set_param("max_candidates", "3000")

-- 更贴合文字轮廓的后处理(略慢)
ppocr_set_param("post_process_mode", "1")
ppocr_set_param("enlarge_ratio", "1.8")

ppocr_detect_image(mat) 已支持 android支持

识别 cv Mat 图像中的文字(Mat 来自 cv.snapshot / cv.imread 等),返回逐行文字及位置。

  • mat {cv.Mat} 待识别图像(必填)
  • 返回:table 结果表 {width, height, lines={{text=, rate=, left=, top=, right=, bottom=}, ...}};失败返回 nil, errMsg
  • width, height 识别图像尺寸;lines 每行文字,text 文字内容,rate 置信度 0~1,left/top/right/bottom 位置坐标(0~1 归一化,乘图像宽高得像素)
local img = cv.snapshot(0, 0, 374, 811)   -- 截取屏幕区域为 Mat
local res = ppocr_detect_image(img)
if res then
    for i, line in ipairs(res.lines) do
        print(i, line.text, string.format("%.2f", line.rate))
    end
end
img:release()   -- 可选:GC 也会自动回收,高频循环建议手动释放

ppocr_detect_file(path) 已支持 android支持

识别指定图片文件中的文字,返回格式同 ppocr_detect_image。

  • path {string} 图片路径
  • 返回:table 结果表;失败返回 nil, errMsg
local res = ppocr_detect_file("/data/local/tmp/com.luatouch.app/screen.png")

ppocr_release() 已支持 android支持

释放识别器资源。

  • 参数:无
  • 返回:bool 是否成功释放
ppocr_release()

hud 模块(悬浮显示)

showUi(path [, countdown [, query [, hash [, w [, h]]]]]) 已支持 android支持

显示 HTML 面板并阻塞等待用户操作。面板跟随屏幕横竖方向(横屏下面板旋转显示,宽高按所见方向自动换算);默认尺寸为屏幕宽高的 90% 居中。返回两个值:操作结果 + JS 带回的表单数据。

  • path {string} 加载目标:绝对路径(/data/local/tmp/...)、file:// 绝对路径(可自带 ?query)、http(s):// 远程 URL、或裸 HTML 字符串
  • countdown {int} 可选,默认 0:开始按钮倒计时秒数;>0 时按钮显示「开始(N)」每秒减一,归零自动触发「开始」
  • query {string} 可选,默认 0 / -1 / 空 = 不传:拼接在 URL ? 后,引擎自动 percent-encode(main.lua 直接传裸 JSON 即可)
  • hash {string} 可选,默认 0 / -1 / 空 = 不传:拼接在 URL # 后,引擎自动 percent-encode(query 的兜底通道)
  • w {number} 可选,默认 0:面板宽(每维独立)——≤0 或不传 = 屏幕宽 × 90%;0~1 = 屏幕宽的比例(如 0.5 = 半屏宽);>1 = 像素值(与 getScreenSize() 同一坐标系)
  • h {number} 可选,默认 0:面板高,规则同 w(按屏幕高计算)
  • 返回:result {int} 1=点「开始」/倒计时归零,0=点「关闭」,-1=叉号/其他方式关闭(含 hideUi 唤醒);data {string|nil} 面板 JS 在开始/关闭时带回的表单 JSON 字符串,无则 nil
-- 打开面板,把上次配置 JSON 作为 query 传入(裸 JSON,引擎 percent-encode 注入 ? 后)
local r, data = showUi("/data/local/tmp/com.luatouch.app/config/ui/index.html", 0, cfgJson)
if r == 1 then
    -- 用户点了「开始」,data 为表单 JSON,可直接落盘下次复用
elseif r == -1 then
    -- 用户关闭了面板
end

参数传递机制:引擎把第三参 percent-encode 后拼到 URL ? 后、第四参拼到 # 后。JS 端读取:location.search 优先 → location.hash 兜底 → 去 ?/# 前缀 → decodeURIComponent → JSON.parse(search 为第一通道,hash 仅在 search 为空时兜底)。

hideUi() 已支持 android支持

隐藏 HTML 面板;若有 showUi 正在阻塞,则唤醒并使其按「叉号关闭」返回 -1(无 data)。

  • 返回:无
hideUi()   -- 关闭面板(定时器等场景主动收起)

isShowUi() 已支持 android支持

检查 HTML 面板是否正在显示。

  • 返回:bool true 显示中 / false 未显示
if isShowUi() then
    -- 面板还开着,先别重复打开
end

toast(message [, x [, y [, duration]]]) 已支持 android支持

显示 Toast 提示信息(非阻塞,自动消失)。

  • message {string} 要显示的提示信息
  • x {int} 可选,默认 -1:显示 X 坐标(-1 = 水平居中)
  • y {int} 可选,默认 -1:显示 Y 坐标(-1 = 垂直居中)
  • duration {int} 可选,默认 -1:显示时长毫秒(-1 = 2000ms)
  • 返回:无
toast("Hello LuaTouch", -1, -1, -1)   -- 默认居中 2 秒
toast("操作完成", 100, 300, 3000)      -- 指定位置 3 秒

alert(title, content [, btn1Text [, btn2Text]]) 已支持 android支持

弹出系统级对话框,阻塞直到用户点击按钮。

  • title {string} 弹窗标题
  • content {string} 弹窗内容
  • btn1Text {string} 可选,默认「确定」:第一个按钮文字
  • btn2Text {string} 可选,默认空:第二个按钮文字;传空字符串则只显示一个按钮
  • 返回:int 0 = 点击第一个按钮,1 = 点击第二个按钮
local r = alert("确认操作", "是否继续?", "取消", "确定")
if r == 1 then
    -- 用户点了确定
end

inputAlert(title, content [, placeholder [, defaultText [, btn1Text [, btn2Text]]]]) API 存在

弹出带输入框的系统级对话框,阻塞等待用户操作。

  • title {string} 弹窗标题
  • content {string} 说明文字
  • placeholder {string} 可选,默认空:输入框占位提示
  • defaultText {string} 可选,默认空:输入框默认文本
  • btn1Text {string} 可选,默认「取消」:取消类按钮文字
  • btn2Text {string} 可选,默认「确定」:确认类按钮文字;为空则只显示一个按钮
  • 返回:text {string} 输入内容;ok {bool} true = 点击确认按钮,false = 点击取消
local text, ok = inputAlert("输入", "请输入备注", "备注", "", "取消", "确定")
if ok then
    -- 使用 text
end

setBallPosition(fx, fy) 已支持 android支持

移动悬浮球并保持停靠(横竖屏自动适配)。

  • fx {number} 停靠边:0=左,1=右
  • fy {number} 边缘高度百分比(0~1,支持小数点后两位)
  • 返回:无
setBallPosition(0, 0.1)   -- 靠左边缘 10% 高
setBallPosition(1, 0.5)   -- 靠右边缘中间

hud.new() 已支持 android支持

创建一个新的 HUD 实例。

  • 参数:无
  • 返回:userdata HUD 实例(方法均返回自身,支持链式调用)
local h = hud.new()

h:setPosition(fx, fy, width, height) 已支持 android支持

设置 HUD 的位置和大小(旋转自动适配)。

  • fx, fy {number} 左上角百分比(0~1,支持小数点后两位)
  • width, height {int} 宽高(屏幕点,整数)
  • 返回:userdata 自身(可链式)
h:setPosition(0.1, 0.8, 300, 60)   -- 左上角 10%、80% 处,宽 300 高 60

h:setBackgroundColor(color) 已支持 android支持

设置 HUD 背景颜色(支持透明度)。

  • color {string} 十六进制,#RRGGBB 或 #RRGGBBAA(AA 为透明度)
  • 返回:userdata 自身
h:setBackgroundColor("#2D2D30")
h:setBackgroundColor("#00000080")  -- 半透明黑色

h:setTextSize(size) 已支持 android支持

设置 HUD 字体大小。

  • size {int} 字体大小(推荐 30~60)
  • 返回:userdata 自身
h:setTextSize(45)

h:setText(items) 已支持 android支持

设置 HUD 文本内容(支持多色文本)。

hud.new() 出来的实例默认是隐藏的:只调 setPosition / setTextSize / setText 不会显示,必须调一次 h:show()。之后循环里不断 setText 刷新内容即可,不用重复 show;调过 h:hide() 之后要重新 show() 才会再出现。

  • items {table} 文本项数组,每项含 TextColor(颜色字符串)与 Text(文本)
  • 返回:userdata 自身
h:setText({
    {TextColor = "#00FF00", Text = "HP: "},
    {TextColor = "#FFFFFF", Text = "100/100"},
})

h:show() 已支持 android支持

显示 HUD。

  • 返回:userdata 自身
h:show()

h:hide() 已支持 android支持

隐藏 HUD。

  • 返回:userdata 自身
h:hide()

h:isVisible() 已支持 android支持

检查 HUD 是否可见。

  • 返回:bool true 可见 / false 隐藏
if h:isVisible() then
    -- HUD 当前可见
end

h:destroy() 已支持 android支持

销毁 HUD 实例,释放窗口资源(也可等 Lua GC 自动回收)。

  • 返回:无
h:destroy()

示例 已支持 android支持

-- 创建并配置 HUD
local h = hud.new()
h:setPosition(0.1, 0.8, 300, 60)   -- 屏幕下方,宽 300 高 60
 :setBackgroundColor("#3D000080")
 :setTextSize(45)
 :show()                             -- ← 必须调,否则不会显示

while true do
    h:setText({
        {TextColor = "#00FF00", Text = "当前时间: "},
        {TextColor = "#FFFFFF", Text = os.date("%Y-%m-%d %H:%M:%S")},
    })
    sleep(1000)
end

draw 模块(屏幕绘制)

drawLine(x0, y0, x1, y1, argb, thickness) 已支持 android支持

绘制一条直线(任意角度斜线均可,两端圆头)。

  • x0, y0 {int} 起始点坐标
  • x1, y1 {int} 终点坐标
  • argb {int} 颜色,如 0xffff0000(红色)
  • thickness {int} 线宽(物理像素,自动换算)
  • 返回:{int} 图形句柄(用于 clearDraw(句柄) 清除)
local id = drawLine(100, 100, 1100, 2000, 0xffff0000, 20)  -- 斜线
-- clearDraw(id) 清除这条线

drawRect(x0, y0, x1, y1, argb, thickness) 已支持 android支持

绘制矩形框;thickness = -1 填充。

  • x0, y0 {int} 左上角坐标
  • x1, y1 {int} 右下角坐标
  • argb {int} 颜色
  • thickness {int} 线宽,-1 填充
  • 返回:{int} 句柄
local id = drawRect(300, 400, 900, 900, 0xff00ff00, 10)  -- 绿框

fillRect(x0, y0, x1, y1, argb) 已支持 android支持

填充一个矩形区域。

  • x0, y0 {int} 左上角坐标
  • x1, y1 {int} 右下角坐标
  • argb {int} 颜色(可用 0x80 前缀做半透明)
  • 返回:{int} 句柄
local id = fillRect(700, 300, 1000, 600, 0x80ff0000)  -- 半透明红填充

drawCircle(x, y, radius, argb, thickness) 已支持 android支持

绘制圆形;thickness = -1 填充。

  • x, y {int} 圆心坐标
  • radius {int} 半径
  • argb {int} 颜色
  • thickness {int} 线宽,-1 填充
  • 返回:{int} 句柄
local id = drawCircle(621, 1104, 200, 0xff0000ff, -1)  -- 屏幕中心蓝色填充圆

drawPolygon(points, argb, thickness, isclosed) 已支持 android支持

绘制多边形;thickness = -1 填充。

  • points {table} 顶点数组 {{x1,y1},{x2,y2},...}
  • argb {int} 颜色
  • thickness {int} 线宽,-1 填充
  • isclosed {boolean} 是否闭合
  • 返回:{int} 句柄
local id = drawPolygon({{200,1600},{500,1500},{450,1850}}, 0xff00ff00, 8, true)

clearDraw(id?) 已支持 android支持

清除屏幕绘制图形。

  • id {int|nil} 可选:传句柄只清除对应图形;不传清除全部
  • 返回:无
clearDraw(id1)   -- 只清句柄 id1 对应的图形
clearDraw()      -- 全部清除

示例 已支持 android支持

-- 标注:找到按钮画框、点击位置画圈(坐标=物理像素,按自己屏幕分辨率换算)
local box = drawRect(300, 400, 900, 900, 0xffff0000, 10)   -- 红框标注
local dot = drawCircle(621, 1104, 60, 0xff00ff00, -1)      -- 绿点标注
sleep(1000)
clearDraw(box)      -- 单独清除红框,绿点保留
sleep(1000)
clearDraw()         -- 全部清除

imgui 模块(即时模式 GUI,100 个函数)

即时模式的悬浮面板,用来给脚本做交互控制台:按钮、滑块、输入框、下拉、页签、菜单、弹窗、图表。面板独立悬浮在最上层,不影响被控应用;系统截图/录屏时可按需隐藏(见 SetSecure)。

1. 即时模式:没有控件对象,返回值就是事件 已支持 android支持

每帧把界面从头描述一遍,控件不保存在任何变量里。你需要的状态(开关、数值、文本)自己用 Lua 变量存,每帧回填旧值、再把返回值写回变量。

-- 固定帧循环(复制这段就能跑)
imgui.Init()                                 -- ① 建悬浮层(异步,用 Ready() 探测)
while not imgui.Ready() do sleep(50) end     -- ② 等图层就绪(一般 <1s)

while imgui.Running() do
  if imgui.NewFrame() then                   -- ③ 帧开始(吸收触摸输入)
    imgui.SetNextWindowSize(600, 400, imgui.Cond.FirstUseEver)
    local visible = imgui.Begin("我的面板")
    if visible then
      imgui.Text("Hello")
    end
    imgui.End()                              -- ⚠️ 必须在 if 外面
    imgui.Render()                           -- ④ 帧结束,渲染上屏
  end
  sleep(16)                                  -- ≈60fps
end
imgui.Shutdown()                             -- ⑤ 收图层

⚠️ Begin() 返回 false 只表示「窗口被折叠」,里面的控件不画,但 End() 照样要调用——漏掉会每帧报 Missing End() 并在日志里刷屏。

⚠️ 控件的 label 是 ImGui 的隐藏 ID:不要写成 "次数: " .. n 这种每帧变化的名字,否则控件每帧都是「新控件」,点击会丢。要显示动态文字就 SameLine() 后跟一个 Text()。

2. 生命周期 已支持 android支持

函数说明
Init()建悬浮图层,返回 true。每次调用都是真重建:内部先摘掉旧图层再建新的,上次被强杀留下的残留状态自动清掉。返回 true 只代表请求已发出,不代表图层能用,接着必须轮询 Ready()
Ready()面板是不是真的能用(能否上屏)。Init() 只是发起创建,是异步的,所以 Init 之后必须先 while not imgui.Ready() do sleep(50) end 再进帧循环;Init() 与 Shutdown() 都会让 Ready() 立刻变回 false,直到面板重新建好
Running()恒返回 true,配合 while 用(语义占位)
NewFrame()帧开始,吸收触摸;返回 false 时本帧跳过(图层未就绪/无焦点)
Render()帧结束,渲染 + 上屏;必须与 NewFrame() 成对
Shutdown()收图层(脚本退出前调;不调也会在脚本停止时被引擎强制收掉)

3. 窗口 已支持 android支持

核心两个:

  • imgui.Begin(name [, open [, flags]]) → 打开窗口,返回 是否可见;第二参传 boolean 时再返回 是否还开着(点了 X 变 false)
  • imgui.End() → 关闭窗口,无条件调用
-- 三种写法
local v1 = imgui.Begin("无关闭按钮")               -- 1 个返回值
local v2, open = imgui.Begin("带 X", true)         -- 2 个返回值
local v3 = imgui.Begin("禁止拖动", imgui.Win.NoMove)  -- 第二参数字=窗口标志
imgui.End()
函数说明
SetNextWindowPos(x, y [, cond])下一个窗口位置;cond 默认 imgui.Cond.FirstUseEver(只在首次生效,之后记住用户拖到哪)
SetNextWindowSize(w, h [, cond])下一个窗口尺寸,cond 同上;传 imgui.Cond.Always 则每帧强制、用户拖不动
SetNextWindowBgAlpha(a)下一个窗口背景透明度 0~1
SetNextWindowFocus()下一个窗口置顶
SetNextWindowScroll(x, y)下一个窗口的滚动位置;回顶用 (0, 0),要在 Begin 之前调
GetWindowPos()返回 x, y
GetWindowSize()返回 w, h
GetScrollY() / SetScrollY(y)读 / 设当前滚动量
SetScrollHereY([ratio])把当前项滚到视口内,ratio 默认 0.5(居中)
SetWindowFontScale(s)本窗口字号倍率(1.0 = 默认)

窗口标志用 imgui.Win.*,常用:NoMove(禁止拖动)、NoResize(禁止拉伸)、NoCollapse(禁止折叠)、NoTitleBar、AlwaysAutoResize、NoScrollbar。多个标志用「加」组合:imgui.Win.NoMove + imgui.Win.NoResize。

4. 文本 已支持 android支持

函数说明
Text(s)普通文本(不做 % 格式化,内容原样显示)
TextDisabled(s)灰色弱化文本,适合放提示/状态
TextWrapped(s)超宽自动换行(长日志用这个)
TextColored(r, g, b [, a], s)彩色文本,颜色 0~1;如 TextColored(1,0,0,"错误")
LabelText(label, s)左标签 + 右值
Bullet() / BulletText(s)圆点 / 带圆点的文本

5. 布局 已支持 android支持

函数说明
Separator()水平分隔线
SameLine([offset] [, spacing])下一个控件摆在同一行(默认接着右侧)
NewLine() / Spacing()换行 / 空一行
Dummy(w, h)占位空白
Indent([w]) / Unindent([w])缩进 / 反缩进
BeginGroup() / EndGroup()逻辑分组:组内多个控件的包围盒合成一个整体参与布局
BeginChild(id [, w, h [, flags]]) / EndChild()子区域,可独立滚动,返回是否可见

6. 控件 已支持 android支持

函数说明
Button(label [, w, h])按钮,返回「本帧是否被点击」;w/h 传 0 表示按标签自适应
SmallButton(label)小号按钮(无边框内边距)
ArrowButton(id, dir)箭头按钮,dir 用 imgui.Dir.Left/Right/Up/Down
Checkbox(label, v)勾选框,传入旧值、返回新值(不会原地改你的变量)
RadioButton(label, selected)单选框,返回是否被点击;组内互斥要自己写 if 点了 then idx = n end
ProgressBar(frac [, text])进度条,frac 0~1;第二参是覆盖显示的字符串
if imgui.Button("开始", 120, 60) then run() end
flag = imgui.Checkbox("启用", flag)
imgui.ProgressBar(done / total, string.format("%d/%d", done, total))

7. 数值 / 输入 已支持 android支持

函数说明
SliderFloat(label, v, min, max)浮点滑块,返回拖动后的实时值
SliderInt(label, v, min, max)整数滑块
DragFloat(label, v [, speed, min, max])拖动调值(无轨道),speed 默认 1
DragInt(label, v [, speed])整数拖动
InputFloat(label, v) / InputInt(label, v)数值框;点击自动弹引擎软键盘,编辑中按输入原样显示(不截小数)
InputText(label, s [, cap])文本输入,返回当前文本;cap 是缓冲区长度,默认 256
Combo(label, index, {items})下拉框,下标从 1 开始,返回新下标
ListBox(label, index, {items})列表框,下标同样 1 起
ColorEdit3(label, r, g, b) / ColorEdit4(label, r, g, b, a)取色器,返回新分量(0~1)
speed = imgui.SliderFloat("速度", speed, 0.1, 5.0)
name  = imgui.InputText("名称", name)
mode  = imgui.Combo("模式", mode, {"快速", "标准", "精细"})   -- mode 从 1 开始
r, g, b = imgui.ColorEdit3("颜色", r, g, b)

8. 树 / 页签 / 菜单 / 弹窗 已支持 android支持

函数说明
TreeNode(label)树节点,返回是否展开;展开时必须调 TreePop()
TreePop()结束树节点
SetNextItemOpen(open [, cond])下一个树节点默认展开/收起
CollapsingHeader(label [, flags])可折叠标题栏,返回是否展开(展开状态由 imgui 自动记忆,不用你存)
Selectable(label [, selected [, flags]])可选行,返回是否被点击
BeginTabBar(id [, flags]) / EndTabBar()页签容器,返回是否可见
BeginTabItem(label [, open]) / EndTabItem()单个页签,返回是否当前选中;传 open 时再返回 是否还开着
BeginMenuBar() / EndMenuBar()窗口内菜单栏(要在 Begin 之后)
BeginMainMenuBar() / EndMainMenuBar()屏幕顶部主菜单栏(在窗口之外调用)
BeginMenu(label [, enabled]) / EndMenu()一级菜单,返回是否展开
MenuItem(label [, shortcut [, selected]])菜单项,返回是否被点击;selected 显示为勾选态
OpenPopup(id [, flags])打开弹窗(配合按钮点击调用)
BeginPopup(id [, flags]) / EndPopup()普通弹窗
BeginPopupModal(name [, open]) / EndPopup()模态框,传 open 时返回 可见, 还开着
CloseCurrentPopup()关闭当前弹窗(在弹窗内部调用)
BeginTooltip() / EndTooltip()自定义 Tooltip 内容
SetTooltip(s)简易 Tooltip(一行文本)
-- 页签
if imgui.BeginTabBar("tabs") then
  if imgui.BeginTabItem("基本") then
    imgui.Text("第一页")
    imgui.EndTabItem()
  end
  if imgui.BeginTabItem("高级") then
    imgui.Text("第二页")
    imgui.EndTabItem()
  end
  imgui.EndTabBar()
end

-- 弹窗:按钮打开 → 模态框里点确定关闭
if imgui.Button("打开设置") then imgui.OpenPopup("设置") end
if imgui.BeginPopupModal("设置") then
  imgui.Text("这里是弹窗内容")
  if imgui.Button("确定") then imgui.CloseCurrentPopup() end
  imgui.EndPopup()
end

9. 查询 已支持 android支持

函数说明
IsItemHovered([flags])上一个控件是否被悬停(手指在上面)
IsItemActive()上一个控件是否正被按住/拖动
IsItemClicked([btn])上一个控件本帧是否被点击
IsItemVisible() / IsItemEdited()上一个控件是否可见 / 本帧是否被编辑
IsMouseDown(btn) / IsMouseClicked(btn) / IsMouseReleased(btn)全局鼠标(触摸)状态,btn 用 imgui.MouseButton.Left 等
GetMousePos()返回 x, y(面板坐标系)
GetDisplaySize()返回画布 w, h(横竖屏旋转时自动对调,用来重排窗口)
SetItemDefaultFocus()弹窗里默认聚焦某个控件
PushID(id) / PopID()区分作用域:循环里生成同名控件时靠它避免 ID 冲突

10. 键盘注入(脚本软键盘) 已支持 android支持

给「脚本自己画键盘」准备的:把字符/按键送进当前聚焦的输入框。

  • imgui.SendChars(s) {string} 插入文本到当前聚焦的 InputText
  • imgui.SendKey(name) {string} 发一个按键;可选值:backspace delete enter escape tab left right up down home end space pageup pagedown insert;未知键名会直接报错
imgui.SendChars("abc")
imgui.SendKey("backspace")

11. 纹理 / 绘图 已支持 android支持

函数说明
CreateTexture(w, h [, mode])生成测试纹理,返回纹理句柄。mode:0=棋盘格(默认,用来看 UV/拉伸是否正常)1=渐变 2=四色块;w/h ≤ 2048
DeleteTexture(tex)释放纹理
Image(tex, w, h [, u0, v0, u1, v1 [, tr, tg, tb, ta]])在面板里画纹理,可指定 UV 范围和着色
PlotLines(label, {values} [, w, h])折线图,values 是数值数组
PlotHistogram(label, {values} [, w, h])柱状图
local tex = imgui.CreateTexture(256, 256, 0)   -- 棋盘格
imgui.Image(tex, 200, 200)
imgui.PlotLines("负载", {3, 7, 2, 9, 5, 6})

12. 样式 / 截图开关 已支持 android支持

函数说明
PushStyleColor(idx, "#RRGGBB" / "#RRGGBBAA")压入颜色覆盖,idx 用 imgui.Col.*(如 imgui.Col.Button)
PushStyleColor(idx, r, g, b [, a])同上,用 0~1 分量
PopStyleColor([n])弹出 n 层(默认 1)
PushStyleVar(idx, v) / PushStyleVar(idx, x, y)压入样式变量:vec2 型(ItemSpacing/FramePadding…)传两个数,其余传一个
PopStyleVar([n])弹出 n 层
SetSecure([on])截图开关,三态:true=系统截图/录屏/镜像跳过本面板(显示与触摸零影响,切换瞬间约 50ms 重建层);false=恢复包含;无参/传 nil = 只查询不修改。三种形态都返回当前态(true = 跳过)
-- 单色按钮 + 自定义间距
imgui.PushStyleColor(imgui.Col.Button, "#3A7BD5")
imgui.PushStyleVar(imgui.StyleVar.FramePadding, 10, 8)
if imgui.Button("蓝色按钮") then end
imgui.PopStyleVar()
imgui.PopStyleColor()

-- 截图保护开关
if imgui.Button("切换截图保护") then
  imgui.SetSecure(not imgui.SetSecure())    -- 无参那次只查询
end
imgui.SameLine()
imgui.TextDisabled(imgui.SetSecure() and "当前:截图跳过面板" or "当前:截图包含面板")

13. 常量表 已支持 android支持

全部挂在 imgui 下的子表,不用记数字:

常量表用途 / 常用值
imgui.Col(61)颜色槽位:Text Button ButtonHovered WindowBg FrameBg TitleBg CheckMark SliderGrab …
imgui.Win(30)窗口标志:NoMove NoResize NoCollapse NoTitleBar NoScrollbar AlwaysAutoResize MenuBar …
imgui.Cond(6)None Always Once FirstUseEver Appearing
imgui.StyleVar(35)FramePadding ItemSpacing WindowPadding WindowRounding FrameRounding …
imgui.Dir(7)Left Right Up Down None
imgui.MouseButton(5)Left Right Middle
imgui.Slider(11)滑块标志:Logarithmic NoInput WrapAround AlwaysClamp …
imgui.TreeNodeFlags(21)DefaultOpen Leaf NoIndent SpanAvailWidth …
其它SelectableFlags(9) TabBar(13) TabItem(11) Popup(13) ComboFlags(11) Child(11) InputTextFlags(26) Hovered(21) ColorEdit(32) Focused(7) Table(38) TableColumn(29)

⚠️ imgui.Table.* 等常量已齐备,但表格函数(BeginTable/TableNextRow…)本期未绑定,需要表格布局请用 SameLine() + 固定宽度控件自行排列。

14. 完整实例 已支持 android支持

一个可直接跑的控制面板:状态栏 + 两个页签 + 按钮/勾选/滑块/输入框/下拉/进度条/折叠区/树节点/截图开关。注意状态都用 Lua 变量自己存。

-- ============================================================
-- imgui 完整实例:脚本控制面板
--   · 即时模式:每帧重画,控件返回值就是事件
--   · 所有状态自己用 Lua 变量存,每帧回填
-- ============================================================

-- ① 用户状态(脚本自己的变量,不是 imgui 的对象)
local cfg = {
  enable = true,        -- 勾选
  speed  = 1.5,         -- 滑块
  name   = "默认配置",  -- 输入框
  mode   = 1,           -- 下拉(下标 1 起)
}
local modes = { "快速", "标准", "精细" }   -- 下拉项(放外面,别每帧新建表)
local clickCount = 0
local logText = "就绪"

-- ② 建图层并等就绪(异步,最多等 5 秒)
imgui.Init()
local waited = 0
while not imgui.Ready() and waited < 5000 do
  sleep(50)
  waited = waited + 50
end
if not imgui.Ready() then
  print("imgui 图层就绪超时")
  return
end
logText = "图层就绪"

-- ③ 帧循环
while imgui.Running() do
  if imgui.NewFrame() then
    -- 仅首次生效:之后记住用户拖到的位置/尺寸
    imgui.SetNextWindowPos(40, 300, imgui.Cond.FirstUseEver)
    imgui.SetNextWindowSize(620, 800, imgui.Cond.FirstUseEver)

    -- 第二参 true = 显示关闭按钮;返回 可见, 还开着
    local visible, open = imgui.Begin("脚本控制面板", true)
    if visible then
      if imgui.BeginTabBar("mainTabs") then

        -- ---------- 页签一:基本 ----------
        if imgui.BeginTabItem("基本") then
          imgui.Text("引擎版本 1.0.9")
          imgui.TextDisabled("灰色文字适合放提示")
          imgui.Separator()

          -- 按钮:返回 true = 本帧被点击。label 固定,次数用 Text 显示
          if imgui.Button("点我 +1", 140, 0) then
            clickCount = clickCount + 1
            logText = "点击次数: " .. clickCount
          end
          imgui.SameLine()
          imgui.Text("次数: " .. clickCount)

          -- 勾选:传入旧值,返回新值
          cfg.enable = imgui.Checkbox("启用功能", cfg.enable)

          -- 滑块:返回拖动后的实时值
          cfg.speed = imgui.SliderFloat("速度", cfg.speed, 0.1, 5.0)
          imgui.ProgressBar(cfg.speed / 5.0,
              string.format("%.0f%%", cfg.speed / 5.0 * 100))

          -- 输入框:点击自动弹引擎软键盘
          cfg.name = imgui.InputText("名称", cfg.name)

          -- 下拉:下标从 1 开始返回
          cfg.mode = imgui.Combo("模式", cfg.mode, modes)
          imgui.TextDisabled("当前模式: " .. modes[cfg.mode])

          imgui.EndTabItem()
        end

        -- ---------- 页签二:高级 ----------
        if imgui.BeginTabItem("高级") then
          -- 折叠区(展开状态 imgui 自己记,不用存变量)
          if imgui.CollapsingHeader("调试选项") then
            if imgui.Button("清空日志") then logText = "" end
            imgui.SameLine()
            if imgui.Button("写一条日志") then logText = "手动写入一条" end
          end

          -- 树节点:展开时才需要 TreePop
          if imgui.TreeNode("详细信息") then
            imgui.BulletText("速度: " .. string.format("%.2f", cfg.speed))
            imgui.BulletText("模式: " .. modes[cfg.mode])
            imgui.BulletText("启用: " .. tostring(cfg.enable))
            imgui.TreePop()
          end

          imgui.Separator()
          -- 截图开关:SetSecure() 无参=只查询,不改变状态
          if imgui.Button("切换截图保护") then
            imgui.SetSecure(not imgui.SetSecure())
          end
          imgui.SameLine()
          imgui.TextDisabled(imgui.SetSecure() and "截图跳过本面板" or "截图包含本面板")

          -- 图表
          imgui.PlotLines("示例曲线", { 3, 7, 2, 9, 5, 6, 8 })

          imgui.EndTabItem()
        end

        imgui.EndTabBar()
      end

      imgui.Separator()
      imgui.TextWrapped("日志: " .. logText)
    end
    imgui.End()      -- ⚠️ 必须在 if 外面:折叠时 Begin 返回 false,但配对不能少

    imgui.Render()   -- 帧结束,渲染上屏

    -- 点 X 关掉面板就退出循环
    if not open then break end
  end
  sleep(16)          -- ≈60fps
end

imgui.Shutdown()     -- 收图层

可用参数速查:Begin 第二参 true 才有 X 关闭按钮;Combo/ListBox 下标 1 起;Checkbox/Slider*/Input* 都是「传旧值、返回新值」,别忘了写回变量。

uiacc 节点

1. 根据节点的id属性匹配 (id) 已支持 android支持

说明: 根据节点的id属性匹配

函数: id(str)

参数名类型必填说明
strstring是指定要查找的具体控件的id
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = id("com.luatouch.app:id/detail_tv_title")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

2. 根据id包含的部分字符串匹配 (idContains) 已支持 android支持

说明: 根据id包含的部分字符串匹配(正则 :match)

函数: idContains(str)

参数名类型必填说明
strstring是指定要查找的模糊的包含id某一段字符串的内容
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = idContains("detail_tv_title")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

3. 根据id的前缀去匹配 (idStartsWith) 已支持 android支持

说明: 根据id的前缀去匹配(正则 :match('^' .. str))

函数: idStartsWith(str)

参数名类型必填说明
strstring是指定要查找的id的前缀
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = idStartsWith("com.luatouch.app")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:id())
end

4. 根据id的后缀去匹配 (idEndsWith) 已支持 android支持

说明: 根据id的后缀去匹配(正则 :match(str .. '$'))

函数: idEndsWith(str)

参数名类型必填说明
strstring是指定要查找的id的后缀
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = idEndsWith("detail_tv_title")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

5. 正则匹配id (idMatches) 已支持 android支持

说明: 正则匹配id

函数: idMatches(str)

参数名类型必填说明
strstring是正则表达式字符串
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = idMatches(".*detail_tv_title$")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

6. 根据节点的text属性匹配 (text) 已支持 android支持

说明: 根据节点的text属性匹配

函数: text(str)

参数名类型必填说明
strstring是指定要查找的具体控件的text
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = text("LuaTouch高级版")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

7. 根据text包含的部分字符串匹配 (textContains) 已支持 android支持

说明: 根据text包含的部分字符串匹配(正则 :match)

函数: textContains(str)

参数名类型必填说明
strstring是指定要查找的模糊的包含text某一段字符串的内容
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = textContains("LuaTouch")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

8. 根据text的前缀去匹配 (textStartsWith) 已支持 android支持

说明: 根据text的前缀去匹配(正则 :match('^' .. str))

函数: textStartsWith(str)

参数名类型必填说明
strstring是指定要查找的text的前缀
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = textStartsWith("LuaTouch")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

9. 根据text的后缀去匹配 (textEndsWith) 已支持 android支持

说明: 根据text的后缀去匹配(正则 :match(str .. '$'))

函数: textEndsWith(str)

参数名类型必填说明
strstring是指定要查找的text的后缀
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = textEndsWith("高级版")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

10. 正则匹配text (textMatches) 已支持 android支持

说明: 正则匹配text

函数: textMatches(str)

参数名类型必填说明
strstring是正则表达式字符串
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = textMatches(".*高级版$")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

11. 根据节点的desc属性匹配 (desc) 已支持 android支持

说明: 根据节点的desc属性匹配

函数: desc(str)

参数名类型必填说明
strstring是指定要查找的具体控件的desc
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = desc("LuaTouch高级版")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

12. 根据desc包含的部分字符串匹配 (descContains) 已支持 android支持

说明: 根据desc包含的部分字符串匹配(正则 :match)

函数: descContains(str)

参数名类型必填说明
strstring是指定要查找的模糊的包含desc某一段字符串的内容
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = descContains("LuaTouch")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

13. 根据desc的前缀去匹配 (descStartsWith) 已支持 android支持

说明: 根据desc的前缀去匹配(正则 :match('^' .. str))

函数: descStartsWith(str)

参数名类型必填说明
strstring是指定要查找的desc的前缀
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = descStartsWith("LuaTouch")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

14. 根据desc的后缀去匹配 (descEndsWith) 已支持 android支持

说明: 根据desc的后缀去匹配(正则 :match(str .. '$'))

函数: descEndsWith(str)

参数名类型必填说明
strstring是指定要查找的desc的后缀
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = descEndsWith("高级版")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

15. 正则匹配desc (descMatches) 已支持 android支持

说明: 正则匹配desc

函数: descMatches(str)

参数名类型必填说明
strstring是正则表达式字符串
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = descMatches(".*高级版$")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

16. 根据节点的className属性匹配 (className) 已支持 android支持

说明: 根据节点的className属性匹配

函数: className(str)

参数名类型必填说明
strstring是指定要查找的具体控件的类名
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = className("AXStaticText")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

17. 根据className属性所包含的字符串模糊匹配 (classNameContains) 已支持 android支持

说明: 根据className属性所包含的字符串模糊匹配(正则 :match)

函数: classNameContains(str)

参数名类型必填说明
strstring是指定要查找className包含该字符的节点
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = classNameContains("Text")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

18. 根据className属性前缀匹配 (classNameStartsWith) 已支持 android支持

说明: 根据className属性前缀匹配(正则 :match('^' .. str))

函数: classNameStartsWith(str)

参数名类型必填说明
strstring是指定要查找className前缀为该字符的节点
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = classNameStartsWith("AX")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

19. 根据className属性后缀匹配 (classNameEndsWith) 已支持 android支持

说明: 根据className属性后缀匹配(正则 :match(str .. '$'))

函数: classNameEndsWith(str)

参数名类型必填说明
strstring是指定要查找className后缀为该字符的节点
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = classNameEndsWith("StaticText")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

20. 根据className属性正则匹配 (classNameMatches) 已支持 android支持

说明: 根据className属性正则匹配

函数: classNameMatches(str)

参数名类型必填说明
strstring是指定要匹配className的正则表达式
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = classNameMatches("^AX.*Text$")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

21. 根据packageName属性全字段匹配 (packageName) 已支持 android支持

说明: 根据packageName属性全字段匹配

函数: packageName(str)

参数名类型必填说明
strstring是指定要匹配节点所属的包名
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = packageName("com.apple.mobilesafari"):className("AXStaticText")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

22. 匹配包含指定字符串的节点 (packageNameContains) 已支持 android支持

说明: 匹配包含指定字符串的节点(正则 :match)

函数: packageNameContains(str)

参数名类型必填说明
strstring是包含该字符串的包名的节点将被匹配到
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = packageNameContains("apple"):className("AXStaticText")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

23. 匹配包名前缀为指定字符串的节点 (packageNameStartsWith) 已支持 android支持

说明: 匹配包名前缀为指定字符串的节点(正则 :match('^' .. str))

函数: packageNameStartsWith(str)

参数名类型必填说明
strstring是包名为该字符的前缀的节点将被匹配到
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = packageNameStartsWith("com.apple"):className("AXStaticText")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

24. 匹配包名后缀为指定字符串的节点 (packageNameEndsWith) 已支持 android支持

说明: 匹配包名后缀为指定字符串的节点(正则 :match(str .. '$'))

函数: packageNameEndsWith(str)

参数名类型必填说明
strstring是包名为该字符的后缀的节点将被匹配到
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = packageNameEndsWith("mobilesafari"):className("AXStaticText")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

25. 包名正则匹配 (packageNameMatches) 已支持 android支持

说明: 包名正则匹配

函数: packageNameMatches(str)

参数名类型必填说明
strstring是根据这个正则字符串匹配所有符合规则包名的节点
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = packageNameMatches("com.apple.*"):className("AXStaticText")
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

26. 根据节点的范围匹配 (bounds) 已支持 android支持

说明: 根据节点的范围匹配(精确匹配 bounds 坐标)

函数: bounds(l, t, r, b)

参数名类型必填说明
lnumber是左范围
tnumber是上范围
rnumber是右范围
bnumber是下范围
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = bounds(30, 212, 236, 250)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

27. 匹配该范围内的节点 (boundsInside) 已支持 android支持

说明: 匹配 bounds 完全包含在指定范围内的节点

函数: boundsInside(l, t, r, b)

参数名类型必填说明
lnumber是左范围
tnumber是上范围
rnumber是右范围
bnumber是下范围
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = boundsInside(30, 212, 236, 250)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

28. 根据绘制顺序匹配 (drawingOrder) 已支持 android支持

说明: 根据绘制顺序匹配

函数: drawingOrder(level)

参数名类型必填说明
levelnumber是绘制顺序级别
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = drawingOrder(1)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

29. 根据深度索引匹配 (depth) 已支持 android支持

说明: 根据深度索引匹配

函数: depth(level)

参数名类型必填说明
levelnumber是深度索引级别
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = depth(1)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

30. 根据在当前父节点里面的索引顺序查找 (index) 已支持 android支持

说明: 根据在当前父节点里面的索引顺序查找

函数: index(level)

参数名类型必填说明
levelnumber是索引级别
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = index(1)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:text())
end

31. 根据是否可见匹配 (visibleToUser) 已支持 android支持

说明: 根据是否可见匹配

函数: visibleToUser(b)

参数名类型必填说明
bboolean是是否可见
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = visibleToUser(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

32. 根据是否选中匹配 (selected) 已支持 android支持

说明: 根据是否选中匹配

函数: selected(b)

参数名类型必填说明
bboolean是是否选中
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = selected(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

33. 根据是否可点击匹配 (clickable) 已支持 android支持

说明: 根据是否可点击匹配

函数: clickable(b)

参数名类型必填说明
bboolean是是否可点击
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = clickable(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

34. 根据是否可长按点击匹配 (longClickable) 已支持 android支持

说明: 根据是否可长按点击匹配

函数: longClickable(b)

参数名类型必填说明
bboolean是是否可长按点击
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = longClickable(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

35. 根据是否可用匹配 (enabled) 已支持 android支持

说明: 根据是否可用匹配

函数: enabled(b)

参数名类型必填说明
bboolean是是否可用
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = enabled(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

36. 根据是否是密码框匹配 (password) 已支持 android支持

说明: 根据是否是密码框匹配

函数: password(b)

参数名类型必填说明
bboolean是是否是密码框
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = password(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

37. 根据是否可以滚动来匹配 (scrollable) 已支持 android支持

说明: 根据是否可以滚动来匹配

函数: scrollable(b)

参数名类型必填说明
bboolean是是否可以滚动
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = scrollable(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

38. 根据是否被勾选来匹配 (checked) 已支持 android支持

说明: 根据是否被勾选来匹配

函数: checked(b)

参数名类型必填说明
bboolean是是否被勾选
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = checked(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

39. 根据是否可以被勾选来匹配 (checkable) 已支持 android支持

说明: 根据是否可以被勾选来匹配

函数: checkable(b)

参数名类型必填说明
bboolean是是否可以被勾选
返回值类型说明
selector返回一个选择器对象,该对象支持级联选择
local sel = checkable(true)
local node = sel:findOne(10000)
if node ~= nil then
    print(node:className())
end

findOne(timeoutMs) 已支持 android支持

查找第一个匹配节点,未找到返回 nil。

一次调用只采集一次节点树(不是内部循环轮询):引擎会拉起一次节点采集并等待结果,拿到后在结果里做匹配。所以「等某个元素出现」需要自己写成循环(见下方示例),或用 exists()。

参数名类型必填说明
timeoutMsint否等待本次采集完成的上限毫秒数,默认 10000;传 0 或负数会按 3000 处理(不会变成“立即返回”)
返回值类型说明
node匹配的节点对象;未找到 / 采集超时 / 采集失败均返回 nil
  • 采集超时(timeoutMs 到点)会终止本次采集并返回 nil
  • 同一时刻只允许一次采集:上一次还没结束时再调用,会直接返回 nil(不会排队等待)
  • 采集过程中子进程要先把「屏幕中心点采样」重试到成功(最坏约 50 次 × 50ms ≈ 2.5 秒),因此 timeoutMs 给得过小(如 1000)可能在产出前就被截断;建议 ≥ 3000
local node = text("LuaTouch"):findOne(5000)
if node then
    print("找到", node:text(), node:bounds())
end

-- findOne 不会自己重试,需要“等元素出现”时自己轮询:
local function waitText(t, ms)
    local deadline = axTimeMs() + ms
    while axTimeMs() < deadline do
        local n = t:findOne(3000)
        if n then return n end
        axSleep(300)
    end
    return nil
end
local btn = waitText(textContains("确定"), 10000)

find(timeoutMs) 已支持 android支持

查找所有匹配节点,返回数组(顺序 = 节点树中的先后顺序);未找到返回空表 {}。

与 findOne 一样是一次采集:采集一次节点树,然后在结果里收集全部匹配节点。

参数名类型必填说明
timeoutMsint否等待本次采集完成的上限毫秒数,默认 10000;传 0 或负数按 3000 处理
返回值类型说明
node[]匹配的节点数组;未找到 / 采集超时 / 采集失败均返回空表 {}
local ns = textContains("确定"):find(3000)
print("找到", #ns, "个")
for i, n in ipairs(ns) do
    print(i, n:text(), n:bounds())
end

findOnce(timeoutMs) / exists(timeoutMs) 已支持 android支持

选择器上的两个便捷方法(同样是一次采集):

方法返回说明
sel:findOnce(t)node | nilfindOne 的别名,行为完全一致(默认 10000ms)
sel:exists(t)boolean是否存在匹配节点,等价于 findOne(t) ~= nil;只关心“有没有”时更直观
-- 等按钮出现:自己轮询(每次采集一次,间隔 300ms)
local function waitExists(sel, ms)
    local deadline = axTimeMs() + ms
    while axTimeMs() < deadline do
        if sel:exists(3000) then return true end
        axSleep(300)
    end
    return false
end

if waitExists(textContains("确定"), 10000) then
    local n = textContains("确定"):findOnce(3000)
    local l, t, r, b = n:bounds()
    tap((l + r) / 2, (t + b) / 2)
end

节点方法

通过 findOne / find 拿到的节点对象是属性读取器:每个方法读取该节点对应的属性并返回,不参与匹配。属性不存在时不会报错——字符串返回 ""、数值返回 0、布尔返回 false。

方法返回类型说明
n:text()string节点显示文本
n:id()string节点唯一标识(resource-id)
n:desc()string无障碍描述(content-desc)
n:className()string节点类名
n:packageName()string所属应用包名
n:bounds()l,t,r,b节点矩形坐标(4 个返回值,物理像素)
n:clickable()boolean是否可点击
n:enabled()boolean是否可用
n:focusable()boolean是否可获得焦点
n:focused()boolean当前是否已聚焦
n:visibleToUser()boolean是否可见
n:selected()boolean是否选中
n:checkable()boolean是否可勾选
n:checked()boolean是否已勾选
n:scrollable()boolean是否可滚动
n:longClickable()boolean是否可长按
n:password()boolean是否是密码框
n:depth()int节点深度
n:index()int在父节点中的索引
n:drawingOrder()int绘制顺序
local n = text("LuaTouch"):findOne(5000)
if n then
    print("text =", n:text())
    print("class =", n:className())
    print("clickable =", n:clickable())
    local l, t, r, b = n:bounds()
    print("bounds =", l, t, r, b)
end

除方法外,节点对象还支持与 iOS 一致的字段写法(n._text 等,按需从节点属性读取,默认值规则同方法):

字段等价方法返回类型
n._textn:text()string
n._idn:id()string
n._classn:className()string
n._descn:desc()string
n._packagen:packageName()string
n._depthn:depth()int
n._indexn:index()int
n._drawingordern:drawingOrder()int
local n = depth(0):findOne(5000)
print(n._class, n._package)   -- android.view.View    android

链式组合(多条件 AND)

用 : 链式串联多个 selector,节点必须同时满足所有条件才匹配。

-- 同时满足:文本包含"确定" 且 可见 且 可点击
local n = textContains("确定"):visibleToUser(true):clickable(true):findOne(5000)

-- 包名 + 类名组合
local n2 = packageName("com.apple.mobilesafari"):className("AXStaticText"):findOne(3000)

点击节点

节点对象没有 click() 方法。标准做法:取节点 bounds 的中心 → 调用引擎 tap(x, y)。bounds 与 tap 都用物理像素,直接传即可,无需换算。

local n = text("LuaTouch"):findOne(5000)
if n then
    local l, t, r, b = n:bounds()
    local cx, cy = (l + r) / 2, (t + b) / 2
    tap(cx, cy)
end

底层 API

函数返回说明
axGetXml(timeout?)string直接取一次节点树 XML 字符串。默认 3000ms;timeout ≤ 0 按 3000 处理。失败/超时返回空字符串 "",不是 nil。同一时刻只允许一次采集,重入时也返回 ""。findOne / find 内部就是调它,一般不用自己调
axSleep(ms?)无阻塞等待指定毫秒,默认 100。属于无障碍模块的休眠,不响应脚本的暂停/停止——脚本里请优先用全局 sleep(),需要与节点采集节奏对齐时才用 axSleep
axTimeMs()int当前时间戳,单位毫秒(Unix epoch)。用于算耗时/超时截止时间

旧版 axGetTree / axDumpAttrs 已删除(不再整树转 Lua 表;属性改由节点对象的方法按需读取)。

-- 取原始节点树 XML(调试用)
local xml = axGetXml(3000)
if xml ~= "" then            -- 注意:失败返回空字符串,不是 nil
    print("XML 长度:", #xml)
else
    print("采集失败/超时")
end

-- 用 axTimeMs 自己控制等待时长
local deadline = axTimeMs() + 5000
while axTimeMs() < deadline do
    if textContains("确定"):exists(3000) then break end
    axSleep(300)
end

注意事项

  • 前台切换:节点树会随前台 App 变化,切换后建议先 findOne(5000) 等新树稳定。
  • 正则引擎:Contains / StartsWith / EndsWith / Matches 内部全用 Lua string.match,支持 Lua 正则语法(非 PCRE)。
  • 精确匹配:text("A") 是精确匹配;模糊匹配用 textContains / textMatches。
  • 性能:取树 12 个窗口 ~3000+ 节点,单次 ~50ms。建议 findOne + 短超时。
本地文档 · 引擎版本 v1.0.5
script 模块(2 个):exitScript / restartScript(脚本退出与重启)
app 模块(13 个):appCurrentPackage / appLaunch / appForceStop / appGetList / appGetBundlePath / appGetDataPath / appSelfPackage / appGetVersion / appUninstall / appInstall / appClear / appOpenUrl / appGetPackageName
device 模块(17 个):deviceGet / deviceGetDisplayInfo / deviceVpnStatus / deviceSetVPNEnabled / deviceSetWiFiEnabled / deviceGetBattery / deviceGetBatteryStatus / deviceIsScreenOn / deviceIsScreenUnlock / deviceGetBrightness / deviceGetTotalMem / deviceGetAvailMem / deviceWakeUp / deviceKeepScreenOn / deviceGetIp / deviceGetWifiMac / deviceReboot
file 模块(6 个):deleteFile / moveFile / unzipFile / readFileAsBase64 / base64Encode / base64Decode(base64 为通用编解码,解码自动忽略空白与填充)
http 模块(5 个):httpGet / httpPost / downloadFile / tableToJson / jsonToTable(支持 HTTP/HTTPS)
ime 模块(4 个):imeInputText / imePasteText / imeGetClipText / imeSetClipText(引擎唯一剪贴板 API)
touch 模块(8 个):tap / swipe / key / keyRaw / keyMeta / touchDown / touchMove / touchUp(坐标为物理像素,与 getScreenSize 一致)
color 模块(12 个):getPixel / getRGB / getScreenSize / findColor / isColor / findMultiColors / tableFindMultiColors / findPic / findPicEx / getColorCountInRegion / detectsMultiColors / screenshot(颜色格式 目标-容差,如 ffffff-323232;isColor 为单点快速判定)
cv 模块(206 个,对象式 cv.xxx):cv.snapshot() 返回 Mat 对象(方法 release/empty/size/type/clone/origin);每个成员支持全小写与首字母大写双写法(cv.snapshot / cv.Snapshot);涵盖创建与生命周期 / 指针辅助类型 / 属性与像素读写 / 算术数学 / 统计 / 滤波增强 / 形态学 / 几何变换 / 阈值边缘轮廓特征 / 色彩通道 / 绘图 / 图像IO / 模板匹配找图 / 杂项(详见 cv 模块章节)
yolo 模块(4 个):yolo_init / yolo_detect_image / yolo_detect_file / yolo_close(YOLO11/v8 ncnn 目标检测;conf 默认 0.25、nms 0.45、input 640;模型须 yolo export format=ncnn 导出,输入名 in0 输出名 out0)
tessocr 模块(8 个):ocr_init / ocr_set_param / ocr_from_file / ocr_from_image / ocr_from_pixels / ocr_set_rectangle / ocr_clear / ocr_close(语言数据在 data_root/models/tessdata)
ppocr 模块(6 个):ppocr_create / ppocr_init / ppocr_set_param / ppocr_detect_image / ppocr_detect_file / ppocr_release(模型在 data_root/models/ch/,坐标归一化 0~1)
hud 模块(15 个):showUi / hideUi / isShowUi / toast / alert / inputAlert / hud.new / setPosition / setBackgroundColor / setTextSize / setText / show / hide / isVisible / destroy(showUi 为全屏 HTML 面板,支持 JSON 配置回填与表单回传,自带输入键盘;toast / alert / inputAlert 为系统级 UI 提示;hud 为多实例彩色文本浮层,坐标为屏幕点,方法返回自身支持链式)
各模块已全部实现,无待实现函数;除 cv 模块(表成员)与 hud 表外均为全局函数(无模块前缀)