SendKeys.Send 如何模拟 AltGr 或右侧 Alt 键?
SendKeys 没有独立的 AltGr 修饰符
SendKeys.Send 的字符串语法没有指定 AltGr 或区分左右 Alt 的修饰符。它支持 +、^、%,分别表示 Shift、Ctrl 和 Alt。%b 表示 Alt+B,无法用它明确指定右侧 Alt。SendKeys 文档
对于使用 AltGr 输入符号的 Windows 键盘布局,可以先尝试 Ctrl+Alt。如果目标窗口当前的布局确实将 AltGr+B 映射为 {,只需做一个小改动:
case '{':
return "^%b";
增加的 ^ 表示 Ctrl。这个组合请求的是 Ctrl+Alt+B,并非独立的右侧 Alt 按键事件。
为什么 Ctrl+Alt 可能有效
对于某些使用右侧 Alt 作为字符修饰键的布局,Windows 会在内部将其转换为 Ctrl+Alt。微软在 VkKeyScanExW 文档中说明了这种情况。VkKeyScanExW 文档
可以按以下顺序确认:
- 将焦点放到目标程序的文本编辑区域,确认当前启用的是预期的匈牙利语键盘布局。
- 手动按 AltGr+B,确认是否得到
{。 - 手动按 Ctrl+Alt+B,检查目标程序是否也得到
{。 - 如果两者都符合预期,再使用
SendKeys.Send("^%b")。
如果目标程序将 Ctrl+Alt+B 注册为快捷键,这种替代方式就不适用。原描述中的“激活粗体”只能说明出现了非预期操作,还无法确定具体是哪个快捷键或输入处理环节触发的。
只需要输入文本时,先尝试发送转义后的字符
如果程序的目标是输出 TextBox 中的文本,可以先移除手写的键盘组合映射,改为传入字符,并对 SendKeys 的特殊语法进行转义。例如:
SendKeys.Send("{{}"); // {
SendKeys.Send("{}}"); // }
SendKeys.Send("{+}"); // +
这会请求输入相应字符,实际结果仍需在目标键盘布局和应用中确认。SendKeys 文档也提醒,多种国际键盘布局下的行为可能不一致。字符转义与键盘布局说明
可以用下面的方法替换原来的 charToKeystroke:
private string charToKeystroke(char c)
{
switch (c)
{
case '\n':
return "{ENTER}";
case '\r':
return "";
case '\t':
return "{TAB}";
case '+':
case '^':
case '%':
case '~':
case '(':
case ')':
case '[':
case ']':
case '{':
case '}':
return "{" + c + "}";
default:
return c.ToString();
}
}
示例将 \n 转为 Enter,并忽略 \r,避免 Windows 的 \r\n 产生两次 Enter。如果输入可能包含单独的 \r,应先统一换行格式。
原代码中的 {PLUS}、{MINUS} 也应调整:输入文本加号时使用 {+},减号可以直接使用 -;需要数字小键盘按键时,对应名称是 {ADD} 和 {SUBTRACT}。空格直接返回 " " 即可。支持的按键名称
必须模拟右侧 Alt 时,使用 SendInput
如果目标程序需要辨别左右 Alt,应使用 Win32 SendInput 构造键盘事件。Windows 为右侧 Alt 定义了 VK_RMENU,值为 0xA5。实现时需要正确构造按下、释放以及扩展键相关信息,不能把 {VK_RMENU} 当作 SendKeys 字符串使用。Virtual-Key Codes、KEYBDINPUT 文档
如果只关心文字结果,也可以考虑 SendInput 的 KEYEVENTF_UNICODE:设置 wVk = 0,通过 wScan 提供 Unicode 字符。这种方式无需手写 AltGr 字符映射,但目标程序必须能处理相应的文本输入消息,不能保证所有应用都接受。Unicode 输入说明
使用时还要注意什么
- SendKeys 将输入发送给当前活动应用。开始前切换焦点后,仍需确保文本编辑区域持续获得焦点。
- 在 WinForms 点击事件中使用
Thread.Sleep会阻塞界面线程。如果需要保留输入间隔,可以改用async事件处理程序与await Task.Delay(...)。 SendWait可以改变等待方式,但不会增加 AltGr 或右侧 Alt 的字符串语法。- 使用
SendInput时,应检查成功插入的事件数。它还受到 UIPI 限制,不能向更高完整性级别的应用注入输入。SendInput 文档
原始代码在 case ' 附近已经损坏,需要先恢复合法的 C# 语法。上面的示例说明了可采用的改法,但没有在该匈牙利语布局和目标程序中实测。
备注:内容仅供参考。
