Rolling One's Own Keyboard/Input system in C/C++
Update: Here is a library I wrote for handling keyboard input. It uses the FreeBSD license. I've even tagged it as v1.0
, so I consider it to be "release-quality".
https://github.com/depp/keycode
I worked very hard recently to get this "just right" for gaming, and I'm not done yet. I'll share what I know.
Key codes
For games, key codes are usually what you want.
When you press a key on your keyboard, the OS first translates the button press into a key code. The key code specifies the physical location of the key on the keyboard. For example code 4 might correspond to the key labeled A on US keyboards (even if that key has a different label in France or Russia). Each platform has a different set of key codes, or possibly multiple sets. You may know them by a different name, such as scan codes or virtual key codes.
Windows uses virtual key codes (MSDN documentation). They are stable across various hardware and software configurations. You can find the definitions in the
<Winuser.h>
header file. On Windows, if you press the leftmost home row key (A in the US, Q in France), you get code 65.Mac OS X has key codes which have been stable since the 80s. They are defined in
<Carbon/Events.h>
. You don't actually need to link to Carbon to use the key codes, but you need the header. On OS X, if you press the leftmost home row key, you get code 4.Linux has several divergent set of key codes. So on Linux, you have a few options. You can either use key syms (which have drawbacks which I'll explain below), you can assume the user is using a specific input driver (Evdev is a very good guess these days), or you can somehow figure out which input driver the machine uses. In order to get keycodes, you have to read the keyboard definition files. For example, look at
/usr/share/X11/xkb/keycodes/evdev
for Evdev key codes. With Evdev, if you press the leftmost home row key, you get code 38.
Of course, it would be too easy if the key code were the same across platforms. You can either use the platform-specific key code or translate it into a platform-independent value. I suggest using the USB HID codes (pdf) as platform-independent codes, since a number of smart people already went through the trouble of agreeing on what to call each key.
The library I've posted above has tables for each platform such as WIN_NATIVE_TO_HID
for translating key codes to USB HID codes.
The hard part is communicating to the user what button they should press, but at least people from other countries can play your game.
Character codes
You don't want to use character codes, even though they're easier to use if you live in the US and your audience also lives in the US.
After translating the button press into a key code, the OS then translates the key code into a character code. The character code is affected by the current keyboard layout, and often affected by modifier keys as well.
So if you press A on your keyboard, you'll get key codes 65, 4, or 38, depending on what platform you're on. But you'll get the character code 'a'
or 'A'
depending on whether the shift key is down, or you might get 'Q'
if the keyboard layout is set to French, or 'Ф'
if the keyboard layout is set to Russian. So, if you code WASD into your game and use character codes, input will be totally broken when someone from another country plays your game. You'd have to use ZQSD in France, ЦФЫВ in Russia, and pretty soon you have a headache.
I use a non-QWERTY layout myself (Dvorak) and most games are utterly broken. In the place of the W key is ,, which becomes < if you have the shift key down, and some games don't recognize that as the same key. For example, I'd press , to move forward, but if I'd release the button while the shift key was down the game would think that I had released the < and think that the , was still down, so I'd keep moving forward. Most games that use SDL are broken on the Mac for me even if I switch to the US keyboard layout (I think this is a glitch in SDL).
LibSDL
SDL 2.0 provides platform-independent key codes, called scan codes. Use the "SDL_scancode.h"
header. The SDL developers came to the same conclusion that the scan codes should be translated back to USB HID codes, so the SDL scan codes are completely compatible with the library I posted above (see keycode.h and SDL_scancode.h, the numeric values are identical).
For this and other reasons, if you are using SDL 1.2, I strongly recommend upgrading to 2.0.