Last time, we looked at how to distinguish the numeric keypad 0 and the top-row 0 in the WM_ message. We may as well look at the analogous table for WM_.
| Event | wParam | Extended? |
|---|---|---|
| Numpad0 with NumLock on | VK_0 | 0 |
| Numpad0 with NumLock off | (no WM_CHAR) |
|
| Ins key | (no WM_CHAR) |
|
| 0 on top row | VK_0 | 0 |
I got the name VK_0 from this comment block in winuser.h.
/* * VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39) * 0x3A - 0x40 : unassigned * VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) */
Uh-oh. The extended bit doesn’t distinguish between the two. They both show up as VK_0, non-extended.
What changes is something not in the above table: The scan code.
So let’s convert the scan code back to a virtual key.
auto vk_from_scan = MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK);
| Event | wParam | Extended? | vk_from_scan |
|---|---|---|---|
| Numpad0 with NumLock on | VK_0 | 0 | VK_INSERT |
| Numpad0 with NumLock off | (no WM_CHAR) |
||
| Ins key | (no WM_CHAR) |
||
| 0 on top row | VK_0 | 0 | VK_0 |
So we can infer which zero was pressed by taking the scan code, mapping it to a virtual key, and seeing whether it’s the Ins key (from the numeric keypad) or the 0 key (from the top row).
But wait, we’re not done yet.
There are ways to type the character 0 without using the numeric keypad or the top row. For example, you can hold the Alt key and then type 4,8 on the numeric keypad, and that will type a 0. I tried it out, and the vk_from_scan was VK_, which is the virtual key code for the Alt key. Another way of entering a 0 is by using an input method editor (IME). Or there might be a custom keyboard layout that generates a 0 through some wacky chord sequence.
Therefore, if the vk_ is neither VK_ nor VK_0, you have to conclude that the 0 was entered by some means other than the numeric keypad or the top row.
Shouldn’t games be using WM_KEYUP then?
Games should be using proper API meant for their usage model in the first place. Be it old DirectInput or newer XInput. Those who don’t will get hit with very “interesting” bugs.
Seconding Krzysztof’s comment: The complexity they describe is before you consider things like Steam Input remapping. Steam allows users to remap their controller buttons to any controller, keyboard, or mouse input, and mix and match those inputs freely in the same control scheme. So you can have the user rapidly switching between input methods in the heat of gameplay, and they probably expect you to “just handle it.”
Yeah, except sometimes games need a standard boring text input box and cursor navigation alongside the typical game stuff. XInput only works with the Xbox controllers (and stuff that pretends to be them) and doesn't handle keyboards. DirectInput is old and really cumbersome. There's newer GameInput that has keyboard support, but even the docs state explicitly it's meant for mapping keys to typical game actions and not suited for text input. Same goes for DirectInput actually. You'd end up reimplementing stuff like autorepeat, cursor navigation etc.
Yeah, you can do a virtual keyboard in some cases, but some games really...
I have a sort of related question.
On at least two PCs, from different manufacturers, when three finger taps are enabled for middleclick, I find it works locally, but not in Remote Desktop sessions. There it works as Win+P and brings op Projection settings (which does not work in RD).
When I look at local keyboard and mouse events (not WindowsMessages, my little .NET application just uses Forms events), I see this when three finger tapping:
LWin down
ControlKey down
ShiftKey down
F22 up
ShiftKey up
ControlKey up
LWin up
Middle down
Middle - 1 click
Middle up
How did it come to this?Read more
Or perhaps what you should conclude is that you shouldn’t be trying to work out how the user entered a
0character.(I’m assuming the
VK_MENUcomes from theWM_KEYUPmessage that indicates the end of theAlt,4,8sequence.)(Sadly we don’t get to use those nice
<kbd>s in comments.)Games. Games do need to distinguish these. I remember RTS that used the top row numbers to select unit groups, but numpad numbers to enter comm codes.
Kile: Right. Good argument. Following it, we should get rid of multi monitor support (most laptop users never ever connect an external monitor). Then, the command line (most users do no need to use it, ever). And perhaps even that outdated mouse/touchpad support (touch screens made it redundant).
Windows is what it is because of choice. It has the largest software library of any OS, period. But it is also the one which supports most form factors and user scenarios. "It just works", which was once the slogan of certain fruit-named company, is actually fulfilled in the Windows ecosystem. I...
this comment has been deleted.
Games should use proper API for their usage in the first place. DirectInput or XInput. Problem becomes trivial then…