1

I am converting an application that currently uses DirectInput to use RawInput instead. (DirectInput is a largely deprecated API.)

Unfortunately, despite RawInput being the recommended successor to DirectInput, it doesn't appear to provide keyboard data in quite the same way as DirectInput.

DirectInput uses DIK_* constants (such as DIK_A, DIK_RETURN, etc...) to define specific physical keys on the keyboard. These keys are consistent across keyboard hardware but do not change depending on keyboard layout. (For example, DIK_Q refers to whatever key is in the physical location that the Q key is at on a standard US-English QWERTY keyboard.) In my case, this is the desired behavior.

RawInput's RAWKEYBOARD structure provides both a MakeCode and a VKey. I can't use VKey because that changes depending on keyboard layout.

But the MakeCode doesn't correspond 1:1 with the DIK_* constants. In particular, it doesn't differentiate between left and right ctrl and alt keys, or most of the number pad keys from their other keys.

So my question is: Is it possible to use the contents of a RAWKEYBOARD structure to figure out the equivalent DIK_* constant? And assuming that the MakeCode is part of figuring that out, can I rely on MakeCode being constant across keyboard hardware, in the same way that the DIK_* constants are?

Walt D
  • 4,491
  • 6
  • 33
  • 43
  • The best way to get keyboard data for a Windows desktop app is to just use Windows messages. RAW input is useful for relative mouse movement, but that's about it. For examples of doing this, see [Keyboard](https://github.com/Microsoft/DirectXTK/blob/master/Src/Keyboard.cpp) and [Mouse](https://github.com/Microsoft/DirectXTK/blob/master/Src/Mouse.cpp) in the _DirectX Tool Kit_ – Chuck Walbourn May 12 '16 at 07:06
  • @ChuckWalbourn Correct me if I'm wrong, but that seems to use the same virtual keys that RawInput uses? – Walt D May 12 '16 at 15:06
  • I use virtual keys for the ``Keyboard`` implementation which is what XNA Game Studio did. Yes the layouts change, but generally speaking the only solution for international keyboards is to provide a few different layout options and/or a remap configuration menu (I note this on the [wiki](https://github.com/Microsoft/DirectXTK/wiki/Keyboard#international-layouts)). – Chuck Walbourn May 12 '16 at 15:24
  • Note you can use ``GetKeyNameText`` to get the name of a given key. – Chuck Walbourn May 12 '16 at 15:31
  • You can use RAWKEYBOARD.VKey, virtual key numbers are not dependent on the keyboard layout. That's why they are "virtual". The VK_xxxx values are a one-to-one mapping to DIK values, you just need a lookup table. – Hans Passant May 12 '16 at 15:45
  • @HansPassant Just tested, and VK_ values change when I change my keyboard layout in Windows, whereas DIK_ does not. In my particular case, I want the DIK_ behavior. VK_ is useful when it's the letter printed on the key that's important (i.e., shortcuts), whereas DIK_ is useful when the position of the key is most important (i.e., WASD movement in games). – Walt D May 12 '16 at 16:13
  • I'll call that one, it is just not possible. Whatever you are looking at are not VK values. The keyboard layout is only used in ToUnicodeEx() to translate VK values to characters. Normally used by Windows to turn a WM_KEYDOWN message into a WM_CHAR message, the TranslateMessage winapi function does that. – Hans Passant May 12 '16 at 16:16
  • @HansPassant No, DIK values definitely can't be 1:1 mapped to VK values. I guess that's the whole point of my question? It just seems weird to me that a deprecated API like DirectInput would provide an important feature that its supposed successor doesn't support? – Walt D May 12 '16 at 16:22
  • @HansPassant Why do you say I'm "doing it wrong"? I'm using well-understood behavior of DirectInput that I'd like to replicate with RawInput. I feel like we're just having some miscommunication about what exactly I'm trying to do? Anyway, I *might* have figured out a solution, which I have posted as an answer below. – Walt D May 12 '16 at 17:26

1 Answers1

1

I'm not 100% sure this is reliable across all keyboard hardware, but it appears that I can use the MakeCode and Flags (specifically the RI_KEY_E0 and RI_KEY_E1 flags) fields of RAWKEYBOARD to determine the actual physical key that was pressed or released, and map this to a DIK_ constant. I used this table to determine most of the make/scan codes for individual keys, and then experimentation to figure out the scan/make codes and flags for the remaining keys.

I have tested this on four different keyboards, and all produce identical make codes / flags: 2 USB keyboards, a PS/2 keyboard, and the built-in keyboard on a Macbook running bootcamp.

I'd love to have some documented confirmation that I can rely on the make code and flags to be consistent across all keyboards, but so far this seems to be working fine.

Update: It's now ~5 years later and my software has had tens of thousands of real-world users and I have not received a single report of incorrect key mapping. At this point I'm 99.999% confident this approach works consistently across all keyboards, with the caveat that I cannot be sure things won't change in the future.

Walt D
  • 4,491
  • 6
  • 33
  • 43