diff --git a/main/main.gd b/main/main.gd index 7a01295..9acff94 100644 --- a/main/main.gd +++ b/main/main.gd @@ -1023,7 +1023,7 @@ func _handle_data_root_controller_input(event: InputEvent) -> bool: ) if not setup_visible and not picker_visible: return false - var use_mapping: bool = _controller_mapping_manager.has_custom_mapping() + var use_mapping: bool = _controller_mapping_manager != null var accept_pressed: bool = ( _controller_mapping_manager.event_matches_role( event, diff --git a/player/player.gd b/player/player.gd index 9c79b2f..3bf0f67 100644 --- a/player/player.gd +++ b/player/player.gd @@ -333,10 +333,7 @@ func _process(delta: float) -> void: func _get_controller_camera_stick() -> Vector2: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): + if _controller_mapping_manager != null: return Vector2( _controller_mapping_manager.get_role_axis( ControllerMappingManagerType.ROLE_RIGHT_STICK_X @@ -352,12 +349,9 @@ func _get_controller_camera_stick() -> Vector2: func _get_controller_zoom_strength() -> float: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): + if _controller_mapping_manager != null: return _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_RT + ControllerMappingManagerType.ROLE_CAMERA_ZOOM ) return Input.get_joy_axis(0, CONTROLLER_ZOOM_TRIGGER_AXIS) diff --git a/settings/controller_mapping_manager.gd b/settings/controller_mapping_manager.gd index b1040bc..acff476 100644 --- a/settings/controller_mapping_manager.gd +++ b/settings/controller_mapping_manager.gd @@ -12,6 +12,7 @@ const PROFILE_BACKUP_PATH: String = "user://controller_mappings.json.backup" const MAX_PROFILE_BYTES: int = 1024 * 1024 const CAPTURE_AXIS_THRESHOLD: float = 0.55 const CAPTURE_AXIS_RELEASE_THRESHOLD: float = 0.30 +const ACTIVE_DEVICE_AXIS_THRESHOLD: float = 0.35 const MUOS_MAPPING_REVISION: String = "muos-v2" const MUOS_CONTROLLER_NAMES: Array[String] = [ "muOS-Keys", @@ -32,8 +33,13 @@ const ROLE_X: StringName = &"x" const ROLE_Y: StringName = &"y" const ROLE_LB: StringName = &"lb" const ROLE_RB: StringName = &"rb" -const ROLE_LT: StringName = &"lt" -const ROLE_RT: StringName = &"rt" +# Keep the serialized keys for profile compatibility, but name the roles after +# their game actions. A handheld may expose either action as a button, a +# dedicated trigger axis, or one half of a shared axis. +const ROLE_POINTER_MODIFIER: StringName = &"lt" +const ROLE_CAMERA_ZOOM: StringName = &"rt" +const ROLE_LT: StringName = ROLE_POINTER_MODIFIER +const ROLE_RT: StringName = ROLE_CAMERA_ZOOM const ROLE_SELECT: StringName = &"select" const ROLE_START: StringName = &"start" const ROLE_LEFT_STICK_CLICK: StringName = &"left_stick_click" @@ -54,8 +60,8 @@ const ROLE_ORDER: Array[StringName] = [ ROLE_Y, ROLE_LB, ROLE_RB, - ROLE_LT, - ROLE_RT, + ROLE_POINTER_MODIFIER, + ROLE_CAMERA_ZOOM, ROLE_SELECT, ROLE_START, ROLE_LEFT_STICK_CLICK, @@ -77,8 +83,8 @@ const ROLE_LABELS: Dictionary = { ROLE_Y: "interact", ROLE_LB: "focus chat or world", ROLE_RB: "primary action", - ROLE_LT: "virtual mouse", - ROLE_RT: "camera zoom", + ROLE_POINTER_MODIFIER: "virtual mouse modifier", + ROLE_CAMERA_ZOOM: "camera zoom", ROLE_SELECT: "chat", ROLE_START: "pause", ROLE_LEFT_STICK_CLICK: "sprint", @@ -100,8 +106,8 @@ const ROLE_PROMPTS: Dictionary = { ROLE_Y: "press the y button", ROLE_LB: "press the left bumper", ROLE_RB: "press the right bumper", - ROLE_LT: "squeeze the left trigger", - ROLE_RT: "squeeze the right trigger", + ROLE_POINTER_MODIFIER: "press or squeeze the virtual mouse modifier", + ROLE_CAMERA_ZOOM: "press or squeeze the camera zoom control", ROLE_SELECT: "press select / back", ROLE_START: "press start", ROLE_LEFT_STICK_CLICK: "click the left stick", @@ -122,7 +128,10 @@ const STICK_AXIS_ROLES: Array[StringName] = [ ROLE_RIGHT_STICK_X, ROLE_RIGHT_STICK_Y, ] -const TRIGGER_ROLES: Array[StringName] = [ROLE_LT, ROLE_RT] +const TRIGGER_ROLES: Array[StringName] = [ + ROLE_POINTER_MODIFIER, + ROLE_CAMERA_ZOOM, +] const BUTTON_ACTION_ROLES: Dictionary = { &"jump": ROLE_A, @@ -174,6 +183,8 @@ func _ready() -> void: ): Input.joy_connection_changed.connect(_on_joy_connection_changed) _install_known_controller_mappings() + for device_id: int in Input.get_connected_joypads(): + _sample_axis_rest_values(device_id) _capture_project_defaults() load_profiles() _refresh_active_controller() @@ -187,7 +198,16 @@ func _input(event: InputEvent) -> void: var motion_event := event as InputEventJoypadMotion if motion_event != null: device_id = motion_event.device - if device_id >= 0 and device_id != _active_device_id: + var claims_active_device: bool = ( + button_event != null and button_event.pressed + ) + if motion_event != null: + claims_active_device = _axis_motion_claims_device(motion_event) + if ( + claims_active_device + and device_id >= 0 + and device_id != _active_device_id + ): _set_active_controller(device_id) if button_event != null or motion_event != null: controller_input_observed.emit(event) @@ -283,6 +303,24 @@ func get_active_controller_name() -> String: return _active_controller_name +func get_active_controller_guid() -> String: + if not Input.get_connected_joypads().has(_active_device_id): + return "" + return Input.get_joy_guid(_active_device_id).strip_edges() + + +func get_active_profile_key() -> String: + return _active_profile_key + + +func get_active_controller_platform() -> String: + return OS.get_name() + + +func recalibrate_active_device() -> void: + _recalibrate_device(_active_device_id) + + func get_role_label(role: StringName) -> String: return str(ROLE_LABELS.get(role, str(role))) @@ -446,18 +484,70 @@ func validate_binding(role: StringName, binding: Dictionary) -> bool: func binding_label(binding: Dictionary) -> String: if str(binding.get("kind", "")) == "button": - return "button %d" % int(binding.get("button", -1)) + return _button_label(int(binding.get("button", -1))) if str(binding.get("kind", "")) == "axis": - return "axis %d %s" % [ - int(binding.get("axis", -1)), + return "%s %s" % [ + _axis_label(int(binding.get("axis", -1))), "+" if float(binding.get("direction", 0.0)) > 0.0 else "−", ] return "unmapped" +static func _button_label(button_index: int) -> String: + match button_index: + JOY_BUTTON_A: + return "A button" + JOY_BUTTON_B: + return "B button" + JOY_BUTTON_X: + return "X button" + JOY_BUTTON_Y: + return "Y button" + JOY_BUTTON_BACK: + return "back / select" + JOY_BUTTON_GUIDE: + return "guide button" + JOY_BUTTON_START: + return "start button" + JOY_BUTTON_LEFT_STICK: + return "left stick click" + JOY_BUTTON_RIGHT_STICK: + return "right stick click" + JOY_BUTTON_LEFT_SHOULDER: + return "left shoulder" + JOY_BUTTON_RIGHT_SHOULDER: + return "right shoulder" + JOY_BUTTON_DPAD_UP: + return "d-pad up" + JOY_BUTTON_DPAD_DOWN: + return "d-pad down" + JOY_BUTTON_DPAD_LEFT: + return "d-pad left" + JOY_BUTTON_DPAD_RIGHT: + return "d-pad right" + _: + return "button %d" % button_index + + +static func _axis_label(axis_index: int) -> String: + match axis_index: + JOY_AXIS_LEFT_X: + return "left stick X" + JOY_AXIS_LEFT_Y: + return "left stick Y" + JOY_AXIS_RIGHT_X: + return "right stick X" + JOY_AXIS_RIGHT_Y: + return "right stick Y" + JOY_AXIS_TRIGGER_LEFT: + return "left trigger axis" + JOY_AXIS_TRIGGER_RIGHT: + return "right trigger axis" + _: + return "axis %d" % axis_index + + func get_role_strength(role: StringName) -> float: - if not has_custom_mapping(): - return 0.0 var binding: Dictionary = get_binding(role) if str(binding.get("kind", "")) == "button": return ( @@ -472,8 +562,6 @@ func get_role_strength(role: StringName) -> float: func get_role_axis(role: StringName) -> float: - if not has_custom_mapping(): - return 0.0 var binding: Dictionary = get_binding(role) if str(binding.get("kind", "")) != "axis": return 0.0 @@ -496,7 +584,7 @@ func get_role_axis(role: StringName) -> float: func event_matches_role(event: InputEvent, role: StringName) -> bool: - if not has_custom_mapping(): + if not _event_belongs_to_active_device(event): return false var binding: Dictionary = get_binding(role) var button := event as InputEventJoypadButton @@ -511,7 +599,7 @@ func event_matches_role(event: InputEvent, role: StringName) -> bool: func event_uses_role(event: InputEvent, role: StringName) -> bool: - if not has_custom_mapping(): + if not _event_belongs_to_active_device(event): return false var binding: Dictionary = get_binding(role) var button := event as InputEventJoypadButton @@ -533,8 +621,12 @@ static func default_bindings() -> Dictionary: str(ROLE_Y): _button_binding(JOY_BUTTON_Y), str(ROLE_LB): _button_binding(JOY_BUTTON_LEFT_SHOULDER), str(ROLE_RB): _button_binding(JOY_BUTTON_RIGHT_SHOULDER), - str(ROLE_LT): _axis_binding(JOY_AXIS_TRIGGER_RIGHT, 1.0, 0.0), - str(ROLE_RT): _axis_binding(JOY_AXIS_TRIGGER_LEFT, 1.0, 0.0), + str(ROLE_POINTER_MODIFIER): _axis_binding( + JOY_AXIS_TRIGGER_RIGHT, 1.0, 0.0 + ), + str(ROLE_CAMERA_ZOOM): _axis_binding( + JOY_AXIS_TRIGGER_LEFT, 1.0, 0.0 + ), str(ROLE_SELECT): _button_binding(JOY_BUTTON_BACK), str(ROLE_START): _button_binding(JOY_BUTTON_START), str(ROLE_LEFT_STICK_CLICK): _button_binding(JOY_BUTTON_LEFT_STICK), @@ -589,12 +681,17 @@ func _axis_binding_strength( func _refresh_active_controller() -> void: var connected: Array[int] = Input.get_connected_joypads() + if connected.has(_active_device_id): + _set_active_controller(_active_device_id) + return _set_active_controller(connected[0] if not connected.is_empty() else 0) func _on_joy_connection_changed(device_id: int, connected: bool) -> void: + _axis_rest_by_device.erase(str(device_id)) if connected: _install_known_controller_mapping(device_id) + call_deferred("_recalibrate_device", device_id) _refresh_active_controller() @@ -648,7 +745,9 @@ static func should_install_muos_compatibility_mapping( func _set_active_controller(device_id: int) -> void: + var previous_device_id: int = _active_device_id var previous_profile_key: String = _active_profile_key + var previous_controller_name: String = _active_controller_name _active_device_id = maxi(device_id, 0) var controller_is_listed: bool = Input.get_connected_joypads().has( _active_device_id @@ -685,7 +784,29 @@ func _set_active_controller(device_id: int) -> void: _save_profiles() _sample_axis_rest_values(_active_device_id) _apply_active_profile() - active_controller_changed.emit(_active_controller_name) + if ( + previous_device_id != _active_device_id + or previous_profile_key != _active_profile_key + or previous_controller_name != _active_controller_name + ): + active_controller_changed.emit(_active_controller_name) + + +func _axis_motion_claims_device(event: InputEventJoypadMotion) -> bool: + var device_key: String = str(event.device) + if not _axis_rest_by_device.has(device_key): + _sample_axis_rest_values(event.device) + return false + var rest: float = _axis_rest_value(event.device, event.axis) + return absf(event.axis_value - rest) >= ACTIVE_DEVICE_AXIS_THRESHOLD + + +func _event_belongs_to_active_device(event: InputEvent) -> bool: + var button := event as InputEventJoypadButton + if button != null: + return button.device == _active_device_id + var motion := event as InputEventJoypadMotion + return motion != null and motion.device == _active_device_id func _sample_axis_rest_values(device_id: int) -> void: @@ -698,6 +819,16 @@ func _sample_axis_rest_values(device_id: int) -> void: _axis_rest_by_device[key] = values +func _recalibrate_device(device_id: int) -> void: + _axis_rest_by_device.erase(str(device_id)) + var connected: Array[int] = Input.get_connected_joypads() + if not connected.has(device_id) and not ( + connected.is_empty() and device_id == 0 + ): + return + _sample_axis_rest_values(device_id) + + func _axis_rest_value(device_id: int, axis: int) -> float: _sample_axis_rest_values(device_id) var values: Dictionary = _axis_rest_by_device.get(str(device_id), {}) @@ -741,7 +872,9 @@ func _restore_project_defaults() -> void: for action_value: Variant in _default_joy_events: var action: StringName = StringName(action_value) for event: InputEvent in _default_joy_events[action]: - InputMap.action_add_event(action, event.duplicate()) + var active_event: InputEvent = event.duplicate() + active_event.device = _active_device_id + InputMap.action_add_event(action, active_event) func _apply_active_profile() -> void: @@ -779,7 +912,7 @@ func _add_button_action_binding(action: StringName, value: Variant) -> void: if str(binding.get("kind", "")) != "button": return var event := InputEventJoypadButton.new() - event.device = -1 + event.device = _active_device_id event.button_index = int(binding.get("button", -1)) InputMap.action_add_event(action, event) @@ -798,7 +931,7 @@ func _add_axis_action_binding( float(binding.get("direction", -1.0)) ) var event := InputEventJoypadMotion.new() - event.device = -1 + event.device = _active_device_id event.axis = int(binding.get("axis", -1)) event.axis_value = logical_direction * -captured_negative_direction InputMap.action_add_event(action, event) diff --git a/tests/controller_mapping_validation.gd b/tests/controller_mapping_validation.gd index 614f15b..4416e2c 100644 --- a/tests/controller_mapping_validation.gd +++ b/tests/controller_mapping_validation.gd @@ -90,19 +90,21 @@ func _validate_manager(manager: ControllerMappingManagerType) -> String: str(defaults.keys()), ] var trigger_button := InputEventJoypadButton.new() + trigger_button.device = manager.get_active_device_id() trigger_button.button_index = JOY_BUTTON_MISC1 trigger_button.pressed = true var trigger_binding: Dictionary = manager.binding_from_event( - ControllerMappingManagerType.ROLE_LT, + ControllerMappingManagerType.ROLE_POINTER_MODIFIER, trigger_button, ) if str(trigger_binding.get("kind", "")) != "button": return "trigger role did not accept a button-backed handheld trigger" var trigger_motion := InputEventJoypadMotion.new() + trigger_motion.device = manager.get_active_device_id() trigger_motion.axis = JOY_AXIS_TRIGGER_RIGHT trigger_motion.axis_value = 1.0 trigger_binding = manager.binding_from_event( - ControllerMappingManagerType.ROLE_LT, + ControllerMappingManagerType.ROLE_POINTER_MODIFIER, trigger_motion, ) if str(trigger_binding.get("kind", "")) != "axis": @@ -119,13 +121,69 @@ func _validate_manager(manager: ControllerMappingManagerType) -> String: "kind": "button", "button": int(JOY_BUTTON_X), } - custom[str(ControllerMappingManagerType.ROLE_LT)] = trigger_binding + custom[str(ControllerMappingManagerType.ROLE_POINTER_MODIFIER)] = ( + trigger_binding + ) if not manager.replace_active_bindings(custom): return "valid custom mapping could not be saved" if not manager.has_custom_mapping(): return "saved custom mapping did not become active" if _keyboard_event_count(&"jump") != keyboard_events_before: return "controller remapping changed keyboard bindings" + var active_button := InputEventJoypadButton.new() + active_button.device = manager.get_active_device_id() + active_button.button_index = JOY_BUTTON_X + active_button.pressed = true + if not manager.event_matches_role( + active_button, + ControllerMappingManagerType.ROLE_A, + ): + return "active controller event did not match its custom role" + var inactive_button := active_button.duplicate() as InputEventJoypadButton + inactive_button.device = manager.get_active_device_id() + 1 + if manager.event_matches_role( + inactive_button, + ControllerMappingManagerType.ROLE_A, + ): + return "inactive controller event matched the active profile" + var inactive_release := InputEventJoypadButton.new() + inactive_release.device = manager.get_active_device_id() + 2 + inactive_release.button_index = JOY_BUTTON_A + inactive_release.pressed = false + var active_device_before_release: int = manager.get_active_device_id() + manager._input(inactive_release) + if manager.get_active_device_id() != active_device_before_release: + return "inactive controller button release stole ownership" + for event: InputEvent in InputMap.action_get_events(&"jump"): + if ( + event is InputEventJoypadButton + and event.device != manager.get_active_device_id() + ): + return "custom InputMap event was not scoped to the active device" + manager._axis_rest_by_device["4"] = {str(JOY_AXIS_LEFT_X): 0.0} + var drift := InputEventJoypadMotion.new() + drift.device = 4 + drift.axis = JOY_AXIS_LEFT_X + drift.axis_value = 0.12 + if manager._axis_motion_claims_device(drift): + return "minor inactive-stick drift claimed controller ownership" + manager._input(drift) + if manager.get_active_device_id() != active_device_before_release: + return "minor inactive-stick drift changed the active controller" + drift.axis_value = 0.72 + if not manager._axis_motion_claims_device(drift): + return "intentional inactive-stick motion did not claim ownership" + manager._input(drift) + if manager.get_active_device_id() != drift.device: + return "intentional stick motion did not change controller ownership" + for event: InputEvent in InputMap.action_get_events(&"jump"): + if event is InputEventJoypadButton and event.device != drift.device: + return "active-device change did not rescope InputMap events" + manager._set_active_controller(active_device_before_release) + manager._axis_rest_by_device["5"] = {str(JOY_AXIS_LEFT_X): 0.0} + manager._on_joy_connection_changed(5, false) + if manager._axis_rest_by_device.has("5"): + return "disconnected controller retained stale axis calibration" if not FileAccess.file_exists( ControllerMappingManagerType.PROFILE_PATH ): @@ -153,11 +211,13 @@ func _validate_auto_map(manager: ControllerMappingManagerType) -> String: ) if str(binding.get("kind", "")) == "button": var button := InputEventJoypadButton.new() + button.device = manager.get_active_device_id() button.button_index = int(binding.get("button", -1)) button.pressed = true manager.controller_input_observed.emit(button) else: var motion := InputEventJoypadMotion.new() + motion.device = manager.get_active_device_id() motion.axis = int(binding.get("axis", -1)) motion.axis_value = float(binding.get("direction", -1.0)) manager.controller_input_observed.emit(motion) @@ -181,16 +241,31 @@ func _validate_auto_map(manager: ControllerMappingManagerType) -> String: != UtilityPageStyle.OCEAN_DANGER ): return "duplicate controller bindings were not marked in red" - panel._begin_manual_capture(ControllerMappingManagerType.ROLE_LT) + manager.set_binding( + ControllerMappingManagerType.ROLE_B, + ControllerMappingManagerType.default_bindings()[ + str(ControllerMappingManagerType.ROLE_B) + ] as Dictionary, + ) + panel._begin_manual_capture( + ControllerMappingManagerType.ROLE_POINTER_MODIFIER + ) panel._process(ControllerMappingPanelType.CAPTURE_NEUTRAL_SECONDS) if "left trigger" in panel._progress_label.text.to_lower(): return "manual remapping still dictates a specific physical input" if "any button" not in panel._progress_label.text.to_lower(): return "manual remapping does not request a generic controller input" - panel._cancel_capture() + var cancel_button := InputEventJoypadButton.new() + cancel_button.device = manager.get_active_device_id() + cancel_button.button_index = JOY_BUTTON_B + cancel_button.pressed = true + manager.controller_input_observed.emit(cancel_button) + if panel.is_capturing(): + return "mapped controller back input did not cancel capture" panel._begin_auto_map() panel._process(ControllerMappingPanelType.CAPTURE_NEUTRAL_SECONDS) var held_left := InputEventJoypadMotion.new() + held_left.device = manager.get_active_device_id() held_left.axis = JOY_AXIS_LEFT_X held_left.axis_value = -1.0 for _index: int in 4: @@ -198,6 +273,7 @@ func _validate_auto_map(manager: ControllerMappingManagerType) -> String: if panel._auto_map_index != 0: return "auto-map accepted repeated analog motion without a neutral gate" var first_button := InputEventJoypadButton.new() + first_button.device = manager.get_active_device_id() first_button.button_index = JOY_BUTTON_A first_button.pressed = true manager.controller_input_observed.emit(first_button) diff --git a/ui/controller_mapping_panel.gd b/ui/controller_mapping_panel.gd index 8089d2a..809f3b5 100644 --- a/ui/controller_mapping_panel.gd +++ b/ui/controller_mapping_panel.gd @@ -58,6 +58,7 @@ func open_panel() -> void: if _mapping_manager == null: return _cancel_capture() + _mapping_manager.recalibrate_active_device() show() _refresh_bindings() _auto_map_button.grab_focus() @@ -140,8 +141,6 @@ func _on_controller_input_observed(event: InputEvent) -> void: if _capturing_role.is_empty(): return get_viewport().set_input_as_handled() - if _waiting_for_neutral: - return var button_event := event as InputEventJoypadButton var motion_event := event as InputEventJoypadMotion var event_device: int = -1 @@ -153,6 +152,20 @@ func _on_controller_input_observed(event: InputEvent) -> void: return if event_device != _capture_device_id: return + if ( + button_event != null + and button_event.pressed + and _capturing_role != ControllerMappingManagerType.ROLE_B + and _mapping_manager.event_matches_role( + event, + ControllerMappingManagerType.ROLE_B, + ) + ): + _cancel_capture() + _progress_label.text = "controller mapping cancelled" + return + if _waiting_for_neutral: + return _try_capture_event(event) @@ -224,8 +237,9 @@ func _build_interface() -> void: _instruction_label = Label.new() _instruction_label.text = ( - "auto-map walks through a standard xbox-style controller. " - + "select any row afterward to override it." + "auto-map walks through NETfishing's controller actions. " + + "select any row afterward to override it; the mapped back " + + "control cancels capture." ) _instruction_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART _instruction_label.add_theme_font_size_override("font_size", 15) diff --git a/ui/emote_radial_menu.gd b/ui/emote_radial_menu.gd index 165ceac..c081e27 100644 --- a/ui/emote_radial_menu.gd +++ b/ui/emote_radial_menu.gd @@ -112,10 +112,7 @@ func _update_selection() -> void: func _get_selection_stick() -> Vector2: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): + if _controller_mapping_manager != null: return Vector2( _controller_mapping_manager.get_role_axis( ControllerMappingManagerType.ROLE_RIGHT_STICK_X diff --git a/ui/game_ui.gd b/ui/game_ui.gd index b4e8518..2683d95 100644 --- a/ui/game_ui.gd +++ b/ui/game_ui.gd @@ -187,6 +187,10 @@ func _ready() -> void: _pause_settings_panel.crisp_reset_focus_requested.connect( crisp_reset_focus_requested.emit ) + if not Input.joy_connection_changed.is_connected( + _on_controller_connection_changed + ): + Input.joy_connection_changed.connect(_on_controller_connection_changed) func setup( @@ -404,7 +408,6 @@ func _handle_controller_chat_controls(event: InputEvent) -> bool: return false var use_mapping: bool = ( _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() ) var select_pressed: bool = ( _controller_mapping_manager.event_matches_role( @@ -541,13 +544,13 @@ func _handle_virtual_mouse_input(event: InputEvent) -> bool: func _handle_mapped_virtual_mouse_input(event: InputEvent) -> bool: var uses_activation: bool = _controller_mapping_manager.event_uses_role( event, - ControllerMappingManagerType.ROLE_LT, + ControllerMappingManagerType.ROLE_POINTER_MODIFIER, ) if uses_activation: var was_active: bool = _virtual_mouse_active _virtual_mouse_trigger_strength = ( _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_LT + ControllerMappingManagerType.ROLE_POINTER_MODIFIER ) ) if ( @@ -589,12 +592,12 @@ func _handle_mapped_virtual_mouse_input(event: InputEvent) -> bool: return true if _controller_mapping_manager.event_uses_role( event, - ControllerMappingManagerType.ROLE_RT, + ControllerMappingManagerType.ROLE_CAMERA_ZOOM, ): _set_virtual_mouse_button( MOUSE_BUTTON_RIGHT, _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_RT + ControllerMappingManagerType.ROLE_CAMERA_ZOOM ) >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD, ) return true @@ -776,7 +779,7 @@ func _poll_virtual_mouse_controller_state() -> void: func _poll_mapped_virtual_mouse_controller_state() -> void: var trigger_strength: float = _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_LT + ControllerMappingManagerType.ROLE_POINTER_MODIFIER ) if _virtual_mouse_active: _virtual_mouse_trigger_strength = trigger_strength @@ -787,7 +790,7 @@ func _poll_mapped_virtual_mouse_controller_state() -> void: _set_virtual_mouse_button( MOUSE_BUTTON_RIGHT, _controller_mapping_manager.get_role_strength( - ControllerMappingManagerType.ROLE_RT + ControllerMappingManagerType.ROLE_CAMERA_ZOOM ) >= VIRTUAL_MOUSE_TRIGGER_THRESHOLD, ) return @@ -1098,16 +1101,26 @@ func _controller_scroll_container_is_available( func _controller_menu_scroll_axis() -> float: - if _controller_mapping_manager.has_custom_mapping(): + if _controller_mapping_manager != null: return _controller_mapping_manager.get_role_axis( ControllerMappingManagerType.ROLE_RIGHT_STICK_Y ) return Input.get_joy_axis( - _controller_mapping_manager.get_active_device_id(), + 0, JOY_AXIS_RIGHT_Y, ) +func _on_controller_connection_changed( + device_id: int, + connected: bool, +) -> void: + _virtual_mouse_trigger_rest_by_device.erase(device_id) + _shared_trigger_rest_by_device.erase(device_id) + if not connected and _virtual_mouse_device_id == device_id: + _end_virtual_mouse() + + func close_player_menu() -> void: _player_menu.close_menu() diff --git a/ui/player_menu.gd b/ui/player_menu.gd index 208d329..09f768d 100644 --- a/ui/player_menu.gd +++ b/ui/player_menu.gd @@ -603,7 +603,6 @@ func _handle_controller_page_switch(event: InputEvent) -> bool: var button_event: InputEventJoypadButton = event as InputEventJoypadButton var use_mapping: bool = ( _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() ) var uses_left_bumper: bool = ( _controller_mapping_manager.event_uses_role( diff --git a/ui/profile_preview.gd b/ui/profile_preview.gd index eaec042..38779f2 100644 --- a/ui/profile_preview.gd +++ b/ui/profile_preview.gd @@ -51,10 +51,7 @@ func _process(delta: float) -> void: _controller_mapping_manager.get_role_axis( ControllerMappingManagerType.ROLE_RIGHT_STICK_X ) - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ) + if _controller_mapping_manager != null else Input.get_joy_axis(0, JOY_AXIS_RIGHT_X) ) if absf(right_stick) > 0.2: diff --git a/ui/quick_radial_menu.gd b/ui/quick_radial_menu.gd index 88b461d..96a9cd5 100644 --- a/ui/quick_radial_menu.gd +++ b/ui/quick_radial_menu.gd @@ -134,10 +134,7 @@ func _update_selection() -> void: func _get_selection_stick() -> Vector2: - if ( - _controller_mapping_manager != null - and _controller_mapping_manager.has_custom_mapping() - ): + if _controller_mapping_manager != null: return Vector2( _controller_mapping_manager.get_role_axis( ControllerMappingManagerType.ROLE_RIGHT_STICK_X