From d8f369b0a2b3e28fbbd5e982cdab4593d1f38020 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Wed, 18 Feb 2026 11:11:13 +0000 Subject: [PATCH 1/2] Skip initial state check for inactive touch controls Add ShouldSkipInitialStateCheck and use it in InputActionState's initial-state loop to avoid treating preserved touch data as actuated during binding re-resolution. --- .../InputSystem/Actions/InputActionState.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Packages/com.unity.inputsystem/InputSystem/Actions/InputActionState.cs b/Packages/com.unity.inputsystem/InputSystem/Actions/InputActionState.cs index 33d782a39c..89ff46598c 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Actions/InputActionState.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Actions/InputActionState.cs @@ -1321,6 +1321,9 @@ private void OnBeforeInitialUpdate() if (IsActiveControl(bindingIndex, controlIndex)) continue; + if (ShouldSkipInitialStateCheck(control)) + continue; + if (!control.CheckStateIsAtDefault()) { // Update press times. @@ -1348,6 +1351,24 @@ private void OnBeforeInitialUpdate() k_InputInitialActionStateCheckMarker.End(); } + private static bool ShouldSkipInitialStateCheck(InputControl control) + { + // UUM-100125 + // Touch controls intentionally preserve state such as position even when no touch is currently active. + // During binding re-resolution this can make inactive touches look actuated and cause invalid triggers. + if (control is TouchControl touchControl) + { + return !touchControl.isInProgress; + } + + if (control.parent is TouchControl parentTouchControl) + { + return !parentTouchControl.isInProgress; + } + + return false; + } + // Called from InputManager when one of our state change monitors has fired. // Tells us the time of the change *according to the state events coming in*. // Also tells us which control of the controls we are binding to triggered the From 6ce4494ba5b9c214d977df899d6216cc5bbd9023 Mon Sep 17 00:00:00 2001 From: Morgan Hoarau Date: Wed, 18 Feb 2026 11:11:56 +0000 Subject: [PATCH 2/2] Add reg test to ensure inactive touch does not trigger --- Assets/Tests/InputSystem/CoreTests_Actions.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Assets/Tests/InputSystem/CoreTests_Actions.cs b/Assets/Tests/InputSystem/CoreTests_Actions.cs index 322a50a250..7ad23c41f7 100644 --- a/Assets/Tests/InputSystem/CoreTests_Actions.cs +++ b/Assets/Tests/InputSystem/CoreTests_Actions.cs @@ -1400,6 +1400,45 @@ public void Actions_ValueActionsEnabledInOnEvent_DoNotReactToCurrentStateOfContr } } + // Regression test for UUM-100125. + [Test] + [Category("Actions")] + public void Actions_InitialStateCheckAfterConfigurationChange_DoesNotTriggerForInactiveTouch() + { + var touchscreen = InputSystem.AddDevice(); + var action = new InputAction(type: InputActionType.Value, binding: "/primaryTouch/position"); + action.Enable(); + + // Run the first initial state check from enabling the action. + InputSystem.Update(); + + using (var trace = new InputActionTrace(action)) + { + BeginTouch(1, new Vector2(123, 234)); + EndTouch(1, new Vector2(345, 456)); + + Assert.That(touchscreen.primaryTouch.isInProgress, Is.False); + Assert.That(touchscreen.primaryTouch.position.ReadValue(), Is.Not.EqualTo(default(Vector2))); + + trace.Clear(); + + // Configuration change causes full re-resolve and schedules initial state check. + InputSystem.QueueConfigChangeEvent(touchscreen); + InputSystem.Update(); + InputSystem.Update(); + + // Full re-resolve may cancel the current action state. What must NOT happen is a synthetic + // Started/Performed pair from persisted inactive touch state. + Assert.AreEqual(1, trace.count); + foreach (var eventPtr in trace) + { + // The trace should only contain a Canceled event for the action. + Assert.AreEqual(InputActionPhase.Canceled, eventPtr.phase, + $"inactive touch state should not produce action callbacks, but received {eventPtr.phase}."); + } + } + } + // https://fogbugz.unity3d.com/f/cases/1192972/ [Test] [Category("Actions")]