feat(engine): createEngine 注入参数 + 消除模块级 driver 捕获(迁移阶段1-A1)

- createEngine(options) 支持 driver 注入,新增 engine.setDriver;
  缺省保持按平台自动选择的行为
- desktop/common-final/system-extended/window-extended 四文件模块加载时
  捕获 defaultEngine.driver 改为惰性 getDriver():非 win32 import 不再抛错
  (此前 darwin 上 import 即炸),调用时才触发 platform_unsupported
- engine-driver.test 补注入/隔离/后置替换 4 例
This commit is contained in:
yu committed 2026-11-06 10:20:29 +08:00
1 parent 9b76dc6987
commit 1da00827ac
7 files changed
+111 -48

No files matched your search

@@ -4,7 +4,7 @@ import { getHostBridge } from "../engine/host-bridge";
import { defaultEngine } from "../engine/engine";
// 桌面自动化驱动(任务 3.3):窗口矩形/鼠标注入原语统一走 WindowsDriver
const driver = defaultEngine.driver;
const getDriver = () => defaultEngine.driver;
function value(args: Record<string, unknown>, keys: string[], fallback = ""): string {
for (const key of keys) {
@@ -77,17 +77,17 @@ function physicalToDip(x: number, y: number): [number, number] {
return [Math.round(x), Math.round(y)];
}
const getWindow: CapabilityHandler = async (_ctx, node, args) => driver.window.findByTitle(requiredTitle(args, node.id, node.componentId));
const getWindow: CapabilityHandler = async (_ctx, node, args) => getDriver().window.findByTitle(requiredTitle(args, node.id, node.componentId));
register(["Window_Get", "Window_GetWindow", "Window_GetWindow_v1"], getWindow);
register("Window_ActiveWindow_v1", async (_ctx, node, args) => {
const title = requiredTitle(args, node.id, node.componentId);
const maximize = [true, 1, "1", "true", "True"].includes(args.isMax as never);
return driver.window.activate(title, { maximize });
return getDriver().window.activate(title, { maximize });
});
register(["Window_GetWindowMessage", "Window_GetWindowMessage_v1"], async (_ctx, node, args) => {
const object = await driver.window.findByTitle(requiredTitle(args, node.id, node.componentId));
const object = await getDriver().window.findByTitle(requiredTitle(args, node.id, node.componentId));
const type = value(args, ["switchType"], "all").toLowerCase();
if (type === "title") return object.title;
if (type === "pid") return object.pid;
@@ -98,7 +98,7 @@ register(["Window_GetWindowMessage", "Window_GetWindowMessage_v1"], async (_ctx,
register(["Window_SetPos", "Window_MoveWindow", "Window_MoveWindow_v1", "Window_SizeWindow"], async (_ctx, node, args) => {
const title = requiredTitle(args, node.id, node.componentId);
const current = await driver.window.findByTitle(title);
const current = await getDriver().window.findByTitle(title);
const moveOnly = node.componentId.includes("MoveWindow");
const sizeOnly = node.componentId === "Window_SizeWindow";
const position = args.location !== undefined ? parsePoint(args.location, "窗口位置", node.id, node.componentId) : [Number(args.x ?? current.x), Number(args.y ?? current.y)] as [number, number];
@@ -109,7 +109,7 @@ register(["Window_SetPos", "Window_MoveWindow", "Window_MoveWindow_v1", "Window_
const width = moveOnly ? Number(current.width) : size[0];
const height = moveOnly ? Number(current.height) : size[1];
if (!(width > 0 && height > 0)) throw new RuntimeError("validation_error", "窗口尺寸必须大于 0", { nodeId: node.id, componentId: node.componentId });
return driver.window.setPos(title, { x, y, width, height });
return getDriver().window.setPos(title, { x, y, width, height });
});
const moveMouse: CapabilityHandler = async (_ctx, node, args) => {
@@ -122,7 +122,7 @@ const moveMouse: CapabilityHandler = async (_ctx, node, args) => {
let dipTarget: [number, number];
if (relative) {
// 相对激活窗口左上角:窗口矩形是物理像素,换回 DIP 再叠加偏移,最后统一转物理
const { x: wx, y: wy } = await driver.window.foregroundPosition();
const { x: wx, y: wy } = await getDriver().window.foregroundPosition();
if (!Number.isFinite(wx) || !Number.isFinite(wy)) throw new RuntimeError("browser_error", "无法获取激活窗口位置", { nodeId: node.id, componentId: node.componentId });
const [dipWx, dipWy] = physicalToDip(wx, wy);
dipTarget = [dipWx + rawX, dipWy + rawY];
@@ -131,10 +131,10 @@ const moveMouse: CapabilityHandler = async (_ctx, node, args) => {
}
const [tx, ty] = dipToPhysical(dipTarget[0], dipTarget[1]);
if (moveType === "2") {
await driver.mouse.moveTo({ x: tx, y: ty });
await getDriver().mouse.moveTo({ x: tx, y: ty });
} else {
// 平滑移动:从当前光标位置出发,按速度插值(路径全程物理像素,与目标同一坐标系)
await driver.mouse.moveSmooth({ x: tx, y: ty }, { ease: moveType === "0", speed });
await getDriver().mouse.moveSmooth({ x: tx, y: ty }, { ease: moveType === "0", speed });
}
return { x: Math.round(dipTarget[0]), y: Math.round(dipTarget[1]) };
};
@@ -147,7 +147,7 @@ const dragMouse: CapabilityHandler = async (_ctx, node, args) => {
const [epx, epy] = dipToPhysical(ex, ey);
const right = ["1", "right"].includes(value(args, ["side"], "0").toLowerCase());
// 旧实现按下后停 80ms、拖到终点立即松开(与桌面版 Window_Mouse 不同,松开前不停顿)
await driver.mouse.drag({ x: spx, y: spy }, { x: epx, y: epy }, { button: right ? "right" : "left", holdMs: 80, releaseDelayMs: 0 });
await getDriver().mouse.drag({ x: spx, y: spy }, { x: epx, y: epy }, { button: right ? "right" : "left", holdMs: 80, releaseDelayMs: 0 });
return { start: [Math.round(sx), Math.round(sy)], end: [Math.round(ex), Math.round(ey)] };
};
register(["Mouse_DragToV1", "Mouse_DragToV2", "Mouse_DragToNew"], dragMouse);
@@ -159,6 +159,6 @@ register(["Mouse_ClickCombine", "Mouse_ClickCombine_v1", "Mouse_ClickCombine_v2"
const right = value(args, ["click_key"], "left").toLowerCase() === "right";
const doubleClick = value(args, ["click_time"], "click").toLowerCase().includes("double");
// 旧实现每次 down-up 之后停 80ms
await driver.mouse.click({ x: px, y: py }, { button: right ? "right" : "left", double: doubleClick, settleMs: 80 });
await getDriver().mouse.click({ x: px, y: py }, { button: right ? "right" : "left", double: doubleClick, settleMs: 80 });
return { x: Math.round(x), y: Math.round(y), button: right ? "right" : "left", clicks: doubleClick ? 2 : 1 };
});