set_action_key_or_button does not work between gamepad/keyboard
Salvakiya opened this issue · 4 comments
using set_action_key_or_button does not properly swap out joypad/keyboard inputs. Adding exposing "swap_if_taken" to set_action_key_or_button and additionally adding the proper logic to handle the swap between joypad/keyboard would be a possible solution.
Possibly might be better to have a separate optional parameter like "swap_if_taken" called "swap_key_and_button_if_taken" which defaults to false as to not introduce breaking changes.
Godot version 4.1.x
Edit: To clarify, the joy buttons will swap with itself just fine.. but swapping buttons and keyboard inputs dont properly talk to eachother... so setting a joypad button on a spot with a keyboard input wont move the keyboard input to the joypads old location.
after viewing the code... it may be a neat solution to combine the update functions all into one.. since their code is very similar.
here is an untested "unified" version of those _update functions. Also partially supporting mouse/joypad motion as "buttons".
its only a partial solution and may not be the one you want.
# Snap vector2 to 8 directions
func vectorTo8(vec2:Vector2) -> float:
# 0.0 = E
# 1.0 = NE
# 2.0 = N
# and so on
var e_dir = atan2(vec2.x,vec2.y)
return fmod(roundf(8.0 * e_dir / (2.0*PI) + 8.0), 8.0)
func _update_action(
target_action: StringName,
actual_event: InputEvent,
swap_if_taken: bool,
only_accept_one: bool,
only_replace_key = "",
only_replace_button = JOY_BUTTON_INVALID,
only_replace_mouse = MOUSE_BUTTON_NONE
) -> Error:
var clashing_action = ""
var clashing_event
if swap_if_taken:
for action in InputMap.get_actions():
if action == target_action: continue
for event in InputMap.action_get_events(action):
if event.get_class() == actual_event.get_class():
var _clash = false
match event.get_class():
"InputEventKey": _clash = (event.physical_keycode == actual_event.physical_keycode)
"InputEventMouseButton": _clash = (event.button_index == actual_event.button_index)
"InputEventMouseMotion": _clash = (vectorTo8(event.velocity) == vectorTo8(actual_event.velocity))
"InputEventJoypadButton": _clash = (event.button_index == actual_event.button_index)
"InputEventJoypadMotion": _clash = (event.axis == actual_event.axis) and (sign(event.axis_value) == sign(actual_event.axis_value))
if _clash:
clashing_action = action
clashing_event = event
# Find the key based event for the target action
for event in InputMap.action_get_events(target_action):
match event.get_class():
"InputEventKey":
if only_replace_key != "" and only_replace_key != OS.get_keycode_string(event.physical_keycode) and only_replace_key != event.as_text():
continue
# Add the current mapping to the clashing action
if clashing_action:
InputMap.action_erase_event(clashing_action, clashing_event)
InputMap.action_add_event(clashing_action, event)
action_key_changed.emit(clashing_action, OS.get_keycode_string(event.physical_keycode))
# Remove the current mapping
InputMap.action_erase_event(target_action, event)
"InputEventJoyButton":
if only_replace_button != JOY_BUTTON_INVALID and only_replace_button != actual_event.button_index:
continue
# Add the current mapping to the clashing action
if clashing_action:
InputMap.action_erase_event(clashing_action, clashing_event)
InputMap.action_add_event(clashing_action, event)
action_button_changed.emit(clashing_action, event.button_index)
# Remove the current mapping
InputMap.action_erase_event(target_action, event)
"InputEventMouseButton":
# Add the current mapping to the clashing action
if clashing_action:
InputMap.action_erase_event(clashing_action, clashing_event)
InputMap.action_add_event(clashing_action, event)
action_mouse_button_changed.emit(clashing_action, event.button_index)
# Remove the current mapping
InputMap.action_erase_event(target_action, event)
match actual_event.get_class():
"InputEventKey":
# Add the new event to the target action
var next_event = InputEventKey.new()
next_event.physical_keycode = OS.find_keycode_from_string(actual_event.physical_keycode)
InputMap.action_add_event(target_action, next_event)
action_key_changed.emit(target_action, OS.get_keycode_string(next_event.physical_keycode))
"InputEventJoyButton":
var next_event = InputEventJoypadButton.new()
next_event.button_index = actual_event.button_index
InputMap.action_add_event(target_action, next_event)
action_button_changed.emit(target_action, next_event.button_index)
"InputEventMouseButton":
var next_event = InputEventMouseButton.new()
next_event.button_index = actual_event.button_index
InputMap.action_add_event(target_action, next_event)
action_mouse_button_changed.emit(target_action, next_event.button_index)
return OK
That's working as expected. Replacing a joypad button should only be done with another joypad button and same for keyboard. If you're trying to set up something for multiplayer then this addon isn't really meant for that yet.
That's working as expected. Replacing a joypad button should only be done with another joypad button and same for keyboard. If you're trying to set up something for multiplayer then this addon isn't really meant for that yet.
this is not related to multiplayer. only that the function set_action_key_or_button
exists and does not behave the same as set_action_key
and set_action_button
when it comes to swapping inputs around.