forked from woofmeow/straywild
Reject conflicting controller bindings
This commit is contained in:
parent
9ea4a6d5e1
commit
5daf97967a
3 changed files with 98 additions and 40 deletions
|
|
@ -282,7 +282,7 @@ func _validated_profiles(raw_profiles: Dictionary) -> Dictionary:
|
||||||
):
|
):
|
||||||
complete = false
|
complete = false
|
||||||
break
|
break
|
||||||
if not complete:
|
if not complete or bindings_have_conflicts(bindings):
|
||||||
continue
|
continue
|
||||||
validated[str(key_value)] = {
|
validated[str(key_value)] = {
|
||||||
"controller_name": str(
|
"controller_name": str(
|
||||||
|
|
@ -402,6 +402,8 @@ func replace_active_bindings(bindings: Dictionary) -> bool:
|
||||||
return false
|
return false
|
||||||
if not validate_binding(role, binding as Dictionary):
|
if not validate_binding(role, binding as Dictionary):
|
||||||
return false
|
return false
|
||||||
|
if bindings_have_conflicts(bindings):
|
||||||
|
return false
|
||||||
var previous: Dictionary = _profiles.duplicate(true)
|
var previous: Dictionary = _profiles.duplicate(true)
|
||||||
_profiles[_active_profile_key] = {
|
_profiles[_active_profile_key] = {
|
||||||
"controller_name": _active_controller_name,
|
"controller_name": _active_controller_name,
|
||||||
|
|
@ -484,6 +486,53 @@ func validate_binding(role: StringName, binding: Dictionary) -> bool:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
static func bindings_have_conflicts(bindings: Dictionary) -> bool:
|
||||||
|
for role_index: int in ROLE_ORDER.size():
|
||||||
|
var first_role: StringName = ROLE_ORDER[role_index]
|
||||||
|
var first_value: Variant = bindings.get(str(first_role), {})
|
||||||
|
if typeof(first_value) != TYPE_DICTIONARY:
|
||||||
|
continue
|
||||||
|
for other_index: int in range(role_index + 1, ROLE_ORDER.size()):
|
||||||
|
var second_role: StringName = ROLE_ORDER[other_index]
|
||||||
|
var second_value: Variant = bindings.get(str(second_role), {})
|
||||||
|
if typeof(second_value) != TYPE_DICTIONARY:
|
||||||
|
continue
|
||||||
|
if bindings_conflict(
|
||||||
|
first_role,
|
||||||
|
first_value as Dictionary,
|
||||||
|
second_role,
|
||||||
|
second_value as Dictionary,
|
||||||
|
):
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
static func bindings_conflict(
|
||||||
|
first_role: StringName,
|
||||||
|
first: Dictionary,
|
||||||
|
second_role: StringName,
|
||||||
|
second: Dictionary,
|
||||||
|
) -> bool:
|
||||||
|
var binding_kind: String = str(first.get("kind", ""))
|
||||||
|
if binding_kind != str(second.get("kind", "")):
|
||||||
|
return false
|
||||||
|
if binding_kind == "button":
|
||||||
|
return int(first.get("button", -1)) == int(
|
||||||
|
second.get("button", -1)
|
||||||
|
)
|
||||||
|
if binding_kind != "axis":
|
||||||
|
return false
|
||||||
|
if int(first.get("axis", -1)) != int(second.get("axis", -1)):
|
||||||
|
return false
|
||||||
|
var opposite_trigger_halves: bool = (
|
||||||
|
first_role in TRIGGER_ROLES
|
||||||
|
and second_role in TRIGGER_ROLES
|
||||||
|
and signf(float(first.get("direction", 0.0)))
|
||||||
|
!= signf(float(second.get("direction", 0.0)))
|
||||||
|
)
|
||||||
|
return not opposite_trigger_halves
|
||||||
|
|
||||||
|
|
||||||
func binding_label(binding: Dictionary) -> String:
|
func binding_label(binding: Dictionary) -> String:
|
||||||
if str(binding.get("kind", "")) == "button":
|
if str(binding.get("kind", "")) == "button":
|
||||||
return _button_label(int(binding.get("button", -1)))
|
return _button_label(int(binding.get("button", -1)))
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,10 @@ func _validate_manager(manager: ControllerMappingManagerType) -> String:
|
||||||
"kind": "button",
|
"kind": "button",
|
||||||
"button": int(JOY_BUTTON_X),
|
"button": int(JOY_BUTTON_X),
|
||||||
}
|
}
|
||||||
|
custom[str(ControllerMappingManagerType.ROLE_X)] = {
|
||||||
|
"kind": "button",
|
||||||
|
"button": int(JOY_BUTTON_A),
|
||||||
|
}
|
||||||
custom[str(ControllerMappingManagerType.ROLE_POINTER_MODIFIER)] = (
|
custom[str(ControllerMappingManagerType.ROLE_POINTER_MODIFIER)] = (
|
||||||
trigger_binding
|
trigger_binding
|
||||||
)
|
)
|
||||||
|
|
@ -159,6 +163,41 @@ func _validate_manager(manager: ControllerMappingManagerType) -> String:
|
||||||
return "valid custom mapping could not be saved"
|
return "valid custom mapping could not be saved"
|
||||||
if not manager.has_custom_mapping():
|
if not manager.has_custom_mapping():
|
||||||
return "saved custom mapping did not become active"
|
return "saved custom mapping did not become active"
|
||||||
|
var duplicate: Dictionary = custom.duplicate(true)
|
||||||
|
duplicate[str(ControllerMappingManagerType.ROLE_X)] = (
|
||||||
|
duplicate[str(ControllerMappingManagerType.ROLE_A)] as Dictionary
|
||||||
|
).duplicate(true)
|
||||||
|
if manager.replace_active_bindings(duplicate):
|
||||||
|
return "duplicate controller buttons were accepted"
|
||||||
|
var shared_trigger_axis: Dictionary = custom.duplicate(true)
|
||||||
|
shared_trigger_axis[
|
||||||
|
str(ControllerMappingManagerType.ROLE_POINTER_MODIFIER)
|
||||||
|
] = {
|
||||||
|
"kind": "axis",
|
||||||
|
"axis": int(JOY_AXIS_TRIGGER_LEFT),
|
||||||
|
"direction": 1.0,
|
||||||
|
"rest": 0.0,
|
||||||
|
}
|
||||||
|
shared_trigger_axis[
|
||||||
|
str(ControllerMappingManagerType.ROLE_CAMERA_ZOOM)
|
||||||
|
] = {
|
||||||
|
"kind": "axis",
|
||||||
|
"axis": int(JOY_AXIS_TRIGGER_LEFT),
|
||||||
|
"direction": -1.0,
|
||||||
|
"rest": 0.0,
|
||||||
|
}
|
||||||
|
if ControllerMappingManagerType.bindings_have_conflicts(
|
||||||
|
shared_trigger_axis
|
||||||
|
):
|
||||||
|
return "opposite halves of a shared trigger axis conflict"
|
||||||
|
var malformed_profiles: Dictionary = manager._validated_profiles({
|
||||||
|
"name:controller": {
|
||||||
|
"controller_name": "controller",
|
||||||
|
"bindings": duplicate,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if not malformed_profiles.is_empty():
|
||||||
|
return "a stored controller profile with duplicate buttons was accepted"
|
||||||
if _keyboard_event_count(&"jump") != keyboard_events_before:
|
if _keyboard_event_count(&"jump") != keyboard_events_before:
|
||||||
return "controller remapping changed keyboard bindings"
|
return "controller remapping changed keyboard bindings"
|
||||||
var active_button := InputEventJoypadButton.new()
|
var active_button := InputEventJoypadButton.new()
|
||||||
|
|
@ -309,12 +348,6 @@ func _validate_auto_map(manager: ControllerMappingManagerType) -> String:
|
||||||
ControllerMappingManagerType.default_bindings()[str(role)]
|
ControllerMappingManagerType.default_bindings()[str(role)]
|
||||||
as Dictionary
|
as Dictionary
|
||||||
)
|
)
|
||||||
if role == ControllerMappingManagerType.ROLE_B:
|
|
||||||
binding = (
|
|
||||||
ControllerMappingManagerType.default_bindings()[
|
|
||||||
str(ControllerMappingManagerType.ROLE_A)
|
|
||||||
] as Dictionary
|
|
||||||
)
|
|
||||||
if str(binding.get("kind", "")) == "button":
|
if str(binding.get("kind", "")) == "button":
|
||||||
var button := InputEventJoypadButton.new()
|
var button := InputEventJoypadButton.new()
|
||||||
button.device = manager.get_active_device_id()
|
button.device = manager.get_active_device_id()
|
||||||
|
|
@ -335,24 +368,12 @@ func _validate_auto_map(manager: ControllerMappingManagerType) -> String:
|
||||||
ControllerMappingManagerType.ROLE_ORDER.size()
|
ControllerMappingManagerType.ROLE_ORDER.size()
|
||||||
):
|
):
|
||||||
return "manual override list does not expose every mapped role"
|
return "manual override list does not expose every mapped role"
|
||||||
var conflict_button := panel._binding_buttons.get(
|
var duplicate_saved: bool = manager.set_binding(
|
||||||
ControllerMappingManagerType.ROLE_A
|
|
||||||
) as Button
|
|
||||||
var conflict_style := conflict_button.get_theme_stylebox(
|
|
||||||
&"normal"
|
|
||||||
) as StyleBoxFlat
|
|
||||||
if (
|
|
||||||
conflict_style == null
|
|
||||||
or conflict_style.bg_color
|
|
||||||
!= UtilityPageStyle.OCEAN_DANGER
|
|
||||||
):
|
|
||||||
return "duplicate controller bindings were not marked in red"
|
|
||||||
manager.set_binding(
|
|
||||||
ControllerMappingManagerType.ROLE_B,
|
ControllerMappingManagerType.ROLE_B,
|
||||||
ControllerMappingManagerType.default_bindings()[
|
manager.get_binding(ControllerMappingManagerType.ROLE_A),
|
||||||
str(ControllerMappingManagerType.ROLE_B)
|
|
||||||
] as Dictionary,
|
|
||||||
)
|
)
|
||||||
|
if duplicate_saved:
|
||||||
|
return "manual mapping accepted a controller button already in use"
|
||||||
panel._begin_manual_capture(
|
panel._begin_manual_capture(
|
||||||
ControllerMappingManagerType.ROLE_POINTER_MODIFIER
|
ControllerMappingManagerType.ROLE_POINTER_MODIFIER
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -580,24 +580,12 @@ func _bindings_conflict(
|
||||||
second_role: StringName,
|
second_role: StringName,
|
||||||
second: Dictionary,
|
second: Dictionary,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
var binding_kind: String = str(first.get("kind", ""))
|
return ControllerMappingManagerType.bindings_conflict(
|
||||||
if binding_kind != str(second.get("kind", "")):
|
first_role,
|
||||||
return false
|
first,
|
||||||
if binding_kind == "button":
|
second_role,
|
||||||
return int(first.get("button", -1)) == int(
|
second,
|
||||||
second.get("button", -1)
|
|
||||||
)
|
|
||||||
if binding_kind != "axis":
|
|
||||||
return false
|
|
||||||
if int(first.get("axis", -1)) != int(second.get("axis", -1)):
|
|
||||||
return false
|
|
||||||
var opposite_trigger_halves: bool = (
|
|
||||||
first_role in ControllerMappingManagerType.TRIGGER_ROLES
|
|
||||||
and second_role in ControllerMappingManagerType.TRIGGER_ROLES
|
|
||||||
and signf(float(first.get("direction", 0.0)))
|
|
||||||
!= signf(float(second.get("direction", 0.0)))
|
|
||||||
)
|
)
|
||||||
return not opposite_trigger_halves
|
|
||||||
|
|
||||||
|
|
||||||
func _apply_binding_button_style(button: Button, has_conflict: bool) -> void:
|
func _apply_binding_button_style(button: Button, has_conflict: bool) -> void:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue