Maaack / Godot-Game-Template

Godot template with a main menu, options menus, pause menu, credits, scene loader, extra tools, and an example game scene.
MIT License
283 stars 17 forks source link

Options: Controls: keys seem to always register and display international US keyboard #96

Closed hsandt closed 4 weeks ago

hsandt commented 1 month ago

I'm using an international US keyboard myself I didn't notice this at first, but when I tried to switch to Azerty to register the Q key, it was still displayed as Q, in both the prompt and registered key. I verified that it was also bound to physical Q = A on Azerty indeed.

2024-06-02_16-44-27 Bug Azerty A is shown as Q

While this allows stable display, it's confusing when using an actual Azerty keyboard, or other.

I see the complexity of displaying the right key at all times though: you'd have to detect system layout change at runtime, and I'm not sure there is a signal for that.

However, it should at least work when the layout doesn't change mid-game.

I found the culprit line:

InputHelper.gd

static func get_text(event : InputEvent) -> String:
    elif event is InputEventKey:
        return OS.get_keycode_string(event.get_physical_keycode_with_modifiers())

Maybe it could use get_keycode_with_modifiers instead. In fact, I just tried it and it works. Can you think of any side effect of doing this?

Ideally it would allow the user to choose a physical mapping like Godot editor itself, but I understand it would be extra work and few people would need to do that.

I also found this function:

InputOptionsMenu.gd

func _get_action_keycode(action_event : InputEvent):
    if action_event is InputEventMouse:
        return 0
    if action_event.keycode != 0:
        return action_event.get_keycode_with_modifiers()
    else:
        return action_event.get_physical_keycode_with_modifiers()

But it's never called.

hsandt commented 1 month ago

OK I found two side effects of this:

So maybe we should add a condition to verify the type of input stored to display it properly for each case?

hsandt commented 1 month ago

OK so I found the solution to both issues thx to https://github.com/godotengine/godot/issues/84731 which mentions the doc: https://docs.godotengine.org/en/latest/classes/class_inputeventkey.html#class-inputeventkey-property-physical-keycode

Applying this to the get_text function:

elif event is InputEventKey:
        var keycode := DisplayServer.keyboard_get_keycode_from_physical(event.physical_keycode)
        return OS.get_keycode_string(keycode)

We can now get the physical keys properly, and also display them according to current keyboard layout.

This means that whenever main menu scene is loaded, it will be filled with the correct key display. Now it's just a matter of refreshing the controls displayed more often than scene loading, e.g. each time the Controls tab is displayed, and users shouldn't have any issue seeing the correct mapping even if they switch layout mid-game! (and of course we can even detect layout change at arbitrary times but that's a bit more complex)

And for the blank entries, we should always define special keys like Space and Escape as physical keys, so they are displayed properly with the code above (but it also works with the current event.get_physical_keycode_with_modifiers(), so it was a separate issue after all).

hsandt commented 1 month ago

Still not fully fixed:

So I have yet to find a solution to display Ctrl+Cmd+F (non-physical) or Cmd+Q (non-physical), common shortcuts on macOS for toggle fullscreen and exit app, properly. I suppose F won't move much so I can make it physical, but even then I need to adapt DisplayServer.keyboard_get_keycode_from_physical + OS.get_keycode_string to work with modifiers. Doc says OS.get_keycode_string supports modifiers so I'm not sure what's missing.

Also, it's hard for user to add a modifier themselves because they must hold the modifier while clicking OK, but that's another issue.

Maaack commented 1 month ago

Thanks for looking into this in-depth and documenting it. This issue can affect more users since I've added default input editing in https://github.com/Maaack/Godot-Game-Template/pull/101 (which closed https://github.com/Maaack/Godot-Game-Template/pull/98). I'm not sure the best course of action and will try to research other solutions.

I also found this function: InputOptionsMenu.gd But it's never called.

I think that is legacy code from the Godot 3 version and should be removed. I was probably hoping it'd be useful again someday.

Also, it's hard for user to add a modifier themselves beause they must hold the modifier while clicking OK, but that's another issue.

Yeah, I do want to iterate on that system again, and mimic the design of Godot's input action editor.

hsandt commented 6 days ago

Thanks, I manually copied the new get_text implementation and it works great!

EDIT: Label keys are displayed properly, but Unicode keys are still invisible...

Maaack commented 6 days ago

Thanks for testing it out. I started a new ticket for it.