为什么GetKeyState改变了ToUnicodeEx的行为?

时间:2017-02-04 06:16:28

标签: c++ winapi

在下面的代码中: -

BYTE ks[256];
auto keyboard_layout = GetKeyboardLayout(0);
GetKeyboardState(ks);
auto w = WCHAR(malloc(1));
ToUnicodeEx(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), ks, LPWSTR(&w), 1, 0, keyboard_layout);
wcout << "KEY:" << w << endl;

输出仅显示小写字母,例如: -

KEY:a
KEY:b
KEY:2

即使按 SHIFT + A SHIFT + 2

在以下代码中添加GetKeyState(VK_SHIFT)和/或GetKeyState(VK_CAPITAL): -

auto shifted = false;
auto caps = false;
if (GetKeyState(VK_SHIFT) < 0)
{
    shifted = true;
    cout << "Shifted!" << endl;
}
if (GetKeyState(VK_CAPITAL) < 0)
{
    shifted = true;
    cout << "Caps!" << endl;
}
BYTE ks[256];
auto keyboard_layout = GetKeyboardLayout(0);
GetKeyboardState(ks);
auto w = WCHAR(malloc(1));
ToUnicodeEx(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), ks, LPWSTR(&w), 1, 0, keyboard_layout);
wcout << "KEY:" << w << endl;

当按 SHIFT + A SHIFT + 2 时,代码的行为直接改变为

KEY:A
KEY:B
KEY:@

我在ToUnicodeToAsciiExToAscii上尝试了此操作,它们显示的情况与上述相同。

我在名为WH_KEYBOARD的单独DLL文件中使用hook.dll钩子并与控制台应用程序链接。

所以我的问题是:为什么GetKeyState函数启用了 SHIFT Caps Lock 键的检测?另外,

1 个答案:

答案 0 :(得分:4)

使用auto w = WCHAR(malloc(1))是错误的。 malloc()动态分配一个字节块,而不是字符。 WCHAR的大小为2个字节,但您只分配1个字节。哪个没关系,因为你还是不使用指针。您正在将指针压缩为单个WCHAR,从而截断指针值。然后,在将&w传递给ToUnicodeEx()时,您将忽略该值,因为它会覆盖w的值。然后,您正在泄漏已分配的内存,因为您没有调用free()来取消分配它。

您根本不需要malloc()

WCHAR w;
ToUnicodeEx(..., &w, 1, ...);
wcout << "KEY:" << w << endl;

但是,ToUnicodeEx()可能会返回超过2个字符,因此您应该为此分配额外的空间。只需使用本地固定数组,就像使用GetKeyboardState()一样。并且要注意返回值,它包含重要信息。

至于关键状态,由于您致电GetKeyboardState(),因此无需使用GetKeyState()

尝试更像这样的事情:

BYTE ks[256];
auto keyboard_layout = GetKeyboardLayout(0);
GetKeyboardState(ks);

if (ks[VK_SHIFT] & 0x80) wcout << L"Shifted!" << endl;
if (ks[VK_CAPITAL] & 0x80) wcout << L"Caps!" << endl;

WCHAR w[5] = {};
int ret = ToUnicodeEx(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), ks, w, 4, 0, keyboard_layout);
switch (ret)
{
case -1:
    wcout << L"DEAD KEY:" << w << endl;
    break;
case 0:
    wcout << L"NO TRANSLATION" << endl;
    break;
case 1:
    wcout << L"KEY:" << w << endl;
    break;
case 2:
case 3:
case 4:
    w[ret] = 0;
    wcout << L"KEYS:" << w << endl;
    break;
}