Skip to content

Commit 16cd820

Browse files
committed
Check for empty pointer states before removal
This fixes ISXB-687 and adds a test.
1 parent 18397a9 commit 16cd820

File tree

2 files changed

+66
-2
lines changed

2 files changed

+66
-2
lines changed

Assets/Tests/InputSystem/Plugins/UITests.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,6 +1529,65 @@ public IEnumerator UI_CanDriveUIFromMultiplePointers(UIPointerBehavior pointerBe
15291529
.Matches((UICallbackReceiver.Event e) => e.pointerData.position == secondPosition));
15301530
}
15311531

1532+
[UnityTest]
1533+
[Category("UI")]
1534+
[Description("Tests that disabling the UI module during a Button click event works correctly with touch pointers." +
1535+
"ISXB-687")]
1536+
public IEnumerator UI_DisablingEventSystemOnClickEventWorksWithTouchPointersWorks()
1537+
{
1538+
var touch = InputSystem.AddDevice<Touchscreen>();
1539+
var scene = CreateTestUI();
1540+
1541+
var actions = ScriptableObject.CreateInstance<InputActionAsset>();
1542+
var uiActions = actions.AddActionMap("UI");
1543+
var pointAction = uiActions.AddAction("point", type: InputActionType.PassThrough);
1544+
var clickAction = uiActions.AddAction("click", type: InputActionType.PassThrough);
1545+
1546+
pointAction.AddBinding("<Touchscreen>/touch*/position");
1547+
clickAction.AddBinding("<Touchscreen>/touch*/press");
1548+
1549+
pointAction.Enable();
1550+
clickAction.Enable();
1551+
1552+
scene.uiModule.point = InputActionReference.Create(pointAction);
1553+
scene.uiModule.pointerBehavior = UIPointerBehavior.SingleMouseOrPenButMultiTouchAndTrack;
1554+
scene.uiModule.leftClick = InputActionReference.Create(clickAction);
1555+
1556+
// Turn left object into a button.
1557+
var button = scene.leftGameObject.AddComponent<MyButton>();
1558+
var clicked = false;
1559+
1560+
// Add a listener to the button to disable the UI module when clicked.
1561+
// This calls InputSystemUIInputModule.OnDisable() which will reset the pointer data during
1562+
// InputSystemUIInputModule.Process() and ProcessPointer(). It will allow us to test that removing
1563+
// a pointer once the UI module is disabled (all pointers are removed) works correctly.
1564+
button.onClick.AddListener(() =>
1565+
{
1566+
clicked = true;
1567+
scene.uiModule.enabled = false; // Disable the UI module to test pointer reset.
1568+
});
1569+
1570+
yield return null;
1571+
1572+
var firstPosition = scene.From640x480ToScreen(100, 100);
1573+
1574+
// This will allocate a pointer for the touch and set the first touch position and press
1575+
BeginTouch(1, firstPosition, screen: touch);
1576+
yield return null;
1577+
1578+
Assert.That(clicked, Is.False, "Button was clicked when it should not have been yet.");
1579+
Assert.That(scene.uiModule.m_PointerStates.length, Is.EqualTo(1),
1580+
"A pointer states was not allocated for the touch pointer.");
1581+
1582+
// Release the touch to make sure we have a Click event that calls the button listener.
1583+
EndTouch(1, firstPosition, screen: touch);
1584+
yield return null;
1585+
1586+
Assert.That(clicked, Is.True, "Button was not clicked when it should have been.");
1587+
Assert.That(scene.uiModule.m_PointerStates.length, Is.EqualTo(0),
1588+
"Pointer states were not cleared when the UI module was disabled after a click event.");
1589+
}
1590+
15321591
[UnityTest]
15331592
[Category("UI")]
15341593
public IEnumerator UI_CanDriveUIFromMultipleTouches()

Packages/com.unity.inputsystem/InputSystem/Plugins/UI/InputSystemUIInputModule.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,6 +2070,11 @@ private bool SendPointerExitEventsAndRemovePointer(int index)
20702070

20712071
private bool RemovePointerAtIndex(int index)
20722072
{
2073+
// Pointers can have be reset before (e.g. when calling OnDisable) which would make m_PointerStates
2074+
// empty (ISXB-687).
2075+
if (m_PointerStates.length == 0)
2076+
return false;
2077+
20732078
Debug.Assert(m_PointerStates[index].eventData.pointerEnter == null, "Pointer should have exited all objects before being removed");
20742079

20752080
// // We don't want to release touch pointers on the same frame they are released (unpressed). They get cleaned up one frame later in Process()
@@ -2458,8 +2463,8 @@ public override void Process()
24582463
// stays true for the touch in the frame of release (see UI_TouchPointersAreKeptForOneFrameAfterRelease).
24592464
if (state.pointerType == UIPointerType.Touch && !state.leftButton.isPressed && !state.leftButton.wasReleasedThisFrame)
24602465
{
2461-
RemovePointerAtIndex(i);
2462-
--i;
2466+
if (RemovePointerAtIndex(i))
2467+
--i;
24632468
continue;
24642469
}
24652470

0 commit comments

Comments
 (0)