问题
I tried to call the ToUnicode
inside a low level keyboard hook and print the character(s) it returned. However, it seems that the function doesn't take into account whether special keys, such as shift or caps lock were pressed, so the output is the same as from MapVirtualKey
function with current key's virtual code passed as parameter.
For example (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)
How I call the function (inside the hook procedure):
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 << ...
}
Later I noticed that calling GetKeyState
with any virtual key code passed as parameter (e.g. VK_RETURN
, VK_SHIFT
) before ToUnicode
causes it to return the correct character, e.g.:
abcd => abcd (correct)
[caps lock]abcd => ABCD (correct)
ab[holding shift]cd => abCD (correct)
It also returns properly keyboard locale dependent keys pressed with AltGr then, e.g. [AltGr]a => ą
.
The above example isn't entirely correct, since there appears another problem - if e.g. caps lock was pressed, the next character still depends on its previous state, only the latter characters are affected, e.g.:
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)
Have you any idea why the GetKeyState(<whatever>)
fixes one of the problems and what's the cause of the latter caps lock (and other special keys) problem?
回答1:
Partial answer:
Windows documentation suggests GetKeyboardState
and GetKeyState
return similar result for the correspond keys, and this is true when these functions are used in a Windows message loop, where keyboard messages are properly translated.
In this case however, we have a hook function, GetKeyboardState
doesn't properly fill the keyboard. Calling GetKeyState
first, will change the keyboard state, the subsequent call to GetKeyboardState
will work as expected. I don't know why!
Other oddities, GetKeyState
returns SHORT
value, while GetKeyboardState
fills BYTE
array. But this shouldn't make a difference since we are only interested in high and low bits.
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);
}
来源:https://stackoverflow.com/questions/53697356/tounicode-doesnt-return-correct-characters