Skip to content

Commit 86b8cee

Browse files
author
Rene Damm
authored
FIX: Not being able to add timeouts while processing a timeout (#714, #816).
1 parent 31935f4 commit 86b8cee

File tree

4 files changed

+73
-6
lines changed

4 files changed

+73
-6
lines changed

Assets/Tests/InputSystem/CoreTests_State.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,38 @@ public void State_StateChangeMonitorTimeout_CanBeAddedFromMonitorCallback()
863863
Assert.That(timeoutFired);
864864
}
865865

866+
[Test]
867+
[Category("State")]
868+
public void State_StateChangeMonitorTimeout_CanBeAddedFromTimeoutCallback()
869+
{
870+
var gamepad = InputSystem.AddDevice<Gamepad>();
871+
872+
var timeoutCount = 0;
873+
874+
IInputStateChangeMonitor monitor = null;
875+
monitor = InputState.AddChangeMonitor(gamepad.buttonSouth,
876+
(control, time, eventPtr, monitorIndex) => {},
877+
timerExpiredCallback: (control, time, monitorIndex, timerIndex) =>
878+
{
879+
++timeoutCount;
880+
InputState.AddChangeMonitorTimeout(control, monitor, time + 1.5);
881+
});
882+
883+
InputState.AddChangeMonitorTimeout(gamepad.buttonSouth, monitor, 1.5);
884+
885+
// Trigger first timeout.
886+
runtime.currentTime += 2;
887+
InputSystem.Update();
888+
889+
Assert.That(timeoutCount, Is.EqualTo(1));
890+
891+
// Trigger second timeout.
892+
runtime.currentTime += 2;
893+
InputSystem.Update();
894+
895+
Assert.That(timeoutCount, Is.EqualTo(2));
896+
}
897+
866898
[Test]
867899
[Category("State")]
868900
public void State_StateChangeMonitor_CanBeAddedFromMonitorCallback()
@@ -914,6 +946,25 @@ public void State_StateChangeMonitor_CanBeRemovedFromMonitorCallback()
914946
LogAssert.NoUnexpectedReceived();
915947
}
916948

949+
[Test]
950+
[Category("State")]
951+
public void State_RemovingMonitorRemovesTimeouts()
952+
{
953+
var gamepad = InputSystem.AddDevice<Gamepad>();
954+
955+
var monitor = InputState.AddChangeMonitor(gamepad.buttonWest,
956+
(c, d, e, m) => {},
957+
timerExpiredCallback: (control, time, monitorIndex, timerIndex) =>
958+
{
959+
Assert.Fail("Should not reach here");
960+
});
961+
InputState.AddChangeMonitorTimeout(gamepad.buttonWest, monitor, 2);
962+
InputState.RemoveChangeMonitor(gamepad.buttonWest, monitor);
963+
964+
runtime.currentTime = 4;
965+
InputSystem.Update();
966+
}
967+
917968
[Test]
918969
[Category("State")]
919970
public void State_CanThrowExceptionFromStateChangeMonitorCallback()

Packages/com.unity.inputsystem/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ however, it has to be formatted properly to pass verification tests.
1010
## [0.9.6-preview] - 2099-1-1
1111

1212
### Fixed
13+
1314
#### Actions
15+
16+
- Setting timeouts from `IInputInteraction.Process` not working as expected when processing happened in response to previous timeout expiring (#714).
17+
- Pending timeouts on a device not being removed when device was removed.
18+
1419
### Changed
1520
### Added
1621

Packages/com.unity.inputsystem/InputSystem/InputManager.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,11 @@ private void RemoveStateChangeMonitors(InputDevice device)
13261326
return;
13271327

13281328
m_StateChangeMonitors[deviceIndex].Clear();
1329+
1330+
// Clear timeouts pending on any control on the device.
1331+
for (var i = 0; i < m_StateChangeMonitorTimeouts.length; ++i)
1332+
if (m_StateChangeMonitorTimeouts[i].control?.device == device)
1333+
m_StateChangeMonitorTimeouts[i] = default;
13291334
}
13301335

13311336
public void RemoveStateChangeMonitor(InputControl control, IInputStateChangeMonitor monitor, long monitorIndex)
@@ -1345,6 +1350,12 @@ public void RemoveStateChangeMonitor(InputControl control, IInputStateChangeMoni
13451350
return;
13461351

13471352
m_StateChangeMonitors[deviceIndex].Remove(monitor, monitorIndex);
1353+
1354+
// Remove pending timeouts on the monitor.
1355+
for (var i = 0; i < m_StateChangeMonitorTimeouts.length; ++i)
1356+
if (m_StateChangeMonitorTimeouts[i].monitor == monitor &&
1357+
m_StateChangeMonitorTimeouts[i].monitorIndex == monitorIndex)
1358+
m_StateChangeMonitorTimeouts[i] = default;
13481359
}
13491360

13501361
public void AddStateChangeMonitorTimeout(InputControl control, IInputStateChangeMonitor monitor, double time, long monitorIndex, int timerIndex)
@@ -1370,8 +1381,7 @@ public void RemoveStateChangeMonitorTimeout(IInputStateChangeMonitor monitor, lo
13701381
&& m_StateChangeMonitorTimeouts[i].monitorIndex == monitorIndex
13711382
&& m_StateChangeMonitorTimeouts[i].timerIndex == timerIndex)
13721383
{
1373-
////TODO: leave state empty and compact array lazily on traversal
1374-
m_StateChangeMonitorTimeouts.RemoveAt(i);
1384+
m_StateChangeMonitorTimeouts[i] = default;
13751385
break;
13761386
}
13771387
}
@@ -2684,16 +2694,15 @@ private unsafe void FireStateChangeNotifications(int deviceIndex, double interna
26842694

26852695
private void ProcessStateChangeMonitorTimeouts()
26862696
{
2687-
var timeoutCount = m_StateChangeMonitorTimeouts.length;
2688-
if (timeoutCount == 0)
2697+
if (m_StateChangeMonitorTimeouts.length == 0)
26892698
return;
26902699

26912700
// Go through the list and both trigger expired timers and remove any irrelevant
26922701
// ones by compacting the array.
26932702
// NOTE: We do not actually release any memory we may have allocated.
26942703
var currentTime = m_Runtime.currentTime - InputRuntime.s_CurrentTimeOffsetToRealtimeSinceStartup;
26952704
var remainingTimeoutCount = 0;
2696-
for (var i = 0; i < timeoutCount; ++i)
2705+
for (var i = 0; i < m_StateChangeMonitorTimeouts.length; ++i)
26972706
{
26982707
// If we have reset this entry in RemoveStateChangeMonitorTimeouts(),
26992708
// skip over it and let compaction get rid of it.

Packages/com.unity.inputsystem/InputSystem/State/InputState.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,9 @@ public static void AddChangeMonitor(InputControl control, IInputStateChangeMonit
140140
InputSystem.s_Manager.AddStateChangeMonitor(control, monitor, monitorIndex);
141141
}
142142

143-
public static IInputStateChangeMonitor AddChangeMonitor(InputControl control, NotifyControlValueChangeAction valueChangeCallback, int monitorIndex = -1, NotifyTimerExpiredAction timerExpiredCallback = null)
143+
public static IInputStateChangeMonitor AddChangeMonitor(InputControl control,
144+
NotifyControlValueChangeAction valueChangeCallback, int monitorIndex = -1,
145+
NotifyTimerExpiredAction timerExpiredCallback = null)
144146
{
145147
if (valueChangeCallback == null)
146148
throw new ArgumentNullException(nameof(valueChangeCallback));

0 commit comments

Comments
 (0)