From 8c5832f8f143f058839783abe86941f74f1b87ae Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 9 Nov 2024 20:53:13 +0000 Subject: [PATCH] Fix NetDriver to also work well in Linux. --- .../ConsoleDrivers/NetDriver/NetDriver.cs | 12 ++- .../ConsoleDrivers/NetDriver/NetEvents.cs | 90 +++++++++++++++---- .../ConsoleDrivers/NetDriver/NetMainLoop.cs | 43 +++++---- 3 files changed, 107 insertions(+), 38 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs index b61ed5693..607028811 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver/NetDriver.cs @@ -756,7 +756,17 @@ internal class NetDriver : ConsoleDriver _mainLoopDriver._netEvents._forceRead = true; } - _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token); + + if (!_ansiResponseTokenSource.IsCancellationRequested) + { + lock (ansiRequest._responseLock) + { + _mainLoopDriver._waitForProbe.Set (); + _mainLoopDriver._netEvents._waitForStart.Set (); + } + + _waitAnsiResponse.Wait (_ansiResponseTokenSource.Token); + } } catch (OperationCanceledException) { diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver/NetEvents.cs b/Terminal.Gui/ConsoleDrivers/NetDriver/NetEvents.cs index d15be6efa..e5a17477f 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver/NetEvents.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver/NetEvents.cs @@ -1,13 +1,14 @@ #nullable enable -using System.Collections.Concurrent; using System.Diagnostics.CodeAnalysis; namespace Terminal.Gui; internal class NetEvents : IDisposable { + private readonly ManualResetEventSlim _inputReady = new (false); private CancellationTokenSource? _inputReadyCancellationTokenSource; - private readonly BlockingCollection _inputQueue = new (new ConcurrentQueue ()); + internal readonly ManualResetEventSlim _waitForStart = new (false); + private readonly Queue _inputQueue = new (); private readonly ConsoleDriver _consoleDriver; private ConsoleKeyInfo []? _cki; private bool _isEscSeq; @@ -30,14 +31,34 @@ internal class NetEvents : IDisposable { while (_inputReadyCancellationTokenSource is { }) { + _waitForStart.Set (); + try { - return _inputQueue.Take (_inputReadyCancellationTokenSource.Token); + if (!_inputReadyCancellationTokenSource.Token.IsCancellationRequested) + { + if (_inputQueue.Count == 0) + { + _inputReady.Wait (_inputReadyCancellationTokenSource.Token); + } + } + + if (_inputQueue.Count > 0) + { + return _inputQueue.Dequeue (); + } } catch (OperationCanceledException) { return null; } + finally + { + if (_inputReadyCancellationTokenSource is { IsCancellationRequested: false }) + { + _inputReady.Reset (); + } + } #if PROCESS_REQUEST _neededProcessRequest = false; @@ -102,6 +123,25 @@ internal class NetEvents : IDisposable { while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false }) { + try + { + if (!_forceRead) + { + _waitForStart.Wait (_inputReadyCancellationTokenSource.Token); + } + } + catch (OperationCanceledException) + { + return; + } + finally + { + if (_inputReadyCancellationTokenSource is { IsCancellationRequested: false }) + { + _waitForStart.Reset (); + } + } + try { if (_inputQueue.Count == 0 || _forceRead) @@ -125,7 +165,9 @@ internal class NetEvents : IDisposable if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is { }) { + _cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki); _cki = AnsiEscapeSequenceRequestUtils.InsertArray (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos, _cki); + AnsiEscapeSequenceRequestUtils.IncompleteCkInfos = null; } if ((consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq) @@ -205,6 +247,8 @@ internal class NetEvents : IDisposable break; } } + + _inputReady.Set (); } catch (OperationCanceledException) { @@ -214,12 +258,12 @@ internal class NetEvents : IDisposable void ProcessMapConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo) { - _inputQueue.Add ( - new () - { - EventType = EventType.Key, ConsoleKeyInfo = AnsiEscapeSequenceRequestUtils.MapConsoleKeyInfo (consoleKeyInfo) - } - ); + _inputQueue.Enqueue ( + new () + { + EventType = EventType.Key, ConsoleKeyInfo = AnsiEscapeSequenceRequestUtils.MapConsoleKeyInfo (consoleKeyInfo) + } + ); _isEscSeq = false; } } @@ -265,6 +309,11 @@ internal class NetEvents : IDisposable try { RequestWindowSize (_inputReadyCancellationTokenSource.Token); + + if (_inputQueue.Count > 0) + { + _inputReady.Set (); + } } catch (OperationCanceledException) { @@ -289,12 +338,12 @@ internal class NetEvents : IDisposable int w = Math.Max (winWidth, 0); int h = Math.Max (winHeight, 0); - _inputQueue.Add ( - new () - { - EventType = EventType.WindowSize, WindowSizeEvent = new () { Size = new (w, h) } - } - ); + _inputQueue.Enqueue ( + new () + { + EventType = EventType.WindowSize, WindowSizeEvent = new () { Size = new (w, h) } + } + ); return true; } @@ -569,9 +618,9 @@ internal class NetEvents : IDisposable { var mouseEvent = new MouseEvent { Position = pos, ButtonState = buttonState }; - _inputQueue.Add ( - new () { EventType = EventType.Mouse, MouseEvent = mouseEvent } - ); + _inputQueue.Enqueue ( + new () { EventType = EventType.Mouse, MouseEvent = mouseEvent } + ); } public enum EventType @@ -684,7 +733,7 @@ internal class NetEvents : IDisposable { var inputResult = new InputResult { EventType = EventType.Key, ConsoleKeyInfo = cki }; - _inputQueue.Add (inputResult); + _inputQueue.Enqueue (inputResult); } public void Dispose () @@ -693,6 +742,9 @@ internal class NetEvents : IDisposable _inputReadyCancellationTokenSource?.Dispose (); _inputReadyCancellationTokenSource = null; + _inputReady.Dispose (); + _waitForStart.Dispose (); + try { // throws away any typeahead that has been typed by diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs b/Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs index 624aec3ce..0b51d2f4d 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver/NetMainLoop.cs @@ -1,5 +1,4 @@ #nullable enable -using System.Collections.Concurrent; namespace Terminal.Gui; @@ -16,9 +15,10 @@ internal class NetMainLoop : IMainLoopDriver internal Action? ProcessInput; private readonly ManualResetEventSlim _eventReady = new (false); - private readonly CancellationTokenSource _inputHandlerTokenSource = new (); - private readonly BlockingCollection _resultQueue = new (new ConcurrentQueue ()); + internal readonly ManualResetEventSlim _waitForProbe = new (false); private readonly CancellationTokenSource _eventReadyTokenSource = new (); + private readonly CancellationTokenSource _inputHandlerTokenSource = new (); + private readonly Queue _resultQueue = new (); private MainLoop? _mainLoop; /// Initializes the class with the console driver. @@ -48,6 +48,8 @@ internal class NetMainLoop : IMainLoopDriver bool IMainLoopDriver.EventsPending () { + _waitForProbe.Set (); + if (_resultQueue.Count > 0 || _mainLoop!.CheckTimersAndIdleHandlers (out int waitTimeout)) { return true; @@ -60,6 +62,13 @@ internal class NetMainLoop : IMainLoopDriver // Note: ManualResetEventSlim.Wait will wait indefinitely if the timeout is -1. The timeout is -1 when there // are no timers, but there IS an idle handler waiting. _eventReady.Wait (waitTimeout, _eventReadyTokenSource.Token); + + _eventReadyTokenSource.Token.ThrowIfCancellationRequested (); + + if (!_eventReadyTokenSource.IsCancellationRequested) + { + return _resultQueue.Count > 0 || _mainLoop.CheckTimersAndIdleHandlers (out _); + } } } catch (OperationCanceledException) @@ -71,13 +80,6 @@ internal class NetMainLoop : IMainLoopDriver _eventReady.Reset (); } - _eventReadyTokenSource.Token.ThrowIfCancellationRequested (); - - if (!_eventReadyTokenSource.IsCancellationRequested) - { - return _resultQueue.Count > 0 || _mainLoop.CheckTimersAndIdleHandlers (out _); - } - // If cancellation was requested then always return true return true; } @@ -86,10 +88,7 @@ internal class NetMainLoop : IMainLoopDriver { while (_resultQueue.Count > 0) { - if (_resultQueue.TryTake (out NetEvents.InputResult dequeueResult)) - { - ProcessInput?.Invoke (dequeueResult); - } + ProcessInput?.Invoke (_resultQueue.Dequeue ()); } } @@ -101,8 +100,9 @@ internal class NetMainLoop : IMainLoopDriver _eventReadyTokenSource.Dispose (); _eventReady.Dispose (); + _waitForProbe.Dispose (); - _resultQueue.Dispose(); + _resultQueue.Clear (); _netEvents?.Dispose (); _netEvents = null; @@ -115,9 +115,9 @@ internal class NetMainLoop : IMainLoopDriver { try { - if (_inputHandlerTokenSource.IsCancellationRequested) + if (!_inputHandlerTokenSource.IsCancellationRequested && !_netEvents!._forceRead) { - return; + _waitForProbe.Wait (_inputHandlerTokenSource.Token); } if (_resultQueue?.Count == 0 || _netEvents!._forceRead) @@ -126,7 +126,7 @@ internal class NetMainLoop : IMainLoopDriver if (result.HasValue) { - _resultQueue?.Add (result.Value); + _resultQueue?.Enqueue (result.Value); } } @@ -139,6 +139,13 @@ internal class NetMainLoop : IMainLoopDriver { return; } + finally + { + if (_inputHandlerTokenSource is { IsCancellationRequested: false }) + { + _waitForProbe.Reset (); + } + } } } }