Dealing with keyboard layouts for input on multiple platforms
For the purpose of discussion let's say I'm working on a game.
My game receives keyboard inputs from keyPressEvent and keyReleaseEvent, which gives me a QKeyEvent. Currently I'm using key() to get which key has been pressed. This has the problem of being dependent on keyboard layout - if a user uses Dvorak for example, the input will change to all over the place, while other layouts like AZERTY and QWERTZ will be just somewhat off. Non-Latin layouts like Hebrew will not work at all.
I must use another method which identifies a PHYSICAL key rather than the function assigned to it, with a constant code independent of the active keyboard layout.
nativeScanCode can be ruled out immediately because it doesn't work on mac:
Note: On Mac OS/X, this function is not useful, because there is no way to get the scan code from Carbon or Cocoa.
So we're left with nativeVirtualKey. This does actually provide a constant code like we want, but now we have a couple of new problems.
Problem 1: Different codes on different platforms
Each platform has a different set of virtual key codes. For Windows, the list can be found here. For mac, it's in Events.h. As a simple comparison to demonstrate that they are different, the virtual key code for the letter key O on Windows is 0x4F, while on mac the same key's code is 0x1F. Not to mention, I couldn't even find any relevant info for Linux.
This makes it impossible to set good default settings that would work on all platforms, forcing me to create separate defaults for each platform (unlike key()).
Problem 2: Display
I need to display the assigned keys to the user. The displayed key needs to change depending on the current layout, and the key to display is not the result of a key press event. There is no universal way to do this.
On Windows, I can use a variation of this code snippet: http://www.setnode.com/blog/mapvirtualkey-getkeynametext-and-a-story-of-how-to/
But that's just Windows. I have no idea how to do the same for mac or Linux. And besides, having to use different code for different platforms for such a basic thing is a real letdown.
So now I've come here to ask: does anyone know how to do this, or have a better suggestion? Why isn't this kind of feature built into Qt?
Thanks. Hope I didn't scare too many people away with this freaking essay..
Hi and welcome to devnet,
Short answer for the why: because it's outside of Qt's scope.
As for your keyboard setup issue, since we are dealing with a game. I would expect to simply have a configuration panel that allows me to assign the keys I want to the corresponding action.
Have sensible defaults like awsd for moving the character left/up/down/right and make it easy for people to re-assign the keys they want.
@SGaist Problem is that WASD is a bad default for non-QWERTY layouts.
You could have a set of defaults based on the locale.
It's more complicated than that, which is the source of the problem.
For starters, there's hundreds of different locales used worldwide. It isn't practical for me to create a separate set of defaults for each one when all I want is to have the exact same physical layout for all of them.
To make matters worse, many users have more than one keyboard layout installed and switch between them on-the-fly, normally using Alt+Shift (at least on Windows). This means that even if the user sets their own key bindings, if they try to play the game while the wrong layout is active, it wouldn't work or may shuffle around all the keys if the two layouts share letters/keys but at different positions (e.g. QWERTY, QWERTZ, AZERTY, Dvorak).
Qt has an event type called KeyboardLayoutChange, which should be helpful, but what Qt doesn't have is any other info about keyboard layouts whatsoever. This event has no extra info in it either.
QLocale doesn't have any keyboard layout info either.
I am just finding no way to even find the active layout, let alone set defaults based on it.
Can this thread be moved to the Game Development section? I feel like it might get better suggestions there.
Starting to lose hope...
Well, it's not something that's provided by Qt out of the box, so you'll have to check the platforms you want to support for how they provide that information.
You could even consider contributing that to Qt to improve it for everybody.
You might also open a feature request on the bug report system for that.