godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Add a function to convert a keycode to a physical keycode #10237

Open GTcreyon opened 1 month ago

GTcreyon commented 1 month ago

Describe the project you are working on

A platformer that supports setting custom keyboard controls. Key names are saved to the configuration file to make them easy to edit manually in a text editor. The key names that are saved should be that of the keys seen on the user's keyboard, rather than US QWERTY.

Describe the problem or limitation you are having in your project

There is no way to convert keycodes to physical keycodes. Physical keycodes can be converted to keycodes, but not the other way around.

The key names of physical keys can be saved to the configuration file by first converting to keycodes with DisplayServer.keyboard_get_keycode_from_physical(), and then to strings with OS.get_keycode_string(). To load the configuration file, the strings can then be converted back to keycodes with OS.find_keycode_from_string(), but there is currently no function to convert those keycodes back into physical keycodes to finish the decode cycle.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

A function to convert keycodes into physical keycodes. This would allow a physical keycode to be found from a keycode, so the user could switch between keyboard layouts during gameplay without breaking their controls, while also having key names saved in their usual recognizable layout.

(Note: We have decided not to actually use this method, since it will cause issues if the config file is loaded with a different keyboard layout to the one it was saved with. Still, there may be utility to the function.)

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

A function such as DisplayServer.keyboard_get_physical_from_keycode(), as an opposite to DisplayServer.keyboard_get_keycode_from_physical(). They should be inverses of each other.

If this enhancement will not be used often, can it be worked around with a few lines of script?

No. As far as I'm aware, doing so would require pre-caching a map of all possible conversions via DisplayServer.keyboard_get_keycode_from_physical() and then reversing it.

Is there a reason why this should be core and not an add-on in the asset library?

I don't think the necessary information is exposed to add-on creators. It also feels like a missing link in what should(?) be a bidirectional conversion.

AThousandShips commented 1 month ago

I don't know that there's a single, simple way to convert a key code into a physical key, can you propose some method to do this? Some idea for how this would be implemented, I can't really think of a way to do it

Lielay9 commented 1 month ago

(Note: We have decided not to actually use this method, since it will cause issues if the config file is loaded with a different keyboard layout to the one it was saved with. Still, there may be utility to the function.)

I think this is a rather good argument to not include such function.

No. As far as I'm aware, doing so would require pre-caching a map of all possible conversions via DisplayServer.keyboard_get_keycode_from_physical() and then reversing it.

This isn't even that arduous of a task; doable in couple minutes (omitting the +2 weeks of debugging the issues caused by saving localized keys would cause):

var key_map: Dictionary = {} # Keycode - PhysicalKeycode pairs
var key_mapper: Callable = func(from: int, to: int) -> void:
    for key: int in range(from, to+1):
        key_map[DisplayServer.keyboard_get_keycode_from_physical(key)] = key
key_mapper.call(4194304, 4194366) # Might not want to include all
key_mapper.call(4194433, 4194447)
#key_mapper.call(4194370, 4194419) # Probably not needed
key_mapper.call(32, 96)
key_mapper.call(123, 126)
key_mapper.call(165, 167)
print(key_map)

Mind you, you'd probably never need the conversion because as was stated before, it only works if the user doesn't change their layout, and if they never change their layout, then the conversion isn't needed; just plug the keycodes to the InputMap actions directly.

Calinou commented 1 month ago

In games, key bindings stored in configuration files should indeed be independent of the keyboard layout. You may be sharing configuration files with other players or synchronizing it across devices that may not be using the same keyboard layout (or OS, as there can be OS-specific differences here too). Lots of games still get it wrong in 2024, so we should make sure Godot doesn't make it easier for more games to get it wrong :slightly_smiling_face:

Even CS2 fixed this issue a few months ago:

  • Fixed issues with implementation of scancode-based key bindings. Bindings are now independent of input locales.

It's a different topic for non-game applications where key bindings are generally expected to be actual key codes (and therefore depend on your keyboard layout), but you don't declare those keys as physical keys in the input map in the first place.