using System; using System.Threading; namespace Terminal.Gui { /// /// Mainloop intended to be used with the .NET System.Console API, and can /// be used on Windows and Unix, it is cross platform but lacks things like /// file descriptor monitoring. /// /// /// This implementation is used for FakeDriver. /// public class FakeMainLoop : IMainLoopDriver { AutoResetEvent keyReady = new AutoResetEvent (false); AutoResetEvent waitForProbe = new AutoResetEvent (false); ConsoleKeyInfo? keyResult = null; MainLoop mainLoop; //Func consoleKeyReaderFn = () => ; /// /// Invoked when a Key is pressed. /// public Action KeyPressed; /// /// Creates an instance of the FakeMainLoop. is not used. /// /// public FakeMainLoop (ConsoleDriver consoleDriver = null) { // consoleDriver is not needed/used in FakeConsole } void MockKeyReader () { while (true) { waitForProbe.WaitOne (); keyResult = FakeConsole.ReadKey (true); keyReady.Set (); } } void IMainLoopDriver.Setup (MainLoop mainLoop) { this.mainLoop = mainLoop; Thread readThread = new Thread (MockKeyReader); readThread.Start (); } void IMainLoopDriver.Wakeup () { } bool IMainLoopDriver.EventsPending (bool wait) { keyResult = null; waitForProbe.Set (); if (CheckTimers (wait, out var waitTimeout)) { return true; } keyReady.WaitOne (waitTimeout); return keyResult.HasValue; } bool CheckTimers (bool wait, out int waitTimeout) { long now = DateTime.UtcNow.Ticks; if (mainLoop.timeouts.Count > 0) { waitTimeout = (int)((mainLoop.timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond); if (waitTimeout < 0) return true; } else { waitTimeout = -1; } if (!wait) waitTimeout = 0; int ic; lock (mainLoop.idleHandlers) { ic = mainLoop.idleHandlers.Count; } return ic > 0; } void IMainLoopDriver.Iteration () { if (keyResult.HasValue) { KeyPressed?.Invoke (keyResult.Value); keyResult = null; } } } }