Looking for key-repeat data in WM_INPUT message - c++

I just started using Raw Input for my app.
Getting straight to the question, in the legacy WM_KEYDOWN messages, the lParam could be checked to obtain extra information about the key press. Like these-
Bits Meaning
0-15 The repeat count for the current message.
The value is the number of times the keystroke is autorepeated as a
result of the user holding down the key. If the keystroke is
held long enough, multiple messages are sent. However, the repeat
count is not cumulative.
16-23 The scan code. The value depends on the OEM.
24 Indicates whether the key is an extended key, such as the right-hand
ALT and CTRL keys that appear on an enhanced 101- or 102-key
keyboard. The value is 1 if it is an extended key; otherwise, it is
0.
25-28 Reserved; do not use.
29 The context code. The value is always 0 for a WM_KEYDOWN message.
30 The previous key state. The value is 1 if the key is down before the
message is sent, or it is zero if the key is up.
31 The transition state. The value is always 0 for a WM_KEYDOWN
message.
I want to know if a WM_INPUT message is for a repeated key, so that I can ignore that message.(turn off keyrepeat.)
The trouble I am having is that this information can't be found for the WM_INPUT message. the lParam of the WM_INPUT message contains the handle to a RAWINPUT structure. On doing some research, I found that inside RAWINPUT::header contains a member called wparam in it and MSDN describes it as
wParam
Type: WPARAM
The value passed in the wParam parameter of the WM_INPUT message.
Will I find the required information in here or is it somewhere else?

The RAW Input API does not provide repeat counts. It is raw data coming from the keyboard directly. The repeat count is calculated at a higher level when the WM_KEY... messages are generated. Using WM_INPUT, you will have to manually keep track of the down/up states of each key to determine their repeat counts yourself. When a key goes down, start counting each WM_INPUT message for that key. When the key goes up, stop counting it.

I needed the same information you are looking for, and I found a reasonable work-around. I didn't care about the key repeat count, I just wanted to know if a WM_INPUT message represents an auto-repeat even if the initial key press occurred while my application was not in focus and the key continued to be held when focus switched to my application.
Throwing out all but the first WM_INPUT message is not sufficient to discern this, as keys held prior to gaining focus will look like new key events after gaining focus. You need the information in WM_KEYDOWN/WM_SYSKEYDOWN lparam bit 30, and it's apparently not available from WM_INPUT.
We work around this by requesting to continue receiving legacy input messages when registering for raw input by omitting the RIDEV_NOLEGACY flag. We get both raw and legacy messages, which arrive interleaved. For any relevant WM_INPUT message containing key information, it will be followed by legacy messages relating to that key before any additional WM_INPUT messages arrive. Our Windows input library gathers key info from both raw & legacy messages before evaluating the key event and it works very well for us.

Related

WM_DEVICECHANGE comes twice when disconnecting/connecting device

I'm listening in my message loop for WM_DEVICECHANGE, and when I remove or thrust my webcam, WM_DEVICECHANGE comes twice, with identical MSG (with same HWND, UINT, WPARAM and LPARAM). How to fix it?
This is to be expected. Although the wParam and lParam should be different to indicate a different stage of the device state change, it would not surprise me to know there are duplicate messages.
If I recall correctly, what we did in our code is that when we received a WM_DEVICECHANGE event is to do any of the following:
Once the first one came in, ignore all subsequent notifications for the next couple of seconds.
Or just use the WM_DEVICECHANGE as a hint and not the truth. When we received such a message, we would re-enumerate the device list with the appropriate API and see if anything changed since the last time we enumerated. If the new list was the same as the original list, then there was nothing to do.

What is the difference about GetKeyState and GetAsyncKeyState?

From MSDN , I have learned that GetKeyState is associated with message queue of current thread.
Then I created two sample applications : KeyPresser and BackChecker.
I press a key in KeyPresser , in this application , I am using GetKeyState/GetAsyncKeyState/GetKeyboardState to retrieve the pressed key state , and they tell me that key is pressing down.
Then I send(or post) a message form KeyPresser to BackChecker , to notify BackChecker to check the key state in it's thread .
I get same result from BackChecker indicate that key is pressed. But I think GetKeyState/GetKeyboardState should return zero because the key is pressed in thread of KeyPresser , which is not associated with thread of BackChecker.
Why?
Keyboard input on Windows is buffered. It ensures the user can keep typing, even if the program is temporarily unresponsive. It always is, to some degree, no loss of keystrokes that way. They are added to the message queue, the program's message loop retrieves them with GetMessage() later.
Along with the keystroke, it also stores the state of all the other keys. To ensure that, when the message is eventually retrieved, you can reliable tell what other keys were down. Very important for the modifier keys for example. A shortcut keystroke like Ctrl+A would not work reliably otherwise.
So you generally always use GetKeyState(), you get the state of the keys as they were recorded originally. Or GetKeyboardState(), you get the whole enchilada. Using GetAsyncKeyState() is much less common, it doesn't rely on the buffered state, only needed if the app has very unusual message handling. Might be appropriate in a game perhaps.

send scancode to my application

I have a question about scan code and extended
OK .
I create a simple window in c++ and I want to detect WM_KEYUP only ( VK_UP value )
Now I run spy++ and I press up key I detect my message like this
keydown vk_up crepeat1 scancode 48 extended1 altdown0 frepeat1 up0
Now if I send a message to my application I get the following message
SendMessage ( wnd , WM_KEYDOWN , VK_UP ,1);
keydown vk_up crepeat1 scancode 00 extended0 altdown0 frepeat1 up0
You see the different in scan code and other value.
My question is why this different even I send the same message?
2 is there any way to send scan code ( and other value to my application and get the same value )
Not sure why the difference but you can use keybd_event or SendInput function to synthesize keystrokes.
Check the docs for WM_KEYDOWN. The scan code is contained in bits 16 through 23 in the LPARAM argument. You passed 1, the scan code bits are thus all zero.
This is okayish, there are not a lot of apps that actually check the scancode. Using SendMessage() is however not correct, keyboard messages go into the message queue. You should use PostMessage(). The difference is that many message loops look at keystrokes to implement accelerators (aka shortcut keys). And call TranslateMesssage() to turn WM_KEYDOWN messages in WM_CHAR messages for typing keys.
There's another problem, an unsolvable one, you cannot control the state of the keyboard. The Ctrl, Alt and Shift modifiers. If the user happens to have the, say, Shift key pressed, the app will see Shift+Up, it may well interpret it very differently, editors certainly do. Only using SendInput() is a cure for that.
SendMessage ( wnd , WM_KEYDOWN , VK_UP ,0x00480001);

Recognizing unknown mouse buttons

So I've been writing a simple Windows program, and it really irks me how in some other programs, they can't recognize the full range of input. For example, in Starcraft 2, you can't bind the extra two mouse buttons on a five-button mouse. For keyboard input, I've been using the WPARAM of the WM_KEYDOWN message, so that if it's unrecognized, I can still recognize it later, even if not display it in a usable form. But for mouse buttons, I've come a cropper, because they have their own messages. So if in the future, I get a seven-button mouse, how can I recognize the sixth and seventh buttons without having to re-write my application?
I don't think there is a generic "WM_BUTTONDOWN" message available.
The best way to check that out is to use Spy++ on a window. You'll see that there is no generic message sent out. Plus the actual values of all the WM_xxBUTTONDOWN do not follow any pattern either.
What I would do is configure the app to be able to understand 6 new messages entered manually or configured somewhere, for WM_[Z]BUTTONDOWN, WM_[Z]BUTTONUP and WM_[Z]BUTTONDBLCLK, plus all the corresponding WM_NCxxx messages, because luckily (sort of...), all existing messages more or less share the same wParam + lParam pattern.

WM_KEYDOWN confusion

I'm trying to get my application to do something when CTRL+S is pressed. I'm just not sure how the W and L params work for WM_KEYDOWN. MSDN has something about bit fields which i'm not sure about. How can I detect CTRL and S?
Thanks
What do I do if another control aside from hWnd has focus?
Well, this is the big list of virtual key codes.
CTRL-S is going to be sent through as 2 WM_KEYDOWN messages - a message when the ctrl key is pressed (VK_LCONTROL or VK_RCONTROL) followed by a 0x53 for the "S" key.
Rather than processing both messages, wait for the key down message for the 'S' press then call GetKeyState using the magic value VK_CONTROL (otheriwse you'd need to test individually for the left AND right control keys) to see if the S was pressed with CTRL held down.
--
Obviously, keyboard messages are sent directly to the window that has focus. To get accelerator combinations to work at the application scope you need to check the messages before dispatching them to the focus window - i.e. in your message pump. See the documentation for TranslateAccelerator.
If you want to handle system wide keypresses, the other answer points to the hot key api.
When the WPARAM is equal to the CTRL VKcode, then set a bool in the state of your object. Then, when S comes up, if Ctrlbool, you've got CTRL-S.