Change to BlockingCollection, thanks to @tznind.

This commit is contained in:
BDisp
2024-11-07 13:04:11 +00:00
parent cc21bd461d
commit 3e952df5f7
3 changed files with 142 additions and 220 deletions

View File

@@ -754,17 +754,7 @@ internal class NetDriver : ConsoleDriver
_mainLoopDriver._netEvents._forceRead = true;
}
if (!_ansiResponseTokenSource.IsCancellationRequested)
{
_mainLoopDriver._netEvents._waitForStart.Set ();
if (!_mainLoopDriver._waitForProbe.IsSet)
{
_mainLoopDriver._waitForProbe.Set ();
}
_waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
}
_waitAnsiResponse.Wait (_ansiResponseTokenSource.Token);
}
catch (OperationCanceledException)
{

View File

@@ -6,13 +6,8 @@ namespace Terminal.Gui;
internal class NetEvents : IDisposable
{
private readonly ManualResetEventSlim _inputReady = new (false);
private CancellationTokenSource _inputReadyCancellationTokenSource;
internal readonly ManualResetEventSlim _waitForStart = new (false);
//CancellationTokenSource _waitForStartCancellationTokenSource;
private readonly ManualResetEventSlim _winChange = new (false);
private readonly ConcurrentQueue<InputResult?> _inputQueue = new ();
private readonly BlockingCollection<InputResult> _inputQueue = new (new ConcurrentQueue<InputResult> ());
private readonly ConsoleDriver _consoleDriver;
private ConsoleKeyInfo [] _cki;
private bool _isEscSeq;
@@ -33,41 +28,20 @@ internal class NetEvents : IDisposable
public InputResult? DequeueInput ()
{
while (_inputReadyCancellationTokenSource != null
&& !_inputReadyCancellationTokenSource.Token.IsCancellationRequested)
while (_inputReadyCancellationTokenSource is { })
{
_waitForStart.Set ();
_winChange.Set ();
try
{
if (!_inputReadyCancellationTokenSource.Token.IsCancellationRequested)
{
if (_inputQueue.Count == 0)
{
_inputReady.Wait (_inputReadyCancellationTokenSource.Token);
}
}
return _inputQueue.Take (_inputReadyCancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
return null;
}
finally
{
_inputReady.Reset ();
}
#if PROCESS_REQUEST
_neededProcessRequest = false;
#endif
if (_inputQueue.Count > 0)
{
if (_inputQueue.TryDequeue (out InputResult? result))
{
return result;
}
}
}
return null;
@@ -130,129 +104,120 @@ internal class NetEvents : IDisposable
{
try
{
if (!_forceRead)
if (_inputQueue.Count == 0 || _forceRead)
{
_waitForStart.Wait (_inputReadyCancellationTokenSource.Token);
ConsoleKey key = 0;
ConsoleModifiers mod = 0;
ConsoleKeyInfo newConsoleKeyInfo = default;
while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
{
ConsoleKeyInfo consoleKeyInfo;
try
{
consoleKeyInfo = ReadConsoleKeyInfo (_inputReadyCancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
return;
}
if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is { })
{
AnsiEscapeSequenceRequestUtils.InsertArray (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos, _cki);
}
if ((consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq)
|| (consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq))
{
if (_cki is null && consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq)
{
_cki = AnsiEscapeSequenceRequestUtils.ResizeArray (
new (
(char)KeyCode.Esc,
0,
false,
false,
false
),
_cki
);
}
_isEscSeq = true;
if ((_cki is { } && _cki [^1].KeyChar != Key.Esc && consoleKeyInfo.KeyChar != Key.Esc && consoleKeyInfo.KeyChar <= Key.Space)
|| (_cki is { } && _cki [^1].KeyChar != '\u001B' && consoleKeyInfo.KeyChar == 127)
|| (_cki is { } && char.IsLetter (_cki [^1].KeyChar) && char.IsLower (consoleKeyInfo.KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar))
|| (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar)))
{
ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
_cki = null;
_isEscSeq = false;
ProcessMapConsoleKeyInfo (consoleKeyInfo);
}
else
{
newConsoleKeyInfo = consoleKeyInfo;
_cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
if (Console.KeyAvailable)
{
continue;
}
ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
_cki = null;
_isEscSeq = false;
}
break;
}
if (consoleKeyInfo.KeyChar == (char)KeyCode.Esc && _isEscSeq && _cki is { })
{
ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
_cki = null;
if (Console.KeyAvailable)
{
_cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
}
else
{
ProcessMapConsoleKeyInfo (consoleKeyInfo);
}
break;
}
ProcessMapConsoleKeyInfo (consoleKeyInfo);
if (_retries > 0)
{
_retries = 0;
}
break;
}
}
}
catch (OperationCanceledException)
{
return;
}
_waitForStart.Reset ();
if (_inputQueue.Count == 0 || _forceRead)
{
ConsoleKey key = 0;
ConsoleModifiers mod = 0;
ConsoleKeyInfo newConsoleKeyInfo = default;
while (_inputReadyCancellationTokenSource is { IsCancellationRequested: false })
{
ConsoleKeyInfo consoleKeyInfo;
try
{
consoleKeyInfo = ReadConsoleKeyInfo (_inputReadyCancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
return;
}
if (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos is { })
{
AnsiEscapeSequenceRequestUtils.InsertArray (AnsiEscapeSequenceRequestUtils.IncompleteCkInfos, _cki);
}
if ((consoleKeyInfo.KeyChar == (char)KeyCode.Esc && !_isEscSeq)
|| (consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq))
{
if (_cki is null && consoleKeyInfo.KeyChar != (char)KeyCode.Esc && _isEscSeq)
{
_cki = AnsiEscapeSequenceRequestUtils.ResizeArray (
new ConsoleKeyInfo (
(char)KeyCode.Esc,
0,
false,
false,
false
),
_cki
);
}
_isEscSeq = true;
if ((_cki is { } && _cki [^1].KeyChar != Key.Esc && consoleKeyInfo.KeyChar != Key.Esc && consoleKeyInfo.KeyChar <= Key.Space)
|| (_cki is { } && _cki [^1].KeyChar != '\u001B' && consoleKeyInfo.KeyChar == 127)
|| (_cki is { } && char.IsLetter (_cki [^1].KeyChar) && char.IsLower (consoleKeyInfo.KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar))
|| (_cki is { Length: > 2 } && char.IsLetter (_cki [^1].KeyChar) && char.IsLetter (consoleKeyInfo.KeyChar)))
{
ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
_cki = null;
_isEscSeq = false;
ProcessMapConsoleKeyInfo (consoleKeyInfo);
}
else
{
newConsoleKeyInfo = consoleKeyInfo;
_cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
if (Console.KeyAvailable)
{
continue;
}
ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
_cki = null;
_isEscSeq = false;
}
break;
}
if (consoleKeyInfo.KeyChar == (char)KeyCode.Esc && _isEscSeq && _cki is { })
{
ProcessRequestResponse (ref newConsoleKeyInfo, ref key, _cki, ref mod);
_cki = null;
if (Console.KeyAvailable)
{
_cki = AnsiEscapeSequenceRequestUtils.ResizeArray (consoleKeyInfo, _cki);
}
else
{
ProcessMapConsoleKeyInfo (consoleKeyInfo);
}
break;
}
ProcessMapConsoleKeyInfo (consoleKeyInfo);
if (_retries > 0)
{
_retries = 0;
}
break;
}
}
_inputReady.Set ();
}
void ProcessMapConsoleKeyInfo (ConsoleKeyInfo consoleKeyInfo)
{
_inputQueue.Enqueue (
new InputResult
{
EventType = EventType.Key, ConsoleKeyInfo = AnsiEscapeSequenceRequestUtils.MapConsoleKeyInfo (consoleKeyInfo)
}
);
_inputQueue.Add (
new ()
{
EventType = EventType.Key, ConsoleKeyInfo = AnsiEscapeSequenceRequestUtils.MapConsoleKeyInfo (consoleKeyInfo)
}
);
_isEscSeq = false;
}
}
@@ -297,17 +262,12 @@ internal class NetEvents : IDisposable
{
try
{
_winChange.Wait (_inputReadyCancellationTokenSource.Token);
_winChange.Reset ();
RequestWindowSize (_inputReadyCancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
return;
}
_inputReady.Set ();
}
}
@@ -327,12 +287,12 @@ internal class NetEvents : IDisposable
int w = Math.Max (winWidth, 0);
int h = Math.Max (winHeight, 0);
_inputQueue.Enqueue (
new InputResult
{
EventType = EventType.WindowSize, WindowSizeEvent = new WindowSizeEvent { Size = new (w, h) }
}
);
_inputQueue.Add (
new ()
{
EventType = EventType.WindowSize, WindowSizeEvent = new () { Size = new (w, h) }
}
);
return true;
}
@@ -609,11 +569,9 @@ internal class NetEvents : IDisposable
{
var mouseEvent = new MouseEvent { Position = pos, ButtonState = buttonState };
_inputQueue.Enqueue (
new InputResult { EventType = EventType.Mouse, MouseEvent = mouseEvent }
);
_inputReady.Set ();
_inputQueue.Add (
new () { EventType = EventType.Mouse, MouseEvent = mouseEvent }
);
}
public enum EventType
@@ -726,7 +684,7 @@ internal class NetEvents : IDisposable
{
var inputResult = new InputResult { EventType = EventType.Key, ConsoleKeyInfo = cki };
_inputQueue.Enqueue (inputResult);
_inputQueue.Add (inputResult);
}
public void Dispose ()

View File

@@ -16,8 +16,7 @@ internal class NetMainLoop : IMainLoopDriver
private readonly ManualResetEventSlim _eventReady = new (false);
private readonly CancellationTokenSource _inputHandlerTokenSource = new ();
private readonly ConcurrentQueue<NetEvents.InputResult?> _resultQueue = new ();
internal readonly ManualResetEventSlim _waitForProbe = new (false);
private readonly BlockingCollection<NetEvents.InputResult> _resultQueue = new (new ConcurrentQueue<NetEvents.InputResult> ());
private readonly CancellationTokenSource _eventReadyTokenSource = new ();
private MainLoop _mainLoop;
@@ -27,12 +26,9 @@ internal class NetMainLoop : IMainLoopDriver
/// <exception cref="ArgumentNullException"></exception>
public NetMainLoop (ConsoleDriver consoleDriver = null)
{
if (consoleDriver is null)
{
throw new ArgumentNullException (nameof (consoleDriver));
}
ArgumentNullException.ThrowIfNull (consoleDriver);
_netEvents = new NetEvents (consoleDriver);
_netEvents = new (consoleDriver);
}
void IMainLoopDriver.Setup (MainLoop mainLoop)
@@ -51,9 +47,7 @@ internal class NetMainLoop : IMainLoopDriver
bool IMainLoopDriver.EventsPending ()
{
_waitForProbe.Set ();
if (_mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout))
if (_resultQueue.Count > 0 || _mainLoop.CheckTimersAndIdleHandlers (out int waitTimeout))
{
return true;
}
@@ -83,6 +77,7 @@ internal class NetMainLoop : IMainLoopDriver
return _resultQueue.Count > 0 || _mainLoop.CheckTimersAndIdleHandlers (out _);
}
// If cancellation was requested then always return true
return true;
}
@@ -91,11 +86,11 @@ internal class NetMainLoop : IMainLoopDriver
while (_resultQueue.Count > 0)
{
// Always dequeue even if it's null and invoke if isn't null
if (_resultQueue.TryDequeue (out NetEvents.InputResult? dequeueResult))
if (_resultQueue.TryTake (out NetEvents.InputResult dequeueResult))
{
if (dequeueResult is { })
{
ProcessInput?.Invoke (dequeueResult.Value);
ProcessInput?.Invoke (dequeueResult);
}
}
}
@@ -110,8 +105,7 @@ internal class NetMainLoop : IMainLoopDriver
_eventReady?.Dispose ();
_resultQueue?.Clear ();
_waitForProbe?.Dispose ();
_resultQueue?.Dispose();
_netEvents?.Dispose ();
_netEvents = null;
@@ -124,50 +118,30 @@ internal class NetMainLoop : IMainLoopDriver
{
try
{
if (!_netEvents._forceRead && !_inputHandlerTokenSource.IsCancellationRequested)
if (_inputHandlerTokenSource.IsCancellationRequested)
{
_waitForProbe.Wait (_inputHandlerTokenSource.Token);
return;
}
if (_resultQueue?.Count == 0 || _netEvents._forceRead)
{
NetEvents.InputResult? result = _netEvents.DequeueInput ();
if (result.HasValue)
{
_resultQueue?.Add (result.Value);
}
}
if (!_inputHandlerTokenSource.IsCancellationRequested && _resultQueue?.Count > 0)
{
_eventReady.Set ();
}
}
catch (OperationCanceledException)
{
return;
}
finally
{
if (_waitForProbe.IsSet)
{
_waitForProbe.Reset ();
}
}
if (_inputHandlerTokenSource.IsCancellationRequested)
{
return;
}
_inputHandlerTokenSource.Token.ThrowIfCancellationRequested ();
if (_resultQueue.Count == 0)
{
_resultQueue.Enqueue (_netEvents.DequeueInput ());
}
try
{
while (_resultQueue.Count > 0 && _resultQueue.TryPeek (out NetEvents.InputResult? result) && result is null)
{
// Dequeue null values
_resultQueue.TryDequeue (out _);
}
}
catch (InvalidOperationException) // Peek can raise an exception
{ }
if (_resultQueue.Count > 0)
{
_eventReady.Set ();
}
}
}
}