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 = null;
///
/// Invoked when a Key is pressed.
///
public Action KeyPressed;
///
/// Initializes the class.
///
///
/// Passing a consoleKeyReaderfn is provided to support unit test scenarios.
///
/// The method to be called to get a key from the console.
public FakeMainLoop (Func consoleKeyReaderFn = null)
{
if (consoleKeyReaderFn == null) {
throw new ArgumentNullException ("key reader function must be provided.");
}
this.consoleKeyReaderFn = consoleKeyReaderFn;
}
void WindowsKeyReader ()
{
while (true) {
waitForProbe.WaitOne ();
keyResult = consoleKeyReaderFn ();
keyReady.Set ();
}
}
void IMainLoopDriver.Setup (MainLoop mainLoop)
{
this.mainLoop = mainLoop;
Thread readThread = new Thread (WindowsKeyReader);
readThread.Start ();
}
void IMainLoopDriver.Wakeup ()
{
}
bool IMainLoopDriver.EventsPending (bool wait)
{
long now = DateTime.UtcNow.Ticks;
int waitTimeout;
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;
keyResult = null;
waitForProbe.Set ();
keyReady.WaitOne (waitTimeout);
return keyResult.HasValue;
}
void IMainLoopDriver.MainIteration ()
{
if (keyResult.HasValue) {
KeyPressed?.Invoke (keyResult.Value);
keyResult = null;
}
}
}
}