godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.68k stars 20.11k forks source link

How to handle non-QWERTY keyboard layouts? #20527

Closed bruvzg closed 4 years ago

bruvzg commented 6 years ago

Following up comments in #18020, I'm making this topic to get better understanding how to handle different keyboard layouts.

Please, take a moment to look at following use cases and users, and answer few questions:


Applications:

:large_blue_circle: Application A:

3D shooter. Player movement is controlled with WASD keys, I key opens inventory.

:large_blue_circle: Application B:

Raster graphics editor. Main menu use following shortcuts: Ctrl(Command) + S for “Save”, Ctrl(Command) + A for “Select all”.

Developer of both apps was using standard QWERTY keyboard to configure default input maps.


Users:

:large_blue_circle: User 1:

Keyboard image: (Standard QWERTY keyboard)

ibm_m

Current selected system keyboard layout: “US English”

:large_blue_circle: User 2:

Keyboard image: (Dvorak keyboard, Originally QWERTY keyboard with manually moved keycaps)

dvrk

Current selected system keyboard layout: “Dvorak”

:large_blue_circle: User 3:

Keyboard image: (Russian JCUKEN keyboard)

rus

Current selected system keyboard layout: “US English”

:large_blue_circle: User 4:

Keyboard image: Same as User 3

Current selected system keyboard layout: “Russian”

:large_blue_circle: User 5:

Keyboard image: (Turkish F keyboard)

turkf

Current selected system keyboard layout: “Turkish F”


Questions:

  1. What key-codes/scan-codes highlighted keys (with red border) on each users keyboard should produce?
  2. Which physical keys on each users keyboard should move player in the Application A?
  3. Which physical key on each users keyboard should open inventory in the Application A?
  4. Which physical keys on each users keyboard should “Save” and “Select” in the Application B?
  5. Which characters should be displayed in the menu shortcut for each user? menu_img
  6. What should be correct return value of OS.get_latin_keyboard_variant() for each of the users?
  7. If you believe different physical keys should be responsible for moving backwards in Application A and saving in Application B, how these cases should be distinguished in code? In Input Map?
  8. In case you are using keyboard layout significantly different from layouts in this topic, please share image of your keyboard and desired handling for aforementioned use cases.

Additionally if you are using non-QWERTY keyboard, please try building #18020 PR, and testing input map behaviour with your keyboard layout. I do not have any non-QWERTY physical keyboard and only tested it by switching OS keyboard layouts.

map

Intended behaviour:

bojidar-bg commented 6 years ago

Haven't experienced all cases but..: User 4: (Qwerty keyboard, non-EN layout) In this case, I expect shortcut keys to work as if the layout is US Qwerty. So, if the Russian user types Ctrl-Ы, it should be interpreted as Ctrl-S.

akien-mga commented 6 years ago

I'll add another use case:

:large_blue_circle: User 6:

Keyboard image: (French AZERTY keyboard)

french_azerty

Current selected system keyboard layout: “French (France)”

Particular pain points of this configuration:

moiman100 commented 6 years ago

Same physical location should always do the same thing and UI should show the character from selected system keyboard layout corresponding to that physical location.

Also currently Godot doesn't even support all keys. For example < key is unknown on Finnish/scandinavian/nordic keyboards and I would assume on French too because of the same location. EDIT3: Actually it does work it just doesn't know what key it is.

EDIT: This is better than no hardware keys at all, but hardware returning some US character, or whatever layout it uses, is just confusing.

When you are modifying input map it should save the physical code and show the character based on user's keyboard layout. Thus if my input map shows key w and akien would open the same project using AZERTY keyboard it would show z.

This of course would mean that if you set inventory action to i on some keyboard, it might not be i on some other keyboard, but it would still be in the same location. Binding actions to keys that start the actions name is only a nicety and binding every action like this would create quite a mess. For example WASD would become FLBR (forward, left, backward, right). My point is binding by name is not really good and one should bind keys by ergonomics/usability in mind.

EDIT2: Also allowing both remapped and hardware keys might lead to unintentional double actions. For example if, on QWERTY keyboard, a was bound to a hardware key and q was bound to a remapped key, on AZERTY keyboard q would do two actions.

romlok commented 6 years ago

I like the idea of there being two different types of key mapping for different uses: hardware and remapped. Though I think it would be clearer to users if they were called something more along the lines of "physical location" and "character/symbol" - reflecting what they are used for, rather than any underlying technical/implementation details.

Another possibility is for Godot to allow multiple layout-specific mappings, chosen based on the current user's locale or settings. This could require more work for the developer (or contractors), but can avoid the issue of unintentionally doubling actions depending on the layout (at least for the layouts explicitly supported). This may also be desirable for when shortcuts are based on a word (eg. Save, Load, Inventory), which may be different depending on the language.

However, there will always be exceptions, and implementing user-modifiable controls should always be encouraged IMO. Perhaps Godot should allow, and automatically check for, a default config file in user:// which can contain custom action mappings? That way, even if no input-GUI is made by the developer, users are able to customise the controls with a text editor.

Also, user 1 is using a US layout on a UK keyboard? That's a capital offence!

starry-abyss commented 6 years ago

User 3 and 4, for both Application A & B, I expect it act as QWERTY. Unless in text input box (or something like quick search and scroll in list by name's first letter) - then currently selected layout.

mldunc commented 5 years ago

I would like to point out an edge case as well. There exists a possibility for a "remapped" key action and a "physical" key action to unintentionally both be triggered by same key. Using a First Person Shooter as an example, on the Colemak layout "r" for reload would collide with physical placement of standard WASD movement setup (WARS on Colemak):

image

This would need to be resolved with some kind of logic. Ignoring it would likely be pretty frustrating/confusing for the player.

Yukitty commented 4 years ago

"R" for "reload" is just a happy coincidence because that key happened to be nearby. It would be more important for the "R" mapping to be replaced by "P" in this layout so that your hand on the "WARS" keys can reach it. In other layouts, the R key might be all the way on the opposite side of the keyboard -- and you would be at a significant disadvantage if you were to constantly have to reach all the way over and press it, just because it means something in English, which might not even be your native language.

Just use physical scancodes for everything. Don't worry about individual keybinds having names.

Calinou commented 4 years ago

@Yukitty While this is a sensible idea for games, I don't think this is a good option for non-game applications. Many people are using Godot to make such applications (e.g. Pixelorama), so we should avoid forcing this change on everyone.

I'm not sure if there's a lot of use in making this adjustable on a per-key basis (due to conflicts), but having a project setting for this might be good enough. The default would be to use physical scancodes, as most people use Godot to make games.

Yukitty commented 4 years ago

Fair.

bruvzg commented 4 years ago

18020 was merged, both mapping methods are now available, closing this.