-
Notifications
You must be signed in to change notification settings - Fork 328
FIX: Fixed multiple interactions on composite bindings (ISXB-619) #2000
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
Changes from 3 commits
7a8dcc2
68dd844
d593f90
2160812
b532149
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10041,6 +10041,112 @@ public void Actions_CanCreateCompositesWithMultipleBindings() | |
Assert.That(value, Is.EqualTo(new Vector2(-1, -1).normalized).Using(Vector2EqualityComparer.Instance)); | ||
} | ||
|
||
// Ensure that https://jira.unity3d.com/browse/ISXB-619 regress | ||
[Test] | ||
[Category("Actions")] | ||
public void Actions_WithCompositeWithMultipleInteractions_Works() | ||
{ | ||
// Will ensure that : | ||
// PressRelease AW trigger a tap | ||
// Long PressRelease AW trigger a hold | ||
// PressRelease AW trigger a tap | ||
|
||
var keyboard = InputSystem.AddDevice<Keyboard>(); | ||
var action = new InputAction(); | ||
action.AddCompositeBinding("Dpad", interactions: "tap,hold(duration=2)") | ||
.With("Up", "<Keyboard>/w") | ||
.With("Down", "<Keyboard>/s") | ||
.With("Left", "<Keyboard>/a") | ||
.With("Right", "<Keyboard>/d"); | ||
action.Enable(); | ||
|
||
IInputInteraction performedInteraction = null; | ||
IInputInteraction canceledInteraction = null; | ||
action.performed += ctx => | ||
{ | ||
performedInteraction = ctx.interaction; | ||
}; | ||
action.canceled += ctx => | ||
{ | ||
canceledInteraction = ctx.interaction; | ||
}; | ||
|
||
// PressRelease AW trigger a tap | ||
currentTime = 0; | ||
InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.A, Key.W)); | ||
InputSystem.Update(); | ||
|
||
// nothing triggered | ||
Assert.That(canceledInteraction, Is.Null); | ||
Assert.That(performedInteraction, Is.Null); | ||
|
||
currentTime = 0.01; | ||
|
||
InputSystem.QueueStateEvent(keyboard, new KeyboardState()); | ||
InputSystem.Update(); | ||
|
||
// tap should be triggered | ||
Assert.That(canceledInteraction, Is.Null); | ||
Assert.That(performedInteraction, Is.TypeOf(typeof(TapInteraction))); | ||
performedInteraction = null; | ||
|
||
// Long PressRelease AW trigger a hold | ||
currentTime = 1; | ||
|
||
InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.A, Key.W)); | ||
InputSystem.Update(); | ||
|
||
// tap should be canceled | ||
currentTime = 2; | ||
InputSystem.Update(); | ||
|
||
Assert.That(canceledInteraction, Is.TypeOf(typeof(TapInteraction))); | ||
Assert.That(performedInteraction, Is.Null); | ||
canceledInteraction = null; | ||
|
||
// hold should be trigered | ||
currentTime = 4; | ||
InputSystem.Update(); | ||
Assert.That(canceledInteraction, Is.Null); | ||
Assert.That(performedInteraction, Is.TypeOf(typeof(HoldInteraction))); | ||
performedInteraction = null; | ||
|
||
// hold should be canceled | ||
currentTime = 5; | ||
InputSystem.QueueStateEvent(keyboard, new KeyboardState()); | ||
InputSystem.Update(); | ||
Assert.That(canceledInteraction, Is.TypeOf(typeof(HoldInteraction))); | ||
Assert.That(performedInteraction, Is.Null); | ||
canceledInteraction = null; | ||
|
||
// Should be no other remaining events | ||
currentTime = 10; | ||
InputSystem.Update(); | ||
Assert.That(canceledInteraction, Is.Null); | ||
Assert.That(performedInteraction, Is.Null); | ||
|
||
// PressRelease AW trigger a tap to ensure that is still working | ||
currentTime = 11; | ||
InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.A, Key.W)); | ||
InputSystem.Update(); | ||
|
||
Assert.That(canceledInteraction, Is.Null); | ||
Assert.That(performedInteraction, Is.Null); | ||
|
||
currentTime = 11.01; | ||
InputSystem.QueueStateEvent(keyboard, new KeyboardState()); | ||
InputSystem.Update(); | ||
|
||
Assert.That(canceledInteraction, Is.Null); | ||
Assert.That(performedInteraction, Is.TypeOf(typeof(TapInteraction))); | ||
performedInteraction = null; | ||
canceledInteraction = null; | ||
|
||
// Should be no other remaining events | ||
currentTime = 100; | ||
InputSystem.Update(); | ||
Assert.That(canceledInteraction, Is.Null); | ||
Assert.That(performedInteraction, Is.Null); | ||
} | ||
|
||
[Test] | ||
[Category("Actions")] | ||
public void Actions_WithMultipleComposites_CancelsIfCompositeIsReleased() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2313,12 +2313,14 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta | |
// Exception: if it was performed and we're to remain in started state, set the interaction | ||
// to started. Note that for that phase transition, there are no callbacks being | ||
// triggered (i.e. we don't call 'started' every time after 'performed'). | ||
if (newPhase == InputActionPhase.Performed && actionStates[actionIndex].interactionIndex != trigger.interactionIndex) | ||
{ | ||
// We performed but we're not the interaction driving the action. We want to stay performed to make | ||
// sure that if the interaction that is currently driving the action cancels, we get to perform | ||
// the action. If we go back to waiting here, then the system can't tell that there's another interaction | ||
// ready to perform (in fact, that has already performed). | ||
if (newPhase == InputActionPhase.Performed && | ||
actionIndex != -1 && !actionStates[actionIndex].isPerformed && | ||
|
||
actionStates[actionIndex].interactionIndex != trigger.interactionIndex) | ||
{ | ||
// If the action was not already performed and we performed but we're not the interaction driving the action. | ||
// We want to stay performed to make sure that if the interaction that is currently driving the action | ||
// cancels, we get to perform the action. If we go back to waiting here, then the system can't tell | ||
// that there's another interaction ready to perform (in fact, that has already performed). | ||
} | ||
else if (newPhase == InputActionPhase.Performed && phaseAfterPerformed != InputActionPhase.Waiting) | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for writing a test with this quite elaborate sequence which I believe is key to avoid regressive behaviour when there are actually interdependencies between the interaction patterns