首页 文章

ToUnicode不返回正确的字符

提问于
浏览
2

我试图在低级键盘钩子里调用 ToUnicode 并打印它返回的字符 . 但是,似乎该功能没有考虑是否按下了特殊键,例如shift或大写锁定,因此输出与 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 之前调用 GetKeyState 作为参数传递的任何虚拟键码(例如 VK_RETURNVK_SHIFT )会导致它返回正确的字符,例如:

abcd => abcd (correct)
[caps lock]abcd => ABCD (correct)
ab[holding shift]cd => abCD (correct)

它还返回正确的键盘区域设置依赖键,用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>) 修复了其中一个问题以及后者大写锁定(以及其他特殊键)问题的原因是什么?

1 回答

  • 0

    部分答案:

    Windows文档建议 GetKeyboardStateGetKeyState 返回相应键的类似结果,当在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);
    }
    

相关问题