Hi guys,
I registered for this topic, because it is IMO very important, and almost all games do it wrong. Right now, I'm using only the Audio module of SFML (hope that will change, though). Therefore, I don't know how keyboard handling works currently. I hope I can contribute nevertheless, as I have thought much about this topic. In my opinion we should first try to find out how it should be done, before we determine if it is possible to do it like that. Therefore I want to begin with the gamer's perspective.
The Gamer's PerspectiveFrom a gamer's perspective, keys should sometimes be mapped according to their physical location (e.g. wasd) let's call this "location keybinding", and sometimes according to what is printed on the key (e.g. e for eject, t for target), let's call this "named keybinding". Almost no game has ever done this right, and this was especially problematic during DOS times with nonmappable keybindings. In many cases, the game used a combination of both for determining the layout of the keys. E.g. many flight simulators and space sims use the letter keys for named keybindings and the area around the enter keys for location keybindings. But all of those games use either only scancodes (thus mixing up the named keybindings on non-english keyboards, e.g. Auto-tracking becomes Ctrl-Q on an Azerty keyboard instead of Ctrl-A in Wing Commander 3), or only the characters that the keyboard produces, forcing Alt Gr-( and Alt GR-) on an Azerty keyboard to decrease/increase throttle, instead of the two keys next to Enter in some games.
If a game offers freely chosable keybindings, as soon as the user selects a key it should (obviously) reflect the location of this key (location keybinding). However, it would still be good if an appropriate default keybindings works equally well on all keyboards. Additionally, in the keybindings menu, it should be shown what is actually on the keyboard of the user (named display).
To sum up:
- A) Some keybindings should be done according to their physical location (location keybinding)
- B) Some keybindings should be done according to what is printed on the key (named keybinding
- C) The programmer should think about why he chooses that key and select the appropriate method
- D) If the keys are shown anywhere in the game, they should always display what the user sees on his keyboard (named display)
- E) If keys can be redistributed by the user, they should always reflect their physical location (location keybinding)
The Programmers PerspectiveThe programmer should always put the user first. Therefore, everything that is written above, remains. However, we now have an additional problem: The programmer himself might have a strange keyboard. Thus
- If he wants to do a location keybinding, how is he supposed to know what the location code for a specific location is?
- If he does a named keybinding, he could bind on a symbol that is hidden or does not exist on the user's keyboard
ProposalA possible solution would be to offer to sets of identifiers, location and named identifiers.
A) Location identifiers need to be provided for every key. They could by default be named according to the Qwerty layout. (In all likelihood they would be constants evaluating to the scancode).
(Regarding 1.:) As a convenience for the programmers, alternative names for the most used keyboards could be used. Thus sf::Keyboard::location::semicolon would be equivalent to sf::Keyboard::location::colon, sf::Keyboard::location::Azerty::M and sf::Keyboard::location::Qwertz::OE. A programmer with an even more exotic keyboard would either have to google a picture of a Qwerty keyboard or write a little program that outputs the location identifier for a pressed key. This program could also be provided.
B) Named identifiers do not need to be provided for every key. They should only be provided for the letters and numerics, possibly some additional keys, like Esc or the F-Keys. The reason for the need for named identifiers does not apply to the symbol keys, and the programmer is discouraged from using a symbol as a named identifier that does not exist on a user's keyboard (regarding 2.).
The operating systems keyboard event should provide those. If they need to be converted to location identifiers (most likely for asynchronous key handling), this should also be done by the operating system (but I don't know if it's possible).
C) Additionally, there should be a function like toDescription(...) that takes both location and named identifiers and returns a descriptive text, that should reflect what the user can see on his keyboard. It should be trivial for named identifiers. For location identifiers, this can only be done by the operating system. It should theoretically be possible (the OS takes a scancode and gives a char), but I don't know if this functionality (simulate a keyboard event in order to receive the correct character according to the user's locale) is available on all operating systems
Problems:This proposal has two problems:
- There is a minor problem because physical key locations differ as well - E.g the key left of backspace in Qwerty is located in the third row left of return in Azwerty and Qwertz. However, I think we can ignore this. There is no software solution to this problem.
- There is a major problem because of the overlapping of named and location identifiers. Say I write a game that uses sf::Keyboard::location::semicolon for "adjust throttle to enemy" and the named keybinding 'm' for "missile". Then a French user (hi Laurent) has a problem, because they evaluate to the same key on Azerty.
The only solution to the second problem that I can think of is that it needs to be emphasized in the documentation that if one uses both named and location identifiers in the same game, then the keys must be reassignable. However, an overlap will occur only in very few cases, and it is IMO still a preferrable alternative to the either - or approach taken by most games, where a reassignment (or the ability to memorize nonsensical key combinations) is needed on almost all foreign keyboards.