ToUnicode 没有 return 正确的字符
ToUnicode doesn't return correct characters
我试图在低级键盘钩子中调用 ToUnicode
并打印它 return 编辑的字符。但是,该函数似乎没有考虑是否按下了特殊键,例如 shift 或 caps lock,因此输出与 MapVirtualKey
函数相同,当前键的虚拟代码作为参数传递。
例如 (pressed keys => characters returned by ToUnicode
):
abcd => abcd (correct)
[caps lock]abcd => abcd (wrong: should be ABCD)
ab[holding shift]cd => abcd (wrong: should be abCD)
我如何调用函数(在挂钩过程中):
KBDLLHOOKSTRUCT* pressedKeyInformation = (KBDLLHOOKSTRUCT*)lParam;
BYTE keysStates[256]; // 256 bo tyle virtualnych klawiszy wpisze GetKeyboardState
if(!GetKeyboardState(keysStates))
//error
else
{
WCHAR charactersPressed[8] = {};
int charactersCopiedAmount = ToUnicode(pressedKeyInformation->vkCode, pressedKeyInformation->scanCode, keysStates, charactersPressed, 8, 0);
//std::wcout << ...
}
后来我注意到在 ToUnicode
之前使用作为参数传递的任何虚拟键码(例如 VK_RETURN
、VK_SHIFT
)调用 GetKeyState
会导致它 return 正确的字符,例如:
abcd => abcd (correct)
[caps lock]abcd => ABCD (correct)
ab[holding shift]cd => abCD (correct)
它还 return 正确地使用 AltGr 按下键盘语言环境相关的键,例如[AltGr]a => ą
.
上面的例子并不完全正确,因为出现了另一个问题 - 例如大写锁定被按下,下一个字符仍然取决于它之前的状态,只有后面的字符受到影响,例如:
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(<whatever>)
解决其中一个问题的原因以及后一个大写锁定(和其他特殊键)问题的原因是什么?
部分答案:
Windows 文档建议 GetKeyboardState
和 GetKeyState
return 相应键的结果相似,当这些函数用于 Windows 消息循环,其中键盘消息被正确翻译。
然而,在这种情况下,我们有一个钩子函数,GetKeyboardState
不能正确地填充键盘。首先调用 GetKeyState
将更改键盘状态,随后调用 GetKeyboardState
将按预期工作。我不知道为什么!
其他奇怪之处,GetKeyState
returns 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);
}
我试图在低级键盘钩子中调用 ToUnicode
并打印它 return 编辑的字符。但是,该函数似乎没有考虑是否按下了特殊键,例如 shift 或 caps lock,因此输出与 MapVirtualKey
函数相同,当前键的虚拟代码作为参数传递。
例如 (pressed keys => characters returned by ToUnicode
):
abcd => abcd (correct)
[caps lock]abcd => abcd (wrong: should be ABCD)
ab[holding shift]cd => abcd (wrong: should be abCD)
我如何调用函数(在挂钩过程中):
KBDLLHOOKSTRUCT* pressedKeyInformation = (KBDLLHOOKSTRUCT*)lParam;
BYTE keysStates[256]; // 256 bo tyle virtualnych klawiszy wpisze GetKeyboardState
if(!GetKeyboardState(keysStates))
//error
else
{
WCHAR charactersPressed[8] = {};
int charactersCopiedAmount = ToUnicode(pressedKeyInformation->vkCode, pressedKeyInformation->scanCode, keysStates, charactersPressed, 8, 0);
//std::wcout << ...
}
后来我注意到在 ToUnicode
之前使用作为参数传递的任何虚拟键码(例如 VK_RETURN
、VK_SHIFT
)调用 GetKeyState
会导致它 return 正确的字符,例如:
abcd => abcd (correct)
[caps lock]abcd => ABCD (correct)
ab[holding shift]cd => abCD (correct)
它还 return 正确地使用 AltGr 按下键盘语言环境相关的键,例如[AltGr]a => ą
.
上面的例子并不完全正确,因为出现了另一个问题 - 例如大写锁定被按下,下一个字符仍然取决于它之前的状态,只有后面的字符受到影响,例如:
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(<whatever>)
解决其中一个问题的原因以及后一个大写锁定(和其他特殊键)问题的原因是什么?
部分答案:
Windows 文档建议 GetKeyboardState
和 GetKeyState
return 相应键的结果相似,当这些函数用于 Windows 消息循环,其中键盘消息被正确翻译。
然而,在这种情况下,我们有一个钩子函数,GetKeyboardState
不能正确地填充键盘。首先调用 GetKeyState
将更改键盘状态,随后调用 GetKeyboardState
将按预期工作。我不知道为什么!
其他奇怪之处,GetKeyState
returns 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);
}