Kaynağa Gözat

Change TryWriteAnsiRequest method to virtual which use common code for all drivers.

BDisp 8 ay önce
ebeveyn
işleme
36876b9899

+ 1 - 2
Terminal.Gui/Application/Application.Run.cs

@@ -1,7 +1,6 @@
 #nullable enable
 #nullable enable
 using System.Diagnostics;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Diagnostics.CodeAnalysis;
-using Microsoft.CodeAnalysis.Diagnostics;
 
 
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
@@ -522,7 +521,7 @@ public static partial class Application // Run (Begin, Run, End, Stop)
 
 
     /// <summary>The <see cref="MainLoop"/> driver for the application</summary>
     /// <summary>The <see cref="MainLoop"/> driver for the application</summary>
     /// <value>The main loop.</value>
     /// <value>The main loop.</value>
-    internal static MainLoop? MainLoop { get; private set; }
+    public static MainLoop? MainLoop { get; private set; }
 
 
     /// <summary>
     /// <summary>
     ///     Set to true to cause <see cref="End"/> to be called after the first iteration. Set to false (the default) to
     ///     Set to true to cause <see cref="End"/> to be called after the first iteration. Set to false (the default) to

+ 7 - 3
Terminal.Gui/Application/MainLoop.cs

@@ -10,7 +10,7 @@ using System.Collections.ObjectModel;
 namespace Terminal.Gui;
 namespace Terminal.Gui;
 
 
 /// <summary>Interface to create a platform specific <see cref="MainLoop"/> driver.</summary>
 /// <summary>Interface to create a platform specific <see cref="MainLoop"/> driver.</summary>
-internal interface IMainLoopDriver
+public interface IMainLoopDriver
 {
 {
     /// <summary>Must report whether there are any events pending, or even block waiting for events.</summary>
     /// <summary>Must report whether there are any events pending, or even block waiting for events.</summary>
     /// <returns><c>true</c>, if there were pending events, <c>false</c> otherwise.</returns>
     /// <returns><c>true</c>, if there were pending events, <c>false</c> otherwise.</returns>
@@ -29,6 +29,10 @@ internal interface IMainLoopDriver
 
 
     /// <summary>Wakes up the <see cref="MainLoop"/> that might be waiting on input, must be thread safe.</summary>
     /// <summary>Wakes up the <see cref="MainLoop"/> that might be waiting on input, must be thread safe.</summary>
     void Wakeup ();
     void Wakeup ();
+
+    bool _forceRead { get; set; }
+
+    ManualResetEventSlim _waitForInput { get; set; }
 }
 }
 
 
 /// <summary>The MainLoop monitors timers and idle handlers.</summary>
 /// <summary>The MainLoop monitors timers and idle handlers.</summary>
@@ -36,7 +40,7 @@ internal interface IMainLoopDriver
 ///     Monitoring of file descriptors is only available on Unix, there does not seem to be a way of supporting this
 ///     Monitoring of file descriptors is only available on Unix, there does not seem to be a way of supporting this
 ///     on Windows.
 ///     on Windows.
 /// </remarks>
 /// </remarks>
-internal class MainLoop : IDisposable
+public class MainLoop : IDisposable
 {
 {
     internal List<Func<bool>> _idleHandlers = new ();
     internal List<Func<bool>> _idleHandlers = new ();
     internal SortedList<long, Timeout> _timeouts = new ();
     internal SortedList<long, Timeout> _timeouts = new ();
@@ -72,7 +76,7 @@ internal class MainLoop : IDisposable
 
 
     /// <summary>The current <see cref="IMainLoopDriver"/> in use.</summary>
     /// <summary>The current <see cref="IMainLoopDriver"/> in use.</summary>
     /// <value>The main loop driver.</value>
     /// <value>The main loop driver.</value>
-    internal IMainLoopDriver MainLoopDriver { get; private set; }
+    public IMainLoopDriver MainLoopDriver { get; private set; }
 
 
     /// <summary>Used for unit tests.</summary>
     /// <summary>Used for unit tests.</summary>
     internal bool Running { get; set; }
     internal bool Running { get; set; }

+ 68 - 1
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -32,6 +32,9 @@ public abstract class ConsoleDriver
 
 
     #region ANSI Esc Sequence Handling
     #region ANSI Esc Sequence Handling
 
 
+    private readonly ManualResetEventSlim _waitAnsiResponse = new (false);
+    private CancellationTokenSource? _ansiResponseTokenSource;
+
     // QUESTION: Should this be virtual with a default implementation that does the common stuff?
     // QUESTION: Should this be virtual with a default implementation that does the common stuff?
     // QUESTION: Looking at the implementations of this method, there is TONs of duplicated code.
     // QUESTION: Looking at the implementations of this method, there is TONs of duplicated code.
     // QUESTION: We should figure out how to find just the things that are unique to each driver and
     // QUESTION: We should figure out how to find just the things that are unique to each driver and
@@ -39,9 +42,73 @@ public abstract class ConsoleDriver
     /// <summary>
     /// <summary>
     ///     Provide handling for the terminal write ANSI escape sequence request.
     ///     Provide handling for the terminal write ANSI escape sequence request.
     /// </summary>
     /// </summary>
+    /// <param name="mainLoopDriver">The <see cref="IMainLoopDriver"/> object.</param>
     /// <param name="ansiRequest">The <see cref="AnsiEscapeSequenceRequest"/> object.</param>
     /// <param name="ansiRequest">The <see cref="AnsiEscapeSequenceRequest"/> object.</param>
     /// <returns>The request response.</returns>
     /// <returns>The request response.</returns>
-    public abstract bool TryWriteAnsiRequest (AnsiEscapeSequenceRequest ansiRequest);
+    public virtual bool TryWriteAnsiRequest (IMainLoopDriver mainLoopDriver, ref AnsiEscapeSequenceRequest ansiRequest)
+    {
+        if (mainLoopDriver is null)
+        {
+            return false;
+        }
+
+        _ansiResponseTokenSource ??= new ();
+
+        try
+        {
+            lock (ansiRequest._responseLock)
+            {
+                AnsiEscapeSequenceRequest? request = ansiRequest;
+
+                ansiRequest.ResponseFromInput += (s, e) =>
+                                                 {
+                                                     Debug.Assert (s == request);
+                                                     Debug.Assert (e == request.AnsiEscapeSequenceResponse);
+
+                                                     _waitAnsiResponse.Set ();
+                                                 };
+
+                AnsiEscapeSequenceRequests.Add (ansiRequest);
+
+                WriteRaw (ansiRequest.Request);
+
+                mainLoopDriver._forceRead = true;
+            }
+
+            if (!_ansiResponseTokenSource.IsCancellationRequested)
+            {
+                mainLoopDriver._waitForInput.Set ();
+
+                _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
+            }
+        }
+        catch (OperationCanceledException)
+        {
+            return false;
+        }
+
+        lock (ansiRequest._responseLock)
+        {
+            mainLoopDriver._forceRead = false;
+
+            if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
+            {
+                if (AnsiEscapeSequenceRequests.Statuses.Count > 0
+                    && string.IsNullOrEmpty (request.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
+                {
+                    lock (request.AnsiRequest._responseLock)
+                    {
+                        // Bad request or no response at all
+                        AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
+                    }
+                }
+            }
+
+            _waitAnsiResponse.Reset ();
+
+            return ansiRequest.AnsiEscapeSequenceResponse is { Valid: true };
+        }
+    }
 
 
     // QUESTION: This appears to be an API to help in debugging. It's only implemented in CursesDriver and WindowsDriver.
     // QUESTION: This appears to be an API to help in debugging. It's only implemented in CursesDriver and WindowsDriver.
     // QUESTION: Can it be factored such that it does not contaminate the ConsoleDriver API?
     // QUESTION: Can it be factored such that it does not contaminate the ConsoleDriver API?

+ 0 - 70
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -727,9 +727,6 @@ internal class CursesDriver : ConsoleDriver
 
 
     internal override void End ()
     internal override void End ()
     {
     {
-        _ansiResponseTokenSource?.Cancel ();
-        _ansiResponseTokenSource?.Dispose ();
-        _waitAnsiResponse.Dispose ();
 
 
         StopReportingMouseMoves ();
         StopReportingMouseMoves ();
         SetCursorVisibility (CursorVisibility.Default);
         SetCursorVisibility (CursorVisibility.Default);
@@ -765,73 +762,6 @@ internal class CursesDriver : ConsoleDriver
         return false;
         return false;
     }
     }
 
 
-    private readonly ManualResetEventSlim _waitAnsiResponse = new (false);
-    private CancellationTokenSource? _ansiResponseTokenSource;
-
-    /// <inheritdoc/>
-    public override bool TryWriteAnsiRequest (AnsiEscapeSequenceRequest ansiRequest)
-    {
-        if (_mainLoopDriver is null)
-        {
-            return false;
-        }
-
-        _ansiResponseTokenSource ??= new ();
-
-        try
-        {
-            lock (ansiRequest._responseLock)
-            {
-                ansiRequest.ResponseFromInput += (s, e) =>
-                                                 {
-                                                     Debug.Assert (s == ansiRequest);
-                                                     Debug.Assert (e == ansiRequest.AnsiEscapeSequenceResponse);
-
-                                                     _waitAnsiResponse.Set ();
-                                                 };
-
-                AnsiEscapeSequenceRequests.Add (ansiRequest);
-
-                WriteRaw (ansiRequest.Request);
-
-                _mainLoopDriver._forceRead = true;
-            }
-
-            if (!_ansiResponseTokenSource.IsCancellationRequested)
-            {
-                _mainLoopDriver._waitForInput.Set ();
-
-                _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
-            }
-        }
-        catch (OperationCanceledException)
-        {
-            return false;
-        }
-
-        lock (ansiRequest._responseLock)
-        {
-            _mainLoopDriver._forceRead = false;
-
-            if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
-            {
-                if (AnsiEscapeSequenceRequests.Statuses.Count > 0
-                    && string.IsNullOrEmpty (request.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
-                {
-                    lock (request.AnsiRequest._responseLock)
-                    {
-                        // Bad request or no response at all
-                        AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
-                    }
-                }
-            }
-
-            _waitAnsiResponse.Reset ();
-
-            return ansiRequest.AnsiEscapeSequenceResponse is { Valid: true };
-        }
-    }
-
     /// <inheritdoc/>
     /// <inheritdoc/>
     internal override void WriteRaw (string ansi) { _mainLoopDriver?.WriteRaw (ansi); }
     internal override void WriteRaw (string ansi) { _mainLoopDriver?.WriteRaw (ansi); }
 }
 }

+ 8 - 8
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -43,7 +43,7 @@ internal class UnixMainLoop (ConsoleDriver consoleDriver) : IMainLoopDriver
     private Pollfd []? _pollMap;
     private Pollfd []? _pollMap;
     private readonly ConcurrentQueue<PollData> _pollDataQueue = new ();
     private readonly ConcurrentQueue<PollData> _pollDataQueue = new ();
     private readonly ManualResetEventSlim _eventReady = new (false);
     private readonly ManualResetEventSlim _eventReady = new (false);
-    internal readonly ManualResetEventSlim _waitForInput = new (false);
+    ManualResetEventSlim IMainLoopDriver._waitForInput { get; set; } = new (false);
     private readonly ManualResetEventSlim _windowSizeChange = new (false);
     private readonly ManualResetEventSlim _windowSizeChange = new (false);
     private readonly CancellationTokenSource _eventReadyTokenSource = new ();
     private readonly CancellationTokenSource _eventReadyTokenSource = new ();
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
@@ -152,7 +152,7 @@ internal class UnixMainLoop (ConsoleDriver consoleDriver) : IMainLoopDriver
         }
         }
     }
     }
 
 
-    internal bool _forceRead;
+    bool IMainLoopDriver._forceRead { get; set; }
     private int _retries;
     private int _retries;
 
 
     private void CursesInputHandler ()
     private void CursesInputHandler ()
@@ -161,9 +161,9 @@ internal class UnixMainLoop (ConsoleDriver consoleDriver) : IMainLoopDriver
         {
         {
             try
             try
             {
             {
-                if (!_inputHandlerTokenSource.IsCancellationRequested && !_forceRead)
+                if (!_inputHandlerTokenSource.IsCancellationRequested && !((IMainLoopDriver)this)._forceRead)
                 {
                 {
-                    _waitForInput.Wait (_inputHandlerTokenSource.Token);
+                    ((IMainLoopDriver)this)._waitForInput.Wait (_inputHandlerTokenSource.Token);
                 }
                 }
             }
             }
             catch (OperationCanceledException)
             catch (OperationCanceledException)
@@ -174,11 +174,11 @@ internal class UnixMainLoop (ConsoleDriver consoleDriver) : IMainLoopDriver
             {
             {
                 if (!_inputHandlerTokenSource.IsCancellationRequested)
                 if (!_inputHandlerTokenSource.IsCancellationRequested)
                 {
                 {
-                    _waitForInput.Reset ();
+                    ((IMainLoopDriver)this)._waitForInput.Reset ();
                 }
                 }
             }
             }
 
 
-            if (_pollDataQueue?.Count == 0 || _forceRead)
+            if (_pollDataQueue?.Count == 0 || ((IMainLoopDriver)this)._forceRead)
             {
             {
                 while (!_inputHandlerTokenSource.IsCancellationRequested)
                 while (!_inputHandlerTokenSource.IsCancellationRequested)
                 {
                 {
@@ -340,7 +340,7 @@ internal class UnixMainLoop (ConsoleDriver consoleDriver) : IMainLoopDriver
 
 
     bool IMainLoopDriver.EventsPending ()
     bool IMainLoopDriver.EventsPending ()
     {
     {
-        _waitForInput.Set ();
+        ((IMainLoopDriver)this)._waitForInput.Set ();
         _windowSizeChange.Set ();
         _windowSizeChange.Set ();
 
 
         if (_mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout))
         if (_mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout))
@@ -390,7 +390,7 @@ internal class UnixMainLoop (ConsoleDriver consoleDriver) : IMainLoopDriver
 
 
         _inputHandlerTokenSource?.Cancel ();
         _inputHandlerTokenSource?.Cancel ();
         _inputHandlerTokenSource?.Dispose ();
         _inputHandlerTokenSource?.Dispose ();
-        _waitForInput?.Dispose ();
+        ((IMainLoopDriver)this)._waitForInput?.Dispose ();
 
 
         _windowSizeChange.Dispose();
         _windowSizeChange.Dispose();
 
 

+ 1 - 1
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -393,7 +393,7 @@ public class FakeDriver : ConsoleDriver
     }
     }
 
 
     /// <inheritdoc />
     /// <inheritdoc />
-    public override bool TryWriteAnsiRequest (AnsiEscapeSequenceRequest ansiRequest) { throw new NotImplementedException (); }
+    public override bool TryWriteAnsiRequest (IMainLoopDriver mainLoopDriver, ref AnsiEscapeSequenceRequest ansiRequest) { throw new NotImplementedException (); }
 
 
     /// <inheritdoc />
     /// <inheritdoc />
     internal override void WriteRaw (string ansi) { throw new NotImplementedException (); }
     internal override void WriteRaw (string ansi) { throw new NotImplementedException (); }

+ 2 - 0
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeMainLoop.cs

@@ -3,6 +3,8 @@
 internal class FakeMainLoop : IMainLoopDriver
 internal class FakeMainLoop : IMainLoopDriver
 {
 {
     public Action<ConsoleKeyInfo> MockKeyPressed;
     public Action<ConsoleKeyInfo> MockKeyPressed;
+    public bool _forceRead { get; set; }
+    public ManualResetEventSlim _waitForInput { get; set; } = new ();
 
 
     public FakeMainLoop (ConsoleDriver consoleDriver = null)
     public FakeMainLoop (ConsoleDriver consoleDriver = null)
     {
     {

+ 0 - 77
Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs

@@ -359,10 +359,7 @@ internal class NetDriver : ConsoleDriver
 
 
         StopReportingMouseMoves ();
         StopReportingMouseMoves ();
 
 
-        _ansiResponseTokenSource?.Cancel ();
-        _ansiResponseTokenSource?.Dispose ();
 
 
-        _waitAnsiResponse.Dispose ();
 
 
         if (!RunningUnitTests)
         if (!RunningUnitTests)
         {
         {
@@ -721,80 +718,6 @@ internal class NetDriver : ConsoleDriver
 
 
     #region Low-Level DotNet tuff
     #region Low-Level DotNet tuff
 
 
-    private readonly ManualResetEventSlim _waitAnsiResponse = new (false);
-    private CancellationTokenSource? _ansiResponseTokenSource;
-
-    /// <inheritdoc/>
-    public override bool TryWriteAnsiRequest (AnsiEscapeSequenceRequest ansiRequest)
-    {
-        lock (ansiRequest._responseLock)
-        {
-            if (_mainLoopDriver is null)
-            {
-                return false;
-            }
-        }
-
-        _ansiResponseTokenSource ??= new ();
-
-        try
-        {
-            lock (ansiRequest._responseLock)
-            {
-                ansiRequest.ResponseFromInput += (s, e) =>
-                                                 {
-                                                     Debug.Assert (s == ansiRequest);
-                                                     Debug.Assert (e == ansiRequest.AnsiEscapeSequenceResponse);
-
-                                                     _waitAnsiResponse.Set ();
-                                                 };
-
-                AnsiEscapeSequenceRequests.Add (ansiRequest);
-
-                _mainLoopDriver._netEvents!._forceRead = true;
-            }
-
-            if (!_ansiResponseTokenSource.IsCancellationRequested)
-            {
-                lock (ansiRequest._responseLock)
-                {
-                    _mainLoopDriver._waitForProbe.Set ();
-                    _mainLoopDriver._netEvents._waitForStart.Set ();
-
-                    WriteRaw (ansiRequest.Request);
-                }
-
-                _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
-            }
-        }
-        catch (OperationCanceledException)
-        {
-            return false;
-        }
-
-        lock (ansiRequest._responseLock)
-        {
-            _mainLoopDriver._netEvents._forceRead = false;
-
-            if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
-            {
-                if (AnsiEscapeSequenceRequests.Statuses.Count > 0
-                    && string.IsNullOrEmpty (request.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
-                {
-                    lock (request.AnsiRequest._responseLock)
-                    {
-                        // Bad request or no response at all
-                        AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
-                    }
-                }
-            }
-
-            _waitAnsiResponse.Reset ();
-
-            return ansiRequest.AnsiEscapeSequenceResponse is { Valid: true };
-        }
-    }
-
     /// <inheritdoc/>
     /// <inheritdoc/>
     internal override void WriteRaw (string ansi)
     internal override void WriteRaw (string ansi)
     {
     {

+ 124 - 136
Terminal.Gui/ConsoleDrivers/NetDriver/NetEvents.cs

@@ -7,7 +7,6 @@ internal class NetEvents : IDisposable
 {
 {
     private readonly ManualResetEventSlim _inputReady = new (false);
     private readonly ManualResetEventSlim _inputReady = new (false);
     private CancellationTokenSource? _inputReadyCancellationTokenSource;
     private CancellationTokenSource? _inputReadyCancellationTokenSource;
-    internal readonly ManualResetEventSlim _waitForStart = new (false);
     private readonly Queue<InputResult> _inputQueue = new ();
     private readonly Queue<InputResult> _inputQueue = new ();
     private readonly ConsoleDriver _consoleDriver;
     private readonly ConsoleDriver _consoleDriver;
     private ConsoleKeyInfo []? _cki;
     private ConsoleKeyInfo []? _cki;
@@ -29,8 +28,6 @@ internal class NetEvents : IDisposable
     {
     {
         while (_inputReadyCancellationTokenSource is { Token.IsCancellationRequested: false })
         while (_inputReadyCancellationTokenSource is { Token.IsCancellationRequested: false })
         {
         {
-            _waitForStart.Set ();
-
             try
             try
             {
             {
                 if (!_inputReadyCancellationTokenSource.Token.IsCancellationRequested)
                 if (!_inputReadyCancellationTokenSource.Token.IsCancellationRequested)
@@ -81,32 +78,7 @@ internal class NetEvents : IDisposable
             // In WSL it takes longer for keys to be available.
             // In WSL it takes longer for keys to be available.
             Task.Delay (100, cancellationToken).Wait (cancellationToken);
             Task.Delay (100, cancellationToken).Wait (cancellationToken);
 
 
-            if (!Console.KeyAvailable && AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && AnsiEscapeSequenceRequests.Statuses.Count > 0)
-            {
-                if (_retries > 1)
-                {
-                    if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? seqReqStatus)
-                        && string.IsNullOrEmpty (seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
-                    {
-                        lock (seqReqStatus.AnsiRequest._responseLock)
-                        {
-                            AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
-
-                            seqReqStatus.AnsiRequest.RaiseResponseFromInput (null);
-                        }
-                    }
-
-                    _retries = 0;
-                }
-                else
-                {
-                    _retries++;
-                }
-            }
-            else
-            {
-                _retries = 0;
-            }
+            ProcessResponse ();
         }
         }
 
 
         cancellationToken.ThrowIfCancellationRequested ();
         cancellationToken.ThrowIfCancellationRequested ();
@@ -114,152 +86,169 @@ internal class NetEvents : IDisposable
         return default (ConsoleKeyInfo);
         return default (ConsoleKeyInfo);
     }
     }
 
 
-    internal bool _forceRead;
+    //internal bool _forceRead;
     private int _retries;
     private int _retries;
 
 
-    private void ProcessInputQueue ()
+    private void ProcessResponse ()
     {
     {
-        while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
+        if (!Console.KeyAvailable && AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && AnsiEscapeSequenceRequests.Statuses.Count > 0)
         {
         {
-            try
+            if (_retries > 1)
             {
             {
-                if (!_forceRead)
+                if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? seqReqStatus)
+                    && string.IsNullOrEmpty (seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
                 {
                 {
-                    _waitForStart.Wait (_inputReadyCancellationTokenSource.Token);
+                    lock (seqReqStatus.AnsiRequest._responseLock)
+                    {
+                        AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
+
+                        seqReqStatus.AnsiRequest.RaiseResponseFromInput (null);
+                    }
                 }
                 }
+
+                _retries = 0;
             }
             }
-            catch (OperationCanceledException)
-            {
-                return;
-            }
-            finally
+            else
             {
             {
-                if (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
-                {
-                    _waitForStart.Reset ();
-                }
+                _retries++;
             }
             }
+        }
+        else
+        {
+            _retries = 0;
+        }
+    }
 
 
+    private void ProcessInputQueue ()
+    {
+        while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
+        {
             try
             try
             {
             {
-                if (_inputQueue.Count == 0 || _forceRead)
+                ConsoleKey key = 0;
+                ConsoleModifiers mod = 0;
+                ConsoleKeyInfo newConsoleKeyInfo = default;
+
+                while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
                 {
                 {
-                    ConsoleKey key = 0;
-                    ConsoleModifiers mod = 0;
-                    ConsoleKeyInfo newConsoleKeyInfo = default;
+                    ConsoleKeyInfo consoleKeyInfo;
 
 
-                    while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
+                    try
                     {
                     {
-                        ConsoleKeyInfo consoleKeyInfo;
-
-                        try
-                        {
-                            consoleKeyInfo = ReadConsoleKeyInfo (_inputReadyCancellationTokenSource.Token);
-                        }
-                        catch (OperationCanceledException)
-                        {
-                            return;
-                        }
-
-                        var ckiAlreadyResized = false;
+                        consoleKeyInfo = ReadConsoleKeyInfo (_inputReadyCancellationTokenSource.Token);
+                    }
+                    catch (OperationCanceledException)
+                    {
+                        return;
+                    }
 
 
-                        if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is { })
-                        {
-                            ckiAlreadyResized = true;
+                    var ckiAlreadyResized = false;
 
 
-                            _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
-                            _cki = AnsiEscapeSequenceRequestUtils.InsertArray (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos, _cki);
-                            AnsiEscapeSequenceRequestUtils.IncompleteCkInfos = null;
+                    if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is { })
+                    {
+                        ckiAlreadyResized = true;
 
 
-                            if (_cki.Length > 1 && _cki [0].KeyChar == '\u001B')
-                            {
-                                _isEscSeq = true;
-                            }
-                        }
+                        _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
+                        _cki = AnsiEscapeSequenceRequestUtils.InsertArray (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos, _cki);
+                        AnsiEscapeSequenceRequestUtils.IncompleteCkInfos = null;
 
 
-                        if ((consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq)
-                            || (consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq))
+                        if (_cki.Length > 1 && _cki [0].KeyChar == '\u001B')
                         {
                         {
-                            if (_cki is null && consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq)
-                            {
-                                _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (
-                                                                                   new (
-                                                                                        (char)KeyCode.Esc,
-                                                                                        0,
-                                                                                        false,
-                                                                                        false,
-                                                                                        false
-                                                                                       ),
-                                                                                   _cki
-                                                                                  );
-                            }
-
                             _isEscSeq = true;
                             _isEscSeq = true;
+                        }
+                    }
 
 
-                            if ((_cki is { } && _cki [^1].KeyChar != Key.Esc && consoleKeyInfo.KeyChar != Key.Esc && consoleKeyInfo.KeyChar <= Key.Space)
-                                || (_cki is { } && _cki [^1].KeyChar != '\u001B' && consoleKeyInfo.KeyChar == 127)
-                                || (_cki is { } && char.IsLetter (_cki [^1].KeyChar) && char.IsLower (consoleKeyInfo.KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar))
-                                || (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsLetterOrDigit (consoleKeyInfo.KeyChar))
-                                || (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsPunctuation (consoleKeyInfo.KeyChar))
-                                || (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsSymbol (consoleKeyInfo.KeyChar)))
-                            {
-                                ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
-                                _cki = null;
-                                _isEscSeq = false;
-
-                                ProcessMapConsoleKeyInfo (consoleKeyInfo);
-                            }
-                            else
-                            {
-                                newConsoleKeyInfo = consoleKeyInfo;
-
-                                if (!ckiAlreadyResized)
-                                {
-                                    _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
-                                }
-
-                                if (Console.KeyAvailable)
-                                {
-                                    continue;
-                                }
-
-                                ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
-                                _cki = null;
-                                _isEscSeq = false;
-                            }
-
-                            break;
+                    if ((consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq)
+                        || (consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq))
+                    {
+                        if (_cki is null && consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq)
+                        {
+                            _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (
+                                                                               new (
+                                                                                    (char)KeyCode.Esc,
+                                                                                    0,
+                                                                                    false,
+                                                                                    false,
+                                                                                    false
+                                                                                   ),
+                                                                               _cki
+                                                                              );
                         }
                         }
 
 
-                        if (consoleKeyInfo.KeyChar == (char)KeyCode.Esc && _isEscSeq && _cki is { })
+                        _isEscSeq = true;
+
+                        if ((_cki is { } && _cki [^1].KeyChar != Key.Esc && consoleKeyInfo.KeyChar != Key.Esc && consoleKeyInfo.KeyChar <= Key.Space)
+                            || (_cki is { } && _cki [^1].KeyChar != '\u001B' && consoleKeyInfo.KeyChar == 127)
+                            || (_cki is { }
+                                && char.IsLetter (_cki [^1].KeyChar)
+                                && char.IsLower (consoleKeyInfo.KeyChar)
+                                && char.IsLetter (consoleKeyInfo.KeyChar))
+                            || (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsLetterOrDigit (consoleKeyInfo.KeyChar))
+                            || (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsPunctuation (consoleKeyInfo.KeyChar))
+                            || (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsSymbol (consoleKeyInfo.KeyChar)))
                         {
                         {
                             ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
                             ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
                             _cki = null;
                             _cki = null;
+                            _isEscSeq = false;
+                            ProcessResponse ();
 
 
-                            if (Console.KeyAvailable)
+                            ProcessMapConsoleKeyInfo (consoleKeyInfo);
+                        }
+                        else
+                        {
+                            newConsoleKeyInfo = consoleKeyInfo;
+
+                            if (!ckiAlreadyResized)
                             {
                             {
                                 _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
                                 _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
                             }
                             }
-                            else
+
+                            if (Console.KeyAvailable)
                             {
                             {
-                                ProcessMapConsoleKeyInfo (consoleKeyInfo);
+                                continue;
                             }
                             }
 
 
-                            break;
+                            ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
+                            _cki = null;
+                            _isEscSeq = false;
+                            ProcessResponse ();
                         }
                         }
 
 
-                        ProcessMapConsoleKeyInfo (consoleKeyInfo);
+                        break;
+                    }
+
+                    if (consoleKeyInfo.KeyChar == (char)KeyCode.Esc && _isEscSeq && _cki is { })
+                    {
+                        ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
+                        _cki = null;
+                        ProcessResponse ();
 
 
-                        if (_retries > 0)
+                        if (Console.KeyAvailable)
                         {
                         {
-                            _retries = 0;
+                            _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
+                        }
+                        else
+                        {
+                            ProcessMapConsoleKeyInfo (consoleKeyInfo);
                         }
                         }
 
 
                         break;
                         break;
                     }
                     }
+
+                    ProcessMapConsoleKeyInfo (consoleKeyInfo);
+
+                    if (_retries > 0)
+                    {
+                        _retries = 0;
+                    }
+
+                    break;
                 }
                 }
 
 
-                _inputReady.Set ();
+                if (!_inputReady.IsSet)
+                {
+                    _inputReady.Set ();
+                }
             }
             }
             catch (OperationCanceledException)
             catch (OperationCanceledException)
             {
             {
@@ -394,12 +383,12 @@ internal class NetEvents : IDisposable
             return;
             return;
         }
         }
 
 
-        //if (seqReqStatus is { })
-        //{
-        //    HandleRequestResponseEvent (c1Control, code, values, terminating);
+        if (seqReqStatus is { })
+        {
+            //HandleRequestResponseEvent (c1Control, code, values, terminating);
 
 
-        //    return;
-        //}
+            return;
+        }
 
 
         if (newConsoleKeyInfo != default)
         if (newConsoleKeyInfo != default)
         {
         {
@@ -731,7 +720,6 @@ internal class NetEvents : IDisposable
         _inputReadyCancellationTokenSource = null;
         _inputReadyCancellationTokenSource = null;
 
 
         _inputReady.Dispose ();
         _inputReady.Dispose ();
-        _waitForStart.Dispose ();
 
 
         try
         try
         {
         {

+ 4 - 2
Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs

@@ -20,6 +20,8 @@ internal class NetMainLoop : IMainLoopDriver
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
     private readonly Queue<NetEvents.InputResult> _resultQueue = new ();
     private readonly Queue<NetEvents.InputResult> _resultQueue = new ();
     private MainLoop? _mainLoop;
     private MainLoop? _mainLoop;
+    bool IMainLoopDriver._forceRead { get; set; }
+    ManualResetEventSlim IMainLoopDriver._waitForInput { get; set; } = new (false);
 
 
     /// <summary>Initializes the class with the console driver.</summary>
     /// <summary>Initializes the class with the console driver.</summary>
     /// <remarks>Passing a consoleDriver is provided to capture windows resizing.</remarks>
     /// <remarks>Passing a consoleDriver is provided to capture windows resizing.</remarks>
@@ -116,12 +118,12 @@ internal class NetMainLoop : IMainLoopDriver
         {
         {
             try
             try
             {
             {
-                if (!_inputHandlerTokenSource.IsCancellationRequested && !_netEvents!._forceRead)
+                if (!_inputHandlerTokenSource.IsCancellationRequested && !((IMainLoopDriver)this)._forceRead)
                 {
                 {
                     _waitForProbe.Wait (_inputHandlerTokenSource.Token);
                     _waitForProbe.Wait (_inputHandlerTokenSource.Token);
                 }
                 }
 
 
-                if (_resultQueue?.Count == 0 || _netEvents!._forceRead)
+                if (_resultQueue?.Count == 0 || ((IMainLoopDriver)this)._forceRead)
                 {
                 {
                     NetEvents.InputResult? result = _netEvents!.DequeueInput ();
                     NetEvents.InputResult? result = _netEvents!.DequeueInput ();
 
 

+ 0 - 62
Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs

@@ -187,68 +187,6 @@ internal class WindowsDriver : ConsoleDriver
         }
         }
     }
     }
 
 
-    private readonly ManualResetEventSlim _waitAnsiResponse = new (false);
-    private CancellationTokenSource? _ansiResponseTokenSource;
-
-    /// <inheritdoc/>
-    public override bool TryWriteAnsiRequest (AnsiEscapeSequenceRequest ansiRequest)
-    {
-        if (_mainLoopDriver is null)
-        {
-            return false;
-        }
-
-        _ansiResponseTokenSource ??= new ();
-
-        try
-        {
-            lock (ansiRequest._responseLock)
-            {
-                ansiRequest.ResponseFromInput += (s, e) =>
-                                                 {
-                                                     Debug.Assert (s == ansiRequest);
-                                                     Debug.Assert (e == ansiRequest.AnsiEscapeSequenceResponse);
-
-                                                     _waitAnsiResponse.Set ();
-                                                 };
-
-                AnsiEscapeSequenceRequests.Add (ansiRequest);
-
-                WriteRaw (ansiRequest.Request);
-
-                _mainLoopDriver._forceRead = true;
-            }
-
-            _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
-        }
-        catch (OperationCanceledException)
-        {
-            return false;
-        }
-
-        lock (ansiRequest._responseLock)
-        {
-            _mainLoopDriver._forceRead = false;
-
-            if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
-            {
-                if (AnsiEscapeSequenceRequests.Statuses.Count > 0
-                    && string.IsNullOrEmpty (request.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
-                {
-                    lock (request.AnsiRequest._responseLock)
-                    {
-                        // Bad request or no response at all
-                        AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
-                    }
-                }
-            }
-
-            _waitAnsiResponse.Reset ();
-
-            return ansiRequest.AnsiEscapeSequenceResponse is { Valid: true };
-        }
-    }
-
     internal override void WriteRaw (string ansi) { WinConsole?.WriteANSI (ansi); }
     internal override void WriteRaw (string ansi) { WinConsole?.WriteANSI (ansi); }
 
 
     #region Not Implemented
     #region Not Implemented

+ 5 - 5
Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs

@@ -21,7 +21,7 @@ internal class WindowsMainLoop : IMainLoopDriver
 
 
     // The records that we keep fetching
     // The records that we keep fetching
     private readonly Queue<WindowsConsole.InputRecord> _resultQueue = new ();
     private readonly Queue<WindowsConsole.InputRecord> _resultQueue = new ();
-    private readonly ManualResetEventSlim _waitForProbe = new (false);
+    ManualResetEventSlim IMainLoopDriver._waitForInput { get; set; } = new (false);
     private readonly WindowsConsole? _winConsole;
     private readonly WindowsConsole? _winConsole;
     private CancellationTokenSource _eventReadyTokenSource = new ();
     private CancellationTokenSource _eventReadyTokenSource = new ();
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
@@ -57,7 +57,7 @@ internal class WindowsMainLoop : IMainLoopDriver
 
 
     bool IMainLoopDriver.EventsPending ()
     bool IMainLoopDriver.EventsPending ()
     {
     {
-        _waitForProbe.Set ();
+        ((IMainLoopDriver)this)._waitForInput.Set ();
 #if HACK_CHECK_WINCHANGED
 #if HACK_CHECK_WINCHANGED
         _winChange.Set ();
         _winChange.Set ();
 #endif
 #endif
@@ -131,7 +131,7 @@ internal class WindowsMainLoop : IMainLoopDriver
             }
             }
         }
         }
 
 
-        _waitForProbe?.Dispose ();
+        ((IMainLoopDriver)this)._waitForInput?.Dispose ();
 
 
         _resultQueue.Clear ();
         _resultQueue.Clear ();
 
 
@@ -146,7 +146,7 @@ internal class WindowsMainLoop : IMainLoopDriver
         _mainLoop = null;
         _mainLoop = null;
     }
     }
 
 
-    internal bool _forceRead;
+    public bool _forceRead { get; set; }
 
 
     private void WindowsInputHandler ()
     private void WindowsInputHandler ()
     {
     {
@@ -156,7 +156,7 @@ internal class WindowsMainLoop : IMainLoopDriver
             {
             {
                 if (_inputHandlerTokenSource.IsCancellationRequested && !_forceRead)
                 if (_inputHandlerTokenSource.IsCancellationRequested && !_forceRead)
                 {
                 {
-                    _waitForProbe.Wait (_inputHandlerTokenSource.Token);
+                    ((IMainLoopDriver)this)._waitForInput.Wait (_inputHandlerTokenSource.Token);
                 }
                 }
 
 
                 if (_resultQueue?.Count == 0 || _forceRead)
                 if (_resultQueue?.Count == 0 || _forceRead)

+ 3 - 2
UICatalog/Scenarios/AnsiEscapeSequenceRequests.cs

@@ -293,7 +293,8 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
                                      };
                                      };
 
 
                                      bool success = Application.Driver!.TryWriteAnsiRequest (
                                      bool success = Application.Driver!.TryWriteAnsiRequest (
-                                                                                             ansiEscapeSequenceRequest
+                                                                                             Application.MainLoop.MainLoopDriver,
+                                                                                             ref ansiEscapeSequenceRequest
                                                                                             );
                                                                                             );
 
 
                                      tvResponse.Text = ansiEscapeSequenceRequest.AnsiEscapeSequenceResponse?.Response ?? "";
                                      tvResponse.Text = ansiEscapeSequenceRequest.AnsiEscapeSequenceResponse?.Response ?? "";
@@ -369,7 +370,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
     {
     {
         _sends.Add (DateTime.Now);
         _sends.Add (DateTime.Now);
         AnsiEscapeSequenceRequest ansiRequest = AnsiEscapeSequenceRequestUtils.CSI_SendDeviceAttributes;
         AnsiEscapeSequenceRequest ansiRequest = AnsiEscapeSequenceRequestUtils.CSI_SendDeviceAttributes;
-        if (Application.Driver!.TryWriteAnsiRequest (ansiRequest))
+        if (Application.Driver!.TryWriteAnsiRequest (Application.MainLoop.MainLoopDriver, ref ansiRequest))
         {
         {
             HandleResponse (ansiRequest.AnsiEscapeSequenceResponse?.Response);
             HandleResponse (ansiRequest.AnsiEscapeSequenceResponse?.Response);
         }
         }

+ 4 - 0
UnitTests/Application/MainLoopTests.cs

@@ -946,10 +946,14 @@ public class MainLoopTests
     private class TestMainloop : IMainLoopDriver
     private class TestMainloop : IMainLoopDriver
     {
     {
         private MainLoop mainLoop;
         private MainLoop mainLoop;
+        private bool _forceRead1;
+        private ManualResetEventSlim _waitForInput1;
         public bool EventsPending () { throw new NotImplementedException (); }
         public bool EventsPending () { throw new NotImplementedException (); }
         public void Iteration () { throw new NotImplementedException (); }
         public void Iteration () { throw new NotImplementedException (); }
         public void TearDown () { throw new NotImplementedException (); }
         public void TearDown () { throw new NotImplementedException (); }
         public void Setup (MainLoop mainLoop) { this.mainLoop = mainLoop; }
         public void Setup (MainLoop mainLoop) { this.mainLoop = mainLoop; }
         public void Wakeup () { throw new NotImplementedException (); }
         public void Wakeup () { throw new NotImplementedException (); }
+        public bool _forceRead { get; set; }
+        public ManualResetEventSlim _waitForInput { get; set; }
     }
     }
 }
 }