Skip to content

Commit ed76202

Browse files
FIX: Handle pointer click events with multiple sources (#1678)
* Handle pointer click events that come from multiple input soruces at the same time * Add changelog * Use old syntax for switch to make formatter happy * Handle all duplicate pointer events instead of only clicks * Read device states for all Pointer behaviors * Add a test to check if Pointer input events from multiple devices at the same time are handled correctly * cleanup * Edit comment, the behaviour also happens under 'normal' conditions * Change comment again... * Add bug case to the CHANGELOG; Add more explanation to test a comment * Extract pointer states filtering to a separate method * fixup CHANGELOG after merging with develop --------- Co-authored-by: James McGill <jamesmcgill@users.noreply.github.com> Co-authored-by: James McGill <james.mcgill@unity3d.com>
1 parent 808a649 commit ed76202

4 files changed

Lines changed: 83 additions & 34 deletions

File tree

Assets/Tests/InputSystem/Plugins/UITests.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,37 @@ public IEnumerator UI_CanDriveUIFromMultiplePointers(UIPointerBehavior pointerBe
13981398
Assert.That(scene.rightChildReceiver.events, Has.None.With.Property("type").EqualTo(EventType.Dragging));
13991399
break;
14001400
}
1401+
1402+
scene.leftChildReceiver.events.Clear();
1403+
scene.rightChildReceiver.events.Clear();
1404+
1405+
// Test if creating Pointer events from different devices at the same time results in only one event
1406+
BeginTouch(0, firstPosition, screen: touch1, queueEventOnly: true);
1407+
Press(mouse1.leftButton);
1408+
yield return null;
1409+
EndTouch(0, firstPosition, screen: touch1, queueEventOnly: true);
1410+
Release(mouse1.leftButton);
1411+
yield return null;
1412+
1413+
switch (pointerBehavior)
1414+
{
1415+
case UIPointerBehavior.SingleUnifiedPointer:
1416+
//// Getting "Drop" event even if using only one type of input device for Press/Release.
1417+
//// E.g. the following test would also produce only a Drop event:
1418+
//// Press(mouse1.leftButton);
1419+
//// yield return null;
1420+
//// Release(mouse1.leftButton);
1421+
//// yield return null;
1422+
break;
1423+
case UIPointerBehavior.SingleMouseOrPenButMultiTouchAndTrack:
1424+
case UIPointerBehavior.AllPointersAsIs:
1425+
// Single pointer click on the left object
1426+
Assert.That(scene.leftChildReceiver.events,
1427+
Has.Exactly(1).With.Property("type").EqualTo(EventType.PointerClick).And
1428+
.Matches((UICallbackReceiver.Event e) => e.pointerData.device == mouse1).And
1429+
.Matches((UICallbackReceiver.Event e) => e.pointerData.position == firstPosition));
1430+
break;
1431+
}
14011432
}
14021433

14031434
[UnityTest]

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ however, it has to be formatted properly to pass verification tests.
1010

1111
## [Unreleased]
1212

13+
### Fixed
14+
- Fixed UI clicks not registering when OS provides multiple input sources for the same event, e.g. on Samsung Dex (case ISX-1416, ISXB-342).
15+
1316
## [1.6.1] - 2023-05-26
1417

1518
### Fixed

Packages/com.unity.inputsystem/InputSystem/InputManager.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2940,9 +2940,8 @@ private unsafe void OnUpdate(InputUpdateType updateType, ref InputEventBuffer ev
29402940
);
29412941

29422942

2943-
bool dropStatusEvents = false;
2944-
29452943
#if UNITY_EDITOR
2944+
var dropStatusEvents = false;
29462945
if (!gameIsPlaying && gameShouldGetInputRegardlessOfFocus && (eventBuffer.sizeInBytes > (100 * 1024)))
29472946
{
29482947
// If the game is not playing but we're sending all input events to the game, the buffer can just grow unbounded.

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

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,35 +1713,6 @@ private int GetPointerStateIndexFor(InputControl control, bool createIfNotExists
17131713
else if (HaveControlForDevice(device, trackedDevicePosition))
17141714
pointerType = UIPointerType.Tracked;
17151715

1716-
// For SingleMouseOrPenButMultiTouchAndTrack, we keep a single pointer for mouse and pen but only for as
1717-
// long as there is no touch or tracked input. If we get that kind, we remove the mouse/pen pointer.
1718-
if (m_PointerBehavior == UIPointerBehavior.SingleMouseOrPenButMultiTouchAndTrack && pointerType != UIPointerType.None)
1719-
{
1720-
if (pointerType == UIPointerType.MouseOrPen)
1721-
{
1722-
// We have input on a mouse or pen. Kill all touch and tracked pointers we may have.
1723-
for (var i = 0; i < m_PointerStates.length; ++i)
1724-
{
1725-
if (m_PointerStates[i].pointerType != UIPointerType.MouseOrPen)
1726-
{
1727-
SendPointerExitEventsAndRemovePointer(i);
1728-
--i;
1729-
}
1730-
}
1731-
}
1732-
else
1733-
{
1734-
// We have touch or tracked input. Kill mouse/pen pointer, if we have it.
1735-
for (var i = 0; i < m_PointerStates.length; ++i)
1736-
{
1737-
if (m_PointerStates[i].pointerType == UIPointerType.MouseOrPen)
1738-
{
1739-
SendPointerExitEventsAndRemovePointer(i);
1740-
--i;
1741-
}
1742-
}
1743-
}
1744-
}
17451716
////REVIEW: For touch, probably makes sense to force-ignore any input other than from primaryTouch.
17461717
// If the behavior is SingleUnifiedPointer, we only ever create a single pointer state
17471718
// and use that for all pointer input that is coming in.
@@ -2126,6 +2097,52 @@ private void OnControlsChanged(object obj)
21262097
m_NeedToPurgeStalePointers = true;
21272098
}
21282099

2100+
private void FilterPointerStatesByType()
2101+
{
2102+
var pointerTypeToProcess = UIPointerType.None;
2103+
// Read all pointers device states
2104+
// Find first pointer that has changed this frame to be processed later
2105+
for (var i = 0; i < m_PointerStates.length; ++i)
2106+
{
2107+
ref var state = ref GetPointerStateForIndex(i);
2108+
state.eventData.ReadDeviceState();
2109+
state.CopyTouchOrPenStateFrom(state.eventData);
2110+
if (state.changedThisFrame && pointerTypeToProcess == UIPointerType.None)
2111+
pointerTypeToProcess = state.pointerType;
2112+
}
2113+
2114+
// For SingleMouseOrPenButMultiTouchAndTrack, we keep a single pointer for mouse and pen but only for as
2115+
// long as there is no touch or tracked input. If we get that kind, we remove the mouse/pen pointer.
2116+
if (m_PointerBehavior == UIPointerBehavior.SingleMouseOrPenButMultiTouchAndTrack && pointerTypeToProcess != UIPointerType.None)
2117+
{
2118+
// var pointerTypeToProcess = m_PointerStates.firstValue.pointerType;
2119+
if (pointerTypeToProcess == UIPointerType.MouseOrPen)
2120+
{
2121+
// We have input on a mouse or pen. Kill all touch and tracked pointers we may have.
2122+
for (var i = 0; i < m_PointerStates.length; ++i)
2123+
{
2124+
if (m_PointerStates[i].pointerType != UIPointerType.MouseOrPen)
2125+
{
2126+
SendPointerExitEventsAndRemovePointer(i);
2127+
--i;
2128+
}
2129+
}
2130+
}
2131+
else
2132+
{
2133+
// We have touch or tracked input. Kill mouse/pen pointer, if we have it.
2134+
for (var i = 0; i < m_PointerStates.length; ++i)
2135+
{
2136+
if (m_PointerStates[i].pointerType == UIPointerType.MouseOrPen)
2137+
{
2138+
SendPointerExitEventsAndRemovePointer(i);
2139+
--i;
2140+
}
2141+
}
2142+
}
2143+
}
2144+
}
2145+
21292146
public override void Process()
21302147
{
21312148
if (m_NeedToPurgeStalePointers)
@@ -2142,14 +2159,13 @@ public override void Process()
21422159
// Navigation input.
21432160
ProcessNavigation(ref m_NavigationState);
21442161

2162+
FilterPointerStatesByType();
2163+
21452164
// Pointer input.
21462165
for (var i = 0; i < m_PointerStates.length; i++)
21472166
{
21482167
ref var state = ref GetPointerStateForIndex(i);
21492168

2150-
state.eventData.ReadDeviceState();
2151-
state.CopyTouchOrPenStateFrom(state.eventData);
2152-
21532169
ProcessPointer(ref state);
21542170

21552171
// If it's a touch and the touch has ended, release the pointer state.

0 commit comments

Comments
 (0)