Skip to content

FIX: Changed to frame based comparison for tracking UI click/navigation events #2112

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Mar 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
063ddb9
reduce complexity for checking UI interactions in update - frame base…
ritamerkl Jan 22, 2025
5067af8
added changelog
ritamerkl Jan 22, 2025
29c0eda
changelog formatting
ritamerkl Jan 22, 2025
7beeb2b
switch to additional InFrame and InputSystem update logic
ritamerkl Jan 23, 2025
b6e48dc
fixed wrong reference to update instead of frame
ritamerkl Jan 23, 2025
ea856c3
temporary workaround for rebinding test
ritamerkl Jan 24, 2025
a814fa2
save frame count when status changed
ritamerkl Jan 24, 2025
e581aad
fixed frame state saving
ritamerkl Jan 24, 2025
94b59a1
switched to coroutine with rebinding test to fix UI submit framebased…
ritamerkl Jan 24, 2025
65b20c9
removed redundant frame from InputActionState and InputAction
ritamerkl Jan 24, 2025
18dedda
Removed m_Frame
ritamerkl Jan 24, 2025
6e01bb1
Merge remote-tracking branch 'origin/develop' into fix-ui-behavior-fo…
ritamerkl Feb 3, 2025
b486ebd
changed to proposal 2
ritamerkl Feb 4, 2025
f49ccf0
fix comments in InputAction tests
ritamerkl Feb 4, 2025
39e057c
Fixed spelling
ritamerkl Feb 4, 2025
cb8cc82
updated documentation
ritamerkl Feb 7, 2025
9d8b5b4
Merge branch 'develop' into fix-ui-behavior-for-update-non-dynamic
ritamerkl Feb 7, 2025
e9367a4
Merge branch 'develop' into fix-ui-behavior-for-update-non-dynamic
Pauliusd01 Feb 10, 2025
adeddc9
Merge branch 'develop' into fix-ui-behavior-for-update-non-dynamic
ritamerkl Feb 12, 2025
e3b1a38
Update CHANGELOG.md
ritamerkl Feb 12, 2025
7114e6f
skip properties
ritamerkl Feb 12, 2025
8332195
added tests
ritamerkl Feb 12, 2025
95e4bfc
update version to 1.14.0
stefanunity Feb 13, 2025
2b4d758
fixed doc
ritamerkl Feb 14, 2025
b826dc2
Merge branch 'fix-ui-behavior-for-update-non-dynamic' of https://gith…
ritamerkl Feb 14, 2025
49fe0dc
Merge branch 'develop' into fix-ui-behavior-for-update-non-dynamic
ritamerkl Feb 14, 2025
998fcda
Update CHANGELOG.md
ritamerkl Feb 14, 2025
8eee052
fix formatting for changelog
ritamerkl Feb 14, 2025
e6cc47a
fix formatting
ritamerkl Feb 14, 2025
c37b912
Merge branch 'develop' into fix-ui-behavior-for-update-non-dynamic
ritamerkl Feb 14, 2025
51b9643
update comment
ritamerkl Feb 19, 2025
676ad0f
Changed naming from RenderingFrame to DynamicUpdate
ritamerkl Feb 21, 2025
fc0bfed
Merge remote-tracking branch 'origin/develop' into fix-ui-behavior-fo…
ritamerkl Feb 21, 2025
92d8773
Fixed comments for rename of method done earlier in 676ad0f
chris-massie Feb 27, 2025
f1af620
update comment
ritamerkl Feb 28, 2025
1deb9ac
Update Packages/com.unity.inputsystem/InputSystem/Actions/InputAction.cs
ritamerkl Feb 28, 2025
6abb34e
update comment
ritamerkl Feb 28, 2025
daa9dc4
update comment
ritamerkl Feb 28, 2025
267954a
Merge branch 'develop' into fix-ui-behavior-for-update-non-dynamic
ritamerkl Mar 3, 2025
40b8910
added line of documentation to explain frame delay
ritamerkl Mar 10, 2025
440af88
added help box to indicate the InputSystem update mode is not recomme…
ritamerkl Mar 10, 2025
3a12620
Merge branch 'develop' into fix-ui-behavior-for-update-non-dynamic
ritamerkl Mar 10, 2025
73725ef
update text
ritamerkl Mar 12, 2025
73aec85
replace link with static to make it easier upgradeable
ritamerkl Mar 12, 2025
d422bf4
Merge branch 'fix-ui-behavior-for-update-non-dynamic' of https://gith…
ritamerkl Mar 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Assets/Samples/UIvsGameInput/UIvsGameInputHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public void Update()
transform.rotation = default;

// When using a pointer-based control scheme, we engage camera look explicitly.
if (m_ControlStyle != ControlStyle.GamepadJoystick && m_LookEngageAction.WasPressedThisFrame() && IsPointerInsideScreen())
if (m_ControlStyle != ControlStyle.GamepadJoystick && m_LookEngageAction.WasPressedThisDynamicUpdate() && IsPointerInsideScreen())
EngageCameraControl();

// With gamepad/joystick, we can freely rotate the camera at any time.
Expand Down Expand Up @@ -166,14 +166,14 @@ public void Update()
if (m_Mouse != null)
m_MousePositionToWarpToAfterCursorUnlock = m_MousePositionToWarpToAfterCursorUnlock.Value + m_Mouse.delta.ReadValue();

if (m_CancelAction.WasPressedThisFrame() || !m_LookEngageAction.IsPressed())
if (m_CancelAction.WasPressedThisDynamicUpdate() || !m_LookEngageAction.IsPressed())
DisengageCameraControl();

break;

case State.InMenu:

if (m_CancelAction.WasPressedThisFrame())
if (m_CancelAction.WasPressedThisDynamicUpdate())
OnContinueClicked();

break;
Expand Down
114 changes: 114 additions & 0 deletions Assets/Tests/InputSystem/CoreTests_Actions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,120 @@ public void Settings_ShouldStoreSettingsAndFeatureFlags(string featureName)
}
}

[UnityTest]
[Category("Actions")]
public IEnumerator Actions_WasStateReachedThisRenderingFrameOperatesIndependentlyFromInputUpdateStep()
{
var updateMode = InputSystem.settings.updateMode;
InputSystem.settings.updateMode = InputSettings.UpdateMode.ProcessEventsInDynamicUpdate;

var gamepad = InputSystem.AddDevice<Gamepad>();
var simpleAction = new InputAction(binding: "<Gamepad>/buttonSouth");
simpleAction.Enable();

Assert.That(simpleAction.WasPerformedThisDynamicUpdate(), Is.False);
Assert.That(simpleAction.WasPressedThisDynamicUpdate(), Is.False);
Assert.That(simpleAction.WasReleasedThisDynamicUpdate(), Is.False);
Assert.That(simpleAction.WasCompletedThisDynamicUpdate(), Is.False);

PressAndRelease(gamepad.buttonSouth);

yield return null; // InputSystem.Update is called and the action state chenges

Assert.That(simpleAction.WasPerformedThisDynamicUpdate(), Is.True);
Assert.That(simpleAction.WasPressedThisDynamicUpdate(), Is.True);
Assert.That(simpleAction.WasReleasedThisDynamicUpdate(), Is.True);

InputSystem.Update(); // a manual update happens between two frames, that does not affect the output of the WasPerformedThisDynamicUpdate

Assert.That(simpleAction.WasPerformedThisDynamicUpdate(), Is.True);
Assert.That(simpleAction.WasPressedThisDynamicUpdate(), Is.True);
Assert.That(simpleAction.WasReleasedThisDynamicUpdate(), Is.True);

//Reset State
InputSystem.settings.updateMode = updateMode;
}

[UnityTest]
[Category("Actions")]
public IEnumerator Actions_WasStateReachedThisFrameOperatesIndependentlyFromRenderingFrame()
{
var updateMode = InputSystem.settings.updateMode;
InputSystem.settings.updateMode = InputSettings.UpdateMode.ProcessEventsManually;

var gamepad = InputSystem.AddDevice<Gamepad>();
var simpleAction = new InputAction(binding: "<Gamepad>/buttonSouth");
simpleAction.Enable();

Assert.That(simpleAction.WasPerformedThisFrame(), Is.False);
Assert.That(simpleAction.WasPressedThisFrame(), Is.False);
Assert.That(simpleAction.WasReleasedThisFrame(), Is.False);
Assert.That(simpleAction.WasCompletedThisFrame(), Is.False);

PressAndRelease(gamepad.buttonSouth);

yield return null; // InputSystem.Update is not called and the action state does not change
yield return null;
yield return null;

Assert.That(simpleAction.WasPerformedThisFrame(), Is.False);
Assert.That(simpleAction.WasPressedThisFrame(), Is.False);
Assert.That(simpleAction.WasReleasedThisFrame(), Is.False);

InputSystem.Update(); // a manual update happens between two frames, that does not affect the output of the WasXYZThisRenderingFrame but does affect the WasXYZThisFrame

Assert.That(simpleAction.WasPerformedThisFrame(), Is.True);
Assert.That(simpleAction.WasPressedThisFrame(), Is.True);
Assert.That(simpleAction.WasReleasedThisFrame(), Is.True);

//Reset State
InputSystem.settings.updateMode = updateMode;
}

[UnityTest]
[Category("Actions")]
public IEnumerator Actions_WasStateReachedThisFrameAndWasStateReachedThisRenderingFrameCanOperateSimultanously()
{
var updateMode = InputSystem.settings.updateMode;
InputSystem.settings.updateMode = InputSettings.UpdateMode.ProcessEventsManually;

var gamepad = InputSystem.AddDevice<Gamepad>();
var simpleAction = new InputAction(binding: "<Gamepad>/buttonSouth");
simpleAction.Enable();

Assert.That(simpleAction.WasPerformedThisFrame(), Is.False);
Assert.That(simpleAction.WasPressedThisFrame(), Is.False);
Assert.That(simpleAction.WasReleasedThisFrame(), Is.False);
Assert.That(simpleAction.WasCompletedThisFrame(), Is.False);

PressAndRelease(gamepad.buttonSouth);

yield return null; // InputSystem.Update is not called and the action state does not change

Assert.That(simpleAction.WasPerformedThisFrame(), Is.False);
Assert.That(simpleAction.WasPressedThisFrame(), Is.False);
Assert.That(simpleAction.WasReleasedThisFrame(), Is.False);

InputSystem.Update(); // a manual update happens between two frames, that does not affect the output of the WasXYZThisRenderingFrame but does affect the WasXYZThisFrame

Assert.That(simpleAction.WasPerformedThisFrame(), Is.True);
Assert.That(simpleAction.WasPressedThisFrame(), Is.True);
Assert.That(simpleAction.WasReleasedThisFrame(), Is.True);

yield return null;

Assert.That(simpleAction.WasPerformedThisDynamicUpdate(), Is.True);
Assert.That(simpleAction.WasPressedThisDynamicUpdate(), Is.True);
Assert.That(simpleAction.WasReleasedThisDynamicUpdate(), Is.True);

yield return null;

Assert.That(simpleAction.WasCompletedThisDynamicUpdate(), Is.False);

//Reset State
InputSystem.settings.updateMode = updateMode;
}

[Test]
[Category("Actions")]
public void Actions_WhenShortcutsDisabled_AllConflictingActionsTrigger()
Expand Down
10 changes: 8 additions & 2 deletions Assets/Tests/Samples/RebindingUITests.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System.Collections;
using System.IO;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Samples.RebindUI;
using UnityEngine.InputSystem.UI;
using UnityEngine.TestTools;
using UnityEngine.UI;

public class RebindingUITests : CoreTestsFixture
Expand Down Expand Up @@ -84,9 +86,9 @@ public void Samples_RebindingUI_UpdatesWhenKeyboardLayoutChanges()
}

// https://fogbugz.unity3d.com/f/cases/1271591/
[Test]
[UnityTest]
[Category("Samples")]
public void Samples_RebindingUI_SuppressingEventsDoesNotInterfereWithUIInput()
public IEnumerator Samples_RebindingUI_SuppressingEventsDoesNotInterfereWithUIInput()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ritamerkl Do we have a test that verifies behavior when configured to run input processing on fixed update?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add tests now

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added 8332195

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

especially tested the update and frame based comparing in co-dependency to another

{
var keyboard = InputSystem.AddDevice<Keyboard>();

Expand Down Expand Up @@ -135,6 +137,8 @@ public void Samples_RebindingUI_SuppressingEventsDoesNotInterfereWithUIInput()
// UI should be fine with that.
PressAndRelease(keyboard.enterKey);
eventSystem.InvokeUpdate();
yield return null;


Assert.That(rebind.ongoingRebind, Is.Not.Null);
Assert.That(rebind.ongoingRebind.started, Is.True);
Expand All @@ -144,6 +148,7 @@ public void Samples_RebindingUI_SuppressingEventsDoesNotInterfereWithUIInput()

Press(keyboard.bKey);
eventSystem.InvokeUpdate();
yield return null;

Assert.That(rebind.ongoingRebind, Is.Not.Null);
Assert.That(rebind.ongoingRebind.started, Is.True);
Expand All @@ -162,6 +167,7 @@ public void Samples_RebindingUI_SuppressingEventsDoesNotInterfereWithUIInput()
// Start another rebind via "Submit".
PressAndRelease(keyboard.enterKey);
eventSystem.InvokeUpdate();
yield return null;

Assert.That(rebind.ongoingRebind, Is.Not.Null);
Assert.That(rebind.ongoingRebind.started, Is.True);
Expand Down
4 changes: 4 additions & 0 deletions Packages/com.unity.inputsystem/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ however, it has to be formatted properly to pass verification tests.
- Fixed arrow key navigation of Input Actions after Action rename. [ISXB-1024](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1024)
- Fixed gamepad navigation in UI Toolkit TextField when using InputSystemUIInputModule. [UUM-77364](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-77364)
- Fixed issue where asset editor window splitter positions were not persisted [ISXB-1316]
- Fixed an issue where updating the InputSystem outside of the dynamic Update would lead to UI input and navigation events get lost. [ISXB-1313](https://issuetracker.unity3d.com/issues/ui-onclick-events-sometimes-do-not-trigger-when-manual-update-is-utilized-with-input-system)
- Fixed a bug that would cause `TrackedPoseDriver` to update position and rotation when no HMD device is connected [ISXB-699](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-699) instead of keeping it unchanged.

### Changed
- Changed default input action asset name from New Controls to New Actions.
- Added disabling of action maps in rebinding UI sample.

### Added
- An alternative way to access if an action state reached a certain phase during this rendering frame (Update()). This can be utilized even if the InputSystem update mode is set to manual or FixedUpdate. It can be used to access the action phase during rendering, eg for perform updates to the UI.

## [1.13.0] - 2025-02-05

### Fixed
Expand Down
Loading