I’ve been looking into some tutorials, mainly this one - https://www.gotut.net/custom-key-bindings-in-godot-4/
My particular problem is that this and every other tutorial of key rebind only deals with 1 action = 1 keybind, while I want my actions to have 3 keybinds: 2 from the keyboard, 1 from a controller. Because of that, I can’t simply empty the InputMap
of a given action and add the newly pressed key.
After quite some time thinking and testing, I’ve managed to cobble together this code (based on the one from the link above) that works as I want: it removes the previous keybind and adds the new one, without messing any of the previous keys.
func _input(event):
if !current_button:
return
if event is InputEventKey and $keypress.visible:
var action: String
match current_button.name:
"rebind_jump":
action = "game_jump"
#Match repeat for each button/action, also "duplicated" for each of the alternative keys/buttons, as "alt_game_jump", etc
#The following lines happen after the match defines the action
rebind(event,action, current_button.text)
current_button.text = event.as_text()
current_button = null
## The rebind function is called by sending the event, a string of the action proper and the button's current text as the "oldkey"
## rebind(event, "game_jump", $rebind_jump.text)
## After the event call, the button's text is set like this: $rebind_jump.text = event.as_text()
func rebind(event: InputEvent, action: String, oldkey:String):
var existing : Dictionary = {}
var key: String
for ia in InputMap.action_get_events(action):
#The split(" ") below happens because physical key presses are sent as "E (Phyisical)" or "Ctrl (Physical)"
if ia.as_text().split(" ")[0] != "Joypad":
key = ia.as_text().split(" ")[0]
else:
key = ia.as_text()
existing[key] = ia
for acts in InputMap.get_actions():
#Removes the key from any other events
InputMap.action_erase_event(acts, event)
InputMap.action_erase_event(action, existing[oldkey])
InputMap.action_add_event(action, event)
While it works as is for keyboard rebind, I haven’t tested it with a controller, as I don’t have one around to test.
But my main question is: is this “ideal”? Is there a better/easier way to do this, rebind an action substituting only one key?
EDIT: Did a few tweaks on the code. One thing that I haven’t figured out yet is a way to update a key that was already bound to another button. For example: if “Ctrl” is bound to jump, and I bind it to attack, it automatically unbinds from jump. If I then try to bind anything to that specific jump button, I’ll get a Invalid Index error at the InputMap.action_erase_event(action, existing[oldkey])