1

我编写了一个程序来使用外部(无线)数字键盘作为游戏的输入设备。我正在使用 NUMPAD0,NUMPAD。和 ENTER 分别用于修饰键 shift、ctrl 和 alt,我已将其余的小键盘键映射到 WASD 和其他一些键。我已经设置了一个 LowLevelKeyboardProc 来拦截并吃掉小键盘的“真实”输入,并将自定义 WM_MESSAGE 发送到我的应用程序的 Windows 消息循环,然后通过 SendInput 发送键映射的“新”输入(使用我想要的键的扫描码模拟)。

这一切都工作正常,正如预期的那样。除了左移键:每当我按下映射到左移的 NUMPAD0 时,不仅会发送正确的扫描码 0x2A = 42,而且还会发送另一个扫描码为 0x022a = 554 的键。这似乎是某种标志第 9 位,因为 554 是 42 + 2^9,但我可以找到任何关于此的文档。 我已经阅读了关于前缀为 0xE0 的扩展 2 字节扫描码,但在这种情况下不是 0x02。这也只发生在模拟的 shift 键上;ctrl 和 alt 表现得很好。键盘钩子和 Windows 消息传递的相关部分:

LowLevelKeyboardProc:

LPWSTR convertToHex(LPBYTE in, size_t size_in_Bytes)
{
    std::stringstream tempS;
    tempS << std::hex;
    for(int i = 0; i<size_in_Bytes; i++)
    {
        tempS << std::setfill('0') << std::setw(2) << int(in[i]) << " ";
    }
    std::string tempString = tempS.str();
    std::wstring tempW(tempString.begin(), tempString.end());

    LPWSTR out= (LPWSTR) malloc((tempW.size()+2)* sizeof(WCHAR));
    StringCbCopyW(out, tempW.size()* sizeof(WCHAR), tempW.c_str());
    return out;
}

LRESULT CALLBACK LowLevelKeyboardProc(__in  int nCode, __in  WPARAM wParam, __in  LPARAM lParam)
{
    KBDLLHOOKSTRUCT *key=(KBDLLHOOKSTRUCT *)lParam;
    wchar_t tempString[128];

    LPWSTR hexOut = convertToHex((LPBYTE) key , sizeof(KBDLLHOOKSTRUCT));
    StringCbPrintfW(tempString, sizeof(tempString), L"HEX: %s \n", hexOut);
    OutputDebugStringW(tempString);
    free(hexOut);

    //if(key->scanCode > 0xFF)
    //  return -1; //ignore strange scancode
    if(nCode==HC_ACTION)
    {
        if(isNumpad)
        {
            auto it = KeyMap.find(key->scanCode);
            if(it != KeyMap.end())
            {
                PostMessage(hwndMain, WM_MY_KEYDOWN, (key->flags & 128), it->first);
                StringCbPrintfW(tempString, sizeof(tempString), L"Intercept Key, VK: %d, scan: %d, flags: %d, time: %d, event: %d \n", key->vkCode, key->scanCode, key->flags, key->time, wParam);
                OutputDebugStringW(tempString);
                return -1;
            } 
        }
    }
    // delete injected flag
    //UINT mask = (1<<4);
    //if(key->flags & mask)
    //  key->flags ^= mask;
    //key->scanCode = MapVirtualKey(key->vkCode, MAPVK_VK_TO_VSC);
    StringCbPrintfW(tempString, sizeof(tempString), L"Output key: VK: %d, scan: %d, flags: %d, time: %d, event: %d \n", key->vkCode, key->scanCode, key->flags, key->time, wParam);
    OutputDebugStringW(tempString);
    return CallNextHookEx(hhkHook,nCode,wParam,lParam);
}

Windows 消息的东西:

case WM_MY_KEYDOWN:
{
    DWORD OLD_KEY = lParam;
    DWORD NEW_KEY = KeyMap[OLD_KEY];
    bool keyUP = wParam;

    INPUT inputdata;
    inputdata.type=INPUT_KEYBOARD;
    inputdata.ki.dwFlags=KEYEVENTF_SCANCODE ;
    inputdata.ki.wScan=NEW_KEY;
    inputdata.ki.wVk=MapVirtualKey(NEW_KEY, MAPVK_VSC_TO_VK);
    inputdata.ki.time = 0;//key->time;
    inputdata.ki.dwExtraInfo = 0;//key->dwExtraInfo;

    if(keyUP)
    {
        inputdata.ki.dwFlags |= KEYEVENTF_KEYUP;
    }
    Sleep(1);
    bool sendKey=false;
    switch(inputdata.ki.wScan)
    {
        //there once was some additional logic here to handle the modifier keys ctrl, alt and shift seperately, but not anymore

        default:
        {
            sendKey=true;
        }
        break;
    }
    if (sendKey)
    {
        UINT result = SendInput(1, &inputdata, sizeof(INPUT));
        if(!result) 
            ErrorExit(L"SendInput didn't work!");
    }

}
break;

按下物理键盘上的普通 shift 键时的输出:

//key down
HEX: a0 00 00 00 2a 00 00 00 00 00 00 00 29 cf d2 00 00 00 00 00 00 00 00 00  
Output key: VK: 160, scan: 42, flags: 0, time: 13815593, event: 256 
//key up
HEX: a0 00 00 00 2a 00 00 00 80 00 00 00 e5 cf d2 00 00 00 00 00 00 00 00 00  
Output key: VK: 160, scan: 42, flags: 128, time: 13815781, event: 257 

按下小键盘上的模拟 shift 键时输出:

//keydown event numpad
HEX: 60 00 00 00 52 00 00 00 00 00 00 00 a1 ea d2 00 00 00 00 00 00 00 00 00  
Intercept Key, VK: 96, scan: 82, flags: 0, time: 13822625, event: 256 
//keydown event simulated shift key
HEX: a0 00 00 00 2a 00 00 00 10 00 00 00 a1 ea d2 00 00 00 00 00 00 00 00 00  
Output key: VK: 160, scan: 42, flags: 0, time: 13822625, event: 256 
// key up event with strange scancode 554 <- THIS IS WHAT I AM TALKING ABOUT!
HEX: a0 00 00 00 2a 02 00 00 80 00 00 00 3d eb d2 00 00 00 00 00 00 00 00 00  
Output key: VK: 160, scan: 554, flags: 128, time: 13822781, event: 257 
// key up event numpad
HEX: 2d 00 00 00 52 00 00 00 80 00 00 00 3d eb d2 00 00 00 00 00 00 00 00 00  
Intercept Key, VK: 45, scan: 82, flags: 128, time: 13822781, event: 257 
// key down with strange scan code
HEX: a0 00 00 00 2a 02 00 00 00 00 00 00 3d eb d2 00 00 00 00 00 00 00 00 00  
Output key: VK: 160, scan: 554, flags: 0, time: 13822781, event: 256 
//key up event simulated shift key
HEX: a0 00 00 00 2a 00 00 00 90 00 00 00 3d eb d2 00 00 00 00 00 00 00 00 00  
Output key: VK: 160, scan: 42, flags: 128, time: 13822781, event: 257 

另一件需要注意的是,这个奇怪的按键扫描代码 554 的按键事件也与其余的完全相反(见输出)。 因为我可以简单地吃掉这个奇怪的扫描码 554 的关键事件,这实际上在功能方面并没有太大的问题,但我仍然想知道这个扫描码 554 的全部内容。

4

0 回答 0