看起来如果你在一个全局WH_KEYBOARD_LL钩子中调用ToAscii()
或ToUnicode()
,并且一个死键被按下,它将被“销毁”。
例如,假设你在Windows中将输入语言配置为西班牙语,你想在程序中输入一个重音字母á,通常你会按单引号键(死键),然后按字母“a”,然后屏幕上会显示一个重音字母á,正如预期的那样。
但是如果你在一个低级的键盘钩子函数中调用ToAscii()
或ToUnicode()
,这个方法就不起作用了。看起来死键被破坏了,所以没有重音字母á出现在屏幕上。删除对上述函数的调用可以解决这个问题...但是不幸的是,我需要能够调用这些函数。
我在谷歌上搜索了一段时间,虽然很多人似乎都有这个问题,但没有提供好的解决方案。
任何帮助将不胜感激!
**EDIT:**我正在调用ToAscii()
,将LowLevelKeyboardProc钩子函数中接收到的虚拟键代码和扫描代码转换为将在屏幕上显示给用户的结果字符。
我尝试了MapVirtualKey(kbHookData->vkCode, 2)
,但是它的函数不如ToAscii()
“完整”;例如,如果你按下Shift + 2,你将得到'2',而不是'@'(或者Shift + 2将为用户的键盘布局/语言产生的任何结果)。ToAscii()
是完美的...直到按下一个死键。
**EDIT 2:**以下是钩子函数,删除了不相关的信息:
LRESULT CALLBACK keyboard_LL_hook_func(int code, WPARAM wParam, LPARAM lParam) {
LPKBDLLHOOKSTRUCT kbHookData = (LPKBDLLHOOKSTRUCT)lParam;
BYTE keyboard_state[256];
if (code < 0) {
return CallNextHookEx(keyHook, code, wParam, lParam);
}
WORD wCharacter = 0;
GetKeyboardState(&keyboard_state);
int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode,
keyboard_state, &wCharacter, 0);
/* If ta == -1, a dead-key was pressed. The dead-key will be "destroyed"
* and you'll no longer be able to create any accented characters. Remove
* the call to ToAscii() above, and you can then create accented characters. */
return CallNextHookEx(keyHook, code, wParam, lParam);
}
9条答案
按热度按时间hzbexzde1#
很老的一个线程。不幸的是,它不包含我正在寻找的答案,而且没有一个答案看起来工作正常。我最终通过在调用
ToUnicode
/ToAscii
之前检查MapVirtualKey
函数的MSB来解决这个问题。看起来工作得很有魅力:在
MapVirtualKey
的返回值上引用MSDN(如果使用MAPVK_VK_TO_CHAR
):[...]死键(变音符号)通过设置返回值的最高位来指示。[...]
wydwbb8l2#
1.停止使用ToAscii()并使用ToUncode()
1.请记住,ToUnicode可能不会返回任何关于死键的信息-这就是为什么它们被称为死键。
1.任何键都将具有扫描码或虚拟键码,但不一定是字符。
您不应该将按钮与字符组合在一起-假设任何键/按钮都有文本表示(Unicode)是错误的。
因此,
fivyi3re3#
调用'ToAscii'函数两次,以正确处理死键,如:
i2byvkas4#
调用
ToAscii
或ToUnicode
两次就是答案,我找到了这个,并将其转换为 Delphi ,它工作了!9vw9lbht5#
我遇到了这个问题,而创建一个键盘记录器在C#和以上的答案没有一个为我工作。
经过深入的博客搜索,我偶然发现了这个keyboard listener,它可以完美地处理死键。
gab6jxml6#
下面是一个完整的代码,涵盖了使用ALT + NUMPAD的死键和快捷键,基本上是一个TextField输入处理的完整实现:
1mrurvl17#
正是known使得
ToUnicode()
及其旧版本ToAscii()
可以更改当前线程的键盘状态,从而使死键和ALT+NUMPAD键击变得混乱:当ToUnicodeEx转换虚拟键代码时,它也会更改内核模式键盘缓冲区的状态。此状态更改会影响死键、连字、alt+numpad键输入等。如果与TranslateMessage(它也会更改内核模式键盘缓冲区的状态)一起使用,它还可能导致不希望的副作用。
为了避免这种情况,您可以在单独的线程中执行ToUnicode()调用(它将具有单独的键盘状态),或者在
wFlags
参数中使用特殊的标志,该标志在ToUnicode() docs中进行了说明:如果设置了位2,则键盘状态不变(Windows 10,版本1607及更高版本)
或者你可以事先准备好sc-〉charMap表,在语言改变时更新它。
我认为它也可以用在
ToAscii()
上,但是最好不要用这种依赖于ANSI代码页的老方法。用ToUnicode()
API代替,它甚至可以返回ligatures和UTF-16代理对--如果键盘布局有它们的话。Some do。请参见Asynchronous input vs synchronous input, a quick introduction了解其背后的原因。
eoxn13cs8#
我将vkCode复制到队列中,然后从另一个线程执行转换
这样做的好处是不会延迟操作系统对密钥的处理
new9mtju9#
这对我有用