@@ -631,7 +631,9 @@ public void Actions_DoNotGetTriggeredByEditorUpdates()
631631
632632 using (var trace = new InputActionTrace(action))
633633 {
634- runtime.PlayerFocusLost();
634+ ScheduleFocusChangedEvent(applicationHasFocus: false);
635+ InputSystem.Update(InputUpdateType.Dynamic);
636+
635637 Set(gamepad.leftTrigger, 0.123f, queueEventOnly: true);
636638 InputSystem.Update(InputUpdateType.Editor);
637639
@@ -661,13 +663,13 @@ public void Actions_DoNotGetTriggeredByOutOfFocusEventInEditor(InputSettings.Bac
661663 // could just rely on order of event. Which means this test work for a fixed timestamp and it should
662664 // changed accordingly.
663665 currentTime += 1.0f;
664- runtime.PlayerFocusLost( );
666+ ScheduleFocusChangedEvent(applicationHasFocus: false );
665667 currentTime += 1.0f;
666668 // Queuing an event like it would be in the editor when the GameView is out of focus.
667669 Set(mouse.position, new Vector2(0.234f, 0.345f) , queueEventOnly: true);
668670 currentTime += 1.0f;
669671 // Gaining focus like it would happen in the editor when the GameView regains focus.
670- runtime.PlayerFocusGained( );
672+ ScheduleFocusChangedEvent(applicationHasFocus: true );
671673 currentTime += 1.0f;
672674 // This emulates a device sync that happens when the player regains focus through an IOCTL command.
673675 // That's why it also has it's time incremented.
@@ -720,14 +722,15 @@ public void Actions_TimeoutsDoNotGetTriggeredInEditorUpdates()
720722
721723 trace.Clear();
722724
723- runtime.PlayerFocusLost();
725+ ScheduleFocusChangedEvent(applicationHasFocus: false);
726+ InputSystem.Update(InputUpdateType.Dynamic);
724727 currentTime = 10;
725728
726729 InputSystem.Update(InputUpdateType.Editor);
727730
728731 Assert.That(trace, Is.Empty);
729732
730- runtime.PlayerFocusGained( );
733+ ScheduleFocusChangedEvent(applicationHasFocus: true );
731734 InputSystem.Update(InputUpdateType.Dynamic);
732735
733736 actions = trace.ToArray();
@@ -1401,6 +1404,45 @@ public void Actions_ValueActionsEnabledInOnEvent_DoNotReactToCurrentStateOfContr
14011404 }
14021405 }
14031406
1407+ // Regression test for UUM-100125.
1408+ [Test]
1409+ [Category("Actions")]
1410+ public void Actions_InitialStateCheckAfterConfigurationChange_DoesNotTriggerForInactiveTouch()
1411+ {
1412+ var touchscreen = InputSystem.AddDevice<Touchscreen>();
1413+ var action = new InputAction(type: InputActionType.Value, binding: "<Touchscreen>/primaryTouch/position");
1414+ action.Enable();
1415+
1416+ // Run the first initial state check from enabling the action.
1417+ InputSystem.Update();
1418+
1419+ using (var trace = new InputActionTrace(action))
1420+ {
1421+ BeginTouch(1, new Vector2(123, 234));
1422+ EndTouch(1, new Vector2(345, 456));
1423+
1424+ Assert.That(touchscreen.primaryTouch.isInProgress, Is.False);
1425+ Assert.That(touchscreen.primaryTouch.position.ReadValue(), Is.Not.EqualTo(default(Vector2)));
1426+
1427+ trace.Clear();
1428+
1429+ // Configuration change causes full re-resolve and schedules initial state check.
1430+ InputSystem.QueueConfigChangeEvent(touchscreen);
1431+ InputSystem.Update();
1432+ InputSystem.Update();
1433+
1434+ // Full re-resolve may cancel the current action state. What must NOT happen is a synthetic
1435+ // Started/Performed pair from persisted inactive touch state.
1436+ Assert.AreEqual(1, trace.count);
1437+ foreach (var eventPtr in trace)
1438+ {
1439+ // The trace should only contain a Canceled event for the action.
1440+ Assert.AreEqual(InputActionPhase.Canceled, eventPtr.phase,
1441+ $"inactive touch state should not produce action callbacks, but received {eventPtr.phase}.");
1442+ }
1443+ }
1444+ }
1445+
14041446 // https://fogbugz.unity3d.com/f/cases/1192972/
14051447 [Test]
14061448 [Category("Actions")]
@@ -12481,17 +12523,20 @@ public void Actions_WithMultipleCompositeBindings_WithoutEvaluateMagnitude_Works
1248112523
1248212524 // Now when enabling actionMap ..
1248312525 actionMap.Enable();
12484- // On the following update we will trigger OnBeforeUpdate which will rise started/performed
12485- // from InputActionState.OnBeforeInitialUpdate as controls are "actuated"
12526+ // Inactive touches (ended before action was enabled) must NOT produce started/performed from
12527+ // OnBeforeInitialUpdate. Their persisted state (position, touchId) is non-default due to
12528+ // dontReset, but only TouchControl.isInProgress should be considered for initial-state check.
12529+ // Related to UUM-100125 and Actions_InitialStateCheckAfterConfigurationChange_DoesNotTriggerForInactiveTouch.
1248612530 InputSystem.Update();
12487- Assert.That(values.Count, Is.EqualTo(prepopulateTouchesBeforeEnablingAction ? 2 : 0)); // started+performed arrive from OnBeforeUpdate
12531+ Assert.That(values.Count, Is.EqualTo(0));
1248812532 values.Clear();
1248912533
12490- // Now subsequent touches should not be ignored
1249112534 BeginTouch(200, new Vector2(1, 1));
12492- Assert.That(values.Count, Is.EqualTo(1));
12493- Assert.That(values[0].InputId, Is.EqualTo(200));
12494- Assert.That(values[0].Position, Is.EqualTo(new Vector2(1, 1)));
12535+ // If prepopulated, action was never actuated (synthetic initial-check is suppressed),
12536+ // so BeginTouch fires started+performed (2 events).
12537+ Assert.That(values.Count, Is.EqualTo(prepopulateTouchesBeforeEnablingAction ? 2 : 1));
12538+ Assert.That(values[values.Count - 1].InputId, Is.EqualTo(200));
12539+ Assert.That(values[values.Count - 1].Position, Is.EqualTo(new Vector2(1, 1)));
1249512540 }
1249612541
1249712542 // FIX: This test is currently checking if shortcut support is enabled by testing that the unwanted behaviour exists.
0 commit comments