From 4d1668549f37f107fa02f62d6ccf59dc7899d365 Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Wed, 14 Feb 2018 22:27:10 -0500 Subject: [PATCH] Progress on the Windows driver --- Terminal.Gui/Driver.cs | 63 ++++++++++++++++++++- Terminal.Gui/MonoCurses/mainloop.cs | 88 +++++++++++++++++++++-------- 2 files changed, 124 insertions(+), 27 deletions(-) diff --git a/Terminal.Gui/Driver.cs b/Terminal.Gui/Driver.cs index 22d7856a9..b164cb476 100644 --- a/Terminal.Gui/Driver.cs +++ b/Terminal.Gui/Driver.cs @@ -257,7 +257,7 @@ namespace Terminal.Gui { /// /// String. public abstract void AddStr (ustring str); - public abstract void PrepareToRun (MainLoop mainLoop, Action target, Action mouse); + public abstract void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action mouseHandler); /// /// Updates the screen to reflect all the changes that have been done to the display buffer @@ -996,8 +996,67 @@ namespace Terminal.Gui { currentAttribute = c.value; } - public override void PrepareToRun (MainLoop mainLoop, Action target, Action mouse) + Key MapKey (ConsoleKeyInfo keyInfo) { + var key = keyInfo.Key; + if (key >= ConsoleKey.A && key <= ConsoleKey.Z){ + var delta = key - ConsoleKey.A; + if (keyInfo.Modifiers == ConsoleModifiers.Control) + return (Key)((uint)Key.ControlA + delta); + if (keyInfo.Modifiers == ConsoleModifiers.Alt) + return (Key) (((uint)Key.AltMask) | ((uint)'A' + delta)); + if (keyInfo.Modifiers == ConsoleModifiers.Shift) + return (Key)((uint)'A' + delta); + else + return (Key)((uint)'a' + delta); + } + if (key >= ConsoleKey.F1 && key <= ConsoleKey.F10) { + var delta = key - ConsoleKey.F1; + + return (Key)(ConsoleKey.F1 + delta); + } + + switch (keyInfo.Key){ + case ConsoleKey.Tab: + return Key.ControlT; + case ConsoleKey.Escape: + return Key.Esc; + case ConsoleKey.Home: + return Key.Home; + case ConsoleKey.End: + return Key.End; + case ConsoleKey.LeftArrow: + return Key.CursorLeft; + case ConsoleKey.RightArrow: + return Key.CursorRight; + case ConsoleKey.UpArrow: + return Key.CursorUp; + case ConsoleKey.DownArrow: + return Key.CursorDown; + case ConsoleKey.PageUp: + return Key.PageUp; + case ConsoleKey.PageDown: + return Key.PageDown; + case ConsoleKey.Enter: + return Key.Enter; + case ConsoleKey.Spacebar: + return Key.Space; + case ConsoleKey.Backspace: + return Key.Backspace; + case ConsoleKey.Delete: + return Key.Delete; + } + return (Key)(0xffffffff); + } + + public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action mouseHandler) + { + mainLoop.WindowsKeyPressed = delegate (ConsoleKeyInfo consoleKey) { + var map = MapKey (consoleKey); + if (map == (Key) 0xffffffff) + return; + keyHandler (new KeyEvent (map)); + }; } public override void SetColors (ConsoleColor foreground, ConsoleColor background) diff --git a/Terminal.Gui/MonoCurses/mainloop.cs b/Terminal.Gui/MonoCurses/mainloop.cs index 9fe55988a..5ebc63414 100644 --- a/Terminal.Gui/MonoCurses/mainloop.cs +++ b/Terminal.Gui/MonoCurses/mainloop.cs @@ -28,6 +28,7 @@ using System.Collections.Generic; using System; using System.Runtime.InteropServices; +using System.Threading; namespace Mono.Terminal { @@ -36,6 +37,8 @@ namespace Mono.Terminal { /// file descriptor, run timers and idle handlers. /// public class MainLoop { + static bool useUnix = true; + /// /// Condition on which to wake up from file descriptor activity. These match the Linux/BSD poll definitions. /// @@ -168,13 +171,20 @@ namespace Mono.Terminal { { if (callback == null) throw new ArgumentNullException ("callback"); - + if (!useUnix) + throw new Exception ("AddWatch is only supported for Unix"); + var watch = new Watch () { Condition = condition, Callback = callback, File = fileDescriptor }; descriptorWatchers [fileDescriptor] = watch; poll_dirty = true; return watch; } + /// + /// This event is raised when a key is pressed when using the Windows driver. + /// + public Action WindowsKeyPressed; + /// /// Removes an active watch from the mainloop. /// @@ -287,6 +297,18 @@ namespace Mono.Terminal { Wakeup (); } + AutoResetEvent keyReady = new AutoResetEvent (false); + AutoResetEvent waitForProbe = new AutoResetEvent (false); + ConsoleKeyInfo? windowsKeyResult = null; + void WindowsKeyReader () + { + while (true) { + waitForProbe.WaitOne (); + var result = Console.ReadKey (); + keyReady.Set (); + } + } + /// /// Determines whether there are pending events to be processed. /// @@ -298,22 +320,29 @@ namespace Mono.Terminal { public bool EventsPending (bool wait = false) { long now = DateTime.UtcNow.Ticks; - int pollTimeout, n; - if (timeouts.Count > 0) - pollTimeout = (int) ((timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond); - else - pollTimeout = -1; - - if (!wait) - pollTimeout = 0; - - UpdatePollMap (); + if (useUnix) { + int pollTimeout, n; + if (timeouts.Count > 0) + pollTimeout = (int)((timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond); + else + pollTimeout = -1; - n = poll (pollmap, (uint) pollmap.Length, pollTimeout); - int ic; - lock (idleHandlers) - ic = idleHandlers.Count; - return n > 0 || timeouts.Count > 0 && ((timeouts.Keys [0] - DateTime.UtcNow.Ticks) < 0) || ic > 0; + if (!wait) + pollTimeout = 0; + + UpdatePollMap (); + + n = poll (pollmap, (uint)pollmap.Length, pollTimeout); + int ic; + lock (idleHandlers) + ic = idleHandlers.Count; + return n > 0 || timeouts.Count > 0 && ((timeouts.Keys [0] - DateTime.UtcNow.Ticks) < 0) || ic > 0; + } else { + windowsKeyResult = null; + waitForProbe.Set (); + keyReady.WaitOne (); + return false; + } } /// @@ -329,18 +358,27 @@ namespace Mono.Terminal { { if (timeouts.Count > 0) RunTimers (); - - foreach (var p in pollmap){ - Watch watch; - if (p.revents == 0) - continue; + if (useUnix) { + foreach (var p in pollmap) { + Watch watch; - if (!descriptorWatchers.TryGetValue (p.fd, out watch)) - continue; - if (!watch.Callback (this)) - descriptorWatchers.Remove (p.fd); + if (p.revents == 0) + continue; + + if (!descriptorWatchers.TryGetValue (p.fd, out watch)) + continue; + if (!watch.Callback (this)) + descriptorWatchers.Remove (p.fd); + } + } else { + if (windowsKeyResult.HasValue) { + if (WindowsKeyPressed != null) + WindowsKeyPressed (windowsKeyResult.Value); + windowsKeyResult = null; + } } + if (idleHandlers.Count > 0) RunIdle (); }