浏览代码

WIP Building after merge conflict resolved - but does it work?

tznind 8 月之前
父节点
当前提交
27b15ec8ee

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

@@ -52,7 +52,7 @@ public class AnsiEscapeSequenceRequest
     ///     Only call this method from the main UI thread. You should use <see cref="AnsiRequestScheduler"/> if
     ///     sending many requests.
     /// </summary>
-    public void Send () { Application.Driver?.RawWrite (Request); }
+    public void Send () { Application.Driver?.WriteRaw (Request); }
 
 
     /// <summary>

+ 1 - 1
Terminal.Gui/ConsoleDrivers/AnsiResponseParser/AnsiRequestScheduler.cs

@@ -9,7 +9,7 @@ namespace Terminal.Gui;
 ///     to prevent console becoming unresponsive and handles evicting ignored requests (no reply from
 ///     terminal).
 /// </summary>
-internal class AnsiRequestScheduler
+public class AnsiRequestScheduler
 {
     private readonly IAnsiResponseParser _parser;
 

+ 2 - 8
Terminal.Gui/ConsoleDrivers/ConsoleDriver.cs

@@ -48,7 +48,7 @@ public abstract class ConsoleDriver : IConsoleDriver
     /// <summary>
     /// How long after Esc has been pressed before we give up on getting an Ansi escape sequence
     /// </summary>
-    internal TimeSpan EscTimeout = TimeSpan.FromMilliseconds (50);
+    public TimeSpan EscTimeout { get; } = TimeSpan.FromMilliseconds (50);
 
     // As performance is a concern, we keep track of the dirty lines and only refresh those.
     // This is in addition to the dirty flag on each cell.
@@ -710,16 +710,10 @@ public abstract class ConsoleDriver : IConsoleDriver
 
     internal abstract IAnsiResponseParser GetParser ();
 
-    internal AnsiRequestScheduler GetRequestScheduler ()
+    public AnsiRequestScheduler GetRequestScheduler ()
     {
         // Lazy initialization because GetParser is virtual
         return _scheduler ??= new (GetParser ());
     }
 
-    /// <summary>
-    /// Writes the given <paramref name="str"/> directly to the console (rather than the output
-    /// draw buffer).
-    /// </summary>
-    /// <param name="str"></param>
-    internal abstract void RawWrite (string str);
 }

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

@@ -116,11 +116,6 @@ internal class CursesDriver : ConsoleDriver
         }
     }
 
-    /// <inheritdoc />
-    internal override void RawWrite (string str)
-    {
-        Console.Out.Write (str);
-    }
 
     public override void Suspend ()
     {

+ 0 - 3
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -400,9 +400,6 @@ public class FakeDriver : ConsoleDriver
     /// <inheritdoc />
     internal override IAnsiResponseParser GetParser () => _parser;
 
-    /// <inheritdoc />
-    internal override void RawWrite (string str) { }
-
     public void SetBufferSize (int width, int height)
     {
         FakeConsole.SetBufferSize (width, height);

+ 13 - 0
Terminal.Gui/ConsoleDrivers/IConsoleDriver.cs

@@ -292,4 +292,17 @@ public interface IConsoleDriver
     /// <param name="alt">If <see langword="true"/> simulates the Alt key being pressed.</param>
     /// <param name="ctrl">If <see langword="true"/> simulates the Ctrl key being pressed.</param>
     void SendKeys (char keyChar, ConsoleKey key, bool shift, bool alt, bool ctrl);
+
+    /// <summary>
+    /// How long after Esc has been pressed before we give up on getting an Ansi escape sequence
+    /// </summary>
+    public TimeSpan EscTimeout { get; }
+
+    /// <summary>
+    /// Queues the given <paramref name="request"/> for execution
+    /// </summary>
+    /// <param name="request"></param>
+    public void QueueAnsiRequest (AnsiEscapeSequenceRequest request);
+
+    public AnsiRequestScheduler GetRequestScheduler ();
 }

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

@@ -227,10 +227,6 @@ internal class NetDriver : ConsoleDriver
     internal override IAnsiResponseParser GetParser () => _mainLoopDriver._netEvents.Parser;
     internal NetMainLoop? _mainLoopDriver;
     /// <inheritdoc />
-    internal override void RawWrite (string str)
-    {
-        Console.Write (str);
-    }
 
     
 

+ 2 - 2
Terminal.Gui/ConsoleDrivers/NetDriver/NetEvents.cs

@@ -11,11 +11,11 @@ internal class NetEvents : IDisposable
     //CancellationTokenSource _waitForStartCancellationTokenSource;
     private readonly ManualResetEventSlim _winChange = new (false);
     private readonly BlockingCollection<InputResult?> _inputQueue = new (new ConcurrentQueue<InputResult?> ());
-    private readonly ConsoleDriver _consoleDriver;
+    private readonly IConsoleDriver _consoleDriver;
 
     public AnsiResponseParser<ConsoleKeyInfo> Parser { get; private set; } = new ();
 
-    public NetEvents (ConsoleDriver consoleDriver)
+    public NetEvents (IConsoleDriver consoleDriver)
     {
         _consoleDriver = consoleDriver ?? throw new ArgumentNullException (nameof (consoleDriver));
 

+ 79 - 34
Terminal.Gui/ConsoleDrivers/WindowsDriver/WindowsDriver.cs

@@ -20,6 +20,7 @@ using System.ComponentModel;
 using System.Diagnostics;
 using System.Runtime.InteropServices;
 using static Terminal.Gui.ConsoleDrivers.ConsoleKeyMapping;
+using static Terminal.Gui.SpinnerStyle;
 
 namespace Terminal.Gui;
 
@@ -187,7 +188,14 @@ internal class WindowsDriver : ConsoleDriver
         }
     }
 
-    public override void WriteRaw (string ansi) { WinConsole?.WriteANSI (ansi); }
+    /// <inheritdoc />
+    internal override IAnsiResponseParser GetParser () => _parser;
+
+
+    public override void WriteRaw (string str)
+    {
+        WinConsole?.WriteANSI (str);
+    }
 
     #region Not Implemented
 
@@ -217,11 +225,6 @@ internal class WindowsDriver : ConsoleDriver
 
     public override void UpdateCursor ()
     {
-        if (RunningUnitTests)
-        {
-            return;
-        }
-
         if (Col < 0 || Row < 0 || Col >= Cols || Row >= Rows)
         {
             GetCursorVisibility (out CursorVisibility cursorVisibility);
@@ -480,14 +483,25 @@ internal class WindowsDriver : ConsoleDriver
 
         if (!RunningUnitTests)
         {
-            WinConsole?.SetInitialCursorVisibility ();
+        WinConsole?.SetInitialCursorVisibility ();
         }
 
         return new MainLoop (_mainLoopDriver);
     }
 
+    private AnsiResponseParser<WindowsConsole.InputRecord> _parser = new ();
+
     internal void ProcessInput (WindowsConsole.InputRecord inputEvent)
     {
+        foreach (var e in Parse (inputEvent))
+        {
+            ProcessInputAfterParsing (e);
+        }
+    }
+
+    internal void ProcessInputAfterParsing (WindowsConsole.InputRecord inputEvent)
+    {
+
         switch (inputEvent.EventType)
         {
             case WindowsConsole.EventType.Key:
@@ -510,22 +524,16 @@ internal class WindowsDriver : ConsoleDriver
                     break;
                 }
 
-                if (inputEvent.KeyEvent.bKeyDown)
-                {
-                    // Avoid sending repeat key down events
-                    OnKeyDown (new Key (map));
-                }
-                else
-                {
-                    OnKeyUp (new Key (map));
-                }
+                // This follows convention in NetDriver
+                OnKeyDown (new Key (map));
+                OnKeyUp (new Key (map));
 
                 break;
 
             case WindowsConsole.EventType.Mouse:
                 MouseEventArgs me = ToDriverMouse (inputEvent.MouseEvent);
 
-                if (me.Flags == MouseFlags.None)
+                if (me is null || me.Flags == MouseFlags.None)
                 {
                     break;
                 }
@@ -563,6 +571,43 @@ internal class WindowsDriver : ConsoleDriver
         }
     }
 
+    private IEnumerable<WindowsConsole.InputRecord> Parse (WindowsConsole.InputRecord inputEvent)
+    {
+        if (inputEvent.EventType != WindowsConsole.EventType.Key)
+        {
+            yield return inputEvent;
+            yield break;
+        }
+
+        // Swallow key up events - they are unreliable
+        if (!inputEvent.KeyEvent.bKeyDown)
+        {
+            yield break;
+        }
+
+        foreach (var i in ShouldRelease ())
+        {
+            yield return i;
+        }
+
+        foreach (Tuple<char, WindowsConsole.InputRecord> output in
+                 _parser.ProcessInput (Tuple.Create (inputEvent.KeyEvent.UnicodeChar, inputEvent)))
+        {
+            yield return output.Item2;
+        }
+    }
+
+    public IEnumerable<WindowsConsole.InputRecord> ShouldRelease ()
+    {
+        if (_parser.State == AnsiResponseParserState.ExpectingBracket &&
+            DateTime.Now - _parser.StateChangedAt > EscTimeout)
+        {
+            return _parser.Release ().Select (o => o.Item2);
+        }
+
+        return [];
+    }
+
 #if HACK_CHECK_WINCHANGED
     private void ChangeWin (object s, SizeChangedEventArgs e)
     {
@@ -661,13 +706,13 @@ internal class WindowsDriver : ConsoleDriver
 
                 if (keyInfo.KeyChar == 0)
                 {
-                    // If the keyChar is 0, keyInfo.Key value is not a printable character.
+                    // If the keyChar is 0, keyInfo.Key value is not a printable character. 
 
-                    // Dead keys (diacritics) are indicated by setting the top bit of the return value.
+                    // Dead keys (diacritics) are indicated by setting the top bit of the return value. 
                     if ((mapResult & 0x80000000) != 0)
                     {
                         // Dead key (e.g. Oem2 '~'/'^' on POR keyboard)
-                        // Option 1: Throw it out.
+                        // Option 1: Throw it out. 
                         //    - Apps will never see the dead keys
                         //    - If user presses a key that can be combined with the dead key ('a'), the right thing happens (app will see '�').
                         //      - NOTE: With Dead Keys, KeyDown != KeyUp. The KeyUp event will have just the base char ('a').
@@ -688,7 +733,7 @@ internal class WindowsDriver : ConsoleDriver
                     if (keyInfo.Modifiers != 0)
                     {
                         // These Oem keys have well-defined chars. We ensure the representative char is used.
-                        // If we don't do this, then on some keyboard layouts the wrong char is
+                        // If we don't do this, then on some keyboard layouts the wrong char is 
                         // returned (e.g. on ENG OemPlus un-shifted is =, not +). This is important
                         // for key persistence ("Ctrl++" vs. "Ctrl+=").
                         mappedChar = keyInfo.Key switch
@@ -754,11 +799,11 @@ internal class WindowsDriver : ConsoleDriver
                     if (keyInfo.KeyChar <= 'Z')
                     {
                         return (KeyCode)keyInfo.Key | KeyCode.ShiftMask;
-                    }
+                }
 
                     // Always return the KeyChar because it may be an Á, À with Oem1, etc
                     return (KeyCode)keyInfo.KeyChar;
-                }
+            }
             }
 
             if (keyInfo.KeyChar <= 'z')
@@ -947,12 +992,12 @@ internal class WindowsDriver : ConsoleDriver
         {
             // TODO: This makes IConsoleDriver dependent on Application, which is not ideal. This should be moved to Application.
             Application.MainLoop!.AddIdle (
-                                           () =>
-                                           {
-                                               Task.Run (async () => await ProcessButtonDoubleClickedAsync ());
+                                          () =>
+                                          {
+                                              Task.Run (async () => await ProcessButtonDoubleClickedAsync ());
 
-                                               return false;
-                                           });
+                                              return false;
+                                          });
         }
 
         // The ButtonState member of the MouseEvent structure has bit corresponding to each mouse button.
@@ -1019,12 +1064,12 @@ internal class WindowsDriver : ConsoleDriver
             {
                 // TODO: This makes IConsoleDriver dependent on Application, which is not ideal. This should be moved to Application.
                 Application.MainLoop!.AddIdle (
-                                               () =>
-                                               {
-                                                   Task.Run (async () => await ProcessContinuousButtonPressedAsync (mouseFlag));
+                                              () =>
+                                              {
+                                                  Task.Run (async () => await ProcessContinuousButtonPressedAsync (mouseFlag));
 
-                                                   return false;
-                                               });
+                                                  return false;
+                                              });
             }
         }
         else if (_lastMouseButtonPressed != null
@@ -1187,4 +1232,4 @@ internal class WindowsDriver : ConsoleDriver
             Flags = mouseFlag
         };
     }
-}
+}

+ 1 - 1
UICatalog/Scenarios/AnsiRequestsScenario.cs

@@ -386,7 +386,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
                                              new ()
                                              {
                                                  Request = EscSeqUtils.CSI_SendDeviceAttributes.Request,
-                                                 Terminator = EscSeqUtils.CSI_ReportDeviceAttributes_Terminator,
+                                                 Terminator = EscSeqUtils.CSI_SendDeviceAttributes.Terminator,
                                                  ResponseReceived = HandleResponse
                                              });
         sends.Add (DateTime.Now);