diff --git a/Assets/Tests/InputSystem/Plugins/OnScreenTests.cs b/Assets/Tests/InputSystem/Plugins/OnScreenTests.cs index fd24a691b9..c25675a958 100644 --- a/Assets/Tests/InputSystem/Plugins/OnScreenTests.cs +++ b/Assets/Tests/InputSystem/Plugins/OnScreenTests.cs @@ -395,7 +395,7 @@ public void Devices_DisablingLastOnScreenControlDoesReportActiveControl() // https://fogbugz.unity3d.com/f/cases/1271942 [UnityTest] [Category("Devices")] - public IEnumerator Devices_CanHaveOnScreenJoystickControls() + public IEnumerator Devices_CanHaveOnScreenJoystickControls([Values(false, true)] bool useInIsolation) { foreach (var c in Camera.allCameras) Object.Destroy(c.gameObject); @@ -422,18 +422,33 @@ public IEnumerator Devices_CanHaveOnScreenJoystickControls() canvasGO.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; - var stickGO = new GameObject("Stick"); - stickGO.SetActive(false); - var stickTransform = stickGO.AddComponent(); - var stick = stickGO.AddComponent(); - stickGO.AddComponent(); - stickTransform.SetParent(canvasTransform); - stickTransform.anchorMin = new Vector2(0, 0); - stickTransform.anchorMax = new Vector2(0, 0); - stickTransform.anchoredPosition = new Vector2(100, 100); - stickTransform.sizeDelta = new Vector2(100, 100); - stick.controlPath = "/leftStick"; - stickGO.SetActive(true); + var stickLeftGO = new GameObject("StickLeft"); + stickLeftGO.SetActive(false); + var stickLeftTransform = stickLeftGO.AddComponent(); + var stickLeft = stickLeftGO.AddComponent(); + stickLeft.useIsolatedInputActions = useInIsolation; + stickLeftGO.AddComponent(); + stickLeftTransform.SetParent(canvasTransform); + stickLeftTransform.anchorMin = new Vector2(0, 0); + stickLeftTransform.anchorMax = new Vector2(0, 0); + stickLeftTransform.anchoredPosition = new Vector2(100, 100); + stickLeftTransform.sizeDelta = new Vector2(100, 100); + stickLeft.controlPath = "/leftStick"; + stickLeftGO.SetActive(true); + + var stickRightGO = new GameObject("StickRight"); + stickRightGO.SetActive(false); + var stickRightTransform = stickRightGO.AddComponent(); + var stickRight = stickRightGO.AddComponent(); + stickRight.useIsolatedInputActions = useInIsolation; + stickRightGO.AddComponent(); + stickRightTransform.SetParent(canvasTransform); + stickRightTransform.anchorMin = new Vector2(0, 0); + stickRightTransform.anchorMax = new Vector2(0, 0); + stickRightTransform.anchoredPosition = new Vector2(500, 100); + stickRightTransform.sizeDelta = new Vector2(100, 100); + stickRight.controlPath = "/rightStick"; + stickRightGO.SetActive(true); var buttonGO = new GameObject("Button"); buttonGO.SetActive(false); @@ -464,7 +479,7 @@ public IEnumerator Devices_CanHaveOnScreenJoystickControls() Assert.That(player.devices, Is.EquivalentTo(new[] { Gamepad.all[0] })); - // Touch the stick and drag it upwards. + // Touch the Left stick and drag it upwards. BeginTouch(1, new Vector2(150, 150)); yield return null; eventSystem.Update(); @@ -491,6 +506,38 @@ public IEnumerator Devices_CanHaveOnScreenJoystickControls() InputSystem.Update(); // Button is feeding events when responding to UI events. Assert.That(Gamepad.all[0].buttonSouth.isPressed, Is.False); + + // Touch the right stick and drag it downwards + BeginTouch(2, new Vector2(550, 150)); + yield return null; + eventSystem.Update(); + Assert.That(eventSystem.IsPointerOverGameObject(), Is.True); + MoveTouch(2, new Vector2(550, 50)); + yield return null; + eventSystem.Update(); + InputSystem.Update(); // Stick is feeding events when responding to UI events. + + Assert.That(Gamepad.all[0].leftStick.ReadValue(), Is.EqualTo(new Vector2(0, 1)).Using(Vector2EqualityComparer.Instance)); + Assert.That(Gamepad.all[0].rightStick.ReadValue(), Is.EqualTo(new Vector2(0, -1)).Using(Vector2EqualityComparer.Instance)); + + // Release finger one and move second and ensure that it still works + EndTouch(1, new Vector2(550, 200)); + MoveTouch(2, new Vector2(600, 150)); + yield return null; + eventSystem.Update(); + InputSystem.Update(); // Stick is feeding events when responding to UI events. + + Assert.That(Gamepad.all[0].leftStick.ReadValue(), Is.EqualTo(new Vector2(0, 0)).Using(Vector2EqualityComparer.Instance)); + Assert.That(Gamepad.all[0].rightStick.ReadValue(), Is.EqualTo(new Vector2(1, 0)).Using(Vector2EqualityComparer.Instance)); + + // Release finger two + EndTouch(2, new Vector2(600, 150)); + yield return null; + eventSystem.Update(); + InputSystem.Update(); // Stick is feeding events when responding to UI events. + + Assert.That(Gamepad.all[0].leftStick.ReadValue(), Is.EqualTo(new Vector2(0, 0)).Using(Vector2EqualityComparer.Instance)); + Assert.That(Gamepad.all[0].rightStick.ReadValue(), Is.EqualTo(new Vector2(0, 0)).Using(Vector2EqualityComparer.Instance)); } [UnityTest] @@ -519,6 +566,9 @@ public IEnumerator Devices_OnScreenStickDoesNotReceivePointerUpEventsInIsolatedM uiTestScene.uiInputModule.actionsAsset.actionMaps[0].LazyResolveBindings(true); }; + // Ensure that the OnScreenStick component has been started + yield return null; + yield return uiTestScene.PressAndDrag(image, new Vector2(50, 50)); // The OnScreenStick when being driven from the UI (non-isolated mode) queues the events into the next diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 7d11b796b5..f60b098202 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -35,6 +35,7 @@ however, it has to be formatted properly to pass verification tests. - Fixed an issue where action map delegates were not updated when the asset already assigned to the PlayerInput component were changed [ISXB-711](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-711). - Fixed Action properties edition in the UI Toolkit version of the Input Actions Asset editor. [ISXB-1277](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1277) - Fixed an issue where batch jobs would fail with "Error: Error building Player because scripts are compiling" if a source generated .inputactions asset is out of sync with its generated source code (ISXB-1300). +- Fixed multiple `OnScreenStick` Components that does not work together when using them simultaneously in isolation mode. [ISXB-813](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-813) ### Changed - Added back the InputManager to InputSystem project-wide asset migration code with performance improvement (ISX-2086). diff --git a/Packages/com.unity.inputsystem/InputSystem/Plugins/OnScreen/OnScreenStick.cs b/Packages/com.unity.inputsystem/InputSystem/Plugins/OnScreen/OnScreenStick.cs index c226926a02..25920c27c2 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Plugins/OnScreen/OnScreenStick.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Plugins/OnScreen/OnScreenStick.cs @@ -6,6 +6,7 @@ using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.Utilities; using UnityEngine.UI; +using UnityEngine.InputSystem.Controls; #if UNITY_EDITOR using UnityEditor; @@ -91,7 +92,10 @@ private void Start() if (m_PointerDownAction == null || m_PointerDownAction.bindings.Count == 0) { if (m_PointerDownAction == null) - m_PointerDownAction = new InputAction(); + m_PointerDownAction = new InputAction(type: InputActionType.PassThrough); + // ensure PassThrough mode + else if (m_PointerDownAction.m_Type != InputActionType.PassThrough) + m_PointerDownAction.m_Type = InputActionType.PassThrough; #if UNITY_EDITOR InputExitPlayModeAnalytic.suppress = true; @@ -121,8 +125,7 @@ private void Start() #endif } - m_PointerDownAction.started += OnPointerDown; - m_PointerDownAction.canceled += OnPointerUp; + m_PointerDownAction.performed += OnPointerChanged; m_PointerDownAction.Enable(); m_PointerMoveAction.Enable(); } @@ -154,8 +157,7 @@ private void OnDestroy() { if (m_UseIsolatedInputActions) { - m_PointerDownAction.started -= OnPointerDown; - m_PointerDownAction.canceled -= OnPointerUp; + m_PointerDownAction.performed -= OnPointerChanged; } } @@ -227,11 +229,20 @@ private void EndInteraction() private void OnPointerDown(InputAction.CallbackContext ctx) { + if (m_IsIsolationActive) { return; } Debug.Assert(EventSystem.current != null); var screenPosition = Vector2.zero; - if (ctx.control?.device is Pointer pointer) + TouchControl touchControl = null; + if (ctx.control?.parent is TouchControl touch) + { + touchControl = touch; + screenPosition = touch.position.ReadValue(); + } + else if (ctx.control?.device is Pointer pointer) + { screenPosition = pointer.position.ReadValue(); + } m_PointerEventData.position = screenPosition; EventSystem.current.RaycastAll(m_PointerEventData, m_RaycastResults); @@ -251,23 +262,63 @@ private void OnPointerDown(InputAction.CallbackContext ctx) return; BeginInteraction(screenPosition, GetCameraFromCanvas()); + if (touchControl != null) + { + m_TouchControl = touchControl; + m_PointerMoveAction.ApplyBindingOverride($"{touchControl.path}/position", path: "/touch*/position"); + } + m_PointerMoveAction.performed += OnPointerMove; + m_IsIsolationActive = true; + } + + private void OnPointerChanged(InputAction.CallbackContext ctx) + { + if (ctx.control.IsPressed()) + OnPointerDown(ctx); + else + OnPointerUp(ctx); } private void OnPointerMove(InputAction.CallbackContext ctx) { // only pointer devices are allowed Debug.Assert(ctx.control?.device is Pointer); + Vector2 screenPosition; - var screenPosition = ((Pointer)ctx.control.device).position.ReadValue(); + // If it's a finger take the value from the finger that initiated the change + if (m_TouchControl != null) + { + // if the finger is up ignore the move + if (m_TouchControl.isInProgress == false) + { + return; + } + screenPosition = m_TouchControl.position.ReadValue(); + } + else + { + screenPosition = ((Pointer)ctx.control.device).position.ReadValue(); + } MoveStick(screenPosition, GetCameraFromCanvas()); } private void OnPointerUp(InputAction.CallbackContext ctx) { + if (!m_IsIsolationActive) return; + + // if it's a finger ensure that is the one that get released + if (m_TouchControl != null) + { + if (m_TouchControl.isInProgress) return; + m_PointerMoveAction.ApplyBindingOverride(null, path: "/touch*/position"); + m_TouchControl = null; + } + EndInteraction(); m_PointerMoveAction.performed -= OnPointerMove; + m_IsIsolationActive = false; } private Camera GetCameraFromCanvas() @@ -430,6 +481,10 @@ public bool useIsolatedInputActions private List m_RaycastResults; [NonSerialized] private PointerEventData m_PointerEventData; + [NonSerialized] + private TouchControl m_TouchControl; + [NonSerialized] + private bool m_IsIsolationActive; protected override string controlPathInternal {