I want to implement a menu for input remapping and I want to display the assigned keys in a readable format.
Why does the code in the ready method print (Unset) for every action? When I press the same buttons that are assigned to the attack action, the input function prints them correctly.
func _input(event: InputEvent) -> void:
if event is InputEventKey:
print(event.as_text_key_label())
func _ready() -> void:
InputMap.load_from_project_settings()
for action: String in InputMap.get_actions():
if action.begins_with("ui"):
continue
for event: InputEvent in InputMap.action_get_events(action):
if event is InputEventKey:
print(event.as_text_key_label())
Looking at your code the problem is that InputMap.action_get_events(action) is returning events of different types than what you’re checking for. Your condition if event is InputEventKey: is only handling keyboard events, but the events in your action mapping arent all keyboard events.
In the UI screenshot, I can see that your “attack” action has physical inputs like “A”, “Apostrophe”, etc., which suggests they’re likely InputEventJoypadButton or other non-keyboard input types rather than InputEventKey instances.
Try modifying your code to check for the specific event types or to handle all event types:
func _ready():
InputMap.load_from_project_settings()
for action: String in InputMap.get_actions():
if action.begins_with("ui"):
continue
print("Action: ", action)
for event: InputEvent in InputMap.action_get_events(action):
print(" Event type: ", event.get_class())
if event is InputEventKey:
print(" Key: ", event.as_text_key_label())
elif event is InputEventJoypadButton:
print(" Joypad Button: ", event.button_index)
Thanks a lot for the suggestions. The events are in fact InputEventKey, I’ve added on of your lines to check.
print("Event type: ", event.get_class()) # prints Event type: InputEventKey
We can also just remove the type check and use the code below. It still prints (Unset), so the problem is elsewhere.
func _ready() -> void:
InputMap.load_from_project_settings()
for action: String in InputMap.get_actions():
if action.begins_with("ui"):
continue
for event: InputEvent in InputMap.action_get_events(action):
print(event.as_text_key_label())
There are three ‘types’ of inputs (Keycode (latin), physical keyboard and unicode). You can specify them in the dropdown at the bottom when specifying the input in the InputMap.
You specified in your InputMap the input as physical key (on a US keyboard) but as_text_key_label returns the Keycode (first type) text.
You could instead
Use InputEvent.as_text. This returns the string representation with the ‘type’ information (e.g. Space (Physical))
Use InputEventKey.as_text_physical_keycode. Similar to as_text_key_label but instead of the keycode it returns the physical keycode (the one that you have set)
Instead of specifying the input on a physics keyboard you could change the type to just Keycode. But then the keys change for different keyboard layouts.
func _ready() -> void:
InputMap.load_from_project_settings()
for action: String in InputMap.get_actions():
if action.begins_with("ui"):
continue
for event: InputEvent in InputMap.action_get_events(action):
if event is InputEventKey:
print(OS.get_keycode_string(event.key_label))
Yes, this looks good. Now the event is associated with the ‘unicode’ character send by the OS. Keep in mind that different keyboard-layouts have the characters at different position.
Btw. I checked the documentation again and OS.get_keycode_string(event.key_label) and event.as_text_key_label() seem to be the same thing (I updated my original answer).
One more thing. DisplayServer has a function to convert a physical-keycode to the label of the current layout: keyboard_get_label_from_physical.
This way you can set the input-event to physical-keyboard (i.e., the key position does not change based on the layout), but you can print the actual label that’s associated with the users keyboard-layout.