Skip to content

Commit e0bdcc7

Browse files
authored
Merge branch 'develop' into isxb-1070-onscreenstick-memory-leak-fix
2 parents 2ece5b2 + 7a28d7b commit e0bdcc7

File tree

4 files changed

+143
-22
lines changed

4 files changed

+143
-22
lines changed

Assets/Tests/InputSystem/CoreTests_Actions.cs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10041,6 +10041,112 @@ public void Actions_CanCreateCompositesWithMultipleBindings()
1004110041
Assert.That(value, Is.EqualTo(new Vector2(-1, -1).normalized).Using(Vector2EqualityComparer.Instance));
1004210042
}
1004310043

10044+
// Ensure that https://jira.unity3d.com/browse/ISXB-619 regress
10045+
[Test]
10046+
[Category("Actions")]
10047+
public void Actions_WithCompositeWithMultipleInteractions_Works()
10048+
{
10049+
// Will ensure that :
10050+
// PressRelease AW trigger a tap
10051+
// Long PressRelease AW trigger a hold
10052+
// PressRelease AW trigger a tap
10053+
10054+
var keyboard = InputSystem.AddDevice<Keyboard>();
10055+
var action = new InputAction();
10056+
action.AddCompositeBinding("Dpad", interactions: "tap,hold(duration=2)")
10057+
.With("Up", "<Keyboard>/w")
10058+
.With("Down", "<Keyboard>/s")
10059+
.With("Left", "<Keyboard>/a")
10060+
.With("Right", "<Keyboard>/d");
10061+
action.Enable();
10062+
10063+
IInputInteraction performedInteraction = null;
10064+
IInputInteraction canceledInteraction = null;
10065+
action.performed += ctx =>
10066+
{
10067+
performedInteraction = ctx.interaction;
10068+
};
10069+
action.canceled += ctx =>
10070+
{
10071+
canceledInteraction = ctx.interaction;
10072+
};
10073+
10074+
// PressRelease AW trigger a tap
10075+
currentTime = 0;
10076+
InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.A, Key.W));
10077+
InputSystem.Update();
10078+
10079+
// nothing triggered
10080+
Assert.That(canceledInteraction, Is.Null);
10081+
Assert.That(performedInteraction, Is.Null);
10082+
10083+
currentTime += InputSystem.settings.defaultTapTime / 2.0f; // half of the tap time to ensure that it performs.
10084+
InputSystem.QueueStateEvent(keyboard, new KeyboardState());
10085+
InputSystem.Update();
10086+
10087+
// tap should be triggered
10088+
Assert.That(canceledInteraction, Is.Null);
10089+
Assert.That(performedInteraction, Is.TypeOf(typeof(TapInteraction)));
10090+
performedInteraction = null;
10091+
10092+
// Long PressRelease AW trigger a hold
10093+
currentTime += 1;
10094+
InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.A, Key.W));
10095+
InputSystem.Update();
10096+
10097+
// tap should be canceled
10098+
currentTime += InputSystem.settings.defaultTapTime * 4.0;
10099+
InputSystem.Update();
10100+
10101+
Assert.That(canceledInteraction, Is.TypeOf(typeof(TapInteraction)));
10102+
Assert.That(performedInteraction, Is.Null);
10103+
canceledInteraction = null;
10104+
10105+
// After (defaultTapTime*4 + 2) seconds hold should be performed with duration=2
10106+
currentTime += 2;
10107+
InputSystem.Update();
10108+
Assert.That(canceledInteraction, Is.Null);
10109+
Assert.That(performedInteraction, Is.TypeOf(typeof(HoldInteraction)));
10110+
performedInteraction = null;
10111+
10112+
// hold should be canceled
10113+
currentTime += 1;
10114+
InputSystem.QueueStateEvent(keyboard, new KeyboardState());
10115+
InputSystem.Update();
10116+
Assert.That(canceledInteraction, Is.TypeOf(typeof(HoldInteraction)));
10117+
Assert.That(performedInteraction, Is.Null);
10118+
canceledInteraction = null;
10119+
10120+
// Should be no other remaining events
10121+
currentTime += 5;
10122+
InputSystem.Update();
10123+
Assert.That(canceledInteraction, Is.Null);
10124+
Assert.That(performedInteraction, Is.Null);
10125+
10126+
// PressRelease AW trigger a tap to ensure that is still working
10127+
currentTime += 1;
10128+
InputSystem.QueueStateEvent(keyboard, new KeyboardState(Key.A, Key.W));
10129+
InputSystem.Update();
10130+
10131+
Assert.That(canceledInteraction, Is.Null);
10132+
Assert.That(performedInteraction, Is.Null);
10133+
10134+
currentTime += InputSystem.settings.defaultTapTime / 2.0f;
10135+
InputSystem.QueueStateEvent(keyboard, new KeyboardState());
10136+
InputSystem.Update();
10137+
10138+
Assert.That(canceledInteraction, Is.Null);
10139+
Assert.That(performedInteraction, Is.TypeOf(typeof(TapInteraction)));
10140+
performedInteraction = null;
10141+
canceledInteraction = null;
10142+
10143+
// Should be no other remaining events
10144+
currentTime += 100;
10145+
InputSystem.Update();
10146+
Assert.That(canceledInteraction, Is.Null);
10147+
Assert.That(performedInteraction, Is.Null);
10148+
}
10149+
1004410150
[Test]
1004510151
[Category("Actions")]
1004610152
public void Actions_WithMultipleComposites_CancelsIfCompositeIsReleased()

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ however, it has to be formatted properly to pass verification tests.
1111
## [Unreleased] - yyyy-mm-dd
1212

1313
### Fixed
14+
- Fixed Multiple interactions could breaks on Composite Binding. [ISXB-619](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-619)
1415
- Fixed memory leak when the OnScreenStick component was destroyed [ISXB-1070](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1070). Contribution by [LukeUnityDev](https://github.com/LukeUnityDev).
1516

1617
### Changed

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,7 +2215,7 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta
22152215

22162216
// See if it affects the phase of an associated action.
22172217
var actionIndex = bindingStates[bindingIndex].actionIndex; // We already had to tap this array and entry in ProcessControlStateChange.
2218-
if (actionIndex != -1)
2218+
if (actionIndex != kInvalidIndex)
22192219
{
22202220
if (actionStates[actionIndex].phase == InputActionPhase.Waiting)
22212221
{
@@ -2313,12 +2313,14 @@ internal void ChangePhaseOfInteraction(InputActionPhase newPhase, ref TriggerSta
23132313
// Exception: if it was performed and we're to remain in started state, set the interaction
23142314
// to started. Note that for that phase transition, there are no callbacks being
23152315
// triggered (i.e. we don't call 'started' every time after 'performed').
2316-
if (newPhase == InputActionPhase.Performed && actionStates[actionIndex].interactionIndex != trigger.interactionIndex)
2317-
{
2318-
// We performed but we're not the interaction driving the action. We want to stay performed to make
2319-
// sure that if the interaction that is currently driving the action cancels, we get to perform
2320-
// the action. If we go back to waiting here, then the system can't tell that there's another interaction
2321-
// ready to perform (in fact, that has already performed).
2316+
if (newPhase == InputActionPhase.Performed &&
2317+
actionIndex != kInvalidIndex && !actionStates[actionIndex].isPerformed &&
2318+
actionStates[actionIndex].interactionIndex != trigger.interactionIndex)
2319+
{
2320+
// If the action was not already performed and we performed but we're not the interaction driving the action.
2321+
// We want to stay performed to make sure that if the interaction that is currently driving the action
2322+
// cancels, we get to perform the action. If we go back to waiting here, then the system can't tell
2323+
// that there's another interaction ready to perform (in fact, that has already performed).
23222324
}
23232325
else if (newPhase == InputActionPhase.Performed && phaseAfterPerformed != InputActionPhase.Waiting)
23242326
{

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

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -320,25 +320,37 @@ public unsafe void AddActionMap(InputActionMap actionMap)
320320
}
321321

322322
// Instantiate interactions.
323-
var interactionString = unresolvedBinding.effectiveInteractions;
324-
if (!string.IsNullOrEmpty(interactionString))
323+
if (isPartOfComposite)
325324
{
326-
// Add interactions from binding.
327-
firstInteractionIndex = InstantiateWithParameters(InputInteraction.s_Interactions, interactionString,
328-
ref interactions, ref totalInteractionCount, actionMap, ref unresolvedBinding);
329-
if (firstInteractionIndex != InputActionState.kInvalidIndex)
330-
numInteractions = totalInteractionCount - firstInteractionIndex;
325+
// Composite's part use composite interactions
326+
if (currentCompositeBindingIndex != InputActionState.kInvalidIndex)
327+
{
328+
firstInteractionIndex = bindingStatesPtr[currentCompositeBindingIndex].interactionStartIndex;
329+
numInteractions = bindingStatesPtr[currentCompositeBindingIndex].interactionCount;
330+
}
331331
}
332-
if (!string.IsNullOrEmpty(action.m_Interactions))
332+
else
333333
{
334-
// Add interactions from action.
335-
var index = InstantiateWithParameters(InputInteraction.s_Interactions, action.m_Interactions,
336-
ref interactions, ref totalInteractionCount, actionMap, ref unresolvedBinding);
337-
if (index != InputActionState.kInvalidIndex)
334+
var interactionString = unresolvedBinding.effectiveInteractions;
335+
if (!string.IsNullOrEmpty(interactionString))
336+
{
337+
// Add interactions from binding.
338+
firstInteractionIndex = InstantiateWithParameters(InputInteraction.s_Interactions, interactionString,
339+
ref interactions, ref totalInteractionCount, actionMap, ref unresolvedBinding);
340+
if (firstInteractionIndex != InputActionState.kInvalidIndex)
341+
numInteractions = totalInteractionCount - firstInteractionIndex;
342+
}
343+
if (!string.IsNullOrEmpty(action.m_Interactions))
338344
{
339-
if (firstInteractionIndex == InputActionState.kInvalidIndex)
340-
firstInteractionIndex = index;
341-
numInteractions += totalInteractionCount - index;
345+
// Add interactions from action.
346+
var index = InstantiateWithParameters(InputInteraction.s_Interactions, action.m_Interactions,
347+
ref interactions, ref totalInteractionCount, actionMap, ref unresolvedBinding);
348+
if (index != InputActionState.kInvalidIndex)
349+
{
350+
if (firstInteractionIndex == InputActionState.kInvalidIndex)
351+
firstInteractionIndex = index;
352+
numInteractions += totalInteractionCount - index;
353+
}
342354
}
343355
}
344356

0 commit comments

Comments
 (0)