'Distinguish between left and right shift keys using RAWINPUT

RAWINPUT provides two flags (RI_KEY_E0 and RI_KEY_E1) to check whether the left or right version of a key is pressed. This works great for CTRL, but not for left and right shift. In fact, the flags are the same for both, and the VKey is also the same (VK_SHIFT). How can I find out which shift was pressed? I'm working on Windows 7. Interestingly, the flags/vkey values are exactly the same no matter which shift key I'm pressing.



Solution 1:[1]

Windows 7, and I only get VK_SHIFT, never the L/R variants

Which is part of the explanation why this doesn't work the way you think it should do. There's ancient history behind this. The keyboard controller was redesigned for the IBM AT, again for the Enhanced keyboard. It started sending out 0xe0 and 0xe1 prefixes for keys that were added to the keyboard layout. Like the right Ctrl and Alt keys.

But keyboards always had two shift keys. The original IBM PC didn't consider them special keys, they simply have a different scan code. Which was maintained in later updates. Accordingly, you don't get the RI_KEY_E0 or E1 flags for them. You have to distinguish them by the RAWKEYBOARD.MakeCode value. The left shift key has makecode 0x2a, the right key is 0x36.

Note that the left Ctrl and Alt keys don't have the flags either. They match the corresponding keys on the old PC keyboard layout. The description of the flags in the MSDN Library article is not very accurate.

Solution 2:[2]

You can distinguish left-right SHIFT/CONTROL/ALT VK codes like this:

 case WM_INPUT:
{
    HRAWINPUT dataHandle = reinterpret_cast<HRAWINPUT>(lParam);

    RAWINPUT input;
    UINT size = sizeof(input);

    ::GetRawInputData(dataHandle, RID_INPUT, &input, &size, sizeof(RAWINPUTHEADER));

    if (input.header.dwType != RIM_TYPEKEYBOARD)
        break;

    const RAWKEYBOARD& keyboard = input.data.keyboard;

    const bool keyUp = (keyboard.Flags & RI_KEY_BREAK) == RI_KEY_BREAK;
    const bool keyHasE0Prefix = (keyboard.Flags & RI_KEY_E0) == RI_KEY_E0;
    const bool keyHasE1Prefix = (keyboard.Flags & RI_KEY_E1) == RI_KEY_E1;

    uint16_t vkCode = keyboard.VKey;
    uint16_t scanCode = keyboard.MakeCode;

    scanCode |= keyHasE0Prefix ? 0xe000 : 0;
    scanCode |= keyHasE1Prefix ? 0xe100 : 0;

    // if we want to distinguish via VK codes:
    // - VK_LSHIFT and VK_RSHIFT
    // - VK_LCONTROL and VK_RCONTROL
    // - VK_LMENU and VK_RMENU
    switch (vkCode)
    {
    case VK_SHIFT:
    case VK_CONTROL:
    case VK_MENU:
        vkCode = LOWORD(MapVirtualKeyW(scanCode, MAPVK_VSC_TO_VK_EX));
        break;
    }

    //...

    return 0;
}

This code should work at least from Vista.

But please note that gamedev programmers are usually manually mapping scancodes to internal game engine specific keycodes - because VK codes are tend to change on different keyboard layouts. For example if you use usual VK_W/VK_A/VK_S/VK_D for movement in QWERTY layout - it could turn into VK_Z/VK_Q/VK_S/VK_D in AZERTY keyboard layout. VK codes are primarily handy in Win32 GUI programming.

You can grab decent scancode<->USB HID Usage conversion table here: https://source.chromium.org/chromium/chromium/src/+/main:ui/events/keycodes/dom/dom_code_data.inc

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Hans Passant
Solution 2 DJm00n