ConsoleInput.cs 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. #nullable enable
  2. using System.Collections.Concurrent;
  3. namespace Terminal.Gui;
  4. /// <summary>
  5. /// Base class for reading console input in perpetual loop
  6. /// </summary>
  7. /// <typeparam name="T"></typeparam>
  8. public abstract class ConsoleInput<T> : IConsoleInput<T>
  9. {
  10. private ConcurrentQueue<T>? _inputBuffer;
  11. /// <summary>
  12. /// Determines how to get the current system type, adjust
  13. /// in unit tests to simulate specific timings.
  14. /// </summary>
  15. public Func<DateTime> Now { get; set; } = () => DateTime.Now;
  16. /// <inheritdoc/>
  17. public virtual void Dispose () { }
  18. /// <inheritdoc/>
  19. public void Initialize (ConcurrentQueue<T> inputBuffer) { _inputBuffer = inputBuffer; }
  20. /// <inheritdoc/>
  21. public void Run (CancellationToken token)
  22. {
  23. try
  24. {
  25. if (_inputBuffer == null)
  26. {
  27. throw new ("Cannot run input before Initialization");
  28. }
  29. do
  30. {
  31. DateTime dt = Now ();
  32. while (Peek ())
  33. {
  34. foreach (T r in Read ())
  35. {
  36. _inputBuffer.Enqueue (r);
  37. }
  38. }
  39. TimeSpan took = Now () - dt;
  40. TimeSpan sleepFor = TimeSpan.FromMilliseconds (20) - took;
  41. Logging.DrainInputStream.Record (took.Milliseconds);
  42. if (sleepFor.Milliseconds > 0)
  43. {
  44. Task.Delay (sleepFor, token).Wait (token);
  45. }
  46. token.ThrowIfCancellationRequested ();
  47. }
  48. while (!token.IsCancellationRequested);
  49. }
  50. catch (OperationCanceledException)
  51. { }
  52. }
  53. /// <summary>
  54. /// When implemented in a derived class, returns true if there is data available
  55. /// to read from console.
  56. /// </summary>
  57. /// <returns></returns>
  58. protected abstract bool Peek ();
  59. /// <summary>
  60. /// Returns the available data without blocking, called when <see cref="Peek"/>
  61. /// returns <see langword="true"/>.
  62. /// </summary>
  63. /// <returns></returns>
  64. protected abstract IEnumerable<T> Read ();
  65. }