Skip to content

Commit

Permalink
add MultiplayerInput.set_ui_action_device
Browse files Browse the repository at this point in the history
and also DeviceInput.take_ui_actions()

and also added some more doc comments, and upgraded to 4.1
  • Loading branch information
matjlars committed Oct 15, 2023
1 parent 930ae93 commit 1914d97
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 25 deletions.
6 changes: 6 additions & 0 deletions addons/multiplayer_input/device_input.gd
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ func is_action_pressed(action: StringName, exact_match: bool = false) -> bool:
if !is_connected: return false
return MultiplayerInput.is_action_pressed(device, action, exact_match)

## Takes exclusive control over all "ui_" actions.
## See MultiplayerInput.set_ui_action_device() doc for more info.
func take_ui_actions():
if !is_connected: return
MultiplayerInput.set_ui_action_device(device)

## Internal method that is called whenever any device is connected or disconnected.
## This is how this object keeps its "is_connected" property updated.
func _on_joy_connection_changed(_device: int, connected: bool):
Expand Down
57 changes: 53 additions & 4 deletions addons/multiplayer_input/multiplayer_input.gd
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var device_actions = {}
func _init():
reset()

# call this if you change any of the core actions or need to reset everything
# Call this if you change any of the core actions or need to reset everything.
func reset():
InputMap.load_from_project_settings()
core_actions = InputMap.get_actions()
Expand All @@ -35,9 +35,10 @@ func reset():
# by setting device id to 8 (out of range, so they'll never trigger)
# I can't just delete them because they're used as blueprints
# ... when a joypad connects
# This skips UI actions so it doesn't mess them up.
for action in core_actions:
for e in InputMap.action_get_events(action):
if _is_joypad_event(e):
if _is_joypad_event(e) and !is_ui_action(action):
e.device = 8

# create actions for already connected gamepads
Expand Down Expand Up @@ -103,22 +104,26 @@ func _delete_actions_for_device(device: int):

# use these functions to query the action states just like normal Input functions

## This is equivalent to Input.get_action_raw_strength except it will only check the relevant device.
func get_action_raw_strength(device: int, action: StringName, exact_match: bool = false) -> float:
if device >= 0:
action = get_action_name(device, action)
return Input.get_action_raw_strength(action, exact_match)


## This is equivalent to Input.get_action_strength except it will only check the relevant device.
func get_action_strength(device: int, action: StringName, exact_match: bool = false) -> float:
if device >= 0:
action = get_action_name(device, action)
return Input.get_action_strength(action, exact_match)

## This is equivalent to Input.get_axis except it will only check the relevant device.
func get_axis(device: int, negative_action: StringName, positive_action: StringName) -> float:
if device >= 0:
negative_action = get_action_name(device, negative_action)
positive_action = get_action_name(device, positive_action)
return Input.get_axis(negative_action, positive_action)

## This is equivalent to Input.get_vector except it will only check the relevant device.
func get_vector(device: int, negative_x: StringName, positive_x: StringName, negative_y: StringName, positive_y: StringName, deadzone: float = -1.0) -> Vector2:
if device >= 0:
negative_x = get_action_name(device, negative_x)
Expand All @@ -127,22 +132,25 @@ func get_vector(device: int, negative_x: StringName, positive_x: StringName, neg
positive_y = get_action_name(device, positive_y)
return Input.get_vector(negative_x, positive_x, negative_y, positive_y, deadzone)

## This is equivalent to Input.is_action_just_pressed except it will only check the relevant device.
func is_action_just_pressed(device: int, action: StringName, exact_match: bool = false) -> bool:
if device >= 0:
action = get_action_name(device, action)
return Input.is_action_just_pressed(action, exact_match)

## This is equivalent to Input.is_action_just_released except it will only check the relevant device.
func is_action_just_released(device: int, action: StringName, exact_match: bool = false) -> bool:
if device >= 0:
action = get_action_name(device, action)
return Input.is_action_just_released(action, exact_match)

## This is equivalent to Input.is_action_pressed except it will only check the relevant device.
func is_action_pressed(device: int, action: StringName, exact_match: bool = false) -> bool:
if device >= 0:
action = get_action_name(device, action)
return Input.is_action_pressed(action, exact_match)

# returns the name of a gamepad-specific action
## Returns the name of a gamepad-specific action
func get_action_name(device: int, action: StringName) -> StringName:
if device >= 0:
assert(device_actions.has(device), "Device %s has no actions. Maybe the joypad is disconnected." % device)
Expand All @@ -154,5 +162,46 @@ func get_action_name(device: int, action: StringName) -> StringName:
# return the normal action name for the keyboard player
return action

## Restricts actions that start with "ui_" to only work on a single device.
## Pass a -2 to reset it back to default behavior, to allow all devices to trigger "ui_" actions.
## For example, pass a -1 if you want only the keyboard/mouse device to control menus.
## NOTE: this calls reset(), so if you make any changes to the InputMap via code, you'll need to make them again.
func set_ui_action_device(device: int):
# First, totally re-create the InputMap for all devices
# This is necessary because this function may have messed up the UI Actions
# ... on a previous call
reset()

# We are back to default behavior.
# So if that's what the caller wants, we're done!
if device == -2: return

# find all ui actions and erase irrelevant events
for action in InputMap.get_actions():
# ignore non-ui-actions
if !is_ui_action(action): break

if device == -1:
# in this context, we want to erase all joypad events
for e in InputMap.action_get_events(action):
if _is_joypad_event(e):
InputMap.action_erase_event(action, e)
else:
# in this context, we want to delete all non-joypad events.
# and we also want to set the event's device to the given device.
for e in InputMap.action_get_events(action):
if _is_joypad_event(e):
e.device = device
else:
# this isn't event a joypad event, so erase it entirely
InputMap.action_erase_event(action, e)

## Returns true if the given event is a joypad event.
func _is_joypad_event(event: InputEvent) -> bool:
return event is InputEventJoypadButton or event is InputEventJoypadMotion

## Returns true if this is a UI action.
## Which basically just means it starts with "ui_".
## But you can override this in your project if you want.
func is_ui_action(action_name: StringName):
return action_name.begins_with("ui_")
2 changes: 1 addition & 1 deletion icon.png.import
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.cte
[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
Expand Down
30 changes: 10 additions & 20 deletions project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,10 @@

config_version=5

_global_script_classes=[{
"base": "RefCounted",
"class": &"DeviceInput",
"language": &"GDScript",
"path": "res://addons/multiplayer_input/device_input.gd"
}]
_global_script_class_icons={
"DeviceInput": ""
}

[application]

config/name="MultiplayerInput"
config/features=PackedStringArray("4.0", "Forward Plus")
config/features=PackedStringArray("4.1", "Forward Plus")

[autoload]

Expand All @@ -35,35 +25,35 @@ enabled=PackedStringArray("res://addons/multiplayer_input/plugin.cfg")

move_left={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":65,"physical_keycode":65,"key_label":65,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
]
}
move_right={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
]
}
move_down={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
]
}
move_up={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
]
}
join={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"unicode":0,"echo":false,"script":null)
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
]
}

0 comments on commit 1914d97

Please sign in to comment.