diff --git a/data/xaction/catalog.json b/data/xaction/catalog.json index d5756f3..14f1cbb 100644 --- a/data/xaction/catalog.json +++ b/data/xaction/catalog.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, - "generatedAt": "2026-08-12 20:29:09", - "moduleCount": 149, + "generatedAt": "2026-08-13 19:01:10", + "moduleCount": 150, "legacyMappedModuleCount": 143, "migratedLegacyModuleCount": 137, "categories": [ @@ -63,7 +63,7 @@ { "key": "Input", "name": "键鼠输入", - "moduleCount": 1 + "moduleCount": 2 } ], "modules": [ @@ -28712,6 +28712,104 @@ } }, "sourceFileName": "sys_aiChat_AI 交互对话.md" + }, + { + "key": "sys:automationScript", + "slug": "automationscript", + "legacySlug": "automationscript", + "ownsLegacyContent": true, + "name": "自动化脚本", + "description": "使用 JavaScript 编排鼠标、键盘等桌面自动化操作。", + "category": "Input", + "categoryName": "键鼠输入", + "stepType": "Action", + "isRisky": true, + "isProOnly": false, + "helpLink": "", + "inputs": [ + { + "key": "script", + "name": "脚本内容", + "type": "Text", + "defaultValue": "import { mouse, key } from \"quicker\";\n\nmouse.moveTo(100, 200);\nmouse.click();\nkey.press(\"enter\");\n\nexport default mouse.position();", + "required": true, + "variableMode": "Input", + "condition": "", + "description": "要执行的桌面自动化 JavaScript。可使用 export default 导出结果。" + }, + { + "key": "input", + "name": "输入", + "type": "Any", + "defaultValue": "", + "required": false, + "variableMode": "UseVarOrInput", + "condition": "", + "description": "传入脚本的受支持数据。脚本可从 quicker 模块导入 input 读取。" + }, + { + "key": "timeoutMs", + "name": "超时时间(毫秒)", + "type": "Integer", + "defaultValue": "30000", + "required": false, + "variableMode": "Input", + "condition": "", + "description": "脚本最长运行时间,范围 100 到 120000 毫秒。" + }, + { + "key": "restoreMousePosition", + "name": "结束后恢复鼠标位置", + "type": "Boolean", + "defaultValue": "false", + "required": false, + "variableMode": "Input", + "condition": "", + "description": "脚本正常结束或失败时恢复开始前的鼠标位置;用户接管或主动取消时不恢复。" + }, + { + "key": "stopIfFail", + "name": "失败后停止", + "type": "Boolean", + "defaultValue": "true", + "required": false, + "variableMode": "Input", + "condition": "", + "description": "失败后是否停止动作" + } + ], + "outputs": [ + { + "key": "isSuccess", + "name": "是否成功", + "type": "Boolean", + "condition": "", + "description": "操作是否成功" + }, + { + "key": "result", + "name": "结果", + "type": "Any", + "condition": "", + "description": "脚本 export default 导出的受支持值。" + }, + { + "key": "errorCode", + "name": "错误码", + "type": "Text", + "condition": "", + "description": "稳定的机器可读错误码。" + }, + { + "key": "errMessage", + "name": "错误消息", + "type": "Text", + "condition": "", + "description": "脚本执行失败时的错误消息。" + } + ], + "selections": {}, + "sourceFileName": "sys_automationScript_自动化脚本.md" } ] } diff --git a/data/xaction/changes.json b/data/xaction/changes.json index 6cacf2b..ee019d5 100644 --- a/data/xaction/changes.json +++ b/data/xaction/changes.json @@ -1,43 +1,19 @@ { "schemaVersion": 1, "baselineCreated": false, - "fromGeneratedAt": "2026-08-03 20:08:03", - "toGeneratedAt": "2026-08-12 20:29:09", + "fromGeneratedAt": "2026-08-12 20:29:09", + "toGeneratedAt": "2026-08-13 19:01:10", "summary": { - "addedModules": 5, + "addedModules": 1, "removedModules": 0, "changedModules": 0 }, "addedModules": [ { - "key": "sys:aiText", - "name": "AI 文本处理", - "slug": "ai-text", - "category": "Text" - }, - { - "key": "sys:aiVision", - "name": "AI 图片理解", - "slug": "ai-vision", - "category": "Image" - }, - { - "key": "sys:aiClassify", - "name": "AI 文本分类", - "slug": "ai-classify", - "category": "Text" - }, - { - "key": "sys:aiExtract", - "name": "AI 结构化提取", - "slug": "ai-extract", - "category": "Text" - }, - { - "key": "sys:aiChat", - "name": "AI 交互对话", - "slug": "ai-chat", - "category": "Network" + "key": "sys:automationScript", + "name": "自动化脚本", + "slug": "automationscript", + "category": "Input" } ], "removedModules": [], diff --git a/data/xaction/modules/sys_automationScript.json b/data/xaction/modules/sys_automationScript.json new file mode 100644 index 0000000..1fe5682 --- /dev/null +++ b/data/xaction/modules/sys_automationScript.json @@ -0,0 +1,98 @@ +{ + "key": "sys:automationScript", + "slug": "automationscript", + "legacySlug": "automationscript", + "ownsLegacyContent": true, + "name": "自动化脚本", + "description": "使用 JavaScript 编排鼠标、键盘等桌面自动化操作。", + "category": "Input", + "categoryName": "键鼠输入", + "stepType": "Action", + "isRisky": true, + "isProOnly": false, + "helpLink": "", + "inputs": [ + { + "key": "script", + "name": "脚本内容", + "type": "Text", + "defaultValue": "import { mouse, key } from \"quicker\";\n\nmouse.moveTo(100, 200);\nmouse.click();\nkey.press(\"enter\");\n\nexport default mouse.position();", + "required": true, + "variableMode": "Input", + "condition": "", + "description": "要执行的桌面自动化 JavaScript。可使用 export default 导出结果。" + }, + { + "key": "input", + "name": "输入", + "type": "Any", + "defaultValue": "", + "required": false, + "variableMode": "UseVarOrInput", + "condition": "", + "description": "传入脚本的受支持数据。脚本可从 quicker 模块导入 input 读取。" + }, + { + "key": "timeoutMs", + "name": "超时时间(毫秒)", + "type": "Integer", + "defaultValue": "30000", + "required": false, + "variableMode": "Input", + "condition": "", + "description": "脚本最长运行时间,范围 100 到 120000 毫秒。" + }, + { + "key": "restoreMousePosition", + "name": "结束后恢复鼠标位置", + "type": "Boolean", + "defaultValue": "false", + "required": false, + "variableMode": "Input", + "condition": "", + "description": "脚本正常结束或失败时恢复开始前的鼠标位置;用户接管或主动取消时不恢复。" + }, + { + "key": "stopIfFail", + "name": "失败后停止", + "type": "Boolean", + "defaultValue": "true", + "required": false, + "variableMode": "Input", + "condition": "", + "description": "失败后是否停止动作" + } + ], + "outputs": [ + { + "key": "isSuccess", + "name": "是否成功", + "type": "Boolean", + "condition": "", + "description": "操作是否成功" + }, + { + "key": "result", + "name": "结果", + "type": "Any", + "condition": "", + "description": "脚本 export default 导出的受支持值。" + }, + { + "key": "errorCode", + "name": "错误码", + "type": "Text", + "condition": "", + "description": "稳定的机器可读错误码。" + }, + { + "key": "errMessage", + "name": "错误消息", + "type": "Text", + "condition": "", + "description": "脚本执行失败时的错误消息。" + } + ], + "selections": {}, + "sourceFileName": "sys_automationScript_自动化脚本.md" +} diff --git a/data/xaction/param-file-ext.ts b/data/xaction/param-file-ext.ts index ea5335d..17887db 100644 --- a/data/xaction/param-file-ext.ts +++ b/data/xaction/param-file-ext.ts @@ -7,6 +7,7 @@ */ export const PARAM_FILE_EXT: Readonly>>> = { 'sys:jsscript': {script: '.js'}, + 'sys:automationScript': {script: '.js'}, 'sys:csscript': { script: '.cs', scriptForLp: '.cs', diff --git a/docs/v2/xaction/index.md b/docs/v2/xaction/index.md index 31ca80a..99c31a1 100644 --- a/docs/v2/xaction/index.md +++ b/docs/v2/xaction/index.md @@ -15,20 +15,20 @@ hide_table_of_contents: true 第一次编写请从 [怎样学会组合动作](/v2/xaction/guides/how-to-learn) 开始。 diff --git a/docs/v2/xaction/modules/basic/mouse.md b/docs/v2/xaction/modules/basic/mouse.md index 45d1dd0..30b66d0 100644 --- a/docs/v2/xaction/modules/basic/mouse.md +++ b/docs/v2/xaction/modules/basic/mouse.md @@ -284,6 +284,11 @@ legacyContentUpdatedAt: "2025-01-20T02:00:01.000Z" + +## 快速开始 + +在组合动作里添加 **自动化脚本**,把下面代码填入 **脚本内容**: + +```javascript +import { mouse } from "quicker"; + +mouse.moveTo(100, 200); +mouse.click(); + +export default mouse.position(); +``` + +脚本会把鼠标移到 `(100, 200)`,单击,然后把最终位置写入步骤的 **结果** 输出。 + + + +### 导入方式 + +`"quicker"` 是 Quicker 在内存中提供的模块,不是 npm 包或本地文件。当前提供 `mouse`、`key`、`screen`、`sleep`、`input` 五个命名导出。 + +按需导入: + +```javascript +import { mouse, key, screen, sleep, input } from "quicker"; +``` + +导入整个命名空间: + +```javascript +import * as qk from "quicker"; + +qk.mouse.click(100, 200); +qk.sleep(200); +``` + +也可以使用别名: + +```javascript +import { mouse as m } from "quicker"; + +m.click(100, 200); +``` + +下面两种写法不支持: + +```javascript +import quicker as qk from "quicker"; // 不是 JavaScript 语法 +import qk from "quicker"; // quicker 没有 default export +``` + +除全局 `console` 外,这些 API 不会自动变成全局变量;漏写 `import` 会运行失败。 + +## 坐标和点 + +坐标使用整个 Windows 虚拟桌面的物理像素:主屏左上角通常是 `(0, 0)`,左侧或上方的副屏可能出现负坐标。X 向右增大,Y 向下增大。 + +一个点可以用三种形式表示: + +```javascript +mouse.click(100, 200); +mouse.click([100, 200]); +mouse.click({ x: 100, y: 200 }); +``` + +:::caution `(x, y)` 不是 JavaScript 的坐标类型 + +```javascript +const p = (100, 200); // p 的值只有 200 +``` + +括号里的逗号是 JavaScript 的逗号表达式。需要保存一个点时,请写 `[100, 200]` 或 `{ x: 100, y: 200 }`。 + +::: + +坐标必须是有限数字,字符串 `"100"` 不会自动转成数字。输入时允许小数,执行前按 JavaScript `Math.round` 的规则归一化到整数像素。目标点必须落在某块实际显示器内,不能位于多屏之间的空白区域。 + +## 常用示例 + +### 循环点击一组坐标 + +```javascript +import { mouse, sleep } from "quicker"; + +const points = [ + [320, 240], + [520, 240], + [720, 240] +]; + +for (const [x, y] of points) { + mouse.click(x, y, { moveDurationMs: 100 }); + sleep(200); +} + +export default { + count: points.length, + last: mouse.position() +}; +``` + +### 使用步骤输入并批量点击 + +把一个词典或对象绑定到步骤的 **输入** 参数,例如: + +```json +{ + "offsetX": 10, + "offsetY": -5, + "points": [[320, 240], [520, 240], [720, 240]] +} +``` + +脚本中从 `input` 读取: + +```javascript +import { mouse, input } from "quicker"; + +const offsetX = input?.offsetX ?? 0; +const offsetY = input?.offsetY ?? 0; +const points = (input?.points ?? []).map(([x, y]) => [ + x + offsetX, + y + offsetY +]); + +export default mouse.clickAll(points, { + moveDurationMs: 100, + intervalMs: 200 +}); +``` + +`result` 将得到 `{ count, last }`,其中 `last` 是最后一次点击后的坐标。 + +### 按屏幕比例拖拽 + +```javascript +import { mouse, screen } from "quicker"; + +const start = screen.pointAt(0.25, 0.5); +const end = screen.pointAt(0.75, 0.5); + +export default mouse.drag(start, end, { + moveDurationMs: 150, + durationMs: 600 +}); +``` + +`screen.pointAt()` 默认以主屏为基准。比例 `0` 到 `1` 会映射到该屏幕内的有效像素。 + +### 在指定位置滚动 + +```javascript +import { mouse } from "quicker"; + +mouse.scroll(-3, { + at: [800, 500], + moveDurationMs: 100 +}); +``` + +正数向上滚,负数向下滚。首版只支持垂直滚轮。 + +### 执行热键并输入文本 + +```javascript +import { key, sleep } from "quicker"; + +key.hotkey(["ctrl", "shift"], "s"); +sleep(200); +key.type("报告.txt", { intervalMs: 30 }); +key.press("enter"); +``` + +`key.press()` 操作一个物理按键,`key.type()` 输入 Unicode 文本。输入中文等文本时使用 `key.type()`,不要逐个猜测对应的键盘布局。 + +### 组合键盘状态和鼠标操作 + +```javascript +import { key, mouse } from "quicker"; + +key.down("shift"); +try { + mouse.click(500, 300); +} finally { + key.up("shift"); +} +``` + +只有确实需要跨多次调用保持按键时才使用 `key.down()` / `key.up()`。普通单键和热键优先使用 `key.press()` / `key.hotkey()`,更不容易留下未释放的按键状态。 + +## `mouse` API + +除特别说明外,坐标操作成功后都返回最终位置 `{ x, y }`。 + +| API | 用途 | +| --- | --- | +| `mouse.position()` | 读取当前鼠标位置。 | +| `mouse.moveTo(x, y, options?)` | 移到绝对坐标。也可把点作为第一个参数。 | +| `mouse.moveBy(dx, dy, options?)` | 从当前位置按像素偏移。 | +| `mouse.click()` | 在当前位置单击逻辑主按钮。 | +| `mouse.click(options)` | 在当前位置按指定按钮单击。 | +| `mouse.click(x, y, options?)` | 移到指定点后单击;点也可写成数组或对象。 | +| `mouse.doubleClick(...)` | 与 `click` 使用相同的参数形式,执行双击。 | +| `mouse.clickAll(points, options?)` | 依次点击点数组,最多 100 个点;返回 `{ count, last }`。 | +| `mouse.scroll(verticalClicks, options?)` | 垂直滚动 `-120..120` click。 | +| `mouse.dragTo(x, y, options?)` | 从当前位置拖到目标点。 | +| `mouse.drag(from, to, options?)` | 先移到起点,再拖到终点。 | +| `mouse.budget()` | 查看本次运行剩余的写操作、按压和滚轮额度。 | + +### 移动选项 + +```javascript +{ + durationMs: 0 // 0..2000,0 表示直接移动 +} +``` + +适用于 `moveTo` 和 `moveBy`。 + +### 点击选项 + +```javascript +{ + button: "primary", // primary | secondary | middle + moveDurationMs: 0 // 0..2000 +} +``` + +`primary` 和 `secondary` 是 Windows 的逻辑主、次按钮,会遵循系统的左右键交换设置。默认使用 `primary`。 + +`clickAll` 还支持点击间隔: + +```javascript +{ + button: "primary", + moveDurationMs: 0, + intervalMs: 200 // 0..10000 +} +``` + +空点数组不会操作鼠标,返回 `{ count: 0, last: mouse.position() }`。 + +### 滚轮选项 + +```javascript +{ + at: [800, 500], // 可选;省略时在当前位置滚动 + moveDurationMs: 0 // 0..2000 +} +``` + +### 拖拽选项 + +```javascript +// dragTo +{ durationMs: 300 } // 50..2000 + +// drag +{ + moveDurationMs: 0, // 先移动到起点,0..2000 + durationMs: 300 // 拖拽过程,50..2000 +} +``` + +拖拽固定使用逻辑主按钮。首版没有独立的 `mouse.down()` / `mouse.up()`,脚本不能跨多次调用保持按钮按下,避免取消或异常后出现“卡键”。 + +传入未知选项、字符串数字或范围外的整数会返回 `INVALID_ARGUMENT`。 + +### 查询剩余额度 + +```javascript +const budget = mouse.budget(); + +console.log(budget.remainingWrites); +console.log(budget.remainingPresses); +console.log(budget.remainingWheelClicks); +``` + +额度由宿主固定,脚本不能提高。任一键鼠输入额度超限后,本次脚本的后续键鼠输入都会被禁用。 + +## `key` API + +| API | 用途 | +| --- | --- | +| `key.down(name)` | 按下一个支持的物理按键,并由本次脚本持有。 | +| `key.up(name)` | 释放本次脚本已持有的物理按键。 | +| `key.press(name, options?)` | 按下并释放一个物理按键。 | +| `key.hotkey(modifiers, name, options?)` | 依次按下修饰键和主键,再按相反顺序释放。修饰键数组最多 4 项。 | +| `key.type(text, options?)` | 向当前前台窗口输入 Unicode 文本;返回实际处理的字符或换行输入项数。 | +| `key.budget()` | 查看键盘剩余额度和本次脚本当前持有的按键数。 | + +### 按键名称 + +按键名称不区分大小写,使用一个封闭列表,不接受虚拟键码、扫描码或鼠标伪按键: + +- 字母 `a..z`、主键盘数字 `0..9` +- 功能键 `f1..f24`、数字键盘 `numpad0..numpad9` +- `backspace`、`tab`、`enter`、`numpadEnter`、`pause`、`escape`、`space` +- `pageUp`、`pageDown`、`end`、`home`、`left`、`up`、`right`、`down`、`insert`、`delete` +- `shift`、`ctrl`、`alt`、`leftShift`、`rightShift`、`leftCtrl`、`rightCtrl`、`leftAlt`、`rightAlt` +- `leftWin`、`rightWin`、`apps`、`printScreen` +- `capsLock`、`numLock`、`scrollLock` +- `numpadMultiply`、`numpadAdd`、`numpadSubtract`、`numpadDecimal`、`numpadDivide` + +还可以使用这些别名:`return` 等同于 `enter`,`esc` 等同于 `escape`,`control` 等同于 `ctrl`,`win` 等同于 `leftWin`,`leftControl` / `rightControl` 分别等同于 `leftCtrl` / `rightCtrl`。 + +通用修饰键名 `shift`、`ctrl`、`alt` 分别使用左侧物理按键,与 `leftShift`、`leftCtrl`、`leftAlt` 是同一个按键身份;需要右侧按键时请显式使用 `rightShift`、`rightCtrl`、`rightAlt`。 + +不在列表里的名称返回 `KEY_NOT_SUPPORTED`。`key.press("A")` 与 `key.press("a")` 都表示物理 A 键;它不会自动按住 Shift 来生成大写文本。需要输入字符时使用 `key.type("A")`。 + +### 按键和热键选项 + +`key.press()` 和 `key.hotkey()` 支持按住时长: + +```javascript +key.press("space", { holdMs: 100 }); +key.hotkey(["ctrl", "shift"], "s", { holdMs: 100 }); +``` + +`holdMs` 默认为 `0`,范围 `0..2000` 毫秒。热键的修饰键不能重复,主键也不能同时出现在修饰键数组中。 + +### 输入 Unicode 文本 + +```javascript +const count = key.type("你好,Quicker\n第二行", { + intervalMs: 20 +}); +``` + +`intervalMs` 默认为 `0`,范围 `0..1000` 毫秒。`\r\n`、`\r` 和 `\n` 都会作为一次 Enter 输入;其它控制字符和不完整的 Unicode 代理项会被拒绝。文本输入面向普通 Windows 文本控件,不等同于剪贴板粘贴,也不保证游戏、远程桌面或自定义输入控件都接受。 + +返回值按实际输入项计数:一个 Unicode 代理对(例如一个 emoji)算 1 项,任一种换行序列也算 1 项。键盘文本额度则按原字符串的 UTF-16 代码单元计数,因此一个 emoji 消耗 2 个额度,`\r\n` 也消耗 2 个额度。 + +### 原始按下和释放 + +`key.down()` 只能按下本次脚本尚未持有的键;重复按下返回 `KEY_ALREADY_HELD`。`key.up()` 只能释放本次脚本持有的键,否则返回 `KEY_NOT_HELD`。每次脚本最多同时持有 8 个键。 + +脚本正常结束、取消、超时或失败时,Quicker 都会按相反顺序尝试释放本次脚本仍持有的键。这个兜底不能撤销已经送出的输入,因此仍应使用 `try` / `finally` 尽早配对 `down()` 和 `up()`。如果脚本正常完成但宿主无法确认清理结果,步骤返回 `INPUT_CLEANUP_FAILED`;如果脚本已经失败、超时或取消,则保留原结果,并在运行日志中记录清理异常。 + +### 查询键盘剩余额度 + +```javascript +const budget = key.budget(); + +console.log(budget.remainingEdges); +console.log(budget.remainingTransactions); +console.log(budget.remainingTextCodeUnits); +console.log(budget.heldKeys); +``` + +一次 `down` 或 `up` 消耗一个按键边沿;一次 `press` 消耗两个。额度由宿主固定,脚本不能提高。 + +## `screen` API + +`screen` 是脚本开始时取得的只读屏幕快照: + +```javascript +import { screen } from "quicker"; + +console.log(screen.virtualBounds); +console.log(screen.primary); +console.log(screen.displays); +``` + +| 成员 | 说明 | +| --- | --- | +| `screen.virtualBounds` | 整个虚拟桌面的边界。 | +| `screen.primary` | 主显示器。 | +| `screen.displays` | 所有显示器数组。 | +| `screen.contains(x, y)` | 坐标归一化后是否落在某块显示器内;也接受点数组或对象。 | +| `screen.pointAt(ratioX, ratioY, displayIndex?)` | 按 `0..1` 比例取得屏幕内的点;默认使用主屏。 | + +边界和显示器对象包含: + +```text +index, deviceName, isPrimary, +left, top, right, bottom, +width, height, centerX, centerY +``` + +`right` 和 `bottom` 是不包含的边界。`screen.pointAt(1, 1)` 会返回屏幕内最后一个有效像素,不会返回边界外的点。 + +运行期间如果显示器布局发生变化,后续输入会停止并返回 `SCREEN_TOPOLOGY_CHANGED`。 + +## `sleep`、`console`、`input` 和结果 + +### 等待 + +```javascript +import { sleep } from "quicker"; + +sleep(500); // 0..10000 毫秒,可被取消 +``` + +自动化脚本是同步运行时,不支持 `await`。需要短暂停顿时使用 `sleep()`;等待和速率限制占用的时间都计入步骤超时。 + +### 日志 + +`console` 是全局对象,不需要从 `quicker` 导入: + +```javascript +console.log("位置", mouse.position()); +console.info("开始"); +console.warn("请检查目标窗口"); +console.error("自定义错误信息"); +``` + +日志进入组合动作运行日志。每次运行最多记录 100 条、总计 32,000 个字符;超过后丢弃后续日志并记录一次警告。 + +### 输入 + +`input` 来自步骤的 **输入** 参数,未提供时为 `null`。运行前 Quicker 会拍摄数据快照并递归冻结;修改 `input` 不会写回动作变量。 + +支持 `null`、布尔、文本、有限数字、数组和键为文本的普通对象。整数必须在 JavaScript 安全整数范围内;数据最多 16 层、10,000 个节点。图片、表格、函数、CLR 对象和循环引用等复杂值不支持。 + +### 输出结果 + +用 `export default` 把结果写到步骤的 **结果** 输出: + +```javascript +export default { + count: 3, + last: mouse.position() +}; +``` + +没有 `export default` 时,脚本仍可成功,但不会设置 `result`。显式导出 `null` 会得到一个真实的空值结果。 + +结果支持的数据形状与输入相同。Promise、函数、Symbol、BigInt、循环引用、对象内部的 `undefined` 等值会被拒绝。 + +## 步骤参数和输出 + +**脚本内容**:要执行的 ESM JavaScript。Quicker 不会把它当成动作表达式求值。 + +**输入**:可绑定动作变量,供脚本中的 `input` 读取。 + +**超时时间(毫秒)**:默认 `30000`,范围 `100..120000`。包括脚本计算、`sleep()`、平滑移动、按键保持、文本间隔和节流等待。 + +**结束后恢复鼠标位置**:正常结束、脚本错误或内部超时时,在输入清理状态可确认时尝试回到开始位置。用户接管或主动取消动作时不会强行恢复,以免把用户刚移动的鼠标拉走。 + +**失败后停止**:脚本失败时是否停止组合动作后续步骤。 + +输出包括: + +- **是否成功**(`isSuccess`) +- **结果**(`result`) +- **错误码**(`errorCode`) +- **错误消息**(`errMessage`) + +用户接管或主动停止属于“动作已取消”,不是普通的脚本失败,因此不保证产生普通失败输出。 + +## 权限、用户接管和输入安全 + +- Quicker 会先静态分析从 `"quicker"` 导入的能力。使用 `mouse`、`key` 或两者时,首次真实运行会分别请求鼠标、键盘或键鼠桌面自动化权限;权限确认前不会执行脚本或注入输入。 +- `import * as qk from "quicker"` 可以访问全部当前导出,因此会按鼠标和键盘两种能力请求权限。只想申请必要能力时请使用命名导入。 +- 授权绑定动作、脚本、超时、恢复位置选项和固定配额策略;这些内容变化后需要重新确认。 +- 授权只保存在当前账号的本机数据中,不随动作导出、分享、状态备份或同步到其它设备。 +- 锁屏、UAC / 安全桌面下不会注入输入。鼠标操作会核对目标坐标下的窗口,键盘操作会核对当前前台窗口;管理员权限或高完整性目标一律拒绝,其它权限高于 Quicker 或权限无法确认的目标也会被拒绝。 +- 启动时已经按住的动作触发键或鼠标按钮,需要在 1 秒内松开;新的按键、鼠标按钮或滚轮输入会立即由用户接管。 +- 真实鼠标在 200 毫秒内累计移动约 5 个物理像素也会接管;极小的传感器抖动不会立刻中止。 +- 如果已经配置 Quicker 的“停止运行中动作”全局热键,也可以用它取消正在执行的自动化脚本。 +- 用户接管、主动取消、超时、异常或部分注入失败后,Quicker 会停止剩余输入,并尽力释放本次脚本按下的鼠标按钮和键盘按键。 +- 已经发生的移动、点击、按键或文本输入不能回滚。失败只会阻止尚未执行的输入。 +- 同一时间只能运行一个已支持输入互斥的自动化;冲突时返回 `INPUT_BUSY`,不会排队。部分旧输入模块暂不受此机制约束。 + +## 运行限制 + +这些限制按每次步骤运行计算,脚本不能修改: + +| 项目 | 上限 | +| --- | ---: | +| 脚本源码 | 100 KiB UTF-8 | +| JavaScript 内存 | 64 MiB | +| 执行语句数 | 500,000 | +| 函数递归深度 | 64 | +| 语法树节点 / 深度 | 100,000 / 256 | +| 桌面写操作(鼠标 API 或键盘事务) | 512 | +| 单击、双击和拖拽的按压事务 | 100 | +| 点击 / 拖拽按压速率 | 每秒 5 次,短时突发 2 次 | +| 垂直滚轮累计 | 120 click | +| 滚轮速率 | 每秒 20 click,短时突发 6 click | +| 键盘按下 / 释放边沿 | 4,096 | +| 键盘事务 | 256 | +| 键盘事务速率 | 每秒 20 次,短时突发 8 次 | +| `key.type()` 文本 | 累计 2,000 个 UTF-16 代码单元 | +| 同时持有的按键 | 8 | +| `key.hotkey()` 修饰键 | 4 | +| 单次平滑移动或拖拽 | 最长 2 秒、最多 120 个采样 | +| 平滑移动采样率 | 最多 60 Hz | +| `clickAll` 点数 | 100 | +| 单次 `sleep` | 10 秒 | +| 日志 | 100 条、总计 32,000 字符 | + +双击消耗 2 次鼠标按压额度,拖拽消耗 1 次。每次键盘 API 调用消耗 1 个键盘事务;`down` / `up` 各消耗 1 个边沿,`press` 消耗 2 个。节流等待仍计入步骤的总超时。 + +## 首版不支持的能力 + +- `async` / `await`、Promise、`setTimeout` 和后台任务 +- 动态 `import()`、其它静态模块、`require()`、npm 和 Node.js 模块 +- `eval()`、`new Function()`、CLR、反射和程序集访问 +- HTTP、文件、进程、剪贴板、浏览器 DOM、动作变量写回和子程序调用 +- 独立 `mouse.down()` / `mouse.up()`、原始键码、扫描码和任意键盘布局映射 +- 录制回放、图片定位、窗口句柄和窗口相对坐标;当前尚未导出 `window` +- 水平滚轮、X1 / X2 按钮和任意点击次数 +- 游戏级、驱动级或硬实时鼠标轨迹 + +需要这些能力时,请组合使用对应的 Quicker 步骤,不要试图从脚本绕过限制。 + +## 常见错误和排障 + +| 错误码 | 处理方法 | +| --- | --- | +| `EMPTY_SCRIPT`、`JS_PARSE_ERROR` | 检查脚本是否为空、括号和引号是否配对。 | +| `IMPORT_NOT_ALLOWED` | 只从 `"quicker"` 做命名导入或命名空间导入,不要使用 default import。 | +| `ASYNC_NOT_SUPPORTED`、`UNSUPPORTED_SYNTAX`、`STRING_COMPILATION_DISABLED` | 删除异步、Promise、动态导入、命名导出、`eval` 或动态函数。 | +| `INVALID_ARGUMENT` | 检查坐标、整数范围、按钮名、热键数组、文本和选项字段;不要传字符串数字。 | +| `KEY_NOT_SUPPORTED` | 改用文档列出的封闭按键名称;不要传虚拟键码或扫描码。 | +| `KEY_ALREADY_HELD`、`KEY_NOT_HELD` | 检查 `key.down()` / `key.up()` 是否成对,并优先改用 `press()` 或 `hotkey()`。 | +| `UNSUPPORTED_VALUE` | 把输入或结果转换成简单值、数组和普通对象。 | +| `POINT_OUTSIDE_DISPLAY`、`INVALID_VIRTUAL_DESKTOP` | 确认坐标落在实际显示器内,并检查主屏和多屏布局。 | +| `SCREEN_TOPOLOGY_CHANGED` | 显示器布局在运行中改变;重新运行脚本。 | +| `TRUST_REQUIRED` | 安装或保存动作后重新运行,并在本机确认当前脚本的桌面控制权限。 | +| `PHYSICAL_INPUT_ACTIVE` | 松开触发动作时按住的键或鼠标按钮,再重新运行。 | +| `INPUT_BUSY` | 另一个已接入协调器的输入自动化正在运行;等待它结束。 | +| `INPUT_MONITOR_UNAVAILABLE` | Quicker 无法可靠监测用户接管;重新启动 Quicker 后再试。 | +| `WINDOWS_LOCKED`、`SECURE_DESKTOP`、`UNSAFE_DESKTOP` | 解锁 Windows,关闭 UAC / 安全桌面后再运行。 | +| `ELEVATED_TARGET_DENIED`、`TARGET_PERMISSION_UNKNOWN` | 管理员权限或高完整性目标一律不支持;其它目标也不能高于 Quicker,且必须能确认权限。 | +| `INPUT_LIMIT_EXCEEDED`、`LIMIT_EXCEEDED` | 减少点击、滚轮、按键、文本、循环、源码规模或复杂度。 | +| `TIMEOUT` | 减少工作量,或谨慎提高步骤的超时时间。 | +| `INPUT_INJECTION_FAILED`、`INPUT_OPERATION_FAILED`、`HOST_OPERATION_FAILED` | 输入未能完整发送;检查系统状态和目标窗口,再从安全位置重试。 | +| `INPUT_CLEANUP_FAILED` | Quicker 无法确认本次脚本持有的按键已完全释放;先人工松开相关按键并检查系统输入状态。 | +| `JS_RUNTIME_ERROR` | 查看 **错误消息** 和动作运行日志,定位普通 JavaScript 运行错误。 | + +## 相关链接 + + + +## 更新历史 + +- 2026-08-13 首次加入自动化脚本模块文档,提供受控的鼠标和键盘 API。 diff --git a/docs/v2/xaction/modules/input/inputscript.md b/docs/v2/xaction/modules/input/inputscript.md index a0a3cb1..7ea0452 100644 --- a/docs/v2/xaction/modules/input/inputscript.md +++ b/docs/v2/xaction/modules/input/inputscript.md @@ -90,6 +90,11 @@ legacyContentUpdatedAt: "2025-02-20T23:53:47.000Z"