Browse Source

Make AnsiEscapeSequenceRequests static.

BDisp 8 months ago
parent
commit
1680ec54d6

+ 3 - 5
Terminal.Gui/ConsoleDrivers/AnsiEscapeSequence/AnsiEscapeSequenceRequestUtils.cs

@@ -183,7 +183,6 @@ public static class AnsiEscapeSequenceRequestUtils
     /// <summary>
     ///     Decodes an ANSI escape sequence.
     /// </summary>
-    /// <param name="escSeqRequests">The <see cref="AnsiEscapeSequenceRequests"/> which may contain a request.</param>
     /// <param name="newConsoleKeyInfo">The <see cref="ConsoleKeyInfo"/> which may change.</param>
     /// <param name="key">The <see cref="ConsoleKey"/> which may change.</param>
     /// <param name="cki">The <see cref="ConsoleKeyInfo"/> array.</param>
@@ -198,7 +197,6 @@ public static class AnsiEscapeSequenceRequestUtils
     /// <param name="seqReqStatus">The <see cref="AnsiEscapeSequenceRequestStatus"/> object.</param>
     /// <param name="continuousButtonPressedHandler">The handler that will process the event.</param>
     public static void DecodeEscSeq (
-        AnsiEscapeSequenceRequests? escSeqRequests,
         ref ConsoleKeyInfo newConsoleKeyInfo,
         ref ConsoleKey key,
         ConsoleKeyInfo [] cki,
@@ -346,9 +344,9 @@ public static class AnsiEscapeSequenceRequestUtils
                     return;
                 }
 
-                if (escSeqRequests is { } && escSeqRequests.HasResponse (terminator, out seqReqStatus))
+                if (AnsiEscapeSequenceRequests.HasResponse (terminator, out seqReqStatus))
                 {
-                    escSeqRequests.Remove (seqReqStatus);
+                    AnsiEscapeSequenceRequests.Remove (seqReqStatus);
 
                     return;
                 }
@@ -376,7 +374,7 @@ public static class AnsiEscapeSequenceRequestUtils
                     else
                     {
                         // It's request response that wasn't handled by a valid request terminator
-                        System.Diagnostics.Debug.Assert (escSeqRequests is null or { Statuses.Count: > 0 });
+                        System.Diagnostics.Debug.Assert (AnsiEscapeSequenceRequests.Statuses.Count > 0);
 
                         InvalidRequestTerminator = ToString (cki);
                     }

+ 19 - 27
Terminal.Gui/ConsoleDrivers/AnsiEscapeSequence/AnsiEscapeSequenceRequests.cs

@@ -4,35 +4,36 @@ using System.Collections.Concurrent;
 
 namespace Terminal.Gui;
 
-// TODO: This class is a singleton. It should use the singleton pattern.
 /// <summary>
 ///     Manages ANSI Escape Sequence requests and responses. The list of <see cref="AnsiEscapeSequenceRequestStatus"/>
 ///     contains the
 ///     status of the request. Each request is identified by the terminator (e.g. ESC[8t ... t is the terminator).
 /// </summary>
-public class AnsiEscapeSequenceRequests
+public static class AnsiEscapeSequenceRequests
 {
     /// <summary>
     ///     Adds a new request for the ANSI Escape Sequence defined by <paramref name="ansiRequest"/>. Adds a
     ///     <see cref="AnsiEscapeSequenceRequestStatus"/> instance to <see cref="Statuses"/> list.
     /// </summary>
     /// <param name="ansiRequest">The <see cref="AnsiEscapeSequenceRequest"/> object.</param>
-    /// <param name="driver">The driver in use.</param>
-    public void Add (AnsiEscapeSequenceRequest ansiRequest, ConsoleDriver? driver = null)
+    public static void Add (AnsiEscapeSequenceRequest ansiRequest)
     {
-        lock (Statuses)
+        lock (ansiRequest._responseLock)
         {
             Statuses.Enqueue (new (ansiRequest));
+        }
 
-            if (driver is null)
-            {
-                Console.Out.Write (ansiRequest.Request);
-                Console.Out.Flush ();
-            }
-            else
-            {
-                driver.WriteRaw (ansiRequest.Request);
-            }
+        System.Diagnostics.Debug.Assert (Statuses.Count > 0);
+    }
+
+    /// <summary>
+    ///     Clear the <see cref="Statuses"/> property.
+    /// </summary>
+    public static void Clear ()
+    {
+        lock (Statuses)
+        {
+            Statuses.Clear ();
         }
     }
 
@@ -43,22 +44,13 @@ public class AnsiEscapeSequenceRequests
     /// <param name="terminator"></param>
     /// <param name="seqReqStatus"></param>
     /// <returns><see langword="true"/> if exist, <see langword="false"/> otherwise.</returns>
-    public bool HasResponse (string terminator, out AnsiEscapeSequenceRequestStatus? seqReqStatus)
+    public static bool HasResponse (string terminator, out AnsiEscapeSequenceRequestStatus? seqReqStatus)
     {
         lock (Statuses)
         {
             Statuses.TryPeek (out seqReqStatus);
 
-            bool result = seqReqStatus?.AnsiRequest.Terminator == terminator;
-
-            if (result)
-            {
-                return true;
-            }
-
-            seqReqStatus = null;
-
-            return false;
+            return seqReqStatus?.AnsiRequest.Terminator == terminator;
         }
     }
 
@@ -70,7 +62,7 @@ public class AnsiEscapeSequenceRequests
     ///     <see cref="Statuses"/>.
     /// </summary>
     /// <param name="seqReqStatus">The <see cref="AnsiEscapeSequenceRequestStatus"/> object.</param>
-    public void Remove (AnsiEscapeSequenceRequestStatus? seqReqStatus)
+    public static void Remove (AnsiEscapeSequenceRequestStatus? seqReqStatus)
     {
         lock (Statuses)
         {
@@ -84,5 +76,5 @@ public class AnsiEscapeSequenceRequests
     }
 
     /// <summary>Gets the <see cref="AnsiEscapeSequenceRequestStatus"/> list.</summary>
-    public ConcurrentQueue<AnsiEscapeSequenceRequestStatus> Statuses { get; } = new ();
+    public static ConcurrentQueue<AnsiEscapeSequenceRequestStatus> Statuses { get; } = new ();
 }

+ 6 - 5
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -806,7 +806,9 @@ internal class CursesDriver : ConsoleDriver
                                                      _waitAnsiResponse.Set ();
                                                  };
 
-                _mainLoopDriver.EscSeqRequests.Add (ansiRequest, this);
+                AnsiEscapeSequenceRequests.Add (ansiRequest);
+
+                WriteRaw (ansiRequest.Request);
 
                 _mainLoopDriver._forceRead = true;
             }
@@ -827,15 +829,15 @@ internal class CursesDriver : ConsoleDriver
         {
             _mainLoopDriver._forceRead = false;
 
-            if (_mainLoopDriver.EscSeqRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
+            if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
             {
-                if (_mainLoopDriver.EscSeqRequests.Statuses.Count > 0
+                if (AnsiEscapeSequenceRequests.Statuses.Count > 0
                     && string.IsNullOrEmpty (request.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
                 {
                     lock (request.AnsiRequest._responseLock)
                     {
                         // Bad request or no response at all
-                        _mainLoopDriver.EscSeqRequests.Statuses.TryDequeue (out _);
+                        AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
                     }
                 }
             }
@@ -848,7 +850,6 @@ internal class CursesDriver : ConsoleDriver
 
     /// <inheritdoc/>
     internal override void WriteRaw (string ansi) { _mainLoopDriver?.WriteRaw (ansi); }
-
 }
 
 // TODO: One type per file - move to another file

+ 24 - 31
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -1,3 +1,4 @@
+#nullable enable
 //
 // mainloop.cs: Linux/Curses MainLoop implementation.
 //
@@ -12,7 +13,7 @@ namespace Terminal.Gui;
 ///     In addition to the general functions of the MainLoop, the Unix version can watch file descriptors using the
 ///     AddWatch methods.
 /// </remarks>
-internal class UnixMainLoop : IMainLoopDriver
+internal class UnixMainLoop (ConsoleDriver consoleDriver) : IMainLoopDriver
 {
     /// <summary>Condition on which to wake up from file descriptor activity.  These match the Linux/BSD poll definitions.</summary>
     [Flags]
@@ -37,9 +38,9 @@ internal class UnixMainLoop : IMainLoopDriver
         PollNval = 32
     }
 
-    private readonly CursesDriver _cursesDriver;
-    private MainLoop _mainLoop;
-    private Pollfd [] _pollMap;
+    private readonly CursesDriver _cursesDriver = (CursesDriver)consoleDriver ?? throw new ArgumentNullException (nameof (consoleDriver));
+    private MainLoop? _mainLoop;
+    private Pollfd []? _pollMap;
     private readonly ConcurrentQueue<PollData> _pollDataQueue = new ();
     private readonly ManualResetEventSlim _eventReady = new (false);
     internal readonly ManualResetEventSlim _waitForInput = new (false);
@@ -47,13 +48,6 @@ internal class UnixMainLoop : IMainLoopDriver
     private readonly CancellationTokenSource _eventReadyTokenSource = new ();
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
 
-    public UnixMainLoop (ConsoleDriver consoleDriver = null)
-    {
-        _cursesDriver = (CursesDriver)consoleDriver ?? throw new ArgumentNullException (nameof (consoleDriver));
-    }
-
-    public AnsiEscapeSequenceRequests EscSeqRequests { get; } = new ();
-
     void IMainLoopDriver.Wakeup () { _eventReady.Set (); }
 
     void IMainLoopDriver.Setup (MainLoop mainLoop)
@@ -110,7 +104,7 @@ internal class UnixMainLoop : IMainLoopDriver
         return GetTIOCGWINSZValueInternal ();
     }
 
-    private void EscSeqUtils_ContinuousButtonPressed (object sender, MouseEventArgs e)
+    private void EscSeqUtils_ContinuousButtonPressed (object? sender, MouseEventArgs e)
     {
         _pollDataQueue!.Enqueue (EnqueueMouseEvent (e.Flags, e.Position));
     }
@@ -238,15 +232,15 @@ internal class UnixMainLoop : IMainLoopDriver
                         break;
                     }
 
-                    if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && EscSeqRequests is { Statuses.Count: > 0 })
+                    if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && AnsiEscapeSequenceRequests.Statuses.Count > 0)
                     {
                         if (_retries > 1)
                         {
-                            if (EscSeqRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus seqReqStatus) && seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse is { } && string.IsNullOrEmpty (seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse.Response))
+                            if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? seqReqStatus) && seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse is { } && string.IsNullOrEmpty (seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse.Response))
                             {
                                 lock (seqReqStatus!.AnsiRequest._responseLock)
                                 {
-                                    EscSeqRequests.Statuses.TryDequeue (out _);
+                                    AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
 
                                     seqReqStatus.AnsiRequest.RaiseResponseFromInput (null);
                                 }
@@ -299,21 +293,20 @@ internal class UnixMainLoop : IMainLoopDriver
         ConsoleKeyInfo newConsoleKeyInfo = default;
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  EscSeqRequests,
-                                  ref newConsoleKeyInfo,
-                                  ref key,
-                                  cki,
-                                  ref mod,
-                                  out string c1Control,
-                                  out string code,
-                                  out string [] values,
-                                  out string terminating,
-                                  out bool isMouse,
-                                  out List<MouseFlags> mouseFlags,
-                                  out Point pos,
-                                  out AnsiEscapeSequenceRequestStatus seqReqStatus,
-                                  AnsiEscapeSequenceRequestUtils.ProcessMouseEvent
-                                 );
+                                                     ref newConsoleKeyInfo,
+                                                     ref key,
+                                                     cki,
+                                                     ref mod,
+                                                     out string c1Control,
+                                                     out string code,
+                                                     out string [] values,
+                                                     out string terminating,
+                                                     out bool isMouse,
+                                                     out List<MouseFlags> mouseFlags,
+                                                     out Point pos,
+                                                     out AnsiEscapeSequenceRequestStatus seqReqStatus,
+                                                     AnsiEscapeSequenceRequestUtils.ProcessMouseEvent
+                                                    );
 
         if (isMouse)
         {
@@ -339,7 +332,7 @@ internal class UnixMainLoop : IMainLoopDriver
 
         if (!string.IsNullOrEmpty (AnsiEscapeSequenceRequestUtils.InvalidRequestTerminator))
         {
-            if (EscSeqRequests.Statuses.TryDequeue (out AnsiEscapeSequenceRequestStatus result))
+            if (AnsiEscapeSequenceRequests.Statuses.TryDequeue (out AnsiEscapeSequenceRequestStatus? result))
             {
                 lock (result.AnsiRequest._responseLock)
                 {

+ 12 - 6
Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs

@@ -752,9 +752,9 @@ internal class NetDriver : ConsoleDriver
                                                      _waitAnsiResponse.Set ();
                                                  };
 
-                _mainLoopDriver._netEvents!.EscSeqRequests.Add (ansiRequest);
+                AnsiEscapeSequenceRequests.Add (ansiRequest);
 
-                _mainLoopDriver._netEvents._forceRead = true;
+                _mainLoopDriver._netEvents!._forceRead = true;
             }
 
             if (!_ansiResponseTokenSource.IsCancellationRequested)
@@ -763,6 +763,8 @@ internal class NetDriver : ConsoleDriver
                 {
                     _mainLoopDriver._waitForProbe.Set ();
                     _mainLoopDriver._netEvents._waitForStart.Set ();
+
+                    WriteRaw (ansiRequest.Request);
                 }
 
                 _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
@@ -777,15 +779,15 @@ internal class NetDriver : ConsoleDriver
         {
             _mainLoopDriver._netEvents._forceRead = false;
 
-            if (_mainLoopDriver._netEvents.EscSeqRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
+            if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
             {
-                if (_mainLoopDriver._netEvents.EscSeqRequests.Statuses.Count > 0
+                if (AnsiEscapeSequenceRequests.Statuses.Count > 0
                     && string.IsNullOrEmpty (request.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
                 {
                     lock (request.AnsiRequest._responseLock)
                     {
                         // Bad request or no response at all
-                        _mainLoopDriver._netEvents.EscSeqRequests.Statuses.TryDequeue (out _);
+                        AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
                     }
                 }
             }
@@ -797,7 +799,11 @@ internal class NetDriver : ConsoleDriver
     }
 
     /// <inheritdoc/>
-    internal override void WriteRaw (string ansi) { throw new NotImplementedException (); }
+    internal override void WriteRaw (string ansi)
+    {
+        Console.Out.Write (ansi);
+        Console.Out.Flush ();
+    }
 
     private volatile bool _winSizeChanging;
 

+ 18 - 21
Terminal.Gui/ConsoleDrivers/NetDriver/NetEvents.cs

@@ -15,8 +15,6 @@ internal class NetEvents : IDisposable
 #if PROCESS_REQUEST
     bool _neededProcessRequest;
 #endif
-    public AnsiEscapeSequenceRequests EscSeqRequests { get; } = new ();
-
     public NetEvents (ConsoleDriver consoleDriver)
     {
         _consoleDriver = consoleDriver ?? throw new ArgumentNullException (nameof (consoleDriver));
@@ -79,15 +77,15 @@ internal class NetEvents : IDisposable
                 return Console.ReadKey (intercept);
             }
 
-            if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && EscSeqRequests is { Statuses.Count: > 0 })
+            if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && AnsiEscapeSequenceRequests.Statuses.Count > 0)
             {
                 if (_retries > 1)
                 {
-                    if (EscSeqRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? seqReqStatus) && string.IsNullOrEmpty (seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
+                    if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? seqReqStatus) && string.IsNullOrEmpty (seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
                     {
                         lock (seqReqStatus.AnsiRequest._responseLock)
                         {
-                            EscSeqRequests.Statuses.TryDequeue (out _);
+                            AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
 
                             seqReqStatus.AnsiRequest.RaiseResponseFromInput (null);
                         }
@@ -371,21 +369,20 @@ internal class NetEvents : IDisposable
     {
         // isMouse is true if it's CSI<, false otherwise
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  EscSeqRequests,
-                                  ref newConsoleKeyInfo,
-                                  ref key,
-                                  cki,
-                                  ref mod,
-                                  out string c1Control,
-                                  out string code,
-                                  out string [] values,
-                                  out string terminating,
-                                  out bool isMouse,
-                                  out List<MouseFlags> mouseFlags,
-                                  out Point pos,
-                                  out AnsiEscapeSequenceRequestStatus? seqReqStatus,
-                                  (f, p) => HandleMouseEvent (MapMouseFlags (f), p)
-                                 );
+                                                     ref newConsoleKeyInfo,
+                                                     ref key,
+                                                     cki,
+                                                     ref mod,
+                                                     out string c1Control,
+                                                     out string code,
+                                                     out string [] values,
+                                                     out string terminating,
+                                                     out bool isMouse,
+                                                     out List<MouseFlags> mouseFlags,
+                                                     out Point pos,
+                                                     out AnsiEscapeSequenceRequestStatus? seqReqStatus,
+                                                     (f, p) => HandleMouseEvent (MapMouseFlags (f), p)
+                                                    );
 
         if (isMouse)
         {
@@ -413,7 +410,7 @@ internal class NetEvents : IDisposable
 
         if (!string.IsNullOrEmpty (AnsiEscapeSequenceRequestUtils.InvalidRequestTerminator))
         {
-            if (EscSeqRequests.Statuses.TryDequeue (out AnsiEscapeSequenceRequestStatus? result))
+            if (AnsiEscapeSequenceRequests.Statuses.TryDequeue (out AnsiEscapeSequenceRequestStatus? result))
             {
                 lock (result.AnsiRequest._responseLock)
                 {

+ 7 - 7
Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsConsole.cs

@@ -110,10 +110,10 @@ internal class WindowsConsole
                                 ansiSequence.Append (inputChar);
 
                                 // Check if the sequence has ended with an expected command terminator
-                                if (_mainLoop?.EscSeqRequests is { } && _mainLoop.EscSeqRequests.HasResponse (inputChar.ToString (), out AnsiEscapeSequenceRequestStatus? seqReqStatus))
+                                if (AnsiEscapeSequenceRequests.HasResponse (inputChar.ToString (), out AnsiEscapeSequenceRequestStatus? seqReqStatus))
                                 {
                                     // Finished reading the sequence and remove the enqueued request
-                                    _mainLoop.EscSeqRequests.Remove (seqReqStatus);
+                                    AnsiEscapeSequenceRequests.Remove (seqReqStatus);
 
                                     lock (seqReqStatus!.AnsiRequest._responseLock)
                                     {
@@ -130,9 +130,9 @@ internal class WindowsConsole
                     }
                 }
 
-                if (readingSequence && !raisedResponse && AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && _mainLoop?.EscSeqRequests is { Statuses.Count: > 0 })
+                if (readingSequence && !raisedResponse && AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && AnsiEscapeSequenceRequests.Statuses.Count > 0)
                 {
-                    _mainLoop.EscSeqRequests.Statuses.TryDequeue (out AnsiEscapeSequenceRequestStatus? seqReqStatus);
+                    AnsiEscapeSequenceRequests.Statuses.TryDequeue (out AnsiEscapeSequenceRequestStatus? seqReqStatus);
 
                     lock (seqReqStatus!.AnsiRequest._responseLock)
                     {
@@ -143,15 +143,15 @@ internal class WindowsConsole
 
                     _retries = 0;
                 }
-                else if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && _mainLoop?.EscSeqRequests is { Statuses.Count: > 0 })
+                else if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is null && AnsiEscapeSequenceRequests.Statuses.Count > 0)
                 {
                     if (_retries > 1)
                     {
-                        if (_mainLoop.EscSeqRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? seqReqStatus) && string.IsNullOrEmpty (seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
+                        if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? seqReqStatus) && string.IsNullOrEmpty (seqReqStatus.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
                         {
                             lock (seqReqStatus.AnsiRequest._responseLock)
                             {
-                                _mainLoop.EscSeqRequests.Statuses.TryDequeue (out _);
+                                AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
 
                                 seqReqStatus.AnsiRequest.RaiseResponseFromInput (null);
                                 // Clear the terminator for not be enqueued

+ 7 - 8
Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs

@@ -222,7 +222,9 @@ internal class WindowsDriver : ConsoleDriver
                                                      _waitAnsiResponse.Set ();
                                                  };
 
-                _mainLoopDriver.EscSeqRequests.Add (ansiRequest, this);
+                AnsiEscapeSequenceRequests.Add (ansiRequest);
+
+                WriteRaw (ansiRequest.Request);
 
                 _mainLoopDriver._forceRead = true;
             }
@@ -238,15 +240,15 @@ internal class WindowsDriver : ConsoleDriver
         {
             _mainLoopDriver._forceRead = false;
 
-            if (_mainLoopDriver.EscSeqRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
+            if (AnsiEscapeSequenceRequests.Statuses.TryPeek (out AnsiEscapeSequenceRequestStatus? request))
             {
-                if (_mainLoopDriver.EscSeqRequests.Statuses.Count > 0
+                if (AnsiEscapeSequenceRequests.Statuses.Count > 0
                     && string.IsNullOrEmpty (request.AnsiRequest.AnsiEscapeSequenceResponse?.Response))
                 {
                     lock (request.AnsiRequest._responseLock)
                     {
                         // Bad request or no response at all
-                        _mainLoopDriver.EscSeqRequests.Statuses.TryDequeue (out _);
+                        AnsiEscapeSequenceRequests.Statuses.TryDequeue (out _);
                     }
                 }
             }
@@ -257,10 +259,7 @@ internal class WindowsDriver : ConsoleDriver
         }
     }
 
-    internal override void WriteRaw (string ansi)
-    {
-        WinConsole?.WriteANSI (ansi);
-    }
+    internal override void WriteRaw (string ansi) { WinConsole?.WriteANSI (ansi); }
 
     #region Not Implemented
 

+ 17 - 16
Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsMainLoop.cs

@@ -1,5 +1,4 @@
 #nullable enable
-using System.Collections.Concurrent;
 
 namespace Terminal.Gui;
 
@@ -21,7 +20,8 @@ internal class WindowsMainLoop : IMainLoopDriver
     private readonly ManualResetEventSlim _eventReady = new (false);
 
     // The records that we keep fetching
-    private readonly BlockingCollection<WindowsConsole.InputRecord> _resultQueue = new (new ConcurrentQueue<WindowsConsole.InputRecord> ());
+    private readonly Queue<WindowsConsole.InputRecord> _resultQueue = new ();
+    private readonly ManualResetEventSlim _waitForProbe = new (false);
     private readonly WindowsConsole? _winConsole;
     private CancellationTokenSource _eventReadyTokenSource = new ();
     private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
@@ -38,8 +38,6 @@ internal class WindowsMainLoop : IMainLoopDriver
         }
     }
 
-    public AnsiEscapeSequenceRequests EscSeqRequests { get; } = new ();
-
     void IMainLoopDriver.Setup (MainLoop mainLoop)
     {
         _mainLoop = mainLoop;
@@ -59,6 +57,7 @@ internal class WindowsMainLoop : IMainLoopDriver
 
     bool IMainLoopDriver.EventsPending ()
     {
+        _waitForProbe.Set ();
 #if HACK_CHECK_WINCHANGED
         _winChange.Set ();
 #endif
@@ -105,10 +104,7 @@ internal class WindowsMainLoop : IMainLoopDriver
     {
         while (_resultQueue.Count > 0)
         {
-            if (_resultQueue.TryTake (out WindowsConsole.InputRecord dequeueResult))
-            {
-                ((WindowsDriver)_consoleDriver).ProcessInput (dequeueResult);
-            }
+            ((WindowsDriver)_consoleDriver).ProcessInput (_resultQueue.Dequeue ());
         }
 #if HACK_CHECK_WINCHANGED
         if (_winChanged)
@@ -135,7 +131,9 @@ internal class WindowsMainLoop : IMainLoopDriver
             }
         }
 
-        _resultQueue.Dispose ();
+        _waitForProbe?.Dispose ();
+
+        _resultQueue.Clear ();
 
         _eventReadyTokenSource.Cancel ();
         _eventReadyTokenSource.Dispose ();
@@ -156,9 +154,9 @@ internal class WindowsMainLoop : IMainLoopDriver
         {
             try
             {
-                if (_inputHandlerTokenSource.IsCancellationRequested)
+                if (_inputHandlerTokenSource.IsCancellationRequested && !_forceRead)
                 {
-                    return;
+                    _waitForProbe.Wait (_inputHandlerTokenSource.Token);
                 }
 
                 if (_resultQueue?.Count == 0 || _forceRead)
@@ -167,19 +165,22 @@ internal class WindowsMainLoop : IMainLoopDriver
 
                     if (result.HasValue)
                     {
-                        _resultQueue!.Add (result.Value);
+                        _resultQueue!.Enqueue (result.Value);
                     }
                 }
 
-                if (!_inputHandlerTokenSource.IsCancellationRequested && _resultQueue?.Count > 0)
-                {
-                    _eventReady.Set ();
-                }
             }
             catch (OperationCanceledException)
             {
                 return;
             }
+            finally
+            {
+                if (_inputHandlerTokenSource is { IsCancellationRequested: false })
+                {
+                    _eventReady.Set ();
+                }
+            }
         }
     }
 

+ 340 - 359
UnitTests/Input/AnsiEscapeSequenceRequestUtilsTests.cs

@@ -10,7 +10,6 @@ public class AnsiEscapeSequenceRequestUtilsTests
     private Point _arg2;
     private string _c1Control, _code, _terminating;
     private ConsoleKeyInfo [] _cki;
-    private AnsiEscapeSequenceRequests _escSeqReqProc;
     private bool _isKeyMouse;
     [CanBeNull]
     private AnsiEscapeSequenceRequestStatus _seqReqStatus;
@@ -30,22 +29,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         var expectedCki = new ConsoleKeyInfo ('\u001b', ConsoleKey.Escape, false, false, false);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.Escape, _key);
         Assert.Equal (0, (int)_mod);
@@ -65,22 +63,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\u0012', ConsoleKey.R, false, true, true);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.R, _key);
         Assert.Equal (ConsoleModifiers.Alt | ConsoleModifiers.Control, _mod);
@@ -100,22 +97,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('r', ConsoleKey.R, false, true, false);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.R, _key);
         Assert.Equal (ConsoleModifiers.Alt, _mod);
@@ -140,22 +136,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\0', ConsoleKey.F3, false, false, false);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.F3, _key);
         Assert.Equal (0, (int)_mod);
@@ -186,22 +181,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\0', ConsoleKey.F3, true, false, false);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.F3, _key);
         Assert.Equal (ConsoleModifiers.Shift, _mod);
@@ -232,22 +226,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\0', ConsoleKey.F3, false, true, false);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.F3, _key);
         Assert.Equal (ConsoleModifiers.Alt, _mod);
@@ -278,22 +271,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\0', ConsoleKey.F3, true, true, false);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.F3, _key);
         Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt, _mod);
@@ -324,22 +316,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\0', ConsoleKey.F3, false, false, true);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.F3, _key);
         Assert.Equal (ConsoleModifiers.Control, _mod);
@@ -370,22 +361,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\0', ConsoleKey.F3, true, false, true);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.F3, _key);
         Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Control, _mod);
@@ -416,22 +406,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\0', ConsoleKey.F3, false, true, true);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.F3, _key);
         Assert.Equal (ConsoleModifiers.Alt | ConsoleModifiers.Control, _mod);
@@ -462,22 +451,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = new ('\0', ConsoleKey.F3, true, true, true);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.F3, _key);
         Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control, _mod);
@@ -511,22 +499,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = default (ConsoleKeyInfo);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (0, (int)_key);
         Assert.Equal (0, (int)_mod);
@@ -561,22 +548,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = default (ConsoleKeyInfo);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (0, (int)_key);
         Assert.Equal (0, (int)_mod);
@@ -616,22 +602,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = default (ConsoleKeyInfo);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (0, (int)_key);
         Assert.Equal (0, (int)_mod);
@@ -664,22 +649,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = default (ConsoleKeyInfo);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (0, (int)_key);
         Assert.Equal (0, (int)_mod);
@@ -719,22 +703,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = default (ConsoleKeyInfo);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (0, (int)_key);
         Assert.Equal (0, (int)_mod);
@@ -788,22 +771,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         expectedCki = default (ConsoleKeyInfo);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (0, (int)_key);
         Assert.Equal (0, (int)_mod);
@@ -823,9 +805,9 @@ public class AnsiEscapeSequenceRequestUtilsTests
 
         ClearAll ();
 
-        Assert.Null (_escSeqReqProc);
-        _escSeqReqProc = new ();
-        _escSeqReqProc.Add (new () { Request = "", Terminator = "t" });
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
+        AnsiEscapeSequenceRequests.Clear ();
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
 
         _cki = new ConsoleKeyInfo []
         {
@@ -841,26 +823,25 @@ public class AnsiEscapeSequenceRequestUtilsTests
             new ('t', 0, false, false, false)
         };
         expectedCki = default (ConsoleKeyInfo);
-        Assert.Single (_escSeqReqProc.Statuses);
-        Assert.Equal ("t", _escSeqReqProc.Statuses.ToArray () [^1].AnsiRequest.Terminator);
+        Assert.Single (AnsiEscapeSequenceRequests.Statuses);
+        Assert.Equal ("t", AnsiEscapeSequenceRequests.Statuses.ToArray () [^1].AnsiRequest.Terminator);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Empty (_escSeqReqProc.Statuses);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (0, (int)_key);
         Assert.Equal (0, (int)_mod);
@@ -909,22 +890,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         var expectedCki = new ConsoleKeyInfo (keyChar, consoleKey, shift, alt, control);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (consoleKey, _key);
 
@@ -976,22 +956,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         ConsoleKeyInfo expectedCki = default;
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.None, _key);
         Assert.Equal (ConsoleModifiers.None, _mod);
@@ -1019,23 +998,25 @@ public class AnsiEscapeSequenceRequestUtilsTests
 
         expectedCki = default;
 
+        // Add a request to avoid assert failure in the DecodeEscSeq method
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (ConsoleKey.None, _key);
 
@@ -1047,6 +1028,7 @@ public class AnsiEscapeSequenceRequestUtilsTests
         Assert.False (_isKeyMouse);
         Assert.Equal ([0], _mouseFlags);
         Assert.Equal (Point.Empty, _pos);
+        AnsiEscapeSequenceRequests.HasResponse ("t", out _seqReqStatus);
         Assert.Null (_seqReqStatus);
         Assert.Equal (0, (int)_arg1);
         Assert.Equal (Point.Empty, _arg2);
@@ -1073,22 +1055,21 @@ public class AnsiEscapeSequenceRequestUtilsTests
         var expectedCki = new ConsoleKeyInfo (keyChar, consoleKey, shift, alt, control);
 
         AnsiEscapeSequenceRequestUtils.DecodeEscSeq (
-                                  _escSeqReqProc,
-                                  ref _newConsoleKeyInfo,
-                                  ref _key,
-                                  _cki,
-                                  ref _mod,
-                                  out _c1Control,
-                                  out _code,
-                                  out _values,
-                                  out _terminating,
-                                  out _isKeyMouse,
-                                  out _mouseFlags,
-                                  out _pos,
-                                  out _seqReqStatus,
-                                  ProcessContinuousButtonPressed
-                                 );
-        Assert.Null (_escSeqReqProc);
+                                                     ref _newConsoleKeyInfo,
+                                                     ref _key,
+                                                     _cki,
+                                                     ref _mod,
+                                                     out _c1Control,
+                                                     out _code,
+                                                     out _values,
+                                                     out _terminating,
+                                                     out _isKeyMouse,
+                                                     out _mouseFlags,
+                                                     out _pos,
+                                                     out _seqReqStatus,
+                                                     ProcessContinuousButtonPressed
+                                                    );
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
         Assert.Equal (expectedCki, _newConsoleKeyInfo);
         Assert.Equal (consoleKey, _key);
 
@@ -1559,7 +1540,7 @@ public class AnsiEscapeSequenceRequestUtilsTests
 
     private void ClearAll ()
     {
-        _escSeqReqProc = default (AnsiEscapeSequenceRequests);
+        AnsiEscapeSequenceRequests.Clear ();
         _newConsoleKeyInfo = default (ConsoleKeyInfo);
         _key = default (ConsoleKey);
         _cki = default (ConsoleKeyInfo []);

+ 40 - 38
UnitTests/Input/AnsiEscapeSequenceRequestsTests.cs

@@ -5,66 +5,68 @@ public class AnsiEscapeSequenceRequestsTests
     [Fact]
     public void Add_Tests ()
     {
-        var escSeqReq = new AnsiEscapeSequenceRequests ();
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        Assert.Single (escSeqReq.Statuses);
-        Assert.Equal ("t", escSeqReq.Statuses.ToArray () [^1].AnsiRequest.Terminator);
+        AnsiEscapeSequenceRequests.Clear ();
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        Assert.Single (AnsiEscapeSequenceRequests.Statuses);
+        Assert.Equal ("t", AnsiEscapeSequenceRequests.Statuses.ToArray () [^1].AnsiRequest.Terminator);
 
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        Assert.Equal (2, escSeqReq.Statuses.Count);
-        Assert.Equal ("t", escSeqReq.Statuses.ToArray () [^1].AnsiRequest.Terminator);
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        Assert.Equal (2, AnsiEscapeSequenceRequests.Statuses.Count);
+        Assert.Equal ("t", AnsiEscapeSequenceRequests.Statuses.ToArray () [^1].AnsiRequest.Terminator);
 
-        escSeqReq = new ();
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        Assert.Equal (2, escSeqReq.Statuses.Count);
-        Assert.Equal ("t", escSeqReq.Statuses.ToArray () [^1].AnsiRequest.Terminator);
+        AnsiEscapeSequenceRequests.Clear ();
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        Assert.Equal (2, AnsiEscapeSequenceRequests.Statuses.Count);
+        Assert.Equal ("t", AnsiEscapeSequenceRequests.Statuses.ToArray () [^1].AnsiRequest.Terminator);
 
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        Assert.Equal (3, escSeqReq.Statuses.Count);
-        Assert.Equal ("t", escSeqReq.Statuses.ToArray () [^1].AnsiRequest.Terminator);
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        Assert.Equal (3, AnsiEscapeSequenceRequests.Statuses.Count);
+        Assert.Equal ("t", AnsiEscapeSequenceRequests.Statuses.ToArray () [^1].AnsiRequest.Terminator);
     }
 
     [Fact]
     public void Constructor_Defaults ()
     {
-        var escSeqReq = new AnsiEscapeSequenceRequests ();
-        Assert.NotNull (escSeqReq.Statuses);
-        Assert.Empty (escSeqReq.Statuses);
+        AnsiEscapeSequenceRequests.Clear ();
+        Assert.NotNull (AnsiEscapeSequenceRequests.Statuses);
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
     }
 
     [Fact]
     public void Remove_Tests ()
     {
-        var escSeqReq = new AnsiEscapeSequenceRequests ();
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        escSeqReq.HasResponse ("t", out AnsiEscapeSequenceRequestStatus seqReqStatus);
-        escSeqReq.Remove (seqReqStatus);
-        Assert.Empty (escSeqReq.Statuses);
+        AnsiEscapeSequenceRequests.Clear ();
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        AnsiEscapeSequenceRequests.HasResponse ("t", out AnsiEscapeSequenceRequestStatus seqReqStatus);
+        AnsiEscapeSequenceRequests.Remove (seqReqStatus);
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
 
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        escSeqReq.HasResponse ("t", out seqReqStatus);
-        escSeqReq.Remove (seqReqStatus);
-        Assert.Single (escSeqReq.Statuses);
-        Assert.Equal ("t", escSeqReq.Statuses.ToArray () [^1].AnsiRequest.Terminator);
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        AnsiEscapeSequenceRequests.HasResponse ("t", out seqReqStatus);
+        AnsiEscapeSequenceRequests.Remove (seqReqStatus);
+        Assert.Single (AnsiEscapeSequenceRequests.Statuses);
+        Assert.Equal ("t", AnsiEscapeSequenceRequests.Statuses.ToArray () [^1].AnsiRequest.Terminator);
 
-        escSeqReq.HasResponse ("t", out seqReqStatus);
-        escSeqReq.Remove (seqReqStatus);
-        Assert.Empty (escSeqReq.Statuses);
+        AnsiEscapeSequenceRequests.HasResponse ("t", out seqReqStatus);
+        AnsiEscapeSequenceRequests.Remove (seqReqStatus);
+        Assert.Empty (AnsiEscapeSequenceRequests.Statuses);
     }
 
     [Fact]
     public void Requested_Tests ()
     {
-        var escSeqReq = new AnsiEscapeSequenceRequests ();
-        Assert.False (escSeqReq.HasResponse ("t", out AnsiEscapeSequenceRequestStatus seqReqStatus));
+        AnsiEscapeSequenceRequests.Clear ();
+        Assert.False (AnsiEscapeSequenceRequests.HasResponse ("t", out AnsiEscapeSequenceRequestStatus seqReqStatus));
         Assert.Null (seqReqStatus);
 
-        escSeqReq.Add (new () { Request = "", Terminator = "t" });
-        Assert.False (escSeqReq.HasResponse ("r", out seqReqStatus));
-        Assert.Null (seqReqStatus);
-        Assert.True (escSeqReq.HasResponse ("t", out seqReqStatus));
+        AnsiEscapeSequenceRequests.Add (new () { Request = "", Terminator = "t" });
+        Assert.False (AnsiEscapeSequenceRequests.HasResponse ("r", out seqReqStatus));
+        Assert.NotNull (seqReqStatus);
+        Assert.Equal ("t", seqReqStatus.AnsiRequest.Terminator);
+        Assert.True (AnsiEscapeSequenceRequests.HasResponse ("t", out seqReqStatus));
         Assert.NotNull (seqReqStatus);
+        Assert.Equal ("t", seqReqStatus.AnsiRequest.Terminator);
     }
 }