Skip to content

Commit 4b53a18

Browse files
Add fixes for failing unit tests.
1 parent f234b27 commit 4b53a18

2 files changed

Lines changed: 243 additions & 1 deletion

File tree

Assets/Tests/InputSystem/CoreTests_Actions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,6 @@ public void Actions_WhenShortcutsDisabled_AllConflictingActionsTrigger()
211211
public void Actions_WhenShortcutsEnabled_CanConsumeInput(bool legacyComposites)
212212
{
213213
InputSystem.settings.shortcutKeysConsumeInput = true;
214-
InputSystem.settings.shortcutKeysUseActionPriority = true;
215214

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

@@ -240,6 +239,9 @@ public void Actions_WhenShortcutsEnabled_CanConsumeInput(bool legacyComposites)
240239
action5.Priority = 1;
241240

242241
action1.AddBinding("<Keyboard>/space");
242+
// Ordered modifier evaluation: modifier must be pressed before the button for this chord shape.
243+
// With shortcutKeysUseActionPriority on, IsShortcutComplexityModifierOrderActive is false, so
244+
// Default would resolve to Unordered and pressing space then shift would still satisfy the composite.
243245
action2.AddCompositeBinding(legacyComposites ? "ButtonWithOneModifier" : "OneModifier")
244246
.With("Modifier", "<Keyboard>/shift")
245247
.With(legacyComposites ? "Button" : "Binding", "<Keyboard>/space");

Assets/Tests/InputSystem/CoreTests_ActionsPriority.cs

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,25 @@ internal static InputAction SetupTestAction(this InputActionMap map, string[] bi
5959

6060
internal partial class CoreTests
6161
{
62+
/// <summary>
63+
/// Overlap resolution uses <see cref="InputAction.Priority"/> and per-control grouping written from actions.
64+
/// </summary>
65+
private static void EnableActionPriorityShortcutResolution()
66+
{
67+
InputSystem.settings.shortcutKeysUseActionPriority = true;
68+
InputSystem.settings.shortcutKeysConsumeInput = false;
69+
}
70+
71+
/// <summary>
72+
/// Overlap resolution uses composite binding complexity; <see cref="InputAction.Priority"/> is not applied at runtime.
73+
/// Requires shortcut consumption on so control grouping merges slots on the same physical control.
74+
/// </summary>
75+
private static void EnableComplexityShortcutResolution()
76+
{
77+
InputSystem.settings.shortcutKeysConsumeInput = true;
78+
InputSystem.settings.shortcutKeysUseActionPriority = false;
79+
}
80+
6281
private static readonly List<(string[], string[])> k_TwoInputActionTestCases = new()
6382
{
6483
(new[] {"ctrl", "x"}, new[] {"x"}),
@@ -111,6 +130,7 @@ private void ReleaseBindingsForActions(Keyboard keyboard, InputAction action1, I
111130
[TestCaseSource(nameof(k_TwoInputActionTestCases))]
112131
public void Actions_Priority_OnlyOneActionIsFired_WhenOnePriorityIsHigherThanOther((string[] a1, string[] a2) actions)
113132
{
133+
EnableActionPriorityShortcutResolution();
114134
var keyboard = InputSystem.AddDevice<Keyboard>();
115135

116136
InputActionMap map = new InputActionMap("map");
@@ -145,6 +165,7 @@ public void Actions_Priority_OnlyOneActionIsFired_WhenOnePriorityIsHigherThanOth
145165
[TestCaseSource(nameof(k_TwoInputActionTestCases))]
146166
public void Actions_Priority_OnlyOneActionIsFired_WhenOnePriorityIsHigherThanOtherInversePriorityOrder((string[] a1, string[] a2) actions)
147167
{
168+
EnableActionPriorityShortcutResolution();
148169
var keyboard = InputSystem.AddDevice<Keyboard>();
149170

150171
InputActionMap map = new InputActionMap("map");
@@ -179,6 +200,7 @@ public void Actions_Priority_OnlyOneActionIsFired_WhenOnePriorityIsHigherThanOth
179200
[TestCaseSource(nameof(k_TwoInputActionTestCases))] // TODO: Darren, Should both actions be performed this frame here??
180201
public void Actions_Priority_BothActionsArePerformed_DueToKeyPressOrderForShortcut((string[] larger, string[] smaller) actions)
181202
{
203+
EnableActionPriorityShortcutResolution();
182204
var keyboard = InputSystem.AddDevice<Keyboard>();
183205

184206
InputActionMap map = new InputActionMap("map");
@@ -219,6 +241,7 @@ public void Actions_Priority_BothActionsArePerformed_DueToKeyPressOrderForShortc
219241
[TestCaseSource(nameof(k_TwoInputActionTestCases))]
220242
public void Actions_Priority_BothActionFires_WhenPriorityIsEqual((string[] a1, string[] a2) actions)
221243
{
244+
EnableActionPriorityShortcutResolution();
222245
var keyboard = InputSystem.AddDevice<Keyboard>();
223246

224247
InputActionMap map = new InputActionMap("map");
@@ -242,6 +265,7 @@ public void Actions_Priority_BothActionFires_WhenPriorityIsEqual((string[] a1, s
242265
[TestCaseSource(nameof(k_TwoInputActionTestCases))]
243266
public void Actions_Priority_BothActionsFire_WhenPriorityIsZero((string[] a1, string[] a2) actions)
244267
{
268+
EnableActionPriorityShortcutResolution();
245269
var keyboard = InputSystem.AddDevice<Keyboard>();
246270

247271
InputActionMap map = new InputActionMap("map");
@@ -279,6 +303,7 @@ public void Actions_Priority_BothActionsFire_WhenPriorityIsZero((string[] a1, st
279303
[TestCaseSource(nameof(k_TwoInputActionNoConflictingBindingTestCases))]
280304
public void Actions_Priority_BothActionsWithDifferentPriorityFire_WhenThereIsNoConflictingBinding((string[] a1, string[] a2) actions)
281305
{
306+
EnableActionPriorityShortcutResolution();
282307
var keyboard = InputSystem.AddDevice<Keyboard>();
283308

284309
InputActionMap map = new InputActionMap("map");
@@ -309,6 +334,7 @@ public void Actions_Priority_BothActionsWithDifferentPriorityFire_WhenThereIsNoC
309334
[TestCaseSource(nameof(k_TwoInputActionNoConflictingBindingTestCases))]
310335
public void Actions_Priority_BothActionsWithDifferentPriorityFire_WhenThereIsNoConflictingBindingInverseOrder((string[] a1, string[] a2) actions)
311336
{
337+
EnableActionPriorityShortcutResolution();
312338
var keyboard = InputSystem.AddDevice<Keyboard>();
313339

314340
InputActionMap map = new InputActionMap("map");
@@ -339,6 +365,7 @@ public void Actions_Priority_BothActionsWithDifferentPriorityFire_WhenThereIsNoC
339365
[TestCaseSource(nameof(k_TwoInputActionNoConflictingBindingTestCases))]
340366
public void Actions_Priority_BothActionsWithEqualPriorityFire_WhenThereIsNoConflictingBinding((string[] a1, string[] a2) actions)
341367
{
368+
EnableActionPriorityShortcutResolution();
342369
var keyboard = InputSystem.AddDevice<Keyboard>();
343370

344371
InputActionMap map = new InputActionMap("map");
@@ -420,6 +447,7 @@ public void Actions_Priority_InputActionStateMonitorIndex_ImplicitConversionToLo
420447
[Category("Actions Priority")]
421448
public unsafe void Actions_Priority_ControlGrouping_SamePhysicalControlSharesGroupId()
422449
{
450+
EnableActionPriorityShortcutResolution();
423451
var keyboard = InputSystem.AddDevice<Keyboard>();
424452
var map = new InputActionMap("priority_group_test");
425453
map.AddAction("a", binding: "<Keyboard>/z");
@@ -452,6 +480,7 @@ public unsafe void Actions_Priority_ControlGrouping_SamePhysicalControlSharesGro
452480
[Category("Actions Priority")]
453481
public unsafe void Actions_Priority_ControlGrouping_WritesPerControlSlotPriorityFromAction()
454482
{
483+
EnableActionPriorityShortcutResolution();
455484
var keyboard = InputSystem.AddDevice<Keyboard>();
456485
var map = new InputActionMap("priority_per_slot_test");
457486
var actionLow = map.AddAction("low", binding: "<Keyboard>/x");
@@ -494,6 +523,7 @@ public unsafe void Actions_Priority_ControlGrouping_WritesPerControlSlotPriority
494523
[Category("Actions Priority")]
495524
public IEnumerator Actions_Priority_BothActionsArePerformed_WhenAHoldAndBasicActionHaveDifferentTiming()
496525
{
526+
EnableActionPriorityShortcutResolution();
497527
var keyboard = InputSystem.AddDevice<Keyboard>();
498528
using var map = new InputActionMap("HoldChord");
499529

@@ -543,6 +573,7 @@ public IEnumerator Actions_Priority_BothActionsArePerformed_WhenAHoldAndBasicAct
543573
[Category("Actions Priority")]
544574
public IEnumerator Actions_Priority_OnlyOneHoldActionIsPerformed_WhenOnePriorityIsHigher()
545575
{
576+
EnableActionPriorityShortcutResolution();
546577
var keyboard = InputSystem.AddDevice<Keyboard>();
547578
using var map = new InputActionMap("HoldChord");
548579

@@ -583,4 +614,213 @@ public IEnumerator Actions_Priority_OnlyOneHoldActionIsPerformed_WhenOnePriority
583614
Release(keyboard.leftShiftKey);
584615
map.Disable();
585616
}
617+
618+
[Test]
619+
[Category("Actions Priority")]
620+
public unsafe void Actions_Complexity_ControlGrouping_SamePhysicalControlSharesGroupId_WhenShortcutConsumptionEnabled()
621+
{
622+
EnableComplexityShortcutResolution();
623+
624+
InputSystem.AddDevice<Keyboard>();
625+
var map = new InputActionMap("complexity_group_test");
626+
map.AddAction("a", binding: "<Keyboard>/z");
627+
map.AddAction("b", binding: "<Keyboard>/z");
628+
map.Enable();
629+
630+
var state = map.m_State;
631+
Assert.That(state, Is.Not.Null);
632+
Assert.That(state.memory.controlGroupingInitialized, Is.True);
633+
634+
for (var i = 0; i < state.totalControlCount; ++i)
635+
{
636+
for (var j = i + 1; j < state.totalControlCount; ++j)
637+
{
638+
if (state.controls[i] != state.controls[j])
639+
continue;
640+
641+
var gi = InputActionState.ControlGroupingTable.GroupElementIndex(i);
642+
var gj = InputActionState.ControlGroupingTable.GroupElementIndex(j);
643+
Assert.That(state.memory.controlGroupingAndPriority[gi], Is.EqualTo(state.memory.controlGroupingAndPriority[gj]));
644+
Assert.That(state.memory.controlGroupingAndPriority[gi], Is.Not.EqualTo(0));
645+
return;
646+
}
647+
}
648+
649+
Assert.Fail("Expected two control slots bound to the same physical control.");
650+
}
651+
652+
[Test]
653+
[Category("Actions Priority")]
654+
public unsafe void Actions_Complexity_ControlGrouping_WritesPerControlSlotComplexity_NotActionPriority()
655+
{
656+
EnableComplexityShortcutResolution();
657+
658+
var keyboard = InputSystem.AddDevice<Keyboard>();
659+
var map = new InputActionMap("complexity_per_slot_test");
660+
var actionLow = map.AddAction("low", binding: "<Keyboard>/x");
661+
var actionHigh = map.AddAction("high", binding: "<Keyboard>/x");
662+
actionLow.Priority = 4;
663+
actionHigh.Priority = 11;
664+
map.Enable();
665+
666+
var state = map.m_State;
667+
Assert.That(state, Is.Not.Null);
668+
669+
var lowIndex = -1;
670+
var highIndex = -1;
671+
for (var i = 0; i < state.totalControlCount; ++i)
672+
{
673+
if (state.controls[i] != keyboard.xKey)
674+
continue;
675+
var bindingIndex = state.controlIndexToBindingIndex[i];
676+
var actionIndex = state.bindingStates[bindingIndex].actionIndex;
677+
if (actionIndex == actionLow.m_ActionIndexInState)
678+
lowIndex = i;
679+
else if (actionIndex == actionHigh.m_ActionIndexInState)
680+
highIndex = i;
681+
}
682+
683+
Assert.That(lowIndex, Is.GreaterThanOrEqualTo(0));
684+
Assert.That(highIndex, Is.GreaterThanOrEqualTo(0));
685+
686+
var pLow = InputActionState.ControlGroupingTable.PriorityElementIndex(lowIndex);
687+
var pHigh = InputActionState.ControlGroupingTable.PriorityElementIndex(highIndex);
688+
// Secondary column stores composite complexity; two simple bindings on the same key both have depth 1.
689+
Assert.That(state.memory.controlGroupingAndPriority[pLow], Is.EqualTo(1));
690+
Assert.That(state.memory.controlGroupingAndPriority[pHigh], Is.EqualTo(1));
691+
}
692+
693+
[Test]
694+
[Category("Actions Priority")]
695+
public unsafe void Actions_Complexity_ControlGrouping_WritesHigherComplexityOnSharedControlVersusSimpleBinding()
696+
{
697+
EnableComplexityShortcutResolution();
698+
699+
var keyboard = InputSystem.AddDevice<Keyboard>();
700+
var map = new InputActionMap("complexity_composite_vs_simple");
701+
var composite = map.AddAction("chord", binding: null);
702+
composite.AddCompositeBinding("OneModifier")
703+
.With("Modifier", "<Keyboard>/ctrl")
704+
.With("Binding", "<Keyboard>/x");
705+
var simple = map.AddAction("plain", binding: "<Keyboard>/x");
706+
composite.Priority = 0;
707+
simple.Priority = 99;
708+
map.Enable();
709+
710+
var state = map.m_State;
711+
Assert.That(state, Is.Not.Null);
712+
713+
var compositeXIndex = -1;
714+
var simpleXIndex = -1;
715+
for (var i = 0; i < state.totalControlCount; ++i)
716+
{
717+
if (state.controls[i] != keyboard.xKey)
718+
continue;
719+
var bindingIndex = state.controlIndexToBindingIndex[i];
720+
var actionIndex = state.bindingStates[bindingIndex].actionIndex;
721+
if (actionIndex == composite.m_ActionIndexInState)
722+
compositeXIndex = i;
723+
else if (actionIndex == simple.m_ActionIndexInState)
724+
simpleXIndex = i;
725+
}
726+
727+
Assert.That(compositeXIndex, Is.GreaterThanOrEqualTo(0));
728+
Assert.That(simpleXIndex, Is.GreaterThanOrEqualTo(0));
729+
730+
var pComposite = InputActionState.ControlGroupingTable.PriorityElementIndex(compositeXIndex);
731+
var pSimple = InputActionState.ControlGroupingTable.PriorityElementIndex(simpleXIndex);
732+
Assert.That(state.memory.controlGroupingAndPriority[pSimple], Is.EqualTo(1));
733+
Assert.That(
734+
state.memory.controlGroupingAndPriority[pComposite],
735+
Is.GreaterThan(state.memory.controlGroupingAndPriority[pSimple]),
736+
"Composite binding chain depth should exceed a simple binding on the same physical control.");
737+
}
738+
739+
[Test]
740+
[Category("Actions Priority")]
741+
[TestCaseSource(nameof(k_TwoInputActionTestCases))]
742+
public void Actions_Complexity_CompositeWinsOverlappingSimple_IgnoresActionPriority((string[] a1, string[] a2) actions)
743+
{
744+
EnableComplexityShortcutResolution();
745+
746+
var keyboard = InputSystem.AddDevice<Keyboard>();
747+
var map = new InputActionMap("map");
748+
749+
var actionComposite = map.SetupTestAction(actions.a1);
750+
var actionSimple = map.SetupTestAction(actions.a2);
751+
752+
// Deliberately favor the simple binding in the Priority field; complexity resolution must still prefer the composite.
753+
actionComposite.Priority = 0;
754+
actionSimple.Priority = 100;
755+
756+
map.Enable();
757+
758+
Assert.That(actionComposite.WasPerformedThisFrame(), Is.False);
759+
Assert.That(actionSimple.WasPerformedThisFrame(), Is.False);
760+
761+
PressBindingsForInputActions(keyboard, actionComposite, actionSimple);
762+
763+
Assert.That(actionComposite.WasPerformedThisFrame(), Is.True);
764+
Assert.That(actionSimple.WasPerformedThisFrame(), Is.False);
765+
766+
ReleaseBindingsForActions(keyboard, actionComposite, actionSimple);
767+
768+
InputSystem.Update();
769+
770+
Assert.That(actionComposite.WasPerformedThisFrame(), Is.False);
771+
Assert.That(actionSimple.WasPerformedThisFrame(), Is.False);
772+
}
773+
774+
[Test]
775+
[Category("Actions Priority")]
776+
[TestCaseSource(nameof(k_TwoInputActionTestCases))]
777+
public void Actions_Complexity_CompositeWinsOverlappingSimple_EvenWhenCompositeHasHigherPriorityField(
778+
(string[] a1, string[] a2) actions)
779+
{
780+
EnableComplexityShortcutResolution();
781+
782+
var keyboard = InputSystem.AddDevice<Keyboard>();
783+
var map = new InputActionMap("map");
784+
785+
var actionComposite = map.SetupTestAction(actions.a1);
786+
var actionSimple = map.SetupTestAction(actions.a2);
787+
788+
actionComposite.Priority = 100;
789+
actionSimple.Priority = 1;
790+
791+
map.Enable();
792+
793+
PressBindingsForInputActions(keyboard, actionComposite, actionSimple);
794+
795+
Assert.That(actionComposite.WasPerformedThisFrame(), Is.True);
796+
Assert.That(actionSimple.WasPerformedThisFrame(), Is.False);
797+
798+
ReleaseBindingsForActions(keyboard, actionComposite, actionSimple);
799+
}
800+
801+
[Test]
802+
[Category("Actions Priority")]
803+
public void Actions_Complexity_BothSimpleActionsOnSameControlPerform_WhenEqualComplexity()
804+
{
805+
EnableComplexityShortcutResolution();
806+
807+
var keyboard = InputSystem.AddDevice<Keyboard>();
808+
var map = new InputActionMap("map");
809+
var action1 = map.AddAction("a", binding: "<Keyboard>/y");
810+
var action2 = map.AddAction("b", binding: "<Keyboard>/y");
811+
action1.Priority = 2;
812+
action2.Priority = 99;
813+
map.Enable();
814+
815+
Press((ButtonControl)action1.controls[0], queueEventOnly: true);
816+
Press((ButtonControl)action2.controls[0], queueEventOnly: true);
817+
InputSystem.Update();
818+
819+
Assert.That(action1.WasPerformedThisFrame(), Is.True);
820+
Assert.That(action2.WasPerformedThisFrame(), Is.True);
821+
822+
Release((ButtonControl)action1.controls[0], queueEventOnly: true);
823+
Release((ButtonControl)action2.controls[0], queueEventOnly: true);
824+
InputSystem.Update();
825+
}
586826
}

0 commit comments

Comments
 (0)