Skip to content

Commit d209cbe

Browse files
committed
Fixed multiple OnScreenStick Components that does not work together when using them simultaneously in isolation mode.
1 parent d5f8543 commit d209cbe

File tree

3 files changed

+129
-23
lines changed

3 files changed

+129
-23
lines changed

Assets/Tests/InputSystem/Plugins/OnScreenTests.cs

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ public void Devices_DisablingLastOnScreenControlDoesReportActiveControl()
395395
// https://fogbugz.unity3d.com/f/cases/1271942
396396
[UnityTest]
397397
[Category("Devices")]
398-
public IEnumerator Devices_CanHaveOnScreenJoystickControls()
398+
public IEnumerator Devices_CanHaveOnScreenJoystickControls([Values(false, true)] bool useInIsolation)
399399
{
400400
foreach (var c in Camera.allCameras)
401401
Object.Destroy(c.gameObject);
@@ -422,18 +422,33 @@ public IEnumerator Devices_CanHaveOnScreenJoystickControls()
422422
canvasGO.AddComponent<GraphicRaycaster>();
423423
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
424424

425-
var stickGO = new GameObject("Stick");
426-
stickGO.SetActive(false);
427-
var stickTransform = stickGO.AddComponent<RectTransform>();
428-
var stick = stickGO.AddComponent<OnScreenStick>();
429-
stickGO.AddComponent<Image>();
430-
stickTransform.SetParent(canvasTransform);
431-
stickTransform.anchorMin = new Vector2(0, 0);
432-
stickTransform.anchorMax = new Vector2(0, 0);
433-
stickTransform.anchoredPosition = new Vector2(100, 100);
434-
stickTransform.sizeDelta = new Vector2(100, 100);
435-
stick.controlPath = "<Gamepad>/leftStick";
436-
stickGO.SetActive(true);
425+
var stickLeftGO = new GameObject("StickLeft");
426+
stickLeftGO.SetActive(false);
427+
var stickLeftTransform = stickLeftGO.AddComponent<RectTransform>();
428+
var stickLeft = stickLeftGO.AddComponent<OnScreenStick>();
429+
stickLeft.useIsolatedInputActions = useInIsolation;
430+
stickLeftGO.AddComponent<Image>();
431+
stickLeftTransform.SetParent(canvasTransform);
432+
stickLeftTransform.anchorMin = new Vector2(0, 0);
433+
stickLeftTransform.anchorMax = new Vector2(0, 0);
434+
stickLeftTransform.anchoredPosition = new Vector2(100, 100);
435+
stickLeftTransform.sizeDelta = new Vector2(100, 100);
436+
stickLeft.controlPath = "<Gamepad>/leftStick";
437+
stickLeftGO.SetActive(true);
438+
439+
var stickRightGO = new GameObject("StickRight");
440+
stickRightGO.SetActive(false);
441+
var stickRightTransform = stickRightGO.AddComponent<RectTransform>();
442+
var stickRight = stickRightGO.AddComponent<OnScreenStick>();
443+
stickRight.useIsolatedInputActions = useInIsolation;
444+
stickRightGO.AddComponent<Image>();
445+
stickRightTransform.SetParent(canvasTransform);
446+
stickRightTransform.anchorMin = new Vector2(0, 0);
447+
stickRightTransform.anchorMax = new Vector2(0, 0);
448+
stickRightTransform.anchoredPosition = new Vector2(500, 100);
449+
stickRightTransform.sizeDelta = new Vector2(100, 100);
450+
stickRight.controlPath = "<Gamepad>/rightStick";
451+
stickRightGO.SetActive(true);
437452

438453
var buttonGO = new GameObject("Button");
439454
buttonGO.SetActive(false);
@@ -464,7 +479,7 @@ public IEnumerator Devices_CanHaveOnScreenJoystickControls()
464479

465480
Assert.That(player.devices, Is.EquivalentTo(new[] { Gamepad.all[0] }));
466481

467-
// Touch the stick and drag it upwards.
482+
// Touch the Left stick and drag it upwards.
468483
BeginTouch(1, new Vector2(150, 150));
469484
yield return null;
470485
eventSystem.Update();
@@ -491,6 +506,38 @@ public IEnumerator Devices_CanHaveOnScreenJoystickControls()
491506
InputSystem.Update(); // Button is feeding events when responding to UI events.
492507

493508
Assert.That(Gamepad.all[0].buttonSouth.isPressed, Is.False);
509+
510+
// Touch the right stick and drag it downwards
511+
BeginTouch(2, new Vector2(550, 150));
512+
yield return null;
513+
eventSystem.Update();
514+
Assert.That(eventSystem.IsPointerOverGameObject(), Is.True);
515+
MoveTouch(2, new Vector2(550, 50));
516+
yield return null;
517+
eventSystem.Update();
518+
InputSystem.Update(); // Stick is feeding events when responding to UI events.
519+
520+
Assert.That(Gamepad.all[0].leftStick.ReadValue(), Is.EqualTo(new Vector2(0, 1)).Using(Vector2EqualityComparer.Instance));
521+
Assert.That(Gamepad.all[0].rightStick.ReadValue(), Is.EqualTo(new Vector2(0, -1)).Using(Vector2EqualityComparer.Instance));
522+
523+
// Release finger one and move second and ensure that it still works
524+
EndTouch(1, new Vector2(550, 200));
525+
MoveTouch(2, new Vector2(600, 150));
526+
yield return null;
527+
eventSystem.Update();
528+
InputSystem.Update(); // Stick is feeding events when responding to UI events.
529+
530+
Assert.That(Gamepad.all[0].leftStick.ReadValue(), Is.EqualTo(new Vector2(0, 0)).Using(Vector2EqualityComparer.Instance));
531+
Assert.That(Gamepad.all[0].rightStick.ReadValue(), Is.EqualTo(new Vector2(1, 0)).Using(Vector2EqualityComparer.Instance));
532+
533+
// Release finger two
534+
EndTouch(2, new Vector2(600, 150));
535+
yield return null;
536+
eventSystem.Update();
537+
InputSystem.Update(); // Stick is feeding events when responding to UI events.
538+
539+
Assert.That(Gamepad.all[0].leftStick.ReadValue(), Is.EqualTo(new Vector2(0, 0)).Using(Vector2EqualityComparer.Instance));
540+
Assert.That(Gamepad.all[0].rightStick.ReadValue(), Is.EqualTo(new Vector2(0, 0)).Using(Vector2EqualityComparer.Instance));
494541
}
495542

496543
[UnityTest]
@@ -518,6 +565,9 @@ public IEnumerator Devices_OnScreenStickDoesNotReceivePointerUpEventsInIsolatedM
518565
{
519566
uiTestScene.uiInputModule.actionsAsset.actionMaps[0].LazyResolveBindings(true);
520567
};
568+
569+
// Ensure that the OnScreenStick component has been started
570+
yield return null;
521571

522572
yield return uiTestScene.PressAndDrag(image, new Vector2(50, 50));
523573

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ however, it has to be formatted properly to pass verification tests.
3434
- Fixed an issue with default device selection when adding new Control Scheme.
3535
- 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).
3636
- 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)
37+
- 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)
3738

3839
### Changed
3940
- Added back the InputManager to InputSystem project-wide asset migration code with performance improvement (ISX-2086).

Packages/com.unity.inputsystem/InputSystem/Plugins/OnScreen/OnScreenStick.cs

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using UnityEngine.InputSystem.Layouts;
77
using UnityEngine.InputSystem.Utilities;
88
using UnityEngine.UI;
9+
using UnityEngine.InputSystem.Controls;
910

1011
#if UNITY_EDITOR
1112
using UnityEditor;
@@ -91,7 +92,10 @@ private void Start()
9192
if (m_PointerDownAction == null || m_PointerDownAction.bindings.Count == 0)
9293
{
9394
if (m_PointerDownAction == null)
94-
m_PointerDownAction = new InputAction();
95+
m_PointerDownAction = new InputAction(type: InputActionType.PassThrough);
96+
// ensure PassThrough mode
97+
else if (m_PointerDownAction.m_Type != InputActionType.PassThrough)
98+
m_PointerDownAction.m_Type = InputActionType.PassThrough;
9599

96100
#if UNITY_EDITOR
97101
InputExitPlayModeAnalytic.suppress = true;
@@ -121,8 +125,7 @@ private void Start()
121125
#endif
122126
}
123127

124-
m_PointerDownAction.started += OnPointerDown;
125-
m_PointerDownAction.canceled += OnPointerUp;
128+
m_PointerDownAction.performed += OnPointerChanged;
126129
m_PointerDownAction.Enable();
127130
m_PointerMoveAction.Enable();
128131
}
@@ -154,8 +157,7 @@ private void OnDestroy()
154157
{
155158
if (m_UseIsolatedInputActions)
156159
{
157-
m_PointerDownAction.started -= OnPointerDown;
158-
m_PointerDownAction.canceled -= OnPointerUp;
160+
m_PointerDownAction.performed -= OnPointerChanged;
159161
}
160162
}
161163

@@ -227,12 +229,21 @@ private void EndInteraction()
227229

228230
private void OnPointerDown(InputAction.CallbackContext ctx)
229231
{
232+
if (m_IsIsolationActive) { return; }
230233
Debug.Assert(EventSystem.current != null);
231234

232235
var screenPosition = Vector2.zero;
233-
if (ctx.control?.device is Pointer pointer)
236+
TouchControl touchControl = null;
237+
if (ctx.control?.parent is TouchControl touch)
238+
{
239+
touchControl = touch;
240+
screenPosition = touch.position.ReadValue();
241+
}
242+
else if (ctx.control?.device is Pointer pointer)
243+
{
234244
screenPosition = pointer.position.ReadValue();
235-
245+
}
246+
236247
m_PointerEventData.position = screenPosition;
237248
EventSystem.current.RaycastAll(m_PointerEventData, m_RaycastResults);
238249
if (m_RaycastResults.Count == 0)
@@ -251,23 +262,63 @@ private void OnPointerDown(InputAction.CallbackContext ctx)
251262
return;
252263

253264
BeginInteraction(screenPosition, GetCameraFromCanvas());
265+
if (touchControl != null)
266+
{
267+
m_TouchControl = touchControl;
268+
m_PointerMoveAction.ApplyBindingOverride($"{touchControl.path}/position", path: "<Touchscreen>/touch*/position");
269+
}
270+
254271
m_PointerMoveAction.performed += OnPointerMove;
272+
m_IsIsolationActive = true;
273+
}
274+
275+
private void OnPointerChanged(InputAction.CallbackContext ctx)
276+
{
277+
if (ctx.control.IsPressed())
278+
OnPointerDown(ctx);
279+
else
280+
OnPointerUp(ctx);
255281
}
256282

257283
private void OnPointerMove(InputAction.CallbackContext ctx)
258284
{
259285
// only pointer devices are allowed
260286
Debug.Assert(ctx.control?.device is Pointer);
261-
262-
var screenPosition = ((Pointer)ctx.control.device).position.ReadValue();
287+
Vector2 screenPosition;
288+
289+
// If it's a finger take the value from the finger that initiated the change
290+
if (m_TouchControl != null)
291+
{
292+
// if the finger is up ignore the move
293+
if (m_TouchControl.isInProgress == false)
294+
{
295+
return;
296+
}
297+
screenPosition = m_TouchControl.position.ReadValue();
298+
}
299+
else
300+
{
301+
screenPosition = ((Pointer)ctx.control.device).position.ReadValue();
302+
}
263303

264304
MoveStick(screenPosition, GetCameraFromCanvas());
265305
}
266306

267307
private void OnPointerUp(InputAction.CallbackContext ctx)
268308
{
309+
if (!m_IsIsolationActive) return;
310+
311+
// if it's a finger ensure that is the one that get released
312+
if (m_TouchControl != null)
313+
{
314+
if (m_TouchControl.isInProgress) return;
315+
m_PointerMoveAction.ApplyBindingOverride(null, path: "<Touchscreen>/touch*/position");
316+
m_TouchControl = null;
317+
}
318+
269319
EndInteraction();
270320
m_PointerMoveAction.performed -= OnPointerMove;
321+
m_IsIsolationActive = false;
271322
}
272323

273324
private Camera GetCameraFromCanvas()
@@ -430,6 +481,10 @@ public bool useIsolatedInputActions
430481
private List<RaycastResult> m_RaycastResults;
431482
[NonSerialized]
432483
private PointerEventData m_PointerEventData;
484+
[NonSerialized]
485+
private TouchControl m_TouchControl;
486+
[NonSerialized]
487+
private bool m_IsIsolationActive;
433488

434489
protected override string controlPathInternal
435490
{

0 commit comments

Comments
 (0)