Is this the best way to add multiple keybinds to a single action?

I’ve been looking into some tutorials, mainly this one - 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.


<span style="color:#323232;">func _input(event):
</span><span style="color:#323232;">	if !current_button:
</span><span style="color:#323232;">		return
</span><span style="color:#323232;">	if event is InputEventKey and $keypress.visible:
</span><span style="color:#323232;">		var action: String
</span><span style="color:#323232;">		match current_button.name:
</span><span style="color:#323232;">			"rebind_jump":
</span><span style="color:#323232;">				action = "game_jump"
</span><span style="color:#323232;">		#Match repeat for each button/action, also "duplicated" for each of the alternative keys/buttons, as "alt_game_jump", etc
</span><span style="color:#323232;">		#The following lines happen after the match defines the action 
</span><span style="color:#323232;">		rebind(event,action, current_button.text)
</span><span style="color:#323232;">		current_button.text = event.as_text()
</span><span style="color:#323232;">		current_button = null
</span><span style="color:#323232;">
</span><span style="color:#323232;">
</span><span style="color:#323232;">## The rebind function is called by sending the event, a string of the action proper and the button's current text as the "oldkey"
</span><span style="color:#323232;">## rebind(event, "game_jump", $rebind_jump.text)
</span><span style="color:#323232;">## After the event call, the button's text is set like this: $rebind_jump.text = event.as_text()
</span><span style="color:#323232;">
</span><span style="color:#323232;">func rebind(event: InputEvent, action: String, oldkey:String):
</span><span style="color:#323232;">	var existing : Dictionary = {}
</span><span style="color:#323232;">	var key: String
</span><span style="color:#323232;">	for ia in InputMap.action_get_events(action):
</span><span style="color:#323232;">		#The split(" ") below happens because physical key presses are sent as "E (Phyisical)" or "Ctrl (Physical)"
</span><span style="color:#323232;">		if ia.as_text().split(" ")[0] != "Joypad":
</span><span style="color:#323232;">			key = ia.as_text().split(" ")[0]
</span><span style="color:#323232;">		else:
</span><span style="color:#323232;">			key = ia.as_text()
</span><span style="color:#323232;">		existing[key] = ia
</span><span style="color:#323232;">	for acts in InputMap.get_actions():
</span><span style="color:#323232;">		#Removes the key from any other events 
</span><span style="color:#323232;">		InputMap.action_erase_event(acts, event)
</span><span style="color:#323232;">	InputMap.action_erase_event(action, existing[oldkey])
</span><span style="color:#323232;">	InputMap.action_add_event(action, event)
</span>

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])

ICastFist, (edited )
@ICastFist@programming.dev avatar

Instead of another edit, here’s the “final” code i’ve managed to make. If a different button has that keybind, it gets erased. Haven’t managed to cause any errors:


<span style="color:#323232;">func rebind(event: InputEvent, action: String, oldkey:String):
</span><span style="color:#323232;">	var existing : Dictionary = {}
</span><span style="color:#323232;">	var key: String
</span><span style="color:#323232;">	for ia in InputMap.action_get_events(action):
</span><span style="color:#323232;">		if ia.as_text().split(" ")[0] != "Joypad":
</span><span style="color:#323232;">			key = ia.as_text().split(" ")[0]
</span><span style="color:#323232;">		else:
</span><span style="color:#323232;">			key = ia.as_text()
</span><span style="color:#323232;">		existing[key] = ia
</span><span style="color:#323232;">	for acts in InputMap.get_actions():
</span><span style="color:#323232;">		#Removes the key from any other events 
</span><span style="color:#323232;">		InputMap.action_erase_event(acts, event)
</span><span style="color:#323232;">	InputMap.action_add_event(action, event)
</span><span style="color:#323232;">	check_existing(event.as_text()) #Removes the keybind if it's present in any other key
</span><span style="color:#323232;">	current_button.text = event.as_text()
</span><span style="color:#323232;">
</span><span style="color:#323232;">func check_existing(event):
</span><span style="color:#323232;">	#This is the Array with all the buttons of "default" keybinds
</span><span style="color:#323232;">	for aa in df_keybinds:
</span><span style="color:#323232;">		if aa.text == event:
</span><span style="color:#323232;">			aa.text = ""
</span><span style="color:#323232;">	#This is the Array with all the buttons of "alternative" keybinds
</span><span style="color:#323232;">	for alt in alt_keybinds:
</span><span style="color:#323232;">		if alt.text == event:
</span><span style="color:#323232;">			alt.text = ""
</span><span style="color:#323232;">
</span><span style="color:#323232;">func _input(event):
</span><span style="color:#323232;">	if !current_button:
</span><span style="color:#323232;">		return
</span><span style="color:#323232;">	if event is InputEventKey and $keypress.visible:
</span><span style="color:#323232;">		var action = ""
</span><span style="color:#323232;">		match current_button.name:
</span><span style="color:#323232;">			"rebind_jump":
</span><span style="color:#323232;">				action = "game_jump"
</span><span style="color:#323232;">			#Other matches...
</span><span style="color:#323232;">		rebind(event,action, current_button.text)
</span><span style="color:#323232;">		$keypress.hide()
</span><span style="color:#323232;">		current_button = null
</span>
  • All
  • Subscribed
  • Moderated
  • Favorites
  • random
  • uselessserver093
  • Food
  • aaaaaaacccccccce
  • test
  • CafeMeta
  • [email protected]
  • testmag
  • MUD
  • RhythmGameZone
  • RSS
  • dabs
  • TheResearchGuardian
  • Ask_kbincafe
  • KbinCafe
  • feritale
  • Socialism
  • oklahoma
  • SuperSentai
  • KamenRider
  • All magazines