From 1ff6f59990e581a551bf0f87b2a90bdb04aecc44 Mon Sep 17 00:00:00 2001 From: yu <191972707@qq.com> Date: Wed, 4 Nov 2026 09:36:45 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9D=9E=20ASCII=20=E5=AD=97=E7=AC=A6=E8=B5=B0?= =?UTF-8?q?=20char=20code=20=E6=9E=84=E9=80=A0=E7=BB=95=E5=BC=80=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E5=BC=95=E5=8F=B7=E8=A7=A3=E6=9E=90=E9=99=B7=E9=98=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/capabilities/desktop.ts | 24 ++++++++++++++----- .../capabilities/keyboard-send-smoke.test.ts | 7 ++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/main/capabilities/desktop.ts b/src/main/capabilities/desktop.ts index 6316e37..ae3b614 100644 --- a/src/main/capabilities/desktop.ts +++ b/src/main/capabilities/desktop.ts @@ -140,6 +140,16 @@ function sendKeysEscape(ch: string): string { return "+^%~(){}[]".includes(ch) ? `{${ch}}` : ch; } +/** + * 把字符包装成 PowerShell 安全字面量。 + * ASCII 直接用单引号字符串(撇号内部 '' 转义);非 ASCII 用 [char]0xXXXX 数值构造—— + * Windows PowerShell 5.1 会把 ‘ ’ “ ” 等智能引号当作引号变体解析,直接放进字符串字面量会报「字符串缺少终止符」。 + */ +function psCharLiteral(text: string): string { + if (/^[\x20-\x7E]*$/.test(text)) return psString(text); + return Array.from(text).map((c) => `[char]0x${c.codePointAt(0)!.toString(16).padStart(4, "0")}`).join("+") || psString(""); +} + const keyboardSend: CapabilityHandler = async (_ctx, node, args) => { // 字段: words=输入内容(键盘输入), keys/key=按键组合(按键系列), interval=输入间隔(V1毫秒/基础版秒), fuctype=输入方式(0后台接口/1人工模拟/2剪贴板粘贴), window_title=输入目标窗口(留空=当前焦点窗口) const keys = text(args, ["words", "keys", "key", "text", "value"]); @@ -156,18 +166,20 @@ const keyboardSend: CapabilityHandler = async (_ctx, node, args) => { // 三种输入方式:脚本尽量简单,转义逻辑放 JS 侧,避免 PowerShell 字符串拼接的语法陷阱 let send: string; if (mode === "2") { - // 剪贴板粘贴:原文进剪贴板 + Ctrl+V,不做 SendKeys 转义 - send = `Set-Clipboard -Value ${psString(keys)}; Start-Sleep -Milliseconds 120; [System.Windows.Forms.SendKeys]::SendWait('^v')`; + // 剪贴板粘贴:原文进剪贴板 + Ctrl+V,不做 SendKeys 转义;内容含智能引号等非 ASCII 时同样走 [char] 构造 + const contentExpr = /^[\x20-\x7E]*$/.test(keys) ? psString(keys) : `(-join @(${Array.from(keys).map((c) => psCharLiteral(c)).join(",")}))`; + send = `Set-Clipboard -Value ${contentExpr}; Start-Sleep -Milliseconds 120; [System.Windows.Forms.SendKeys]::SendWait('^v')`; } else if (mode === "1" && isTextSend) { // 人工模拟:逐字符;JS 侧把每个字符转义成 SendKeys 字面量,PS 侧只做数组循环 - // 数组元素必须用 psString 统一包裹转义(先包 '' 再转义内部引号,顺序反了会产生 ''' 未闭合字符串) + // 数组元素必须用 psCharLiteral:ASCII 走引号字符串,非 ASCII 走 [char]0xXXXX(避开 PS5.1 智能引号解析陷阱) const escapedChars = Array.from(keys).map((ch) => sendKeysEscape(ch)); - const arr = escapedChars.map((c) => psString(c)).join(","); - send = `$chars = @(${arr}); foreach ($c in $chars) { [System.Windows.Forms.SendKeys]::SendWait($c); Start-Sleep -Milliseconds ${intervalMs} }`; + const arr = escapedChars.map((c) => psCharLiteral(c)).join(","); + send = `$chars = @(${arr}); foreach ($c in $chars) { [System.Windows.Forms.SendKeys]::SendWait([string]$c); Start-Sleep -Milliseconds ${intervalMs} }`; } else { // 后台接口 / 按键组合 / 人工模拟(按键组合组件):整段发送,文本特殊字符转义 const escaped = isTextSend ? Array.from(keys).map(sendKeysEscape).join("") : keys; - send = `[System.Windows.Forms.SendKeys]::SendWait(${psString(escaped)})`; + const contentExpr = /^[\x20-\x7E]*$/.test(escaped) ? psString(escaped) : `(-join @(${Array.from(escaped).map((c) => psCharLiteral(c)).join(",")}))`; + send = `[System.Windows.Forms.SendKeys]::SendWait(${contentExpr})`; } await powershell(`${USER32}; ${activate}Add-Type -AssemblyName System.Windows.Forms; ${send}`); await manualDelay(); diff --git a/src/main/capabilities/keyboard-send-smoke.test.ts b/src/main/capabilities/keyboard-send-smoke.test.ts index a1d3869..78c3215 100644 --- a/src/main/capabilities/keyboard-send-smoke.test.ts +++ b/src/main/capabilities/keyboard-send-smoke.test.ts @@ -38,6 +38,13 @@ describe("键盘输入组件真实冒烟", () => { console.log("[键盘输入] 人工模拟+撇号+特殊字符 ✓:", out); }, 60000); + it("人工模拟模式含中文标点(用户 09:32 踩坑场景:】【‘;。/ 智能引号)不抛语法错", async () => { + const words = "jashfjksudfgisa54445哈哈哈哈AAAAHHBHG+t】【‘;。/"; + const out = await invoke("Keyboard_Send_V1", { words, interval: "10", fuctype: "1" }); + expect(out).toBe(words); + console.log("[键盘输入] 人工模拟+中文标点+智能引号 ✓"); + }, 60000); + it("剪切板粘贴模式: 原文进入剪贴板并发送 Ctrl+V", async () => { const content = `粘贴${Date.now()}`; const out = await invoke("Keyboard_Send_V1", { words: content, fuctype: "2" });