用户脚本入口函数 def tick(ctx): ... 中的 ctx 类型为 ScriptContext(定义于 core/script_context.py)。它是脚本与 VisionScript 运行时交互的唯一推荐入口:截图、感知/识别、键鼠执行、日志、向 UI 发事件、读写全局状态、使用事件总线。
相关代码:core/script_context.py、core/script_host.py、core/world_state.py、core/script_manifest.py、executor/actions.py、core/event_bus.py、core/visionscript_events.py。
- API 总览
- API 详解
- 脚本生命周期与主循环
- 属性(简明)
- 日志
log - UI 脚本事件
emit_ui/emit_ui_sync - 截图
capture_frame/release_capture - 感知流水线与识别
- 可中断等待与录制回放
- 事件总线
ctx.bus - 世界状态
ctx.state - 动作执行器
ctx.actions - 清单
ctx.manifest - 事件类型常量
- 示例
- 注意事项汇总
| 成员 | 类别 | 说明 |
|---|---|---|
ctx.manifest |
属性 | 当前脚本的 ScriptManifest(路径、入口、fps、capture、perception 等) |
ctx.state |
属性 | 全局 WorldState(暂停/停止、fps、扩展数据等) |
ctx.bus |
属性 | EventBus,与 UI/其它模块通讯 |
ctx.actions |
属性 | ActionExecutor,键鼠高层 API |
ctx.finish() |
方法 | 将 state.stop_requested 置为 True,结束引擎主循环 |
ctx.log(msg, level="info") |
方法 | 同步发 ui.log 并写文件日志 |
ctx.emit_ui(name, **kwargs) |
方法 | 异步发送 ui.script 自定义事件 |
ctx.emit_ui_sync(name, **kwargs) |
方法 | 同步发送 ui.script |
ctx.capture_frame() |
方法 | 返回一帧 BGR 图像,或 None |
ctx.release_capture() |
方法 | 释放窗口捕获资源(由引擎在脚本卸载时也会调用) |
ctx.perception_pipeline |
属性 | 未启用则为 None;否则为 PerceptionPipeline 实例 |
ctx.recognition_runner() |
方法 | 懒加载 RecognitionRunner(可带 OCR) |
ctx.run_perception(frame_bgr) |
方法 | 对整帧跑感知流水线,未启用则 None |
ctx.make_template_match_ro(...) |
方法 | 构造模板匹配用的 RecognitionObject |
ctx.run_recognition(frame_bgr, ro) |
方法 | 对整帧执行给定识别配置 |
ctx.wait_interruptible(seconds, slice_s=0.05) |
方法 | 可被打断的睡眠(响应 stop_requested) |
ctx.run_recorded_ops(steps) |
方法 | 执行录制器生成的步骤元组 |
- 以下划线开头的懒加载字段(
_window_capture、_screen_capture、_pipeline、_recognition_runner)为内部实现,勿在脚本中访问。 ScriptContext无公开继承扩展点;逻辑放在用户脚本的模块级状态或ctx.state.extras中即可。
本节与源码逐项对齐,涵盖 ScriptContext 全部公开成员,以及通过 ctx.state / ctx.bus / ctx.actions / ctx.manifest 暴露的子对象 API。第三节起为按主题归纳的简明版与示例表,便于速查;细节若有出入以本节为准。
以下按「从 ctx 能访问到什么」说明:用途、签名、行为、返回值、典型用法与注意。实现均以 core/script_context.py 及嵌套类型源码为准。
- 用途:只读使用当前运行脚本的项目元数据与
visionscript/ YAML 中的运行时配置(截图模式、感知开关、OCR 语言、fps 等)。构造ScriptContext时已注入,脚本内不要重新赋值。 - 主要字段:
project_root、manifest_path、name、script_version、entry、entry_path、library、fps、capture(CaptureSection)、perception(PerceptionSection)、ui、raw。 - 注意:
entry_path为project_root / entry的绝对路径;library目录在宿主初始化时已加入sys.path,用于脚本侧import扩展模块。
- 用途:与引擎、UI 共享的唯一运行时状态(暂停、停止、帧率、UI 命令、扩展字典等)。脚本可读写其中多数字段;
ui_command/ui_payload的并发写入由内部锁保护。 - 与
ctx.manifest的关系:ScriptRuntimeModule.init会把解析后的ScriptManifest赋给state.manifest,并把target_fps设为清单fps。 - 注意:修改
stop_requested与调用ctx.finish()等价于请求结束;pause为真时本帧不会调用tick(ctx),因此暂停期间脚本逻辑完全静止。
- 用途:类型为
core.event_bus.EventBus,在Engine.start()时已start(),后台线程从队列取事件并_dispatch。脚本通过emit/emit_sync与on/off与 UI 或其它模块通讯。 - 线程语义:
emit将事件放入队列,处理可能发生在另一线程;emit_sync在当前调用线程立即执行所有订阅者,便于与 UI 同步但需注意重入与耗时回调阻塞主循环。 - 注意:队列满时
emit会丢弃事件并记日志;脚本侧一般不要bus.stop()(由引擎管理生命周期)。
- 用途:封装
MouseController与KeyboardController的高层键鼠 API(点击、拖拽、快捷键、组合动作、等待等)。ScriptContext.__init__中固定ActionExecutor(),即默认human_like=True。 - 属性:
mouse、keyboard为底层控制器;human_like为可读实例属性,控制navigate_click/click_at等路径上的随机短延迟。 - 注意:
wait(seconds)使用time.sleep,不会检查stop_requested;需要可中断等待请用ctx.wait_interruptible或在循环里自判ctx.state.stop_requested。
- 签名:
finish() -> None - 行为:
self.state.stop_requested = True,无其它副作用。 - 用途:显式声明「本脚本逻辑结束」,引擎主循环退出;脚本队列场景下可衔接下一脚本。
- 等价写法:
ctx.state.stop_requested = True;或与tick内return False(字面量)结合ScriptHost.tick_once的约定等价。
- 参数:
seconds总等待时长(秒),<=0立即返回;slice_s每小段最长睡眠,内部夹紧为>=0.01,且每段不超过剩余时间。 - 行为:循环直到
time.perf_counter()到达终点;任意时刻若state.stop_requested则提前返回。用于替代长time.sleep,使停止/结束更快生效。 - 注意:不响应
pause(暂停在帧边界不进入tick);若在tick外无法调用(脚本只能在tick内跑)。
- 参数:
steps为元组,元素为子元组,首元素标签支持
"w"|"c"|"t"|"k"|"D"|"U"|"Bd"|"Bu"|"m"|"h"|"H"|"M"|"s"。 - 行为:按顺序执行;每一步开始前若
stop_requested则return。("w", t)→wait_interruptible(t)("c", x, y, button)→actions.click_at(...)("t", text)→actions.type_text(text)("k", key)→actions.keyboard.key_press(key)("D", key)/("U", key)→actions.keyboard.key_down(key)/key_up(key)("h", ("ctrl","s"))→actions.shortcut(*keys)("H", key, sec)→actions.keyboard.hold_key(key, sec)("M", ("shift","w"), sec)→ 依次key_down组合键,等待sec(可中断),再逆序key_up("m", x, y)→mouse.move_to(x, y, smooth=False)瞬时定位(避免默认类人贝塞尔导致轨迹回放极慢)("Bd", button, x, y)/("Bu", button, x, y)→ 先瞬时move_to,再mouse_down/mouse_up("s", amount, direction)→actions.mouse.scroll(...)
- 注意:当前录制器已改为按键原子事件(
key_down/key_up)并在生成阶段换算为D/U(以及必要的h/H/M);如需保证“按住主键不被组合拆断”,优先依赖D/U序列。
- 参数:
msg文本;level字符串,用于 UI 与文件侧日志级别。 - 行为:先
emit_sync(UI_LOG, {"message": msg, "level": level}),再按_LOG_LEVEL_NUM(仅识别 debug/info/warning/error)映射到数值logger.log;未知级别按数值 20(info) 写入文件 logger。 - 注意:UI 收到的
level为原始字符串;仅当你依赖「文件日志级别数值」时,才受未知字符串回落影响。
- 行为:
bus.emit(UI_SCRIPT, {"name": name, **kwargs}),异步队列。 - 用途:向订阅
ui.script的界面发业务事件(名称 + 任意命名参数),不阻塞当前tick返回后的后续逻辑(但emit入队本身很快)。
- 行为:
bus.emit_sync(UI_SCRIPT, {"name": name, **kwargs}),当前线程立即分发。 - 用途:需要同一调用栈内 UI 已更新时用;避免在处理器里再同步
emit_sync造成死锁。
- 返回值:成功为 BGR
uint8ndarray,(H,W,3);失败None。 - 行为:若
manifest.capture.mode == "screen",懒加载ScreenCapture并grab();否则走_grab_window():懒加载WindowCapture(hwnd, title_pattern),resolve()失败则打警告日志并None;否则首次grab()前可按auto_fix_win11_bitblt调用start(settings)。 - 注意:屏幕模式与窗口模式各自缓存一个捕获器实例;切换清单配置通常需换脚本进程或自行理解缓存生命周期。
- 行为:若存在
_window_capture,close()并置None。不释放_screen_capture(全屏捕获器无对称逻辑于此方法)。 - 用途:释放窗口 DC/钩子等;
ScriptHost.close()也会调用。
- 行为:若
manifest.perception.use_pipeline为假 →None;否则懒加载PerceptionPipeline,并按配置注册UIRecognizer。 - 用途:需要直接访问流水线实例时(多数情况用
run_perception即可)。
- 行为:懒加载单例;首次创建时尝试
PaddleOCREngine(lang=perception.ocr_lang),异常则ctx.log警告且 OCR 为None,仍构造RecognitionRunner(ocr=None)。 - 用途:模板匹配不强制 OCR;但若要用 OCR,需保证依赖安装否则仅有模板等分支可用。
- 参数:一帧 BGR 图像。
- 返回值:流水线未启用
None;否则perception_pipeline.process(frame_bgr),字典结构由感知模块定义。 - 注意:与
run_recognition不同:前者跑整条流水线,后者跑单个RecognitionObject。
ctx.make_template_match_ro(template_bgr, *, threshold=0.8, roi=None, use_mask=False, use_3_channels=False, name="")
- 返回值:
RecognitionObject(感知模块类型)。 - 行为:
RecognitionObject.template_match(...)后设置use_3_channels;不提前加载recognition_runner。 - 参数要点:
roi为整图上的(x,y,w,h);use_mask按模块约定处理纯绿背景;name便于调试日志。
- 行为:
recognition_runner().run(frame_bgr, ro)。 - 用途:对单帧、单配置做匹配/OCR 等;结果对象字段见
perception包(如success、template_hits)。
| 符号 | 详解 |
|---|---|
script_manifest_path |
解析清单时设置的路径;脚本只读为宜。 |
pause |
由 UI ui.command 同步处理器写入;为真时 ScriptRuntimeModule.tick 不调用用户 tick。 |
stop_requested |
停止请求;为真时引擎主循环退出且不再 tick_once。 |
target_fps |
主循环睡眠用;运行时模块会把清单 fps 同步进来。 |
ui_command / ui_payload |
自定义 UI 命令槽;set_ui_command 写入,consume_ui_command 读取并清空。每帧 tick 前由运行时调用 consume_ui_command(),故你在本轮 **tick 内读到的应是「已被清空后的」状态——若需在本帧处理命令,应使用 EventBus 订阅 UI_COMMAND 或在文档约定的其它路径获取(见运行时实现)。 |
manifest |
当前 ScriptManifest 引用。 |
extras |
任意可序列化/不可序列化 Python 对象字典,脚本用于跨 **tick 或跨模块共享;无自动持久化。 |
set_ui_command(cmd, payload=None) |
线程安全写入命令。 |
consume_ui_command() |
返回 (cmd: str, payload: dict) 并清空内部存储。 |
| 符号 | 详解 |
|---|---|
on(event_type, handler) |
注册 handler(Event);多处理器按注册顺序在 _dispatch 中调用。 |
off(event_type, handler) |
需传入同一函数对象引用方可移除。 |
emit(event_type, payload=None, source="") |
构造 Event 入队;异步处理。 |
emit_sync(event_type, payload=None, source="") |
立即 _dispatch;同一 event_type 的所有 handler 同步执行。 |
Event:type、payload、source、timestamp。
| 符号 | 详解 |
|---|---|
human_like |
若为真,navigate_click、drag_between 等路径上 _human_delay 随机延迟;为假时延迟更短。 |
click_at(x, y, button="left", random_offset=0, clicks=1) |
若 random_offset>0,在 ±random_offset 内随机修正坐标,再 mouse.click。 |
click_region(region, button="left", clicks=1) |
region=(left,top,right,bottom),在矩形内均匀随机选点再 click_at。 |
navigate_click(x, y, pre_delay=0.0, post_delay=0.0) |
可选前置/后置 sleep,再 move_to → 人性化延迟 → click。 |
drag_between(x1,y1,x2,y2, button="left") |
移动到起点 → 短延迟 → drag_to 终点。 |
shortcut(*keys) |
展开为 keyboard.hotkey(*keys)。 |
type_text(text, interval=None) |
keyboard.typewrite;长文本期间不检查停止。 |
combo_action(actions) |
遍历 dict 列表,按 type 分发到 _execute_action;未知类型 warning。 |
wait(seconds) |
time.sleep(seconds),不可被 stop_requested 打断。 |
wait_for(predicate, timeout=5.0, interval=0.1) |
轮询 predicate(),超时返回 False;不默认检查 stop_requested,可在 **predicate 内自行判断。 |
mouse |
MouseController(executor/mouse.py):见下表。 |
keyboard |
KeyboardController(executor/keyboard.py):见下表。 |
MouseController 常用公开方法:move_to、move_relative、click(可选坐标与 button、clicks)、double_click、scroll(amount, direction="vertical")、drag_to、drag_relative、mouse_down / mouse_up、get_position、is_on_screen。
KeyboardController 常用公开方法:key_down / key_up、key_press(可选 presses)、hotkey(*keys)、hold_key、typewrite、press_sequence、is_key_pressed。
| 字段 | 详解 |
|---|---|
project_root |
清单所在目录(绝对路径);入口 entry、资源路径均相对此目录。 |
manifest_path |
当前清单文件路径;目录加载 manifest.json 时非空。 |
manifest_version |
清单格式版本号(整数)。 |
name / script_version / description / authors |
展示与发布用元数据;不影响运行时逻辑。 |
library |
相对 project_root 的额外源码目录列表;存在目录会被插入 sys.path(见 ScriptHost._prepend_search_paths)。 |
entry |
入口模块相对路径(如 tick.py);与 main(JSON)同源字段。 |
entry_path |
project_root / entry 解析后的绝对路径;用户 tick 所在文件。 |
fps |
建议主循环帧率;运行时写入 state.target_fps。 |
capture |
CaptureSection:mode(window | screen)、title_pattern、hwnd、auto_fix_win11_bitblt → 决定 capture_frame 行为。 |
perception |
PerceptionSection:use_pipeline、register_ui_recognizer、ocr_lang → 流水线与 OCR。 |
ui |
自定义键值,供脚本或扩展读取(引擎核心不强制解释)。 |
raw |
解析后的原始字典(JSON/YAML),便于读取未建模字段。 |
工程约定字符串,供 bus.emit / 订阅 与文档交叉引用:UI_COMMAND、UI_LOG、UI_STATE、UI_SCRIPT、UI_ERROR、UI_SCRIPT_LOADED。脚本侧**ctx.log** 使用 UI_LOG;emit_ui* 使用 UI_SCRIPT;用户脚本异常由 ScriptHost 发 UI_ERROR。
- 引擎按清单中的
fps(ctx.manifest.fps→ 同步到ctx.state.target_fps)驱动主循环;每一帧会调用已注册运行时模块的tick,其中ScriptRuntimeModule.tick在用户脚本未停止且未暂停时调用ScriptHost.tick_once(),进而执行用户脚本的tick(ctx)。 state.pause == True时:本帧不会调用tick(ctx)(脚本完全暂停)。state.stop_requested == True时:主循环即将退出;同一帧内脚本tick也会因ScriptRuntimeModule提前 return 而不再执行。
因此:长时间阻塞且不使用 wait_interruptible 的 time.sleep,会拖慢整帧、且无法在等待期间响应暂停(暂停是在帧边界生效的)。
等同于 ctx.state.stop_requested = True。用于声明「当前脚本任务已完成」,引擎主循环结束;在 GUI 脚本队列 中,结束后会自动加载下一脚本(见 script_queue.md)。
在 ScriptHost.tick_once 中:
- 若
tick显式return False(必须为字面量False),运行时会设置state.stop_requested = True,效果与finish()相同。 return、return None、不写return均不会结束脚本。return 0、return []等其它假值不会触发结束。
| 属性 | 类型 | 说明 |
|---|---|---|
ctx.manifest |
ScriptManifest |
当前脚本清单(解析自 YAML/JSON 或项目 manifest.json) |
ctx.state |
WorldState |
全局运行时状态 |
ctx.bus |
EventBus |
事件总线实例(引擎启动时已 start()) |
ctx.actions |
ActionExecutor |
默认 human_like=True,操作带轻微随机延迟 |
行为:
emit_sync(UI_LOG, {"message": msg, "level": level})— 同步派发,UI 侧订阅ui.log可立即更新日志面板等。- 使用内部
_LOG_LEVEL_NUM将字符串级别映射为数值后写入core.script_context模块 logger,从而进入文件日志体系。
支持的 level(大小写不敏感,strip 后匹配): "debug"、"info"、"warning"、"error"。其它字符串会按数值 20(info) 写入 logger。
建议: 业务脚本统一使用上述四类字符串,避免依赖「未知级别回落为 info」的细节。
二者均向 UI_SCRIPT(事件类型字符串 "ui.script")派发,payload 形状为:
{"name": name, **kwargs}例如 ctx.emit_ui("battle_start", hp=100) → payload 为 {"name": "battle_start", "hp": 100}。
| 方法 | 派发方式 | 适用场景 |
|---|---|---|
ctx.emit_ui(name, **kwargs) |
bus.emit → 入队异步处理 |
一般业务事件,不阻塞脚本线程 |
ctx.emit_ui_sync(name, **kwargs) |
bus.emit_sync → 立即在同线程调用订阅者 |
需要同一调用栈内立刻刷新 UI 时(注意避免重入与死锁) |
主窗口是否展示脚本事件取决于 UI 是否订阅 ui.script;可自行扩展。
- 返回值:成功为
numpy.ndarray,BGR、uint8,形状(H, W, 3);失败为None。 - 模式由清单
ctx.manifest.capture.mode决定:"screen":全屏捕获;懒加载capture.ScreenCapture,调用grab()。"window"(默认):窗口客户区;懒加载capture.WindowCapture,使用title_pattern和/或hwnd解析窗口。
- 窗口模式首次
grab()前若resolve()失败,会ctx.log(..., "warning")并返回None。 - 若清单
capture.auto_fix_win11_bitblt为真,start({"auto_fix_win11_bitblt": True})。
JSON 清单中上述字段位于 visionscript.capture(兼容旧键 vhsr)。YAML 清单可为根级 capture。
关闭窗口捕获实例(若存在),重置内部引用。ScriptHost.close() 在脚本宿主卸载时会调用,用于释放 DXGI/GDI 等资源。若你在脚本内切换截图策略或长时间不用窗口捕获,可主动调用。
- 若
manifest.perception.use_pipeline为False→None。 - 否则懒加载
PerceptionPipeline;若register_ui_recognizer为真,会register_source(UIRecognizer())。
- 流水线未启用 →
None。 - 否则
perception_pipeline.process(frame_bgr),返回字典(具体键由感知模块定义)。
- 首次调用时尝试构造
PaddleOCREngine(lang=manifest.perception.ocr_lang);失败则ctx.log("OCR 未启用: ...", "warning"),OCR 为None,但RecognitionRunner仍可用于模板匹配等。 ocr_lang来自清单perception.ocr_lang(默认"ch")。
ctx.make_template_match_ro(template_bgr, *, threshold=0.8, roi=None, use_mask=False, use_3_channels=False, name="") -> RecognitionObject
- 内部调用
RecognitionObject.template_match(...),再设置ro.use_3_channels。 - 不会单独触发
recognition_runner的懒加载;首次run_recognition仍会加载运行器。
等价于 ctx.recognition_runner().run(frame_bgr, ro)。返回值类型由 perception 包定义(如 success、template_hits、error 等属性)。
seconds <= 0:立即返回。- 否则循环:若
state.stop_requested则立刻返回;否则time.sleep(min(slice_s, 剩余时间)),slice_s下限夹紧为0.01。 - 用于在长等待期间响应 UI 停止(以及任何将
stop_requested置位的逻辑)。
按顺序执行 steps 中每个子元组;每一步开始前若 stop_requested 则立即 return。
("w", sec) 使用 wait_interruptible,而非死睡眠。
| 首元素 | 含义 | 元组形状 |
|---|---|---|
"w" |
等待 | ("w", float秒) |
"c" |
点击 | ("c", x, y, button_str) 如 "left" |
"t" |
输入文本 | ("t", text_str) → actions.type_text |
"k" |
单键 | ("k", key_str) → actions.keyboard.key_press |
"D" |
键按下 | ("D", key_str) → actions.keyboard.key_down |
"U" |
键抬起 | ("U", key_str) → actions.keyboard.key_up |
"h" |
快捷键点击 | ("h", ("ctrl","s",...)) → actions.shortcut(*keys) |
"H" |
单键长按 | ("H", key_str, duration_sec) → actions.keyboard.hold_key |
"M" |
组合键长按 | ("M", ("shift","w",...), duration_sec)(按下组合→等待→释放) |
"m" |
鼠标绝对坐标 | ("m", x, y) → mouse.move_to(x, y, smooth=False)(轨迹录制用,关闭贝塞尔曲线) |
"Bd" |
鼠标键按下 | ("Bd", button, x, y) → 先 move_to 再 mouse_down(button) |
"Bu" |
鼠标键抬起 | ("Bu", button, x, y) → 先 move_to 再 mouse_up(button) |
"s" |
滚轮 | ("s", amount_int, "vertical" | "horizontal") → **actions.mouse.scroll`** |
录制源码生成见 utils.input_recorder.events_to_tick_source;当前实现优先生成 D/U 以精确复现按键按住与交叠时序,必要时补充 h/H/M。生成代码末尾常会追加 ctx.finish() 以便队列进入下一项。type_text 执行过程中一般不在字符间隙检查停止,停止多在步骤边界生效。
同步/异步最终都会构造 Event(event_type, payload, source),处理器接收的 event 含:
| 属性 | 说明 |
|---|---|
event.type |
事件类型字符串 |
event.payload |
任意负载 |
event.source |
来源字符串,默认 "" |
event.timestamp |
创建时间(time.time()) |
| 方法 | 说明 |
|---|---|
emit(event_type, payload=None, source="") |
事件入队,由 EventBus 后台线程 _loop 中 _dispatch |
emit_sync(event_type, payload=None, source="") |
当前线程立即 _dispatch,顺序调用全部订阅者 |
on(event_type, handler) |
注册 Callable[[Event], None] |
off(event_type, handler) |
注销;handler 需为同一对象引用 |
队列满:emit 在队列满时会丢弃事件并打日志,不阻塞脚本。
引擎侧:EventBus 在 Engine.start() 时已 start();脚本内通常不要再 stop 总线。
WorldState 为 dataclass(core/world_state.py),脚本可读写下列字段(线程上 UI 命令通过锁更新 ui_command / ui_payload)。
| 字段 | 类型 | 说明 |
|---|---|---|
script_manifest_path |
Optional[Path] |
当前加载的清单路径 |
pause |
bool |
暂停时引擎不调用 tick(ctx) |
stop_requested |
bool |
为真时主循环与脚本 tick 均停止 |
target_fps |
float |
主循环目标帧率(与清单 fps 同步) |
ui_command / ui_payload |
str / dict |
最近一次 UI 命令(见 set_ui_command / consume_ui_command) |
manifest |
Optional[ScriptManifest] |
运行时模块 init 后填入 |
extras |
dict |
脚本间或跨模块共享的扩展字典 |
set_ui_command(cmd, payload=None):写命令与负载(带锁)。consume_ui_command() -> tuple[str, dict]:读取并清空当前命令。
ScriptRuntimeModule.tick 在每帧调用用户 tick 之前会执行 state.consume_ui_command(),若脚本需要在本帧处理 UI 命令,应依赖 tick 返回前已被消费 的设计,或通过 EventBus 自行订阅(取决于你的 UI 实现)。
类型 ActionExecutor(executor/actions.py)。构造参数 human_like 默认为 True:navigate_click、click_at 间会通过 _human_delay 插入随机短延迟;False 时间更短(仍有一定最小间隔)。
| 方法 | 说明 |
|---|---|
click_at(x, y, button="left", random_offset=0, clicks=1) |
坐标点击;random_offset>0 时坐标随机偏移 |
click_region(region, button="left", clicks=1) |
region=(left,top,right,bottom) 内随机点点击 |
navigate_click(x, y, pre_delay=0.0, post_delay=0.0) |
移动到位后点击 |
drag_between(x1,y1,x2,y2, button="left") |
拖拽 |
| 方法 | 说明 |
|---|---|
shortcut(*keys) |
如 shortcut("ctrl","s") → keyboard.hotkey |
type_text(text, interval=None) |
透传 keyboard.typewrite |
顺序执行。支持 type 键:move、click、drag、scroll、key、hotkey、type(注意与 Python 关键字同名,JSON 里为字符串 "type")、wait、hold。
type |
主要字段 |
|---|---|
move |
x, y |
click |
可选 button, x, y, clicks |
drag |
x, y,可选 button |
scroll |
amount,可选 direction(默认 vertical) |
key |
key,可选 presses |
hotkey |
keys(列表或序列,由实现 hotkey(*action["keys"]) 使用) |
type |
text,可选 interval |
wait |
duration |
hold |
key,可选 duration |
未知 type 会打 warning 并跳过。
| 方法 | 说明 |
|---|---|
wait(seconds) |
time.sleep,不可被 stop_requested 打断 |
wait_for(predicate, timeout=5.0, interval=0.1) -> bool |
轮询 predicate(),超时返回 False |
| 属性 | 说明 |
|---|---|
ctx.actions.mouse |
MouseController:move_to、click、drag_to、scroll 等 |
ctx.actions.keyboard |
KeyboardController:key_press、hotkey、typewrite、hold_key 等 |
需要更短延迟或细粒度控制时,可优先用底层 API 并自行控制间隔。
ScriptManifest(core/script_manifest.py)主要字段:
| 属性 | 说明 |
|---|---|
project_root |
清单所在项目目录(绝对路径) |
manifest_path |
清单文件路径,可为 None |
name / script_version / description / authors |
元数据 |
entry |
入口文件相对路径 |
entry_path |
project_root / entry 的绝对路径 |
library |
额外 library 目录相对路径列表(解析后在 sys.path 前插) |
fps |
建议帧率 |
capture |
CaptureSection |
perception |
PerceptionSection |
ui |
自定义 UI 配置字典 |
raw |
原始解析字典(JSON/YAML 全文) |
| 字段 | 默认 | 说明 |
|---|---|---|
mode |
"window" |
window / screen |
title_pattern |
None |
窗口标题匹配 |
hwnd |
0 |
窗口句柄 |
auto_fix_win11_bitblt |
False |
Win11 BitBlt 兼容 |
| 字段 | 默认 | 说明 |
|---|---|---|
use_pipeline |
False |
是否启用感知流水线 |
register_ui_recognizer |
False |
是否注册 UIRecognizer |
ocr_lang |
"ch" |
PaddleOCR 语言 |
定义于 core/visionscript_events.py:
| 常量 | 值 | 方向 / 用途 |
|---|---|---|
UI_COMMAND |
ui.command |
UI → 运行时:暂停/恢复/停止等 |
UI_LOG |
ui.log |
核心/脚本 → UI:日志行 |
UI_STATE |
ui.state |
状态同步 |
UI_SCRIPT |
ui.script |
emit_ui / emit_ui_sync 使用 |
UI_ERROR |
ui.error |
用户脚本异常(由 ScriptHost 同步发出) |
UI_SCRIPT_LOADED |
ui.script_loaded |
清单加载完成信息 |
UI_COMMAND 的 payload 建议格式见源码注释:{"cmd": "pause"|"resume"|"stop", ...}。
import time
from pathlib import Path
import numpy as np
from PIL import Image
TARGET_IMAGE = "target.png"
MATCH_THRESHOLD = 0.75
_state = {"ro": None, "retries": 0, "done": False}
def _load_bgr(path: Path):
with Image.open(path) as im:
rgb = np.asarray(im.convert("RGB"), dtype=np.uint8)
return rgb[:, :, ::-1].copy()
def tick(ctx):
if _state["done"]:
return
if _state["ro"] is None:
target_path = Path(ctx.manifest.project_root) / TARGET_IMAGE
template_bgr = _load_bgr(target_path)
_state["ro"] = ctx.make_template_match_ro(
template_bgr,
threshold=MATCH_THRESHOLD,
use_3_channels=True,
name="target",
)
frame = ctx.capture_frame()
if frame is None:
time.sleep(0.5)
return
result = ctx.run_recognition(frame, _state["ro"])
if result.success and result.template_hits:
cx, cy = result.template_hits[0].center
ctx.log(f"找到目标,位置: ({cx}, {cy})")
ctx.actions.click_at(cx, cy, clicks=2)
_state["done"] = True
ctx.finish()
else:
_state["retries"] += 1
ctx.log(f"未找到,重试 {_state['retries']}")
time.sleep(0.5)def tick(ctx):
a = ctx.actions
a.click_at(400, 300, random_offset=2)
a.shortcut("ctrl", "c")
a.type_text("hello", interval=0.05)
a.combo_action([
{"type": "move", "x": 200, "y": 200},
{"type": "click"},
{"type": "wait", "duration": 0.3},
{"type": "key", "key": "esc"},
])
ctx.emit_ui("my_event", status="ok")
ctx.log("动作执行完毕", "info")- 清单中的 capture / fps:JSON 使用
visionscript(或兼容vhsr)嵌套capture、fps、perception;根级若另有同名键,以加载器实现为准(参见load_script_manifest)。 - 中文或空格路径读图:避免依赖
cv2.imread;可用np.fromfile+cv2.imdecode或 PIL 读入再转 BGRnumpy。 - 懒加载:首次
capture_frame、perception_pipeline、run_recognition可能加载较重依赖;建议在循环外复用RecognitionObject。 - 跨
tick状态:模块全局变量或ctx.state.extras;多脚本间共享用extras需注意生命周期。 - 停止脚本:
ctx.finish()、ctx.state.stop_requested = True、或return False(字面量)。 - 暂停与停止:
pause跳过tick;stop_requested结束引擎。wait_interruptible与run_recorded_ops内的stop_requested检查在长逻辑内部仍有用。 ctx.actions.human_like:默认人性化延迟;追求极限响应时可使用mouse/keyboard并自控间隔。ctx.log的级别:未知字符串在内部 logger 侧按 info 数值处理;UI 侧仍收到原始level字符串(取决于订阅实现)。
更多运行时与 EventBus 总览见 core.md;脚本队列行为见 script_queue.md。