Winapi 图尼科德不';不能返回正确的字符
我试图在低级键盘挂钩中调用Winapi 图尼科德不';不能返回正确的字符,winapi,keyboard,hook,keyboard-hook,Winapi,Keyboard,Hook,Keyboard Hook,我试图在低级键盘挂钩中调用ToUnicode,并打印它返回的字符。但是,该函数似乎没有考虑是否按下了shift或caps lock等特殊键,因此输出与MapVirtualKey函数相同,当前键的虚拟代码作为参数传递 例如(pressed keys=>ToUnicode返回的字符): 如何调用函数(在钩子过程中): 它还正确返回使用AltGr按下的键盘区域设置相关键,例如[AltGr]a=>ą 上述示例并不完全正确,因为出现了另一个问题-如果按下caps lock,下一个字符仍取决于其先前的状态,
ToUnicode
,并打印它返回的字符。但是,该函数似乎没有考虑是否按下了shift或caps lock等特殊键,因此输出与MapVirtualKey
函数相同,当前键的虚拟代码作为参数传递
例如(pressed keys=>ToUnicode返回的字符
):
如何调用函数(在钩子过程中):
它还正确返回使用AltGr按下的键盘区域设置相关键,例如[AltGr]a=>ą
上述示例并不完全正确,因为出现了另一个问题-如果按下caps lock,下一个字符仍取决于其先前的状态,只有后面的字符受到影响,例如:
abcd => abcd (correct)
(caps lock is off)[caps lock]abcd => aBCD (wrong: should be ABCD)
(caps lock is off)ab[caps lock]cd => abcD (wrong: should be abCD)
您知道为什么GetKeyState()
修复了其中一个问题,以及后一个大写锁(和其他特殊钥匙)问题的原因吗?部分答案:
Windows文档建议GetKeyboardState
和GetKeyState
为相应的键返回类似的结果,当在Windows消息循环中使用这些函数时,键盘消息会被正确转换,这是正确的
然而,在本例中,我们有一个钩子函数,GetKeyboardState
不能正确填充键盘。首先调用GetKeyState
将更改键盘状态,随后调用GetKeyboardState
将按预期工作。我不知道为什么
其他奇怪的是,GetKeyState
返回SHORT
值,而GetKeyboardState
填充BYTE
数组。但这不会有什么区别,因为我们只对高位和低位感兴趣
HHOOK hook;
LRESULT CALLBACK hook_procedure(int code, WPARAM wparam, LPARAM lparam)
{
if(code == HC_ACTION)
{
if(wparam == WM_KEYDOWN)
{
KBDLLHOOKSTRUCT *kb = (KBDLLHOOKSTRUCT*)lparam;
BYTE state[256] = { 0 };
wchar_t str[10] = { 0 };
GetKeyState(VK_SHIFT);
GetKeyState(VK_MENU);
GetKeyboardState(state);
if (ToUnicode(kb->vkCode, kb->scanCode,
state, str, sizeof(str)/sizeof(*str) - 1, 0) > 0)
{
if(kb->vkCode == VK_RETURN) std::wcout << "\r\n";
else std::wcout << str;
}
}
}
return CallNextHookEx(hook, code, wparam, lparam);
}
HHOOK-hook;
LRESULT回调钩子_过程(int代码、WPARAM WPARAM、LPARAM LPARAM)
{
如果(代码==HC\U动作)
{
if(wparam==WM_KEYDOWN)
{
KBDLLHOOKSTRUCT*kb=(KBDLLHOOKSTRUCT*)LPRAM;
字节状态[256]={0};
wchar_t str[10]={0};
GetKeyState(VK_移位);
GetKeyState(VK_菜单);
GetKeyboardState(状态);
如果(字节->vkCode,字节->扫描码,
状态,str,sizeof(str)/sizeof(*str)-1,0)>0)
{
如果(kb->vkCode==VK_RETURN)std::wcout同时调用GetKeyState(VK_SHIFT)
和GetKeyState(VK_大写)
在调用GetKeyboardState
之前。您的密码不清楚。您是否正在响应WM\u KEYDOWN
?@Barmak Shemirani是的,我正在响应WM\u KEYDOWN
。我会在回家后更改密码,所以在几个小时内。@BarmakShemirani它现在工作得很好,谢谢。但是这些调用实际上有什么作用呢?我相信de>GetKeyState(键)
在内部更新key
的状态,对吗?我找不到任何关于msdn的线索。您应该将您的评论作为答案发布。谢谢!显示ToUnicode
返回的字符的一个注释-根据msdn:但是,缓冲区可能包含的字符数超过返回值指定的字符数。发生这种情况时,任何xtra字符无效,应该忽略。
,因此如果只显示N
字符就好了,其中N
是ToUnicode
@Jason返回的值,是的,这很有意义。这也适用于AltGr
吗?如果您的意思是死键是否生成单个字符,答案是肯定的,但是仅当死键可以与另一个按下的键组合时-根据msdn:最常见的原因[即ToUnicode缓冲区包含>=2个字符]是死键字符(重音或变音符号)存储在键盘布局中的虚拟键不能与指定的虚拟键组合成单个字符。
顺便说一句,如果我们必须遵守规则,在截取任何键之前,您应该返回CallNextHookEx
ifcode<0
,如hook proc文档中所述。此外,如果复制了8个字符s到str缓冲区,则str[8]=0
将导致未定义的行为。但是:此缓冲区可能返回而不以null结尾,即使变量名表明它以null结尾。
。好的,我为缓冲区添加了一个额外的索引。
abcd => abcd (correct)
[caps lock]abcd => ABCD (correct)
ab[holding shift]cd => abCD (correct)
abcd => abcd (correct)
(caps lock is off)[caps lock]abcd => aBCD (wrong: should be ABCD)
(caps lock is off)ab[caps lock]cd => abcD (wrong: should be abCD)
HHOOK hook;
LRESULT CALLBACK hook_procedure(int code, WPARAM wparam, LPARAM lparam)
{
if(code == HC_ACTION)
{
if(wparam == WM_KEYDOWN)
{
KBDLLHOOKSTRUCT *kb = (KBDLLHOOKSTRUCT*)lparam;
BYTE state[256] = { 0 };
wchar_t str[10] = { 0 };
GetKeyState(VK_SHIFT);
GetKeyState(VK_MENU);
GetKeyboardState(state);
if (ToUnicode(kb->vkCode, kb->scanCode,
state, str, sizeof(str)/sizeof(*str) - 1, 0) > 0)
{
if(kb->vkCode == VK_RETURN) std::wcout << "\r\n";
else std::wcout << str;
}
}
}
return CallNextHookEx(hook, code, wparam, lparam);
}