I started making use of Win32's raw input features to detect all keys on the keyboard. So far, everything is working great! I can distinguish between numbers on the top row and numbers in the keypad on the right. I can even detect between the left and right shift keys. However, the control and alt keys do not return unique scan codes. The control key returns 29, and the alt key returns 56.
The popular method for checking key states on these keys is GetAsyncKeyState
. I have tested that function using VK_LCONTROL
and VK_RCONTROL
, and it works, but that only helps me for capturing key down events. I would really like to be able to capture key up events as well. It is obvious that the API is somehow aware of which key is being pressed; how do I get ahold of that information?
I am currently extracting the scan code from the RAWKEYBOARD
structure's MakeCode
field. That gives me information about every key (and its left/right alignment) except CTRL and ALT. How would I go about capturing the key up events (and knowing whether it is left/right)? Is it possible using just the RAWKEYBOARD
structure? Or do I have to concoct some kind of workaround?
If you want to get low level enough to detect key up events, you should process the WM_KEYDOWN and WM_KEYUP events:
Pressing a key causes a WM_KEYDOWN or WM_SYSKEYDOWN message to be placed in the thread message queue attached to the window that has the keyboard focus. Releasing a key causes a WM_KEYUP or WM_SYSKEYUP message to be placed in the queue.
Key-up and key-down messages typically occur in pairs, but if the user holds down a key long enough to start the keyboard's automatic repeat feature, the system generates a number of WM_KEYDOWN or WM_SYSKEYDOWN messages in a row. It then generates a single WM_KEYUP or WM_SYSKEYUP message when the user releases the key.
To distinguish between the left and right versions of the Shift, Ctrl, or Alt keys, you have to use the MapVirtualKey()
function or the 'extended key' bit in the lParam passed with the virtual key's message. The following function will perform that translation for you - just pass in the virtual keycode and the lParam from the message, and you'll get back the left/right specific virtual keycodes as appropriate:
WPARAM MapLeftRightKeys( WPARAM vk, LPARAM lParam)
{
WPARAM new_vk = vk;
UINT scancode = (lParam & 0x00ff0000) >> 16;
int extended = (lParam & 0x01000000) != 0;
switch (vk) {
case VK_SHIFT:
new_vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX);
break;
case VK_CONTROL:
new_vk = extended ? VK_RCONTROL : VK_LCONTROL;
break;
case VK_MENU:
new_vk = extended ? VK_RMENU : VK_LMENU;
break;
default:
// not a key we map from generic to left/right specialized
// just return it.
new_vk = vk;
break;
}
return new_vk;
}
If the virtual keycode passed in isn't one that maps to a left/right version, the original keycode is passed back unchanged. So you can just run the WM_KEYDOWN
/WM_KEYUP
/WM_SYSKEYDOWN
/WM_SYSKEYUP
message parameters through the function whenever you need to distinguish between the left and right variants.
GetAsyncKeyState's documentation says that:
... If the most significant bit is set, the key is down ...
which also means that if the MSB it cleared, the key is up.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With