ToUnicode doesn't return correct characters

与世无争的帅哥 提交于 2019-12-22 13:57:55

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!