非 ASCII 字符走 char code 构造绕开智能引号解析陷阱
This commit is contained in:
parent
143fcae34a
commit
1ff6f59990
@ -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();
|
||||
|
||||
@ -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" });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user