|
@@ -59,31 +59,40 @@ namespace Terminal.Gui {
|
|
|
public bool WriteToConsole (CharInfo [] charInfoBuffer, Coord coords, SmallRect window)
|
|
|
{
|
|
|
if (ScreenBuffer == IntPtr.Zero) {
|
|
|
- ScreenBuffer = CreateConsoleScreenBuffer (
|
|
|
- DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
|
|
|
- ShareMode.FileShareRead | ShareMode.FileShareWrite,
|
|
|
- IntPtr.Zero,
|
|
|
- 1,
|
|
|
- IntPtr.Zero
|
|
|
- );
|
|
|
- if (ScreenBuffer == INVALID_HANDLE_VALUE) {
|
|
|
- var err = Marshal.GetLastWin32Error ();
|
|
|
-
|
|
|
- if (err != 0)
|
|
|
- throw new System.ComponentModel.Win32Exception (err);
|
|
|
- }
|
|
|
+ window = ReadFromConsoleOutput (new Size (Console.WindowWidth, Console.WindowHeight), coords, window);
|
|
|
+ }
|
|
|
+
|
|
|
+ return WriteConsoleOutput (ScreenBuffer, charInfoBuffer, coords, new Coord () { X = window.Left, Y = window.Top }, ref window);
|
|
|
+ }
|
|
|
+
|
|
|
+ public SmallRect ReadFromConsoleOutput (Size size, Coord coords, SmallRect window)
|
|
|
+ {
|
|
|
+ ScreenBuffer = CreateConsoleScreenBuffer (
|
|
|
+ DesiredAccess.GenericRead | DesiredAccess.GenericWrite,
|
|
|
+ ShareMode.FileShareRead | ShareMode.FileShareWrite,
|
|
|
+ IntPtr.Zero,
|
|
|
+ 1,
|
|
|
+ IntPtr.Zero
|
|
|
+ );
|
|
|
+ if (ScreenBuffer == INVALID_HANDLE_VALUE) {
|
|
|
+ var err = Marshal.GetLastWin32Error ();
|
|
|
|
|
|
- if (!SetConsoleActiveScreenBuffer (ScreenBuffer)) {
|
|
|
- var err = Marshal.GetLastWin32Error ();
|
|
|
+ if (err != 0 && HeightAsBuffer) {
|
|
|
throw new System.ComponentModel.Win32Exception (err);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- OriginalStdOutChars = new CharInfo [Console.WindowHeight * Console.WindowWidth];
|
|
|
-
|
|
|
- ReadConsoleOutput (OutputHandle, OriginalStdOutChars, coords, new Coord () { X = 0, Y = 0 }, ref window);
|
|
|
+ if (!SetConsoleActiveScreenBuffer (ScreenBuffer)) {
|
|
|
+ var err = Marshal.GetLastWin32Error ();
|
|
|
+ if (HeightAsBuffer) {
|
|
|
+ throw new System.ComponentModel.Win32Exception (err);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return WriteConsoleOutput (ScreenBuffer, charInfoBuffer, coords, new Coord () { X = window.Left, Y = window.Top }, ref window);
|
|
|
+ OriginalStdOutChars = new CharInfo [size.Height * size.Width];
|
|
|
+ ReadConsoleOutput (OutputHandle, OriginalStdOutChars, coords, new Coord () { X = 0, Y = 0 }, ref window);
|
|
|
+
|
|
|
+ return window;
|
|
|
}
|
|
|
|
|
|
public bool SetCursorPosition (Coord position)
|
|
@@ -120,6 +129,8 @@ namespace Terminal.Gui {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public bool HeightAsBuffer { get; set; }
|
|
|
+
|
|
|
[Flags]
|
|
|
public enum ConsoleModes : uint {
|
|
|
EnableProcessedInput = 1,
|
|
@@ -207,7 +218,7 @@ namespace Terminal.Gui {
|
|
|
public override string ToString () => $"({X},{Y})";
|
|
|
};
|
|
|
|
|
|
- internal struct WindowBufferSizeRecord {
|
|
|
+ public struct WindowBufferSizeRecord {
|
|
|
public Coordinate size;
|
|
|
|
|
|
public WindowBufferSizeRecord (short x, short y)
|
|
@@ -355,6 +366,20 @@ namespace Terminal.Gui {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ [StructLayout (LayoutKind.Sequential)]
|
|
|
+ public struct ConsoleKeyInfoEx {
|
|
|
+ public ConsoleKeyInfo consoleKeyInfo;
|
|
|
+ public bool CapsLock;
|
|
|
+ public bool NumLock;
|
|
|
+
|
|
|
+ public ConsoleKeyInfoEx (ConsoleKeyInfo consoleKeyInfo, bool capslock, bool numlock)
|
|
|
+ {
|
|
|
+ this.consoleKeyInfo = consoleKeyInfo;
|
|
|
+ CapsLock = capslock;
|
|
|
+ NumLock = numlock;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
[DllImport ("kernel32.dll", SetLastError = true)]
|
|
|
static extern IntPtr GetStdHandle (int nStdHandle);
|
|
|
|
|
@@ -431,231 +456,147 @@ namespace Terminal.Gui {
|
|
|
|
|
|
return numberEventsRead == 0
|
|
|
? null
|
|
|
- : new [] {Marshal.PtrToStructure<InputRecord> (pRecord)};
|
|
|
+ : new [] { Marshal.PtrToStructure<InputRecord> (pRecord) };
|
|
|
} catch (Exception) {
|
|
|
return null;
|
|
|
} finally {
|
|
|
Marshal.FreeHGlobal (pRecord);
|
|
|
}
|
|
|
}
|
|
|
-#if false // Not needed on the constructor. Perhaps could be used on resizing. To study.
|
|
|
- [DllImport ("kernel32.dll", ExactSpelling = true)]
|
|
|
- private static extern IntPtr GetConsoleWindow ();
|
|
|
|
|
|
- [DllImport ("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
|
|
- private static extern bool ShowWindow (IntPtr hWnd, int nCmdShow);
|
|
|
-
|
|
|
- public const int HIDE = 0;
|
|
|
- public const int MAXIMIZE = 3;
|
|
|
- public const int MINIMIZE = 6;
|
|
|
- public const int RESTORE = 9;
|
|
|
+ // Not needed on the constructor. Perhaps could be used on resizing. To study.
|
|
|
+ [DllImport ("kernel32.dll", ExactSpelling = true)]
|
|
|
+ static extern IntPtr GetConsoleWindow ();
|
|
|
|
|
|
- internal void ShowWindow (int state)
|
|
|
+ internal IntPtr GetConsole ()
|
|
|
{
|
|
|
- IntPtr thisConsole = GetConsoleWindow ();
|
|
|
- ShowWindow (thisConsole, state);
|
|
|
- }
|
|
|
+ return GetConsoleWindow ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [DllImport ("user32.dll")]
|
|
|
+ [return: MarshalAs (UnmanagedType.Bool)]
|
|
|
+ static extern bool GetWindowPlacement (IntPtr hWnd, ref WindowPlacement lpwndpl);
|
|
|
+
|
|
|
+ [DllImport ("user32.dll", SetLastError = true)]
|
|
|
+ [return: MarshalAs (UnmanagedType.Bool)]
|
|
|
+ static extern bool SetWindowPlacement (IntPtr hWnd, [In] ref WindowPlacement lpwndpl);
|
|
|
+
|
|
|
+ internal struct WindowPlacement {
|
|
|
+ public int length;
|
|
|
+ public int flags;
|
|
|
+ public int showCmd;
|
|
|
+ public System.Drawing.Point ptMinPosition;
|
|
|
+ public System.Drawing.Point ptMaxPosition;
|
|
|
+ public System.Drawing.Rectangle rcNormalPosition;
|
|
|
+#if _MAC
|
|
|
+ public System.Drawing.Rectangle rcDevice;
|
|
|
#endif
|
|
|
-#if false // See: https://github.com/migueldeicaza/gui.cs/issues/357
|
|
|
- [StructLayout (LayoutKind.Sequential)]
|
|
|
- public struct SMALL_RECT {
|
|
|
- public short Left;
|
|
|
- public short Top;
|
|
|
- public short Right;
|
|
|
- public short Bottom;
|
|
|
-
|
|
|
- public SMALL_RECT (short Left, short Top, short Right, short Bottom)
|
|
|
- {
|
|
|
- this.Left = Left;
|
|
|
- this.Top = Top;
|
|
|
- this.Right = Right;
|
|
|
- this.Bottom = Bottom;
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- [StructLayout (LayoutKind.Sequential)]
|
|
|
- public struct CONSOLE_SCREEN_BUFFER_INFO {
|
|
|
- public int dwSize;
|
|
|
- public int dwCursorPosition;
|
|
|
- public short wAttributes;
|
|
|
- public SMALL_RECT srWindow;
|
|
|
- public int dwMaximumWindowSize;
|
|
|
- }
|
|
|
+ // flags
|
|
|
+ public const int WPF_SET_MIN_POSITION = 1;
|
|
|
+ public const int WPF_RESTORE_TO_MAXIMIZED = 2;
|
|
|
+ public const int WPF_ASYNC_WINDOWPLACEMENT = 4;
|
|
|
|
|
|
- [DllImport ("kernel32.dll", SetLastError = true)]
|
|
|
- static extern bool GetConsoleScreenBufferInfo (IntPtr hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo);
|
|
|
+ // showCmd
|
|
|
+ public const int HIDE = 0;
|
|
|
+ public const int SHOW_NORMAL = 1;
|
|
|
+ public const int SHOW_MINIMIZED = 2;
|
|
|
+ public const int SHOW_MAXIMIZED = 3;
|
|
|
+ public const int SHOW_NOACTIVATE = 4;
|
|
|
+ public const int SHOW = 5;
|
|
|
+ public const int MINIMIZE = 6;
|
|
|
+ public const int SHOW_MIN_NOACTIVE = 7;
|
|
|
+ public const int SHOW_NA = 8;
|
|
|
+ public const int RESTORE = 9;
|
|
|
+ public const int SHOW_DEFAULT = 10;
|
|
|
+ public const int FORCE_MINIMIZE = 11;
|
|
|
|
|
|
- // Theoretically GetConsoleScreenBuffer height should give the console Windoww size
|
|
|
- // It does not work, however, and always returns the size the window was initially created at
|
|
|
- internal Size GetWindowSize ()
|
|
|
+ internal bool GetWindow (IntPtr handle, ref WindowPlacement placement)
|
|
|
{
|
|
|
- var consoleScreenBufferInfo = new CONSOLE_SCREEN_BUFFER_INFO ();
|
|
|
- //consoleScreenBufferInfo.dwSize = Marshal.SizeOf (typeof (CONSOLE_SCREEN_BUFFER_INFO));
|
|
|
- GetConsoleScreenBufferInfo (OutputHandle, out consoleScreenBufferInfo);
|
|
|
- return new Size (consoleScreenBufferInfo.srWindow.Right - consoleScreenBufferInfo.srWindow.Left,
|
|
|
- consoleScreenBufferInfo.srWindow.Bottom - consoleScreenBufferInfo.srWindow.Top);
|
|
|
+ placement = new WindowPlacement {
|
|
|
+ length = Marshal.SizeOf (typeof (WindowPlacement))
|
|
|
+ };
|
|
|
+ return GetWindowPlacement (handle, ref placement);
|
|
|
}
|
|
|
-#endif
|
|
|
- }
|
|
|
-
|
|
|
- internal class WindowsDriver : ConsoleDriver, IMainLoopDriver {
|
|
|
- static bool sync = false;
|
|
|
- ManualResetEventSlim eventReady = new ManualResetEventSlim (false);
|
|
|
- ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false);
|
|
|
- MainLoop mainLoop;
|
|
|
- WindowsConsole.CharInfo [] OutputBuffer;
|
|
|
- int cols, rows;
|
|
|
- WindowsConsole winConsole;
|
|
|
- WindowsConsole.SmallRect damageRegion;
|
|
|
-
|
|
|
- public override int Cols => cols;
|
|
|
- public override int Rows => rows;
|
|
|
- public override int Top => 0;
|
|
|
|
|
|
- public WindowsDriver ()
|
|
|
+ internal bool SetWindow (IntPtr handle, ref WindowPlacement placement)
|
|
|
{
|
|
|
- winConsole = new WindowsConsole ();
|
|
|
-
|
|
|
- SetupColorsAndBorders ();
|
|
|
-
|
|
|
- cols = Console.WindowWidth;
|
|
|
- rows = Console.WindowHeight;
|
|
|
-#if false
|
|
|
- winConsole.ShowWindow (WindowsConsole.RESTORE);
|
|
|
-#endif
|
|
|
- WindowsConsole.SmallRect.MakeEmpty (ref damageRegion);
|
|
|
-
|
|
|
- ResizeScreen ();
|
|
|
- UpdateOffScreen ();
|
|
|
-
|
|
|
- Task.Run ((Action)WindowsInputHandler);
|
|
|
+ return SetWindowPlacement (handle, ref placement);
|
|
|
}
|
|
|
|
|
|
- private void SetupColorsAndBorders ()
|
|
|
- {
|
|
|
- Colors.TopLevel = new ColorScheme ();
|
|
|
- Colors.Base = new ColorScheme ();
|
|
|
- Colors.Dialog = new ColorScheme ();
|
|
|
- Colors.Menu = new ColorScheme ();
|
|
|
- Colors.Error = new ColorScheme ();
|
|
|
-
|
|
|
- Colors.TopLevel.Normal = MakeColor (ConsoleColor.Green, ConsoleColor.Black);
|
|
|
- Colors.TopLevel.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkCyan);
|
|
|
- Colors.TopLevel.HotNormal = MakeColor (ConsoleColor.DarkYellow, ConsoleColor.Black);
|
|
|
- Colors.TopLevel.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkCyan);
|
|
|
-
|
|
|
- Colors.Base.Normal = MakeColor (ConsoleColor.White, ConsoleColor.DarkBlue);
|
|
|
- Colors.Base.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
|
|
|
- Colors.Base.HotNormal = MakeColor (ConsoleColor.DarkCyan, ConsoleColor.DarkBlue);
|
|
|
- Colors.Base.HotFocus = MakeColor (ConsoleColor.Blue, ConsoleColor.Gray);
|
|
|
+ [DllImport ("user32.dll", SetLastError = true)]
|
|
|
+ static extern bool GetWindowRect (IntPtr hwnd, out System.Drawing.Rectangle lpRect);
|
|
|
|
|
|
- Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.DarkGray);
|
|
|
- Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black);
|
|
|
- Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.DarkGray);
|
|
|
- Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black);
|
|
|
- Colors.Menu.Disabled = MakeColor (ConsoleColor.Gray, ConsoleColor.DarkGray);
|
|
|
-
|
|
|
- Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
|
|
|
- Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkGray);
|
|
|
- Colors.Dialog.HotNormal = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.Gray);
|
|
|
- Colors.Dialog.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkGray);
|
|
|
-
|
|
|
- Colors.Error.Normal = MakeColor (ConsoleColor.DarkRed, ConsoleColor.White);
|
|
|
- Colors.Error.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkRed);
|
|
|
- Colors.Error.HotNormal = MakeColor (ConsoleColor.Black, ConsoleColor.White);
|
|
|
- Colors.Error.HotFocus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkRed);
|
|
|
+ internal bool GetRect (IntPtr handle, out System.Drawing.Rectangle lpRect)
|
|
|
+ {
|
|
|
+ return GetWindowRect (handle, out lpRect);
|
|
|
}
|
|
|
|
|
|
- [StructLayout (LayoutKind.Sequential)]
|
|
|
- public struct ConsoleKeyInfoEx {
|
|
|
- public ConsoleKeyInfo consoleKeyInfo;
|
|
|
- public bool CapsLock;
|
|
|
- public bool NumLock;
|
|
|
+#if false
|
|
|
+ // size of a device name string
|
|
|
+ private const int CCHDEVICENAME = 32;
|
|
|
|
|
|
- public ConsoleKeyInfoEx (ConsoleKeyInfo consoleKeyInfo, bool capslock, bool numlock)
|
|
|
- {
|
|
|
- this.consoleKeyInfo = consoleKeyInfo;
|
|
|
- CapsLock = capslock;
|
|
|
- NumLock = numlock;
|
|
|
- }
|
|
|
+ [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|
|
+ internal struct MonitorInfoEx {
|
|
|
+ public uint cbSize;
|
|
|
+ public System.Drawing.Rectangle rcMonitor;
|
|
|
+ public System.Drawing.Rectangle rcWork;
|
|
|
+ public int dwFlags;
|
|
|
+ [MarshalAs (UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
|
|
|
+ public string szDevice;
|
|
|
}
|
|
|
|
|
|
- // The records that we keep fetching
|
|
|
- WindowsConsole.InputRecord [] result, records = new WindowsConsole.InputRecord [1];
|
|
|
+ [DllImport ("user32.dll", CharSet = CharSet.Auto)]
|
|
|
+ static extern bool GetMonitorInfo (IntPtr hMonitor, ref MonitorInfoEx lpmi);
|
|
|
|
|
|
- void WindowsInputHandler ()
|
|
|
+ internal bool GetMonitor(IntPtr hMonitor, ref MonitorInfoEx minfo)
|
|
|
{
|
|
|
- while (true) {
|
|
|
- waitForProbe.Wait ();
|
|
|
- waitForProbe.Reset ();
|
|
|
+ minfo.cbSize = (uint)Marshal.SizeOf (minfo);
|
|
|
+ return GetMonitorInfo (hMonitor, ref minfo);
|
|
|
+ }
|
|
|
|
|
|
- result = winConsole.ReadConsoleInput ();
|
|
|
+ [DllImport ("user32.dll")]
|
|
|
+ static extern IntPtr MonitorFromWindow (IntPtr hwnd, uint dwFlags);
|
|
|
|
|
|
- eventReady.Set ();
|
|
|
- }
|
|
|
- }
|
|
|
+ public const int MONITOR_DEFAULTTONULL = 0;
|
|
|
+ public const int MONITOR_DEFAULTTOPRIMARY = 1;
|
|
|
+ public const int MONITOR_DEFAULTTONEAREST = 2;
|
|
|
|
|
|
- void IMainLoopDriver.Setup (MainLoop mainLoop)
|
|
|
+ internal IntPtr GetMonitorWindow (IntPtr hwnd, uint dwFlag)
|
|
|
{
|
|
|
- this.mainLoop = mainLoop;
|
|
|
+ return MonitorFromWindow (hwnd, dwFlag);
|
|
|
}
|
|
|
|
|
|
- void IMainLoopDriver.Wakeup ()
|
|
|
- {
|
|
|
- //tokenSource.Cancel ();
|
|
|
- eventReady.Reset ();
|
|
|
- eventReady.Set ();
|
|
|
- }
|
|
|
+ [DllImport ("kernel32.dll", SetLastError = true)]
|
|
|
+ static extern bool GetConsoleScreenBufferInfo (IntPtr hConsoleOutput, out ConsoleScreenBufferInfo ConsoleScreenBufferInfo);
|
|
|
|
|
|
- bool IMainLoopDriver.EventsPending (bool wait)
|
|
|
+ // Theoretically GetConsoleScreenBuffer height should give the console Window size, but the Top is always 0.
|
|
|
+ // It does not work, however, and always returns the size the window was initially created at
|
|
|
+ internal Size GetWindowSize (IntPtr handle)
|
|
|
{
|
|
|
- if (CheckTimers (wait, out var waitTimeout)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- result = null;
|
|
|
- waitForProbe.Set ();
|
|
|
-
|
|
|
- try {
|
|
|
- if (!tokenSource.IsCancellationRequested) {
|
|
|
- eventReady.Wait (waitTimeout, tokenSource.Token);
|
|
|
- }
|
|
|
- } catch (OperationCanceledException) {
|
|
|
- return true;
|
|
|
- } finally {
|
|
|
- eventReady.Reset ();
|
|
|
- }
|
|
|
-
|
|
|
- if (!tokenSource.IsCancellationRequested) {
|
|
|
- return result != null || CheckTimers (wait, out waitTimeout);
|
|
|
- }
|
|
|
-
|
|
|
- tokenSource.Dispose ();
|
|
|
- tokenSource = new CancellationTokenSource ();
|
|
|
- return true;
|
|
|
+ GetConsoleScreenBufferInfo (handle, out ConsoleScreenBufferInfo consoleScreenBufferInfo);
|
|
|
+ return new Size (consoleScreenBufferInfo.srWindow.Right - consoleScreenBufferInfo.srWindow.Left + 1,
|
|
|
+ consoleScreenBufferInfo.srWindow.Bottom - consoleScreenBufferInfo.srWindow.Top + 1);
|
|
|
}
|
|
|
+#endif
|
|
|
+ }
|
|
|
|
|
|
- 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;
|
|
|
+ internal class WindowsDriver : ConsoleDriver {
|
|
|
+ static bool sync = false;
|
|
|
+ WindowsConsole.CharInfo [] OutputBuffer;
|
|
|
+ int cols, rows, top;
|
|
|
+ WindowsConsole winConsole;
|
|
|
+ WindowsConsole.SmallRect damageRegion;
|
|
|
|
|
|
- int ic;
|
|
|
- lock (mainLoop.idleHandlers) {
|
|
|
- ic = mainLoop.idleHandlers.Count;
|
|
|
- }
|
|
|
+ public override int Cols => cols;
|
|
|
+ public override int Rows => rows;
|
|
|
+ public override int Top => top;
|
|
|
+ public override bool HeightAsBuffer { get; set; }
|
|
|
|
|
|
- return ic > 0;
|
|
|
+ public WindowsConsole WinConsole {
|
|
|
+ get => winConsole;
|
|
|
+ private set => winConsole = value;
|
|
|
}
|
|
|
|
|
|
Action<KeyEvent> keyHandler;
|
|
@@ -663,20 +604,58 @@ namespace Terminal.Gui {
|
|
|
Action<KeyEvent> keyUpHandler;
|
|
|
Action<MouseEvent> mouseHandler;
|
|
|
|
|
|
+ public WindowsDriver ()
|
|
|
+ {
|
|
|
+ winConsole = new WindowsConsole () {
|
|
|
+ HeightAsBuffer = this.HeightAsBuffer
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ MainLoop mainLoop;
|
|
|
+
|
|
|
public override void PrepareToRun (MainLoop mainLoop, Action<KeyEvent> keyHandler, Action<KeyEvent> keyDownHandler, Action<KeyEvent> keyUpHandler, Action<MouseEvent> mouseHandler)
|
|
|
{
|
|
|
this.keyHandler = keyHandler;
|
|
|
this.keyDownHandler = keyDownHandler;
|
|
|
this.keyUpHandler = keyUpHandler;
|
|
|
this.mouseHandler = mouseHandler;
|
|
|
+ this.mainLoop = mainLoop;
|
|
|
+
|
|
|
+ var mLoop = mainLoop.Driver as WindowsMainLoop;
|
|
|
+
|
|
|
+ mLoop.ProcessInput = (e) => ProcessInput (e);
|
|
|
+
|
|
|
+ mLoop.WinChanged = (e) => ChangeWin (e);
|
|
|
}
|
|
|
|
|
|
- void IMainLoopDriver.MainIteration ()
|
|
|
+ bool winChanging;
|
|
|
+ bool wasChangeWin;
|
|
|
+
|
|
|
+ void ChangeWin (Size size)
|
|
|
{
|
|
|
- if (result == null)
|
|
|
- return;
|
|
|
+ if (!HeightAsBuffer) {
|
|
|
+ winChanging = true;
|
|
|
+ top = 0;
|
|
|
+ cols = size.Width;
|
|
|
+ rows = size.Height;
|
|
|
+ ResizeScreen ();
|
|
|
+ UpdateOffScreen ();
|
|
|
+ var bufferCoords = new WindowsConsole.Coord () {
|
|
|
+ X = (short)cols,
|
|
|
+ Y = (short)rows
|
|
|
+ };
|
|
|
+ winConsole.ReadFromConsoleOutput (size, bufferCoords, damageRegion);
|
|
|
+ if (!winChanging) {
|
|
|
+ TerminalResized.Invoke ();
|
|
|
+ }
|
|
|
+ wasChangeWin = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bool isFromRestore;
|
|
|
|
|
|
- var inputEvent = result [0];
|
|
|
+ void ProcessInput (WindowsConsole.InputRecord inputEvent)
|
|
|
+ {
|
|
|
switch (inputEvent.EventType) {
|
|
|
case WindowsConsole.EventType.Key:
|
|
|
var map = MapKey (ToConsoleKeyInfoEx (inputEvent.KeyEvent));
|
|
@@ -766,20 +745,30 @@ namespace Terminal.Gui {
|
|
|
break;
|
|
|
|
|
|
case WindowsConsole.EventType.WindowBufferSize:
|
|
|
- cols = inputEvent.WindowBufferSizeEvent.size.X;
|
|
|
- rows = inputEvent.WindowBufferSizeEvent.size.Y;
|
|
|
- ResizeScreen ();
|
|
|
- UpdateOffScreen ();
|
|
|
- TerminalResized?.Invoke ();
|
|
|
+ if (HeightAsBuffer) {
|
|
|
+ cols = inputEvent.WindowBufferSizeEvent.size.X;
|
|
|
+ rows = inputEvent.WindowBufferSizeEvent.size.Y;
|
|
|
+ ResizeScreen ();
|
|
|
+ UpdateOffScreen ();
|
|
|
+ TerminalResized?.Invoke ();
|
|
|
+ } else if (!HeightAsBuffer && !wasChangeWin && !(mainLoop.Driver as WindowsMainLoop).Maximized
|
|
|
+ && !isFromRestore) {
|
|
|
+ ChangeWin (new Size (inputEvent.WindowBufferSizeEvent.size.X,
|
|
|
+ inputEvent.WindowBufferSizeEvent.size.Y));
|
|
|
+ } else if (!HeightAsBuffer && wasChangeWin && (mainLoop.Driver as WindowsMainLoop).Restored) {
|
|
|
+ (mainLoop.Driver as WindowsMainLoop).Restored = false;
|
|
|
+ isFromRestore = true;
|
|
|
+ } else if (!HeightAsBuffer && wasChangeWin && !(mainLoop.Driver as WindowsMainLoop).Maximized
|
|
|
+ && !(mainLoop.Driver as WindowsMainLoop).Restored && !isFromRestore) {
|
|
|
+ wasChangeWin = false;
|
|
|
+ } else if (isFromRestore) {
|
|
|
+ isFromRestore = false;
|
|
|
+ }
|
|
|
break;
|
|
|
|
|
|
case WindowsConsole.EventType.Focus:
|
|
|
break;
|
|
|
-
|
|
|
- default:
|
|
|
- break;
|
|
|
}
|
|
|
- result = null;
|
|
|
}
|
|
|
|
|
|
WindowsConsole.ButtonState? LastMouseButtonPressed = null;
|
|
@@ -810,6 +799,11 @@ namespace Terminal.Gui {
|
|
|
IsButtonReleased = false;
|
|
|
}
|
|
|
|
|
|
+ var p = new Point () {
|
|
|
+ X = mouseEvent.MousePosition.X,
|
|
|
+ Y = mouseEvent.MousePosition.Y
|
|
|
+ };
|
|
|
+
|
|
|
if ((mouseEvent.ButtonState != 0 && mouseEvent.EventFlags == 0 && LastMouseButtonPressed == null && !IsButtonDoubleClicked) ||
|
|
|
(mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved &&
|
|
|
mouseEvent.ButtonState != 0 && !IsButtonReleased && !IsButtonDoubleClicked)) {
|
|
@@ -865,32 +859,24 @@ namespace Terminal.Gui {
|
|
|
IsButtonPressed = false;
|
|
|
IsButtonReleased = true;
|
|
|
} else if ((mouseEvent.EventFlags == 0 || mouseEvent.EventFlags == WindowsConsole.EventFlags.MouseMoved) &&
|
|
|
- IsButtonReleased) {
|
|
|
- var p = new Point () {
|
|
|
+ IsButtonReleased && p == point) {
|
|
|
+ switch (LastMouseButtonPressed) {
|
|
|
+ case WindowsConsole.ButtonState.Button1Pressed:
|
|
|
+ mouseFlag = MouseFlags.Button1Clicked;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WindowsConsole.ButtonState.Button2Pressed:
|
|
|
+ mouseFlag = MouseFlags.Button2Clicked;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case WindowsConsole.ButtonState.RightmostButtonPressed:
|
|
|
+ mouseFlag = MouseFlags.Button3Clicked;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ point = new Point () {
|
|
|
X = mouseEvent.MousePosition.X,
|
|
|
Y = mouseEvent.MousePosition.Y
|
|
|
};
|
|
|
- //if (p == point) {
|
|
|
- switch (LastMouseButtonPressed) {
|
|
|
- case WindowsConsole.ButtonState.Button1Pressed:
|
|
|
- mouseFlag = MouseFlags.Button1Clicked;
|
|
|
- break;
|
|
|
-
|
|
|
- case WindowsConsole.ButtonState.Button2Pressed:
|
|
|
- mouseFlag = MouseFlags.Button2Clicked;
|
|
|
- break;
|
|
|
-
|
|
|
- case WindowsConsole.ButtonState.RightmostButtonPressed:
|
|
|
- mouseFlag = MouseFlags.Button3Clicked;
|
|
|
- break;
|
|
|
- }
|
|
|
- point = new Point () {
|
|
|
- X = mouseEvent.MousePosition.X,
|
|
|
- Y = mouseEvent.MousePosition.Y
|
|
|
- };
|
|
|
- //} else {
|
|
|
- // mouseFlag = 0;
|
|
|
- //}
|
|
|
LastMouseButtonPressed = null;
|
|
|
IsButtonReleased = false;
|
|
|
} else if (mouseEvent.EventFlags.HasFlag (WindowsConsole.EventFlags.DoubleClick)) {
|
|
@@ -975,7 +961,7 @@ namespace Terminal.Gui {
|
|
|
async Task ProcessContinuousButtonPressedAsync (WindowsConsole.MouseEventRecord mouseEvent, MouseFlags mouseFlag)
|
|
|
{
|
|
|
while (IsButtonPressed) {
|
|
|
- await Task.Delay (200);
|
|
|
+ await Task.Delay (100);
|
|
|
var me = new MouseEvent () {
|
|
|
X = mouseEvent.MousePosition.X,
|
|
|
Y = mouseEvent.MousePosition.Y,
|
|
@@ -1009,7 +995,7 @@ namespace Terminal.Gui {
|
|
|
|
|
|
KeyModifiers keyModifiers;
|
|
|
|
|
|
- public ConsoleKeyInfoEx ToConsoleKeyInfoEx (WindowsConsole.KeyEventRecord keyEvent)
|
|
|
+ public WindowsConsole.ConsoleKeyInfoEx ToConsoleKeyInfoEx (WindowsConsole.KeyEventRecord keyEvent)
|
|
|
{
|
|
|
var state = keyEvent.dwControlKeyState;
|
|
|
|
|
@@ -1036,10 +1022,10 @@ namespace Terminal.Gui {
|
|
|
keyModifiers.Scrolllock = scrolllock;
|
|
|
|
|
|
var ConsoleKeyInfo = new ConsoleKeyInfo (keyEvent.UnicodeChar, (ConsoleKey)keyEvent.wVirtualKeyCode, shift, alt, control);
|
|
|
- return new ConsoleKeyInfoEx (ConsoleKeyInfo, capslock, numlock);
|
|
|
+ return new WindowsConsole.ConsoleKeyInfoEx (ConsoleKeyInfo, capslock, numlock);
|
|
|
}
|
|
|
|
|
|
- public Key MapKey (ConsoleKeyInfoEx keyInfoEx)
|
|
|
+ public Key MapKey (WindowsConsole.ConsoleKeyInfoEx keyInfoEx)
|
|
|
{
|
|
|
var keyInfo = keyInfoEx.consoleKeyInfo;
|
|
|
switch (keyInfo.Key) {
|
|
@@ -1163,7 +1149,7 @@ namespace Terminal.Gui {
|
|
|
return (Key)(0xffffffff);
|
|
|
}
|
|
|
|
|
|
- private Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key)
|
|
|
+ Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key)
|
|
|
{
|
|
|
Key keyMod = new Key ();
|
|
|
if ((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0)
|
|
@@ -1179,7 +1165,48 @@ namespace Terminal.Gui {
|
|
|
public override void Init (Action terminalResized)
|
|
|
{
|
|
|
TerminalResized = terminalResized;
|
|
|
- SetupColorsAndBorders ();
|
|
|
+
|
|
|
+ cols = Console.WindowWidth;
|
|
|
+ rows = Console.WindowHeight;
|
|
|
+#if false
|
|
|
+ winConsole.ShowWindow (WindowsConsole.RESTORE);
|
|
|
+#endif
|
|
|
+ WindowsConsole.SmallRect.MakeEmpty (ref damageRegion);
|
|
|
+
|
|
|
+ ResizeScreen ();
|
|
|
+ UpdateOffScreen ();
|
|
|
+
|
|
|
+ Colors.TopLevel = new ColorScheme ();
|
|
|
+ Colors.Base = new ColorScheme ();
|
|
|
+ Colors.Dialog = new ColorScheme ();
|
|
|
+ Colors.Menu = new ColorScheme ();
|
|
|
+ Colors.Error = new ColorScheme ();
|
|
|
+
|
|
|
+ Colors.TopLevel.Normal = MakeColor (ConsoleColor.Green, ConsoleColor.Black);
|
|
|
+ Colors.TopLevel.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkCyan);
|
|
|
+ Colors.TopLevel.HotNormal = MakeColor (ConsoleColor.DarkYellow, ConsoleColor.Black);
|
|
|
+ Colors.TopLevel.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkCyan);
|
|
|
+
|
|
|
+ Colors.Base.Normal = MakeColor (ConsoleColor.White, ConsoleColor.DarkBlue);
|
|
|
+ Colors.Base.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
|
|
|
+ Colors.Base.HotNormal = MakeColor (ConsoleColor.DarkCyan, ConsoleColor.DarkBlue);
|
|
|
+ Colors.Base.HotFocus = MakeColor (ConsoleColor.Blue, ConsoleColor.Gray);
|
|
|
+
|
|
|
+ Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.DarkGray);
|
|
|
+ Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black);
|
|
|
+ Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.DarkGray);
|
|
|
+ Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black);
|
|
|
+ Colors.Menu.Disabled = MakeColor (ConsoleColor.Gray, ConsoleColor.DarkGray);
|
|
|
+
|
|
|
+ Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray);
|
|
|
+ Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkGray);
|
|
|
+ Colors.Dialog.HotNormal = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.Gray);
|
|
|
+ Colors.Dialog.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkGray);
|
|
|
+
|
|
|
+ Colors.Error.Normal = MakeColor (ConsoleColor.DarkRed, ConsoleColor.White);
|
|
|
+ Colors.Error.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkRed);
|
|
|
+ Colors.Error.HotNormal = MakeColor (ConsoleColor.Black, ConsoleColor.White);
|
|
|
+ Colors.Error.HotFocus = MakeColor (ConsoleColor.Black, ConsoleColor.DarkRed);
|
|
|
}
|
|
|
|
|
|
void ResizeScreen ()
|
|
@@ -1196,12 +1223,15 @@ namespace Terminal.Gui {
|
|
|
|
|
|
void UpdateOffScreen ()
|
|
|
{
|
|
|
- for (int row = 0; row < rows; row++)
|
|
|
+ for (int row = 0; row < rows; row++) {
|
|
|
for (int col = 0; col < cols; col++) {
|
|
|
int position = row * cols + col;
|
|
|
OutputBuffer [position].Attributes = (ushort)Colors.TopLevel.Normal;
|
|
|
OutputBuffer [position].Char.UnicodeChar = ' ';
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ winChanging = false;
|
|
|
}
|
|
|
|
|
|
int ccol, crow;
|
|
@@ -1245,21 +1275,20 @@ namespace Terminal.Gui {
|
|
|
}
|
|
|
|
|
|
int currentAttribute;
|
|
|
- CancellationTokenSource tokenSource = new CancellationTokenSource ();
|
|
|
|
|
|
public override void SetAttribute (Attribute c)
|
|
|
{
|
|
|
- currentAttribute = c.value;
|
|
|
+ currentAttribute = c.Value;
|
|
|
}
|
|
|
|
|
|
Attribute MakeColor (ConsoleColor f, ConsoleColor b)
|
|
|
{
|
|
|
// Encode the colors into the int value.
|
|
|
- return new Attribute () {
|
|
|
- value = ((int)f | (int)b << 4),
|
|
|
- foreground = (Color)f,
|
|
|
- background = (Color)b
|
|
|
- };
|
|
|
+ return new Attribute (
|
|
|
+ value: ((int)f | (int)b << 4),
|
|
|
+ foreground: (Color)f,
|
|
|
+ background: (Color)b
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
public override Attribute MakeAttribute (Color fore, Color back)
|
|
@@ -1298,16 +1327,16 @@ namespace Terminal.Gui {
|
|
|
Y = (short)Clip.Height
|
|
|
};
|
|
|
|
|
|
- var window = new WindowsConsole.SmallRect () {
|
|
|
- Top = 0,
|
|
|
- Left = 0,
|
|
|
- Right = (short)Clip.Right,
|
|
|
- Bottom = (short)Clip.Bottom
|
|
|
- };
|
|
|
+ //var window = new WindowsConsole.SmallRect () {
|
|
|
+ // Top = 0,
|
|
|
+ // Left = 0,
|
|
|
+ // Right = (short)Clip.Right,
|
|
|
+ // Bottom = (short)Clip.Bottom
|
|
|
+ //};
|
|
|
|
|
|
UpdateCursor ();
|
|
|
winConsole.WriteToConsole (OutputBuffer, bufferCoords, damageRegion);
|
|
|
- // System.Diagnostics.Debugger.Log(0, "debug", $"Region={damageRegion.Right - damageRegion.Left},{damageRegion.Bottom - damageRegion.Top}\n");
|
|
|
+ //System.Diagnostics.Debugger.Log(0, "debug", $"Region={damageRegion.Right - damageRegion.Left},{damageRegion.Bottom - damageRegion.Top}\n");
|
|
|
WindowsConsole.SmallRect.MakeEmpty (ref damageRegion);
|
|
|
}
|
|
|
|
|
@@ -1325,7 +1354,12 @@ namespace Terminal.Gui {
|
|
|
winConsole.Cleanup ();
|
|
|
}
|
|
|
|
|
|
-#region Unused
|
|
|
+ public override Attribute GetAttribute ()
|
|
|
+ {
|
|
|
+ return currentAttribute;
|
|
|
+ }
|
|
|
+
|
|
|
+ #region Unused
|
|
|
public override void SetColors (ConsoleColor foreground, ConsoleColor background)
|
|
|
{
|
|
|
}
|
|
@@ -1353,8 +1387,242 @@ namespace Terminal.Gui {
|
|
|
public override void CookMouse ()
|
|
|
{
|
|
|
}
|
|
|
-#endregion
|
|
|
-
|
|
|
+ #endregion
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Mainloop intended to be used with the <see cref="WindowsDriver"/>, and can
|
|
|
+ /// only be used on Windows.
|
|
|
+ /// </summary>
|
|
|
+ /// <remarks>
|
|
|
+ /// This implementation is used for WindowsDriver.
|
|
|
+ /// </remarks>
|
|
|
+ internal class WindowsMainLoop : IMainLoopDriver {
|
|
|
+ ManualResetEventSlim eventReady = new ManualResetEventSlim (false);
|
|
|
+ ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false);
|
|
|
+ ManualResetEventSlim winChange = new ManualResetEventSlim (false);
|
|
|
+ MainLoop mainLoop;
|
|
|
+ ConsoleDriver consoleDriver;
|
|
|
+ WindowsConsole winConsole;
|
|
|
+ bool winChanged;
|
|
|
+ Size windowSize;
|
|
|
+ CancellationTokenSource tokenSource = new CancellationTokenSource ();
|
|
|
+
|
|
|
+ // The records that we keep fetching
|
|
|
+ WindowsConsole.InputRecord [] result = new WindowsConsole.InputRecord [1];
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Invoked when a Key is pressed or released.
|
|
|
+ /// </summary>
|
|
|
+ public Action<WindowsConsole.InputRecord> ProcessInput;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Invoked when the window is changed.
|
|
|
+ /// </summary>
|
|
|
+ public Action<Size> WinChanged;
|
|
|
+
|
|
|
+ public bool Maximized;
|
|
|
+ public bool Restored;
|
|
|
+
|
|
|
+ public WindowsMainLoop (ConsoleDriver consoleDriver = null)
|
|
|
+ {
|
|
|
+ if (consoleDriver == null) {
|
|
|
+ throw new ArgumentNullException ("Console driver instance must be provided.");
|
|
|
+ }
|
|
|
+ this.consoleDriver = consoleDriver;
|
|
|
+ winConsole = ((WindowsDriver)consoleDriver).WinConsole;
|
|
|
+ }
|
|
|
+
|
|
|
+ void IMainLoopDriver.Setup (MainLoop mainLoop)
|
|
|
+ {
|
|
|
+ this.mainLoop = mainLoop;
|
|
|
+ Task.Run (WindowsInputHandler);
|
|
|
+ Task.Run (CheckWinChange);
|
|
|
+ }
|
|
|
+
|
|
|
+ void WindowsInputHandler ()
|
|
|
+ {
|
|
|
+ while (true) {
|
|
|
+ waitForProbe.Wait ();
|
|
|
+ waitForProbe.Reset ();
|
|
|
+
|
|
|
+ result = winConsole.ReadConsoleInput ();
|
|
|
+
|
|
|
+ eventReady.Set ();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void CheckWinChange ()
|
|
|
+ {
|
|
|
+ while (true) {
|
|
|
+ winChange.Wait ();
|
|
|
+ winChange.Reset ();
|
|
|
+ WaitWinChange ();
|
|
|
+ winChanged = true;
|
|
|
+ eventReady.Set ();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const int Width_Divider = 8;
|
|
|
+ const int Height_Divider = 18;
|
|
|
+ bool docked;
|
|
|
+
|
|
|
+ void WaitWinChange ()
|
|
|
+ {
|
|
|
+ var handle = winConsole.GetConsole ();
|
|
|
+
|
|
|
+ while (!consoleDriver.HeightAsBuffer) {
|
|
|
+ WindowsConsole.WindowPlacement windowPlacement = new WindowsConsole.WindowPlacement ();
|
|
|
+ winConsole.GetWindow (handle, ref windowPlacement);
|
|
|
+
|
|
|
+ if (windowPlacement.rcNormalPosition.Size.Height > -1) {
|
|
|
+ windowSize = SetWindowSize (windowPlacement.rcNormalPosition);
|
|
|
+
|
|
|
+ if (windowPlacement.showCmd != WindowsConsole.SHOW_MAXIMIZED && !Maximized && !Restored && !docked
|
|
|
+ && (windowSize.Width != consoleDriver.Cols || windowSize.Height != consoleDriver.Rows)) {
|
|
|
+ docked = false;
|
|
|
+ return;
|
|
|
+ } else if (windowPlacement.showCmd == WindowsConsole.SHOW_MAXIMIZED && !Maximized
|
|
|
+ && (Console.LargestWindowWidth != consoleDriver.Cols || Console.LargestWindowHeight != consoleDriver.Rows)) {
|
|
|
+ windowSize = new Size (Console.LargestWindowWidth, Console.LargestWindowHeight);
|
|
|
+ Maximized = true;
|
|
|
+ docked = false;
|
|
|
+ return;
|
|
|
+ } else if (windowPlacement.showCmd != WindowsConsole.SHOW_MAXIMIZED && Maximized) {
|
|
|
+ windowPlacement = new WindowsConsole.WindowPlacement () {
|
|
|
+ showCmd = WindowsConsole.RESTORE
|
|
|
+ };
|
|
|
+ winConsole.SetWindow (handle, ref windowPlacement);
|
|
|
+ Restored = true;
|
|
|
+ Maximized = false;
|
|
|
+ docked = false;
|
|
|
+ return;
|
|
|
+ } else if (!Maximized && IsDockedToMonitor (handle, windowPlacement)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Size SetWindowSize (System.Drawing.Rectangle rect)
|
|
|
+ {
|
|
|
+ return new Size (Math.Max (((rect.Width - rect.X) / Width_Divider) - 2, 0),
|
|
|
+ Math.Max (((rect.Height - rect.Y) / Height_Divider) - 2, 0));
|
|
|
+ }
|
|
|
+
|
|
|
+ bool IsDockedToMonitor (IntPtr hWnd, WindowsConsole.WindowPlacement placement)
|
|
|
+ {
|
|
|
+ System.Drawing.Rectangle rc;
|
|
|
+ winConsole.GetRect (hWnd, out rc);
|
|
|
+
|
|
|
+ var changed = placement.showCmd == WindowsConsole.SHOW_NORMAL
|
|
|
+ && (rc.Left != placement.rcNormalPosition.Left ||
|
|
|
+ rc.Top != placement.rcNormalPosition.Top ||
|
|
|
+ rc.Right != placement.rcNormalPosition.Right ||
|
|
|
+ rc.Bottom != placement.rcNormalPosition.Bottom);
|
|
|
+
|
|
|
+ if (changed) {
|
|
|
+ var pSize = new Size (placement.rcNormalPosition.Size.Width - placement.rcNormalPosition.X,
|
|
|
+ placement.rcNormalPosition.Size.Height - placement.rcNormalPosition.Y);
|
|
|
+ var rSize = new Size (rc.Width - rc.X,
|
|
|
+ rc.Height - rc.Y);
|
|
|
+ windowSize = SetWindowSize (rc);
|
|
|
+
|
|
|
+ if ((rc.X < 0) || (rc.Y == 0) || (rc.Y == 0 && rc.X < 0)
|
|
|
+ || (rc.Y == 0 && rc.Right / Width_Divider >= Console.LargestWindowWidth)
|
|
|
+ || (rc.X < 0 && rc.Bottom / Height_Divider >= Console.LargestWindowHeight)
|
|
|
+ || (rc.X / Width_Divider >= Console.LargestWindowWidth / 2 - 1 && rc.Bottom / Height_Divider >= Console.LargestWindowHeight)) {
|
|
|
+ if (!docked || consoleDriver.Cols != windowSize.Width
|
|
|
+ || consoleDriver.Rows != windowSize.Height) {
|
|
|
+ docked = true;
|
|
|
+ } else {
|
|
|
+ changed = false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (!docked && (pSize == rSize || rSize.Width / Width_Divider >= Console.LargestWindowWidth
|
|
|
+ || rSize.Height / Height_Divider >= Console.LargestWindowHeight)) {
|
|
|
+ changed = false;
|
|
|
+ }
|
|
|
+ docked = false;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ docked = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return changed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void IMainLoopDriver.Wakeup ()
|
|
|
+ {
|
|
|
+ //tokenSource.Cancel ();
|
|
|
+ eventReady.Set ();
|
|
|
+ }
|
|
|
+
|
|
|
+ bool IMainLoopDriver.EventsPending (bool wait)
|
|
|
+ {
|
|
|
+ if (CheckTimers (wait, out var waitTimeout)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ //result = null;
|
|
|
+ waitForProbe.Set ();
|
|
|
+ if (!consoleDriver.HeightAsBuffer) {
|
|
|
+ winChange.Set ();
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (!tokenSource.IsCancellationRequested) {
|
|
|
+ eventReady.Wait (waitTimeout, tokenSource.Token);
|
|
|
+ }
|
|
|
+ } catch (OperationCanceledException) {
|
|
|
+ return true;
|
|
|
+ } finally {
|
|
|
+ eventReady.Reset ();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!tokenSource.IsCancellationRequested) {
|
|
|
+ return result != null || CheckTimers (wait, out _) || winChanged;
|
|
|
+ }
|
|
|
+
|
|
|
+ tokenSource.Dispose ();
|
|
|
+ tokenSource = new CancellationTokenSource ();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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.MainIteration ()
|
|
|
+ {
|
|
|
+ if (result != null) {
|
|
|
+ var inputEvent = result [0];
|
|
|
+ result = null;
|
|
|
+ ProcessInput?.Invoke (inputEvent);
|
|
|
+ }
|
|
|
+ if (winChanged) {
|
|
|
+ winChanged = false;
|
|
|
+ WinChanged?.Invoke (windowSize);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|