@@ -1072,6 +1072,8 @@ public class ReplayController : IDisposable
10721072 private double m_StartTimeAsPerRuntime ;
10731073 private int m_AllEventsByTimeIndex = 0 ;
10741074 private List < InputEventPtr > m_AllEventsByTime ;
1075+ private bool m_ReplayBypassActive ;
1076+ private Action m_ClearReplayBypassCallback ;
10751077
10761078 internal ReplayController ( InputEventTrace trace)
10771079 {
@@ -1088,12 +1090,52 @@ public void Dispose()
10881090 {
10891091 InputSystem . onBeforeUpdate -= OnBeginFrame ;
10901092 finished = true ;
1093+ EndReplayBypass ( ) ;
10911094
10921095 foreach ( var device in m_CreatedDevices )
10931096 InputSystem . RemoveDevice ( device ) ;
10941097 m_CreatedDevices = default ;
10951098 }
10961099
1100+ // Signals InputManager to treat events as if game view has focus, bypassing
1101+ // editor focus routing that would otherwise defer pointer/keyboard events to
1102+ // editor updates where they reach the editor UI instead of the game.
1103+ private void BeginReplayBypass ( )
1104+ {
1105+ if ( ! m_ReplayBypassActive )
1106+ {
1107+ m_ReplayBypassActive = true ;
1108+ ++ InputSystem . s_Manager . m_ActiveReplayCount ;
1109+ }
1110+ }
1111+
1112+ // Schedules the bypass to be cleared after the current OnUpdate finishes processing
1113+ // events (via onAfterUpdate). This ensures events already queued in the native buffer
1114+ // are still processed with the bypass active before it is removed.
1115+ private void ScheduleEndReplayBypass ( )
1116+ {
1117+ if ( ! m_ReplayBypassActive )
1118+ return ;
1119+
1120+ if ( m_ClearReplayBypassCallback == null )
1121+ m_ClearReplayBypassCallback = EndReplayBypass ;
1122+ InputSystem . onAfterUpdate += m_ClearReplayBypassCallback ;
1123+ }
1124+
1125+ private void EndReplayBypass ( )
1126+ {
1127+ if ( m_ClearReplayBypassCallback != null )
1128+ {
1129+ InputSystem . onAfterUpdate -= m_ClearReplayBypassCallback ;
1130+ m_ClearReplayBypassCallback = null ;
1131+ }
1132+ if ( m_ReplayBypassActive )
1133+ {
1134+ m_ReplayBypassActive = false ;
1135+ -- InputSystem . s_Manager . m_ActiveReplayCount ;
1136+ }
1137+ }
1138+
10971139 /// <summary>
10981140 /// Replay events recorded from <paramref name="recordedDevice"/> on device <paramref name="playbackDevice"/>.
10991141 /// </summary>
@@ -1249,6 +1291,7 @@ public ReplayController Rewind()
12491291 public ReplayController PlayAllFramesOneByOne ( )
12501292 {
12511293 finished = false ;
1294+ BeginReplayBypass ( ) ;
12521295 InputSystem . onBeforeUpdate += OnBeginFrame ;
12531296 return this ;
12541297 }
@@ -1267,6 +1310,7 @@ public ReplayController PlayAllFramesOneByOne()
12671310 public ReplayController PlayAllEvents ( )
12681311 {
12691312 finished = false ;
1313+ BeginReplayBypass ( ) ;
12701314 try
12711315 {
12721316 while ( MoveNext ( true , out var eventPtr ) )
@@ -1311,6 +1355,7 @@ public ReplayController PlayAllEventsAccordingToTimestamps()
13111355
13121356 // Start playback.
13131357 finished = false ;
1358+ BeginReplayBypass ( ) ;
13141359 m_StartTimeAsPerFirstEvent = - 1 ;
13151360 m_AllEventsByTimeIndex = - 1 ;
13161361 InputSystem . onBeforeUpdate += OnBeginFrame ;
@@ -1381,6 +1426,9 @@ private void Finished()
13811426 {
13821427 finished = true ;
13831428 InputSystem . onBeforeUpdate -= OnBeginFrame ;
1429+ // Schedule bypass removal for after the next OnUpdate, so any events already
1430+ // queued into the native buffer this frame are still processed with the bypass active.
1431+ ScheduleEndReplayBypass ( ) ;
13841432 m_OnFinished ? . Invoke ( ) ;
13851433 }
13861434
0 commit comments