Skip to content

Commit 8816429

Browse files
committed
Fix: Improved the fix to the main issue that this branch addresses so that button submit events also work consistently
1 parent 86a1a35 commit 8816429

File tree

7 files changed

+102
-58
lines changed

7 files changed

+102
-58
lines changed

Assets/Samples/RebindingUI/RebindActionUI.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ void CleanUp()
322322
// Since this sample has no interactable UI during rebinding we also want to suppress non-matching events.
323323
//.WithNonMatchingEventsBeingSuppressed()
324324
// We want device state to update but not actions firing during rebinding.
325-
.WithActionsBeingSuppressed()
325+
.WithActionEventNotificationsBeingSuppressed()
326326
// We use a timeout to illustrate that its possible to skip cancel buttons and let rebind timeout.
327327
.WithTimeout(m_RebindTimeout)
328328
.OnComplete(

Assets/Tests/InputSystem/CoreTests_Events.cs

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,8 +1224,8 @@ public void EventHandledPolicy_ShouldReflectUserSetting()
12241224
Assert.That(InputSystem.s_Manager.inputEventHandledPolicy, Is.EqualTo(InputEventHandledPolicy.SuppressStateUpdates));
12251225

12261226
// Assert policy can be changed
1227-
InputSystem.s_Manager.inputEventHandledPolicy = InputEventHandledPolicy.SuppressActionUpdates;
1228-
Assert.That(InputSystem.s_Manager.inputEventHandledPolicy, Is.EqualTo(InputEventHandledPolicy.SuppressActionUpdates));
1227+
InputSystem.s_Manager.inputEventHandledPolicy = InputEventHandledPolicy.SuppressActionEventNotifications;
1228+
Assert.That(InputSystem.s_Manager.inputEventHandledPolicy, Is.EqualTo(InputEventHandledPolicy.SuppressActionEventNotifications));
12291229

12301230
// Assert policy can be changed back
12311231
InputSystem.s_Manager.inputEventHandledPolicy = InputEventHandledPolicy.SuppressStateUpdates;
@@ -1245,27 +1245,37 @@ class SuppressedActionEventData
12451245
public int CanceledCount;
12461246
}
12471247

1248-
// Note that each element in the expected value arrays correspond to accumulated count per test step.
1248+
// Note that each element in the expected value arrays correspond to accumulated count per test step, in summary:
1249+
// Step 0: Initialize state
1250+
// Step 1: Press gamepad north and stick (Event marked handled)
1251+
// Step 2: Periodic state update/reading without changes (north and stick still actuated)
1252+
// Step 3: Release button north and stick while no longer being suppressed.
1253+
// Step 4: Press gamepad north and stick.
1254+
1255+
// Press event is detected in step 2 (false positive) with default interaction
12491256
[TestCase(InputEventHandledPolicy.SuppressStateUpdates, // policy
12501257
null, // interactions
12511258
new int[] { 0, 0, 1, 1, 2}, // started
12521259
new int[] { 0, 0, 1, 1, 2}, // performed
12531260
new int[] {0, 0, 0, 1, 1})] // cancelled
1254-
[TestCase(InputEventHandledPolicy.SuppressActionUpdates,
1261+
// Press event is not detected in step 1/2 with default interaction
1262+
[TestCase(InputEventHandledPolicy.SuppressActionEventNotifications,
12551263
null,
12561264
new int[] { 0, 0, 0, 0, 1},
12571265
new int[] { 0, 0, 0, 0, 1},
1258-
new int[] {0, 0, 0, 0, 0})]
1266+
new int[] {0, 0, 0, 1, 1})]
1267+
// Press event is detected in step 2 (false positive) with explicit press interaction
12591268
[TestCase(InputEventHandledPolicy.SuppressStateUpdates,
12601269
"press",
12611270
new int[] { 0, 0, 1, 1, 2},
12621271
new int[] { 0, 0, 1, 1, 2},
12631272
new int[] {0, 0, 0, 1, 1})]
1264-
[TestCase(InputEventHandledPolicy.SuppressActionUpdates,
1273+
// Press event is not detected in step 1/2 (false positive) with explicit press interaction
1274+
[TestCase(InputEventHandledPolicy.SuppressActionEventNotifications,
12651275
"press",
12661276
new int[] { 0, 0, 0, 0, 1},
12671277
new int[] { 0, 0, 0, 0, 1},
1268-
new int[] {0, 0, 0, 0, 0})]
1278+
new int[] {0, 0, 0, 1, 1})]
12691279
[Category("Events")]
12701280
[Description("ISXB-1524, ISXB-1396 Events suppressed has side-effects on actions")]
12711281
public void Events_ShouldRespectHandledPolicyUponUpdateAndSuppressedPressTransition(
@@ -1274,6 +1284,7 @@ public void Events_ShouldRespectHandledPolicyUponUpdateAndSuppressedPressTransit
12741284
{
12751285
// Update setting to match desired scenario
12761286
InputSystem.s_Manager.inputEventHandledPolicy = policy;
1287+
var seesControlChangesUnderSuppression = policy == InputEventHandledPolicy.SuppressActionEventNotifications;
12771288

12781289
// Use a boxed boolean to allow lambda to capture reference.
12791290
var data = new SuppressedActionEventData();
@@ -1296,7 +1307,7 @@ public void Events_ShouldRespectHandledPolicyUponUpdateAndSuppressedPressTransit
12961307
action.performed += _ => ++ data.PerformedCount;
12971308
action.canceled += _ => ++ data.CanceledCount;
12981309

1299-
// Ensure state is updated/initialized
1310+
// Step 0: Ensure state is updated/initialized
13001311
InputSystem.QueueStateEvent(device, new GamepadState() { leftStick = new Vector2(0.01f, 0.0f) });
13011312
InputSystem.Update();
13021313
Assert.That(data.StartedCount, Is.EqualTo(expectedStarted[0]));
@@ -1307,9 +1318,12 @@ public void Events_ShouldRespectHandledPolicyUponUpdateAndSuppressedPressTransit
13071318
Assert.That(action.WasPressedThisFrame, Is.EqualTo(performedThisFrame));
13081319
var releasedThisFrame = expectedCancelled[0] != 0;
13091320
Assert.That(action.WasReleasedThisFrame, Is.EqualTo(releasedThisFrame));
1310-
// TODO Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.False); <-- TODO Needs separate handling, just suppress?
1321+
Assert.That(action.IsPressed, Is.False); // Note: This is not an event and hence not suppressed
1322+
1323+
Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.False);
1324+
Assert.That(Gamepad.current.buttonNorth.wasReleasedThisFrame, Is.False);
13111325

1312-
// Press button north and left stick with event suppression active
1326+
// Step 1: Press button north and left stick with event suppression active
13131327
data.MarkNextEventHandled = true;
13141328
InputSystem.QueueStateEvent(device, new GamepadState() { leftStick = new Vector2(1.00f, 0.01f) }
13151329
.WithButton(GamepadButton.North));
@@ -1322,9 +1336,12 @@ public void Events_ShouldRespectHandledPolicyUponUpdateAndSuppressedPressTransit
13221336
Assert.That(action.WasPressedThisFrame, Is.EqualTo(performedThisFrame));
13231337
releasedThisFrame = expectedCancelled[1] - expectedCancelled[0] > 0;
13241338
Assert.That(action.WasReleasedThisFrame, Is.EqualTo(releasedThisFrame));
1325-
// TODO Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.EqualTo(expectedPerformed[1] - expectedPerformed[0] > 0));
1339+
Assert.That(action.IsPressed, Is.EqualTo(seesControlChangesUnderSuppression)); // Note: This is not an event and hence not suppressed
13261340

1327-
// Simulate a periodic reading (e.g. driven by noise or irrelevant control), this will trigger performed count.
1341+
Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.EqualTo(seesControlChangesUnderSuppression));
1342+
Assert.That(Gamepad.current.buttonNorth.wasReleasedThisFrame, Is.False);
1343+
1344+
// Step 2: Simulate a periodic reading (e.g. driven by noise or irrelevant control), this will trigger performed count.
13281345
// Note that for SuppressStateUpdates (default), this would trigger a state change since North button
13291346
// transitions from 0 to 1 which is considered a press.
13301347
data.MarkNextEventHandled = false;
@@ -1339,9 +1356,12 @@ public void Events_ShouldRespectHandledPolicyUponUpdateAndSuppressedPressTransit
13391356
Assert.That(action.WasPressedThisFrame, Is.EqualTo(performedThisFrame));
13401357
releasedThisFrame = expectedCancelled[2] - expectedCancelled[1] > 0;
13411358
Assert.That(action.WasReleasedThisFrame, Is.EqualTo(releasedThisFrame));
1342-
// TODO Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.EqualTo(expectedPerformed[2] - expectedPerformed[1] > 0));
1359+
Assert.That(action.IsPressed, Is.True); // Note: This is not an event and hence not suppressed
1360+
1361+
Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.EqualTo(!seesControlChangesUnderSuppression));
1362+
Assert.That(Gamepad.current.buttonNorth.wasReleasedThisFrame, Is.False);
13431363

1344-
// Release button north and stick while no longer being suppressed. This may result in a release if
1364+
// Step 3: Release button north and stick while no longer being suppressed. This may result in a release if
13451365
// previous event was completely ignored without updating interaction state.
13461366
InputSystem.QueueStateEvent(device, new GamepadState() { leftStick = new Vector2(0.00f, 0.01f) });
13471367
InputSystem.Update();
@@ -1353,9 +1373,12 @@ public void Events_ShouldRespectHandledPolicyUponUpdateAndSuppressedPressTransit
13531373
Assert.That(action.WasPressedThisFrame, Is.EqualTo(performedThisFrame));
13541374
releasedThisFrame = expectedCancelled[3] - expectedCancelled[2] > 0;
13551375
Assert.That(action.WasReleasedThisFrame, Is.EqualTo(releasedThisFrame));
1356-
// TODO Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.EqualTo(expectedPerformed[3] - expectedPerformed[2] > 0));
1376+
Assert.That(action.IsPressed, Is.False); // Note: This is not an event and hence not suppressed
13571377

1358-
// Press button north and stick again while not being suppressed.
1378+
Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.False);
1379+
Assert.That(Gamepad.current.buttonNorth.wasReleasedThisFrame, Is.True);
1380+
1381+
// Step 4: Press button north and stick again while not being suppressed.
13591382
InputSystem.QueueStateEvent(device, new GamepadState() { leftStick = new Vector2(0.99f, 0.00f) }
13601383
.WithButton(GamepadButton.North));
13611384
InputSystem.Update();
@@ -1367,6 +1390,10 @@ public void Events_ShouldRespectHandledPolicyUponUpdateAndSuppressedPressTransit
13671390
Assert.That(action.WasPressedThisFrame, Is.EqualTo(performedThisFrame));
13681391
releasedThisFrame = expectedCancelled[4] - expectedCancelled[3] > 0;
13691392
Assert.That(action.WasReleasedThisFrame, Is.EqualTo(releasedThisFrame));
1393+
Assert.That(action.IsPressed, Is.True); // Note: This is not an event and hence not suppressed
1394+
1395+
Assert.That(Gamepad.current.buttonNorth.wasPressedThisFrame, Is.True);
1396+
Assert.That(Gamepad.current.buttonNorth.wasReleasedThisFrame, Is.False);
13701397
}
13711398

13721399
[StructLayout(LayoutKind.Explicit, Size = 2)]

Packages/com.unity.inputsystem/InputSystem/Actions/InputAction.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,7 +1259,7 @@ private int ExpectedFrame()
12591259
public unsafe bool WasPressedThisFrame()
12601260
{
12611261
var state = GetOrCreateActionMap().m_State;
1262-
if (state != null)
1262+
if (state != null && !state.isSuppressed)
12631263
{
12641264
var actionStatePtr = &state.actionStates[m_ActionIndexInState];
12651265
var currentUpdateStep = InputUpdate.s_UpdateStepCount;
@@ -1448,7 +1448,7 @@ public unsafe bool WasPerformedThisFrame()
14481448
{
14491449
var state = GetOrCreateActionMap().m_State;
14501450

1451-
if (state != null)
1451+
if (state != null && !state.isSuppressed)
14521452
{
14531453
var actionStatePtr = &state.actionStates[m_ActionIndexInState];
14541454
var currentUpdateStep = InputUpdate.s_UpdateStepCount;

Packages/com.unity.inputsystem/InputSystem/Actions/InputActionRebindingExtensions.cs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,7 +1562,7 @@ public RebindingOperation WithAction(InputAction action)
15621562
/// click input should come through. For this reason, input from controls matching <see cref="WithControlsExcluding"/>
15631563
/// is still let through.
15641564
///
1565-
/// See <see cref="WithActionsBeingSuppressed"/> for how this configuration relates to suppressing
1565+
/// See <see cref="WithActionEventNotificationsBeingSuppressed"/> for how this configuration relates to suppressing
15661566
/// actions during rebind.
15671567
/// </remarks>
15681568
public RebindingOperation WithMatchingEventsBeingSuppressed(bool value = true)
@@ -2088,32 +2088,37 @@ public RebindingOperation OnMatchWaitForAnother(float seconds)
20882088
}
20892089

20902090
/// <summary>
2091-
/// Ensures state changes are allowed to propagate during rebinding but suppresses action updates
2092-
/// to prevent unexpected actions triggering as soon as rebinding ends (event suppression stops).
2091+
/// Ensures state changes are allowed to propagate during rebinding but suppresses action event
2092+
/// notifications to prevent unexpected actions triggering as soon as rebinding ends
2093+
/// (event suppression stops).
20932094
/// </summary>
2094-
/// <param name="value">If true disables action propagation, if false enables action propagation.</param>
2095+
/// <param name="value">If true, disables action event notifications for changes driven by handled events
2096+
/// during rebinding, if false this feature is disabled.</param>
20952097
/// <remarks>
20962098
/// If events are suppressed during rebinding using <see cref="WithMatchingEventsBeingSuppressed"/>
2097-
/// and/or <see cref="WithNonMatchingEventsBeingSuppressed"/> without suppressing action propagation,
2098-
/// events will not update their associated device state. This may lead to unexpected actions triggering
2099-
/// as soon as rebinding completes (event suppression stops), due to missed state transitions.
2100-
/// Action propagation resumes to normal as soon as rebinding operation completes or cancels.
2099+
/// without suppressing action event notifications, events will not update their associated device state
2100+
/// and be suppressed earlier in the processing chain. This may lead to unexpected actions triggering
2101+
/// as soon as rebinding completes (event suppression stops), due to missed recording of state transitions.
2102+
/// Action event notification resumes to normal as soon as rebinding operation completes or cancels.
21012103
///
21022104
/// When this configuration is active, any events suppressed via
2103-
/// <see cref="WithMatchingEventsBeingSuppressed"/> and/or
2104-
/// <see cref="WithNonMatchingEventsBeingSuppressed"/> will still be allowed to update their associated
2105-
/// device state but will not propagate into action interaction updates which could cause undesirable
2106-
/// triggering of actions caused by the difference between device state prior to rebinding and after
2107-
/// rebinding.
2105+
/// <see cref="WithMatchingEventsBeingSuppressed"/> will still be allowed to update their associated
2106+
/// device state but will not propagate into action interaction event notifications which could cause
2107+
/// undesirable triggering of actions caused by the difference between device state prior to rebinding
2108+
/// and after rebinding.
21082109
///
21092110
/// Note that if event suppression is not active, this setting will have no effect.
2111+
///
2112+
/// In addition to interaction event notifications, the following APIs will also return false when the
2113+
/// action reflects a state subject for suppression: <see cref="InputAction.WasPerformedThisFrame"/>,
2114+
/// <see cref="InputAction.WasPressedThisFrame"/>, <see cref="InputAction.WasReleasedThisFrame"/>.
21102115
/// </remarks>
21112116
/// <returns>Reference to this rebinding operation.</returns>
2112-
public RebindingOperation WithActionsBeingSuppressed(bool value = true)
2117+
public RebindingOperation WithActionEventNotificationsBeingSuppressed(bool value = true)
21132118
{
21142119
ThrowIfRebindInProgress();
21152120
m_TargetInputEventHandledPolicy = value
2116-
? InputEventHandledPolicy.SuppressActionUpdates
2121+
? InputEventHandledPolicy.SuppressActionEventNotifications
21172122
: InputEventHandledPolicy.SuppressStateUpdates;
21182123
return this;
21192124
}

0 commit comments

Comments
 (0)