Skip to content

Commit e8fec32

Browse files
author
Rene Damm
authored
FIX: Successive UI clicks not working with TouchSimulation (case 1330014, #1449).
1 parent fb983da commit e8fec32

5 files changed

Lines changed: 138 additions & 46 deletions

File tree

Assets/Tests/InputSystem/Plugins/UITests.cs

Lines changed: 83 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1583,14 +1583,19 @@ public IEnumerator UI_CanUseTouchSimulationWithUI()
15831583
scene.uiModule.AssignDefaultActions();
15841584
TouchSimulation.Enable();
15851585

1586+
// https://fogbugz.unity3d.com/f/cases/1330014/
1587+
// Scale the left button down on X just a little bit so as to give us some space where we can hit nothing.
1588+
// This makes sure that if the code ends up putting something at (0,0), it'll hit nothing.
1589+
((RectTransform)scene.leftGameObject.transform).localScale = new Vector3(0.95f, 1, 1);
1590+
15861591
try
15871592
{
15881593
yield return null;
15891594
scene.leftChildReceiver.events.Clear();
15901595

15911596
InputSystem.QueueStateEvent(mouse, new MouseState
15921597
{
1593-
position = scene.From640x480ToScreen(123, 123)
1598+
position = scene.From640x480ToScreen(180, 180)
15941599
}.WithButton(MouseButton.Left));
15951600
InputSystem.Update();
15961601

@@ -1600,26 +1605,88 @@ public IEnumerator UI_CanUseTouchSimulationWithUI()
16001605
Assert.That(scene.uiModule.m_PointerIds.length, Is.EqualTo(1));
16011606
Assert.That(scene.uiModule.m_PointerTouchControls.length, Is.EqualTo(1));
16021607
Assert.That(scene.uiModule.m_PointerTouchControls[0], Is.SameAs(Touchscreen.current.touches[0]));
1603-
Assert.That(scene.leftChildReceiver.events.Select(x => x.type),
1604-
Is.EquivalentTo(new[]
1605-
{
1606-
EventType.PointerEnter,
1607-
#if UNITY_2021_2_OR_NEWER
1608-
EventType.PointerMove,
1609-
#endif
1610-
EventType.PointerDown,
1611-
EventType.InitializePotentialDrag
1612-
}));
16131608
Assert.That(scene.leftChildReceiver.events,
1614-
Has.All.Matches((UICallbackReceiver.Event evt) => evt.pointerData.pointerType == UIPointerType.Touch));
1609+
EventSequence(
1610+
AllEvents("pointerType", UIPointerType.Touch),
1611+
AllEvents("touchId", 1),
1612+
AllEvents("position", scene.From640x480ToScreen(180, 180)),
1613+
OneEvent("type", EventType.PointerEnter)
1614+
#if UNITY_2021_2_OR_NEWER
1615+
, OneEvent("type", EventType.PointerMove)
1616+
#endif
1617+
, OneEvent("type", EventType.PointerDown)
1618+
, OneEvent("type", EventType.InitializePotentialDrag)
1619+
)
1620+
);
1621+
1622+
scene.leftChildReceiver.events.Clear();
1623+
1624+
Release(mouse.leftButton);
1625+
yield return null;
1626+
1627+
// Touch pointer record lingers for one frame.
1628+
1629+
Assert.That(scene.uiModule.m_CurrentPointerType, Is.EqualTo(UIPointerType.Touch));
1630+
Assert.That(scene.uiModule.m_PointerIds.length, Is.EqualTo(1));
1631+
Assert.That(scene.uiModule.m_PointerTouchControls.length, Is.EqualTo(1));
1632+
Assert.That(scene.uiModule.m_PointerTouchControls[0], Is.SameAs(Touchscreen.current.touches[0]));
1633+
Assert.That(scene.leftChildReceiver.events,
1634+
EventSequence(
1635+
AllEvents("pointerType", UIPointerType.Touch),
1636+
AllEvents("touchId", 1),
1637+
AllEvents("position", scene.From640x480ToScreen(180, 180)),
1638+
OneEvent("type", EventType.PointerUp),
1639+
OneEvent("type", EventType.PointerClick)
1640+
)
1641+
);
1642+
1643+
scene.leftChildReceiver.events.Clear();
1644+
1645+
yield return null;
1646+
1647+
Assert.That(scene.uiModule.m_CurrentPointerType, Is.EqualTo(UIPointerType.None));
1648+
Assert.That(scene.uiModule.m_PointerIds.length, Is.Zero);
1649+
Assert.That(scene.uiModule.m_PointerTouchControls.length, Is.Zero);
1650+
Assert.That(scene.leftChildReceiver.events,
1651+
EventSequence(
1652+
AllEvents("pointerType", UIPointerType.Touch),
1653+
AllEvents("touchId", 1),
1654+
AllEvents("position", scene.From640x480ToScreen(180, 180)),
1655+
OneEvent("type", EventType.PointerExit)
1656+
)
1657+
);
1658+
1659+
scene.leftChildReceiver.events.Clear();
1660+
1661+
yield return null;
1662+
Press(mouse.leftButton);
1663+
yield return null;
1664+
16151665
Assert.That(scene.leftChildReceiver.events,
1616-
Has.All.Matches((UICallbackReceiver.Event evt) => evt.pointerData.touchId == 1));
1666+
EventSequence(
1667+
AllEvents("pointerType", UIPointerType.Touch),
1668+
AllEvents("touchId", 2),
1669+
AllEvents("position", scene.From640x480ToScreen(180, 180)),
1670+
OneEvent("type", EventType.PointerEnter),
1671+
OneEvent("type", EventType.PointerDown),
1672+
OneEvent("type", EventType.InitializePotentialDrag)
1673+
)
1674+
);
1675+
1676+
scene.leftChildReceiver.events.Clear();
16171677

1618-
// Release the mouse button so the touch ends. TouchSimulation.Disable() will remove
1619-
// the touchscreen and thus cancel ongoing actions (like Point). This should not result
1620-
// in exceptions from the input module trying to read data from the already removed touchscreen.
16211678
Release(mouse.leftButton);
16221679
yield return null;
1680+
1681+
Assert.That(scene.leftChildReceiver.events,
1682+
EventSequence(
1683+
AllEvents("pointerType", UIPointerType.Touch),
1684+
AllEvents("touchId", 2),
1685+
AllEvents("position", scene.From640x480ToScreen(180, 180)),
1686+
OneEvent("type", EventType.PointerUp),
1687+
OneEvent("type", EventType.PointerClick)
1688+
)
1689+
);
16231690
}
16241691
finally
16251692
{

Assets/TextMesh Pro/Sprites/EmojiOne.json.meta

Lines changed: 0 additions & 8 deletions
This file was deleted.

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ however, it has to be formatted properly to pass verification tests.
2222

2323
- Fixed writing values into the half-axis controls of sticks (such as `Gamepad.leftStick.left`) producing incorrect values on the stick ([case 1336240](https://issuetracker.unity3d.com/issues/inputtestfixture-tests-return-inverted-values-when-pressing-gamepads-left-or-down-joystick-buttons)).
2424
- Fixed setting size of event trace in input debugger always growing back to largest size set before.
25+
- Fixed successive clicks not getting triggered with `TouchSimulation` on when not moving the mouse in-between clicks ([case 1330014](https://issuetracker.unity3d.com/issues/onclick-isnt-triggered-on-the-second-click-when-the-mouse-isnt-moved-and-simulate-touch-input-from-mouse-or-pen-is-enabled)).
2526
- Fixed `InputSystemUIInputModule` showing incorrect bindings after pressing the 'Fix UI Input Module' button in PlayerInput component([case 1319968](https://issuetracker.unity3d.com/product/unity/issues/guid/1319968/)).
2627
- Fixed an issue where UI button clicks could be ignored by `InputSystemUIInputModule` if modifying on-screen devices from Update() callbacks ([case 1365070](https://issuetracker.unity3d.com/product/unity/issues/guid/1365070)).
2728
- Fixed an issue with `InputSystemUIInputModule` that would cause UI to stop responding during play mode after changing a script file while Recompile and Continue mode is active, or by forcing a script recompile using `RequestScriptCompilation`([case 1324215](https://issuetracker.unity3d.com/product/unity/issues/guid/1324215/)).

Packages/com.unity.inputsystem/InputSystem/Plugins/EnhancedTouch/TouchSimulation.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,11 @@ private unsafe void OnEvent(InputEventPtr eventPtr, InputDevice device)
181181
{
182182
// No, so add it.
183183
touchIndex = m_Touches.IndexOfReference((ButtonControl)null);
184-
m_Touches[touchIndex] = (ButtonControl)control;
185184
if (touchIndex >= 0) // If negative, we're at max touch count and can't add more.
185+
{
186+
m_Touches[touchIndex] = (ButtonControl)control;
186187
UpdateTouch(touchIndex, pointerIndex, TouchPhase.Began, eventPtr);
188+
}
187189
}
188190
else
189191
{

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

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,18 +1370,33 @@ protected override void OnEnable()
13701370
if (HasNoActions())
13711371
AssignDefaultActions();
13721372

1373+
ResetPointers();
1374+
13731375
HookActions();
13741376
EnableAllActions();
13751377
}
13761378

13771379
protected override void OnDisable()
13781380
{
1379-
base.OnDisable();
1381+
ResetPointers();
13801382

13811383
InputActionState.s_GlobalState.onActionControlsChanged.RemoveCallback(m_OnControlsChangedDelegate);
13821384

13831385
DisableAllActions();
13841386
UnhookActions();
1387+
1388+
base.OnDisable();
1389+
}
1390+
1391+
private void ResetPointers()
1392+
{
1393+
var numPointers = m_PointerStates.length;
1394+
for (var i = 0; i < numPointers; ++i)
1395+
SendPointerExitEventsAndRemovePointer(0);
1396+
1397+
m_CurrentPointerId = -1;
1398+
m_CurrentPointerIndex = -1;
1399+
m_CurrentPointerType = UIPointerType.None;
13851400
}
13861401

13871402
private bool HasNoActions()
@@ -1512,10 +1527,13 @@ private ref PointerModel GetPointerStateForIndex(int index)
15121527
return ref m_PointerStates.additionalValues[index - 1];
15131528
}
15141529

1515-
private ref PointerModel GetPointerStateFor(ref InputAction.CallbackContext context)
1530+
private int GetPointerStateIndexFor(ref InputAction.CallbackContext context)
15161531
{
1517-
var index = GetPointerStateIndexFor(context.control);
1518-
return ref GetPointerStateForIndex(index);
1532+
if (CheckForRemovedDevice(ref context))
1533+
return -1;
1534+
1535+
var phase = context.phase;
1536+
return GetPointerStateIndexFor(context.control, createIfNotExists: phase != InputActionPhase.Canceled);
15191537
}
15201538

15211539
// This is the key method for determining which pointer a particular input is associated with.
@@ -1558,17 +1576,20 @@ private int GetPointerStateIndexFor(InputControl control, bool createIfNotExists
15581576

15591577
var pointerId = device.deviceId;
15601578
var touchId = 0;
1579+
var touchPosition = Vector2.zero;
15611580

15621581
// Need to check if it's a touch so that we get a correct pointerId.
15631582
if (controlParent is TouchControl touchControl)
15641583
{
15651584
touchId = touchControl.touchId.ReadValue();
1585+
touchPosition = touchControl.position.ReadValue();
15661586
}
15671587
// Could be it's a toplevel control on Touchscreen (like "<Touchscreen>/position"). In that case,
15681588
// read the touch ID from primaryTouch.
15691589
else if (controlParent is Touchscreen touchscreen)
15701590
{
15711591
touchId = touchscreen.primaryTouch.touchId.ReadValue();
1592+
touchPosition = touchscreen.primaryTouch.position.ReadValue();
15721593
}
15731594
if (touchId != 0)
15741595
pointerId = ExtendedPointerEventData.MakePointerIdForTouch(pointerId, touchId);
@@ -1668,6 +1689,9 @@ private int GetPointerStateIndexFor(InputControl control, bool createIfNotExists
16681689
eventData.trackedDevicePosition = default;
16691690
}
16701691

1692+
if (pointerType == UIPointerType.Touch)
1693+
GetPointerStateForIndex(m_CurrentPointerIndex).screenPosition = touchPosition;
1694+
16711695
m_CurrentPointerId = pointerId;
16721696
m_CurrentPointerType = pointerType;
16731697

@@ -1725,6 +1749,9 @@ private int GetPointerStateIndexFor(InputControl control, bool createIfNotExists
17251749
}
17261750
}
17271751

1752+
if (pointerType == UIPointerType.Touch)
1753+
GetPointerStateForIndex(index).screenPosition = touchPosition;
1754+
17281755
m_CurrentPointerId = pointerId;
17291756
m_CurrentPointerIndex = index;
17301757
m_CurrentPointerType = pointerType;
@@ -1888,10 +1915,7 @@ private bool IgnoreNextClick(ref InputAction.CallbackContext context)
18881915

18891916
private void OnLeftClickCallback(InputAction.CallbackContext context)
18901917
{
1891-
if (CheckForRemovedDevice(ref context))
1892-
return;
1893-
1894-
var index = GetPointerStateIndexFor(context.control, createIfNotExists: !context.canceled);
1918+
var index = GetPointerStateIndexFor(ref context);
18951919
if (index == -1)
18961920
return;
18971921

@@ -1904,10 +1928,7 @@ private void OnLeftClickCallback(InputAction.CallbackContext context)
19041928

19051929
private void OnRightClickCallback(InputAction.CallbackContext context)
19061930
{
1907-
if (CheckForRemovedDevice(ref context))
1908-
return;
1909-
1910-
var index = GetPointerStateIndexFor(context.control, createIfNotExists: !context.canceled);
1931+
var index = GetPointerStateIndexFor(ref context);
19111932
if (index == -1)
19121933
return;
19131934

@@ -1920,10 +1941,7 @@ private void OnRightClickCallback(InputAction.CallbackContext context)
19201941

19211942
private void OnMiddleClickCallback(InputAction.CallbackContext context)
19221943
{
1923-
if (CheckForRemovedDevice(ref context))
1924-
return;
1925-
1926-
var index = GetPointerStateIndexFor(context.control, createIfNotExists: !context.canceled);
1944+
var index = GetPointerStateIndexFor(ref context);
19271945
if (index == -1)
19281946
return;
19291947

@@ -1952,7 +1970,11 @@ private bool CheckForRemovedDevice(ref InputAction.CallbackContext context)
19521970

19531971
private void OnScrollCallback(InputAction.CallbackContext context)
19541972
{
1955-
ref var state = ref GetPointerStateFor(ref context);
1973+
var index = GetPointerStateIndexFor(ref context);
1974+
if (index == -1)
1975+
return;
1976+
1977+
ref var state = ref GetPointerStateForIndex(index);
19561978
// The old input system reported scroll deltas in lines, we report pixels.
19571979
// Need to scale as the UI system expects lines.
19581980
state.scrollDelta = context.ReadValue<Vector2>() * (1 / kPixelPerLine);
@@ -1966,13 +1988,21 @@ private void OnMoveCallback(InputAction.CallbackContext context)
19661988

19671989
private void OnTrackedDeviceOrientationCallback(InputAction.CallbackContext context)
19681990
{
1969-
ref var state = ref GetPointerStateFor(ref context);
1991+
var index = GetPointerStateIndexFor(ref context);
1992+
if (index == -1)
1993+
return;
1994+
1995+
ref var state = ref GetPointerStateForIndex(index);
19701996
state.worldOrientation = context.ReadValue<Quaternion>();
19711997
}
19721998

19731999
private void OnTrackedDevicePositionCallback(InputAction.CallbackContext context)
19742000
{
1975-
ref var state = ref GetPointerStateFor(ref context);
2001+
var index = GetPointerStateIndexFor(ref context);
2002+
if (index == -1)
2003+
return;
2004+
2005+
ref var state = ref GetPointerStateForIndex(index);
19762006
state.worldPosition = context.ReadValue<Vector3>();
19772007
}
19782008

@@ -2183,8 +2213,8 @@ private struct InputActionReferenceState
21832213
public bool enabledByInputModule;
21842214
}
21852215

2186-
private bool m_ActionsHooked;
2187-
private bool m_NeedToPurgeStalePointers;
2216+
[NonSerialized] private bool m_ActionsHooked;
2217+
[NonSerialized] private bool m_NeedToPurgeStalePointers;
21882218

21892219
private Action<InputAction.CallbackContext> m_OnPointDelegate;
21902220
private Action<InputAction.CallbackContext> m_OnMoveDelegate;

0 commit comments

Comments
 (0)