【问题标题】:SendInput() and non-English characters and keyboard layoutsSendInput() 和非英文字符和键盘布局
【发布时间】:2009-12-28 18:45:50
【问题描述】:

当在 Windows 中使用非英语输入键盘语言时,我无法模拟字符按键。

我尝试使用 KEYEVENTF_UNICODE 调用 SendInput():

KEYBDINPUT ki;
INPUT input;
int character = 0;

ki.wVk = 0;
ki.wScan = character;
ki.dwFlags = KEYEVENTF_UNICODE;
ki.time = 0;
ki.dwExtraInfo = 0;   
input.type = INPUT_KEYBOARD;
input.ki = ki;
SendInput(1, &input, sizeof(INPUT));

这确实有效(当然,在我的代码中,我也在按键按下后执行 KEYUP)...除了在 GTK+ 应用程序中(可能在其他情况下它也不起作用)。

根据MSDN如果指定了 KEYEVENTF_UNICODE,SendInput 将 WM_KEYDOWN 或 WM_KEYUP 消息发送到前台线程的消息队列,其中 wParam 等于 VK_PACKET。一旦 GetMessage 或 PeekMessage 获得此消息,将消息传递给 TranslateMessage 就会发布一条 WM_CHAR 消息,该消息具有最初由 wScan 指定的 Unicode 字符。如果将此 Unicode 字符发布到 ANSI 窗口,它将自动转换为适当的 ANSI 值。

所以我相信当 KEYEVENTF_UNICODE 被传递时,SendInput() 的功能就不同了……不像平时那么低级。

对于我的生活,我想不出任何其他方法来让 SendInput() 为用户的键盘语言正确打印字符。例如,如果键盘输入语言是“瑞典语”,我不能让它输出'@'(而是打印出一个引号),我不能让它正确输出非 ASCII 字符,要么(重音字母等)。

提前致谢。

【问题讨论】:

  • 这是什么,C? C++? C#?
  • @Carl:我使用的是 C,尽管任何语言的任何示例——只要它使用 Win32 API 调用——都会有所帮助。

标签: windows unicode keyboard-events keyboard-layout


【解决方案1】:

我发现执行此操作的正确方法是通过使用字符调用VkKeyScanEx() 来获取字符的虚拟键代码。返回值的高位字节将告诉您需要“按下”哪些修饰键:Control、Alt 和/或 Shift;低位字节是实际的虚拟键码。

要获取VK的扫描码,请拨打MapVirtualKeyEx(vkCode, 0);

那么就用刚刚得到的信息做按键模拟就好了。

【讨论】:

  • 我不确定您如何使用此信息,但您应该记住,结果取决于当前的键盘布局。
【解决方案2】:

据我了解,SendInput() 只是对 mouse_event() 和 keybd_event() 调用的封装,可确保您的输入不会与用户或其他调用者的输入混杂。

所以我想我的问题是,您是否尝试过使用 keybd_event()?

【讨论】:

  • 是的,我实际上是在尝试使用 keybd_event(),直到我注意到 SendInput 直接使用 KEYEVENTF_UNICODE 标志接受 Unicode 字符。由于 keybd_event() 像 SendInput() 一样采用虚拟键码和扫描码,所以我也无法弄清楚如何让 keybd_event() 为我工作。
  • 是的。一些国际键盘使用多个按键来“组合”单个按键事件。 SendInput 让您无需构建(或知道)所有进入其中的小按键即可获得该按键事件。
  • 恐怕我对此无能为力。我可以指出,扫描码与它们映射到的虚拟键码不同,但我想你已经知道了。
【解决方案3】:

在 .NET 中,所有字符串在内部都保存为 Unicode (UTF-8) 字符串。您可以通过将字符串转换为数组来验证这一点(byte[],而不是 char[]!)。因此,您可以忽略有关扫描码、键盘布局和虚拟键码的任何内容。

以下内容在 C#/.NET 中适用于我:

string myText = "greekcyrillicjapaneseorwhathaveyou"; // can be input via a Forms textbox

char[] Mychars = myText.ToCharArray();

UInt16 uniCode = chars[5]; // if you want to simulate, say, the sixth' char of the string

...

ki.wScan = unicode

ki.dwFlags = KEYEVENTF_UNICODE;

...

【讨论】:

  • .NET 字符串是 UTF-16,而不是 UTF-8。
  • 这也适用于基本多语言平面之外的 Unicode 代码点,例如表情符号,尽管它们需要分成两个char 单元。 (Notepad++ 除外。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-22
  • 1970-01-01
  • 1970-01-01
  • 2013-07-25
  • 1970-01-01
  • 2013-09-12
  • 1970-01-01
相关资源
最近更新 更多