#nullable enable using System.Collections.Concurrent; namespace Terminal.Gui; /// /// Base class for reading console input in perpetual loop /// /// public abstract class ConsoleInput : IConsoleInput { private ConcurrentQueue? _inputBuffer; /// /// Determines how to get the current system type, adjust /// in unit tests to simulate specific timings. /// public Func Now { get; set; } = () => DateTime.Now; /// public virtual void Dispose () { } /// public void Initialize (ConcurrentQueue inputBuffer) { _inputBuffer = inputBuffer; } /// public void Run (CancellationToken token) { try { if (_inputBuffer == null) { throw new ("Cannot run input before Initialization"); } do { DateTime dt = Now (); while (Peek ()) { foreach (T r in Read ()) { _inputBuffer.Enqueue (r); } } TimeSpan took = Now () - dt; TimeSpan sleepFor = TimeSpan.FromMilliseconds (20) - took; Logging.DrainInputStream.Record (took.Milliseconds); if (sleepFor.Milliseconds > 0) { Task.Delay (sleepFor, token).Wait (token); } token.ThrowIfCancellationRequested (); } while (!token.IsCancellationRequested); } catch (OperationCanceledException) { } } /// /// When implemented in a derived class, returns true if there is data available /// to read from console. /// /// protected abstract bool Peek (); /// /// Returns the available data without blocking, called when /// returns . /// /// protected abstract IEnumerable Read (); }