Browse Source

merged develop - mostly

Tigger Kindel 2 years ago
parent
commit
8c319ee189
32 changed files with 2845 additions and 1773 deletions
  1. 2 2
      ReactiveExample/ReactiveExample.csproj
  2. 84 395
      Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
  3. 3 27
      Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs
  4. 14 21
      Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs
  5. 0 5
      Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs
  6. 2 2
      Terminal.Gui/ConsoleDrivers/CursesDriver/constants.cs
  7. 284 289
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs
  8. 14 12
      Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs
  9. 258 828
      Terminal.Gui/ConsoleDrivers/NetDriver.cs
  10. 56 36
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  11. 35 13
      Terminal.Gui/Core/Application.cs
  12. 2 2
      Terminal.Gui/Core/Border.cs
  13. 24 71
      Terminal.Gui/Core/ConsoleDriver.cs
  14. 19 0
      Terminal.Gui/Core/ConsoleKeyMapping.cs
  15. 109 0
      Terminal.Gui/Core/EscSeqUtils/EscSeqReq.cs
  16. 907 0
      Terminal.Gui/Core/EscSeqUtils/EscSeqUtils.cs
  17. 1 1
      Terminal.Gui/Core/Event.cs
  18. 7 12
      Terminal.Gui/Core/Window.cs
  19. 1 1
      Terminal.Gui/Resources/config.json
  20. 4 5
      Terminal.Gui/Terminal.Gui.csproj
  21. 7 1
      Terminal.Gui/Views/FrameView.cs
  22. 6 4
      UICatalog/Properties/launchSettings.json
  23. 3 2
      UICatalog/Scenarios/BordersComparisons.cs
  24. 15 13
      UICatalog/UICatalog.cs
  25. 6 7
      UnitTests/Application/ApplicationTests.cs
  26. 4 4
      UnitTests/Configuration/ConfigurationMangerTests.cs
  27. 1 1
      UnitTests/Configuration/SettingsScopeTests.cs
  28. 12 2
      UnitTests/Core/BorderTests.cs
  29. 78 0
      UnitTests/Core/EscSeqReqTests.cs
  30. 870 0
      UnitTests/Core/EscSeqUtilsTests.cs
  31. 15 15
      UnitTests/Drivers/ConsoleDriverTests.cs
  32. 2 2
      UnitTests/UnitTests.csproj

+ 2 - 2
ReactiveExample/ReactiveExample.csproj

@@ -11,8 +11,8 @@
     <InformationalVersion>1.0</InformationalVersion>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="ReactiveUI.Fody" Version="18.4.1" />
-    <PackageReference Include="ReactiveUI" Version="18.4.1" />
+    <PackageReference Include="ReactiveUI.Fody" Version="18.4.22" />
+    <PackageReference Include="ReactiveUI" Version="18.4.22" />
     <PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="1.2.3" PrivateAssets="all" />
   </ItemGroup>
   <ItemGroup>

+ 84 - 395
Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs

@@ -1,9 +1,6 @@
 //
 // Driver.cs: Curses-based Driver
 //
-// Authors:
-//   Miguel de Icaza ([email protected])
-//
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -23,7 +20,12 @@ namespace Terminal.Gui {
 		public override int Rows => Curses.Lines;
 		public override int Left => 0;
 		public override int Top => 0;
-		public override bool HeightAsBuffer { get; set; }
+		public override bool EnableConsoleScrolling { get; set; }
+		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
+		public override bool HeightAsBuffer {
+			get => EnableConsoleScrolling;
+			set => EnableConsoleScrolling = value;
+		}
 		public override IClipboard Clipboard { get => clipboard; }
 
 		CursorVisibility? initialCursorVisibility = null;
@@ -116,7 +118,7 @@ namespace Terminal.Gui {
 			if (runeWidth < 0 || runeWidth > 0) {
 				ccol++;
 			}
-			
+
 			if (runeWidth > 1) {
 				if (validClip && ccol < Clip.Right) {
 					contents [crow, ccol, 1] = CurrentAttribute;
@@ -158,26 +160,10 @@ namespace Terminal.Gui {
 
 		public override void End ()
 		{
-			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition)) {
-				StopReportingMouseMoves ();
-			}
-
+			StopReportingMouseMoves ();
 			SetCursorVisibility (CursorVisibility.Default);
 
 			Curses.endwin ();
-
-			// I'm commenting this because was used in a trying to fix the Linux hanging and forgot to exclude it.
-			// Clear and reset entire screen.
-			//Console.Out.Write ("\x1b[2J");
-			//Console.Out.Flush ();
-
-			// Set top and bottom lines of a window.
-			//Console.Out.Write ("\x1b[1;25r");
-			//Console.Out.Flush ();
-
-			//Set cursor key to cursor.
-			//Console.Out.Write ("\x1b[?1l");
-			//Console.Out.Flush ();
 		}
 
 		public override void UpdateScreen () => window.redrawwin ();
@@ -324,305 +310,6 @@ namespace Terminal.Gui {
 			}
 		}
 
-		Curses.Event? lastMouseButtonPressed;
-		bool isButtonPressed;
-		bool cancelButtonClicked;
-		bool isReportMousePosition;
-		Point point;
-		int buttonPressedCount;
-
-		MouseEvent ToDriverMouse (Curses.MouseEvent cev)
-		{
-			MouseFlags mouseFlag = MouseFlags.AllEvents;
-
-			if (lastMouseButtonPressed != null && cev.ButtonState != Curses.Event.ReportMousePosition) {
-				lastMouseButtonPressed = null;
-				isButtonPressed = false;
-			}
-
-			if (cev.ButtonState == Curses.Event.Button1Pressed
-				|| cev.ButtonState == Curses.Event.Button2Pressed
-				|| cev.ButtonState == Curses.Event.Button3Pressed) {
-
-				isButtonPressed = true;
-				buttonPressedCount++;
-			} else {
-				buttonPressedCount = 0;
-			}
-			//System.Diagnostics.Debug.WriteLine ($"buttonPressedCount: {buttonPressedCount}");
-
-			if (buttonPressedCount == 2
-				&& (cev.ButtonState == Curses.Event.Button1Pressed
-				|| cev.ButtonState == Curses.Event.Button2Pressed
-				|| cev.ButtonState == Curses.Event.Button3Pressed)) {
-
-				switch (cev.ButtonState) {
-				case Curses.Event.Button1Pressed:
-					mouseFlag = MouseFlags.Button1DoubleClicked;
-					break;
-
-				case Curses.Event.Button2Pressed:
-					mouseFlag = MouseFlags.Button2DoubleClicked;
-					break;
-
-				case Curses.Event.Button3Pressed:
-					mouseFlag = MouseFlags.Button3DoubleClicked;
-					break;
-				}
-				cancelButtonClicked = true;
-
-			} else if (buttonPressedCount == 3
-			       && (cev.ButtonState == Curses.Event.Button1Pressed
-			       || cev.ButtonState == Curses.Event.Button2Pressed
-			       || cev.ButtonState == Curses.Event.Button3Pressed)) {
-
-				switch (cev.ButtonState) {
-				case Curses.Event.Button1Pressed:
-					mouseFlag = MouseFlags.Button1TripleClicked;
-					break;
-
-				case Curses.Event.Button2Pressed:
-					mouseFlag = MouseFlags.Button2TripleClicked;
-					break;
-
-				case Curses.Event.Button3Pressed:
-					mouseFlag = MouseFlags.Button3TripleClicked;
-					break;
-				}
-				buttonPressedCount = 0;
-
-			} else if ((cev.ButtonState == Curses.Event.Button1Clicked || cev.ButtonState == Curses.Event.Button2Clicked ||
-			       cev.ButtonState == Curses.Event.Button3Clicked) &&
-			       lastMouseButtonPressed == null) {
-
-				isButtonPressed = false;
-				mouseFlag = ProcessButtonClickedEvent (cev);
-
-			} else if (((cev.ButtonState == Curses.Event.Button1Pressed || cev.ButtonState == Curses.Event.Button2Pressed ||
-				cev.ButtonState == Curses.Event.Button3Pressed) && lastMouseButtonPressed == null) ||
-				isButtonPressed && lastMouseButtonPressed != null && cev.ButtonState == Curses.Event.ReportMousePosition) {
-
-				mouseFlag = MapCursesButton (cev.ButtonState);
-				if (cev.ButtonState != Curses.Event.ReportMousePosition)
-					lastMouseButtonPressed = cev.ButtonState;
-				isButtonPressed = true;
-				isReportMousePosition = false;
-
-				if (cev.ButtonState == Curses.Event.ReportMousePosition) {
-					mouseFlag = MapCursesButton ((Curses.Event)lastMouseButtonPressed) | MouseFlags.ReportMousePosition;
-					cancelButtonClicked = true;
-				}
-				point = new Point () {
-					X = cev.X,
-					Y = cev.Y
-				};
-
-				if ((mouseFlag & MouseFlags.ReportMousePosition) == 0) {
-					Application.MainLoop.AddIdle (() => {
-						Task.Run (async () => await ProcessContinuousButtonPressedAsync (mouseFlag));
-						return false;
-					});
-				}
-
-
-			} else if ((cev.ButtonState == Curses.Event.Button1Released || cev.ButtonState == Curses.Event.Button2Released ||
-				cev.ButtonState == Curses.Event.Button3Released)) {
-
-				mouseFlag = ProcessButtonReleasedEvent (cev);
-				isButtonPressed = false;
-
-			} else if (cev.ButtonState == Curses.Event.ButtonWheeledUp) {
-
-				mouseFlag = MouseFlags.WheeledUp;
-
-			} else if (cev.ButtonState == Curses.Event.ButtonWheeledDown) {
-
-				mouseFlag = MouseFlags.WheeledDown;
-
-			} else if ((cev.ButtonState & (Curses.Event.ButtonWheeledUp & Curses.Event.ButtonShift)) != 0) {
-
-				mouseFlag = MouseFlags.WheeledLeft;
-
-			} else if ((cev.ButtonState & (Curses.Event.ButtonWheeledDown & Curses.Event.ButtonShift)) != 0) {
-
-				mouseFlag = MouseFlags.WheeledRight;
-
-			} else if (cev.ButtonState == Curses.Event.ReportMousePosition) {
-				if (cev.X != point.X || cev.Y != point.Y) {
-					mouseFlag = MouseFlags.ReportMousePosition;
-					isReportMousePosition = true;
-					point = new Point ();
-				} else {
-					mouseFlag = 0;
-				}
-
-			} else {
-				mouseFlag = 0;
-				var eFlags = cev.ButtonState;
-				foreach (Enum value in Enum.GetValues (eFlags.GetType ())) {
-					if (eFlags.HasFlag (value)) {
-						mouseFlag |= MapCursesButton ((Curses.Event)value);
-					}
-				}
-			}
-
-			mouseFlag = SetControlKeyStates (cev, mouseFlag);
-
-			return new MouseEvent () {
-				X = cev.X,
-				Y = cev.Y,
-				//Flags = MapCursesButton (cev.ButtonState)
-				Flags = mouseFlag
-			};
-		}
-
-		MouseFlags ProcessButtonClickedEvent (Curses.MouseEvent cev)
-		{
-			lastMouseButtonPressed = cev.ButtonState;
-			var mf = GetButtonState (cev, true);
-			mouseHandler (ProcessButtonState (cev, mf));
-			if (lastMouseButtonPressed != null && lastMouseButtonPressed == cev.ButtonState) {
-				mf = GetButtonState (cev, false);
-				mouseHandler (ProcessButtonState (cev, mf));
-				if (lastMouseButtonPressed != null && lastMouseButtonPressed == cev.ButtonState) {
-					mf = MapCursesButton (cev.ButtonState);
-				}
-			}
-			lastMouseButtonPressed = null;
-			isButtonPressed = false;
-			return mf;
-		}
-
-		MouseFlags ProcessButtonReleasedEvent (Curses.MouseEvent cev)
-		{
-			var mf = MapCursesButton (cev.ButtonState);
-			if (!cancelButtonClicked && lastMouseButtonPressed == null && !isReportMousePosition) {
-				mouseHandler (ProcessButtonState (cev, mf));
-				mf = GetButtonState (cev);
-			} else if (isReportMousePosition) {
-				mf = MouseFlags.ReportMousePosition;
-			}
-			cancelButtonClicked = false;
-			return mf;
-		}
-
-		async Task ProcessContinuousButtonPressedAsync (MouseFlags mouseFlag)
-		{
-			while (isButtonPressed) {
-				await Task.Delay (100);
-				var me = new MouseEvent () {
-					X = point.X,
-					Y = point.Y,
-					Flags = mouseFlag
-				};
-
-				var view = Application.WantContinuousButtonPressedView;
-				if (view == null)
-					break;
-				if (isButtonPressed && lastMouseButtonPressed != null && (mouseFlag & MouseFlags.ReportMousePosition) == 0) {
-					Application.MainLoop.Invoke (() => mouseHandler (me));
-				}
-			}
-		}
-
-		MouseFlags GetButtonState (Curses.MouseEvent cev, bool pressed = false)
-		{
-			MouseFlags mf = default;
-			switch (cev.ButtonState) {
-			case Curses.Event.Button1Clicked:
-				if (pressed)
-					mf = MouseFlags.Button1Pressed;
-				else
-					mf = MouseFlags.Button1Released;
-				break;
-
-			case Curses.Event.Button2Clicked:
-				if (pressed)
-					mf = MouseFlags.Button2Pressed;
-				else
-					mf = MouseFlags.Button2Released;
-				break;
-
-			case Curses.Event.Button3Clicked:
-				if (pressed)
-					mf = MouseFlags.Button3Pressed;
-				else
-					mf = MouseFlags.Button3Released;
-				break;
-
-			case Curses.Event.Button1Released:
-				mf = MouseFlags.Button1Clicked;
-				break;
-
-			case Curses.Event.Button2Released:
-				mf = MouseFlags.Button2Clicked;
-				break;
-
-			case Curses.Event.Button3Released:
-				mf = MouseFlags.Button3Clicked;
-				break;
-
-			}
-			return mf;
-		}
-
-		MouseEvent ProcessButtonState (Curses.MouseEvent cev, MouseFlags mf)
-		{
-			return new MouseEvent () {
-				X = cev.X,
-				Y = cev.Y,
-				Flags = mf
-			};
-		}
-
-		MouseFlags MapCursesButton (Curses.Event cursesButton)
-		{
-			switch (cursesButton) {
-			case Curses.Event.Button1Pressed: return MouseFlags.Button1Pressed;
-			case Curses.Event.Button1Released: return MouseFlags.Button1Released;
-			case Curses.Event.Button1Clicked: return MouseFlags.Button1Clicked;
-			case Curses.Event.Button1DoubleClicked: return MouseFlags.Button1DoubleClicked;
-			case Curses.Event.Button1TripleClicked: return MouseFlags.Button1TripleClicked;
-			case Curses.Event.Button2Pressed: return MouseFlags.Button2Pressed;
-			case Curses.Event.Button2Released: return MouseFlags.Button2Released;
-			case Curses.Event.Button2Clicked: return MouseFlags.Button2Clicked;
-			case Curses.Event.Button2DoubleClicked: return MouseFlags.Button2DoubleClicked;
-			case Curses.Event.Button2TrippleClicked: return MouseFlags.Button2TripleClicked;
-			case Curses.Event.Button3Pressed: return MouseFlags.Button3Pressed;
-			case Curses.Event.Button3Released: return MouseFlags.Button3Released;
-			case Curses.Event.Button3Clicked: return MouseFlags.Button3Clicked;
-			case Curses.Event.Button3DoubleClicked: return MouseFlags.Button3DoubleClicked;
-			case Curses.Event.Button3TripleClicked: return MouseFlags.Button3TripleClicked;
-			case Curses.Event.ButtonWheeledUp: return MouseFlags.WheeledUp;
-			case Curses.Event.ButtonWheeledDown: return MouseFlags.WheeledDown;
-			case Curses.Event.Button4Pressed: return MouseFlags.Button4Pressed;
-			case Curses.Event.Button4Released: return MouseFlags.Button4Released;
-			case Curses.Event.Button4Clicked: return MouseFlags.Button4Clicked;
-			case Curses.Event.Button4DoubleClicked: return MouseFlags.Button4DoubleClicked;
-			case Curses.Event.Button4TripleClicked: return MouseFlags.Button4TripleClicked;
-			case Curses.Event.ButtonShift: return MouseFlags.ButtonShift;
-			case Curses.Event.ButtonCtrl: return MouseFlags.ButtonCtrl;
-			case Curses.Event.ButtonAlt: return MouseFlags.ButtonAlt;
-			case Curses.Event.ReportMousePosition: return MouseFlags.ReportMousePosition;
-			case Curses.Event.AllEvents: return MouseFlags.AllEvents;
-			default: return 0;
-			}
-		}
-
-		static MouseFlags SetControlKeyStates (Curses.MouseEvent cev, MouseFlags mouseFlag)
-		{
-			if ((cev.ButtonState & Curses.Event.ButtonCtrl) != 0 && (mouseFlag & MouseFlags.ButtonCtrl) == 0)
-				mouseFlag |= MouseFlags.ButtonCtrl;
-
-			if ((cev.ButtonState & Curses.Event.ButtonShift) != 0 && (mouseFlag & MouseFlags.ButtonShift) == 0)
-				mouseFlag |= MouseFlags.ButtonShift;
-
-			if ((cev.ButtonState & Curses.Event.ButtonAlt) != 0 && (mouseFlag & MouseFlags.ButtonAlt) == 0)
-				mouseFlag |= MouseFlags.ButtonAlt;
-			return mouseFlag;
-		}
-
-
 		KeyModifiers keyModifiers;
 
 		KeyModifiers MapKeyModifiers (Key key)
@@ -656,9 +343,18 @@ namespace Terminal.Gui {
 					ProcessWinChange ();
 				}
 				if (wch == Curses.KeyMouse) {
-					Curses.getmouse (out Curses.MouseEvent ev);
-					//System.Diagnostics.Debug.WriteLine ($"ButtonState: {ev.ButtonState}; ID: {ev.ID}; X: {ev.X}; Y: {ev.Y}; Z: {ev.Z}");
-					mouseHandler (ToDriverMouse (ev));
+					int wch2 = wch;
+
+					while (wch2 == Curses.KeyMouse) {
+						KeyEvent key = null;
+						ConsoleKeyInfo [] cki = new ConsoleKeyInfo [] {
+							new ConsoleKeyInfo ((char)Key.Esc, 0, false, false, false),
+							new ConsoleKeyInfo ('[', 0, false, false, false),
+							new ConsoleKeyInfo ('<', 0, false, false, false)
+						};
+						code = 0;
+						GetEscSeq (ref code, ref k, ref wch2, ref key, ref cki);
+					}
 					return;
 				}
 				k = MapCursesKey (wch);
@@ -694,7 +390,7 @@ namespace Terminal.Gui {
 					k = Key.AltMask | MapCursesKey (wch);
 				}
 				if (code == 0) {
-					KeyEvent key;
+					KeyEvent key = null;
 
 					// The ESC-number handling, debatable.
 					// Simulates the AltMask itself by pressing Alt + Space.
@@ -706,55 +402,13 @@ namespace Terminal.Gui {
 						k = (Key)((uint)(Key.AltMask | Key.CtrlMask) + (wch2 + 64));
 					} else if (wch2 >= (uint)Key.D0 && wch2 <= (uint)Key.D9) {
 						k = (Key)((uint)Key.AltMask + (uint)Key.D0 + (wch2 - (uint)Key.D0));
-					} else if (wch2 == 27) {
-						k = (Key)wch2;
-					} else if (wch2 == Curses.KEY_CODE_SEQ) {
-						int [] c = null;
-						while (code == 0) {
-							code = Curses.get_wch (out wch2);
-							if (wch2 > 0) {
-								Array.Resize (ref c, c == null ? 1 : c.Length + 1);
-								c [c.Length - 1] = wch2;
-							}
-						}
-						if (c [0] == 49 && c [1] == 59 && c [2] == 55 && c [3] >= 80 && c [3] <= 83) { // Ctrl+Alt+(F1 - F4)
-							wch2 = c [3] + 185;
-							k = Key.CtrlMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [2] == 59 && c [3] == 55 && c [4] == 126 && c [1] >= 53 && c [1] <= 57) { // Ctrl+Alt+(F5 - F8)
-							wch2 = c [1] == 53 ? c [1] + 216 : c [1] + 215;
-							k = Key.CtrlMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 50 && c [2] == 59 && c [3] == 55 && c [4] == 126 && c [1] >= 48 && c [1] <= 52) { // Ctrl+Alt+(F9 - F12)
-							wch2 = c [1] < 51 ? c [1] + 225 : c [1] + 224;
-							k = Key.CtrlMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [1] == 59 && c [2] == 56 && c [3] >= 80 && c [3] <= 83) { // Ctrl+Shift+Alt+(F1 - F4)
-							wch2 = c [3] + 185;
-							k = Key.CtrlMask | Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [2] == 59 && c [3] == 56 && c [4] == 126 && c [1] >= 53 && c [1] <= 57) { // Ctrl+Shift+Alt+(F5 - F8)
-							wch2 = c [1] == 53 ? c [1] + 216 : c [1] + 215;
-							k = Key.CtrlMask | Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 50 && c [2] == 59 && c [3] == 56 && c [4] == 126 && c [1] >= 48 && c [1] <= 52) {  // Ctrl+Shift+Alt+(F9 - F12)
-							wch2 = c [1] < 51 ? c [1] + 225 : c [1] + 224;
-							k = Key.CtrlMask | Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [1] == 59 && c [2] == 52 && c [3] == 83) {  // Shift+Alt+(F4)
-							wch2 = 268;
-							k = Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 49 && c [2] == 59 && c [3] == 52 && c [4] == 126 && c [1] >= 53 && c [1] <= 57) {  // Shift+Alt+(F5 - F8)
-							wch2 = c [1] < 55 ? c [1] + 216 : c [1] + 215;
-							k = Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 50 && c [2] == 59 && c [3] == 52 && c [4] == 126 && c [1] >= 48 && c [1] <= 52) {  // Shift+Alt+(F9 - F12)
-							wch2 = c [1] < 51 ? c [1] + 225 : c [1] + 224;
-							k = Key.ShiftMask | Key.AltMask | MapCursesKey (wch2);
-						} else if (c [0] == 54 && c [1] == 59 && c [2] == 56 && c [3] == 126) {  // Shift+Ctrl+Alt+KeyNPage
-							k = Key.ShiftMask | Key.CtrlMask | Key.AltMask | Key.PageDown;
-						} else if (c [0] == 53 && c [1] == 59 && c [2] == 56 && c [3] == 126) {  // Shift+Ctrl+Alt+KeyPPage
-							k = Key.ShiftMask | Key.CtrlMask | Key.AltMask | Key.PageUp;
-						} else if (c [0] == 49 && c [1] == 59 && c [2] == 56 && c [3] == 72) {  // Shift+Ctrl+Alt+KeyHome
-							k = Key.ShiftMask | Key.CtrlMask | Key.AltMask | Key.Home;
-						} else if (c [0] == 49 && c [1] == 59 && c [2] == 56 && c [3] == 70) {  // Shift+Ctrl+Alt+KeyEnd
-							k = Key.ShiftMask | Key.CtrlMask | Key.AltMask | Key.End;
-						} else {
-							k = MapCursesKey (wch2);
-						}
+					} else if (wch2 == Curses.KeyCSI) {
+						ConsoleKeyInfo [] cki = new ConsoleKeyInfo [] {
+							new ConsoleKeyInfo ((char)Key.Esc, 0, false, false, false),
+							new ConsoleKeyInfo ('[', 0, false, false, false)
+						};
+						GetEscSeq (ref code, ref k, ref wch2, ref key, ref cki);
+						return;
 					} else {
 						// Unfortunately there are no way to differentiate Ctrl+Alt+alfa and Ctrl+Shift+Alt+alfa.
 						if (((Key)wch2 & Key.CtrlMask) != 0) {
@@ -809,6 +463,52 @@ namespace Terminal.Gui {
 			//}
 		}
 
+		void GetEscSeq (ref int code, ref Key k, ref int wch2, ref KeyEvent key, ref ConsoleKeyInfo [] cki)
+		{
+			ConsoleKey ck = 0;
+			ConsoleModifiers mod = 0;
+			while (code == 0) {
+				code = Curses.get_wch (out wch2);
+				var consoleKeyInfo = new ConsoleKeyInfo ((char)wch2, 0, false, false, false);
+				if (wch2 == 0 || wch2 == 27 || wch2 == Curses.KeyMouse) {
+					EscSeqUtils.DecodeEscSeq (null, ref consoleKeyInfo, ref ck, cki, ref mod, out _, out _, out _, out _, out bool isKeyMouse, out List<MouseFlags> mouseFlags, out Point pos, out _, ProcessContinuousButtonPressed);
+					if (isKeyMouse) {
+						foreach (var mf in mouseFlags) {
+							ProcessMouseEvent (mf, pos);
+						}
+						cki = null;
+						if (wch2 == 27) {
+							cki = EscSeqUtils.ResizeArray (new ConsoleKeyInfo ((char)Key.Esc, 0,
+								false, false, false), cki);
+						}
+					} else {
+						k = ConsoleKeyMapping.MapConsoleKeyToKey (consoleKeyInfo.Key, out _);
+						k = ConsoleKeyMapping.MapKeyModifiers (consoleKeyInfo, k);
+						key = new KeyEvent (k, MapKeyModifiers (k));
+						keyDownHandler (key);
+						keyHandler (key);
+					}
+				} else {
+					cki = EscSeqUtils.ResizeArray (consoleKeyInfo, cki);
+				}
+			}
+		}
+
+		void ProcessMouseEvent (MouseFlags mouseFlag, Point pos)
+		{
+			var me = new MouseEvent () {
+				Flags = mouseFlag,
+				X = pos.X,
+				Y = pos.Y
+			};
+			mouseHandler (me);
+		}
+
+		void ProcessContinuousButtonPressed (MouseFlags mouseFlag, Point pos)
+		{
+			ProcessMouseEvent (mouseFlag, pos);
+		}
+
 		Action<KeyEvent> keyHandler;
 		Action<KeyEvent> keyDownHandler;
 		Action<KeyEvent> keyUpHandler;
@@ -835,17 +535,12 @@ namespace Terminal.Gui {
 			};
 		}
 
-		Curses.Event oldMouseEvents, reportableMouseEvents;
 		public override void Init (Action terminalResized)
 		{
 			if (window != null)
 				return;
 
 			try {
-				//Set cursor key to application.
-				//Console.Out.Write ("\x1b[?1h");
-				//Console.Out.Flush ();
-
 				window = Curses.initscr ();
 				Curses.set_escdelay (10);
 			} catch (Exception e) {
@@ -892,10 +587,8 @@ namespace Terminal.Gui {
 			Curses.noecho ();
 
 			Curses.Window.Standard.keypad (true);
-			reportableMouseEvents = Curses.mousemask (Curses.Event.AllEvents | Curses.Event.ReportMousePosition, out oldMouseEvents);
 			TerminalResized = terminalResized;
-			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition))
-				StartReportingMouseMoves ();
+			StartReportingMouseMoves ();
 
 			CurrentAttribute = MakeColor (Color.White, Color.Black);
 
@@ -944,8 +637,7 @@ namespace Terminal.Gui {
 		public override void ResizeScreen ()
 		{
 			Clip = new Rect (0, 0, Cols, Rows);
-			Console.Out.Write ("\x1b[3J");
-			Console.Out.Flush ();
+			Curses.refresh ();
 		}
 
 		public override void UpdateOffScreen ()
@@ -1065,25 +757,21 @@ namespace Terminal.Gui {
 
 		public override void Suspend ()
 		{
-			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition))
-				StopReportingMouseMoves ();
+			StopReportingMouseMoves ();
 			Platform.Suspend ();
 			Curses.Window.Standard.redrawwin ();
 			Curses.refresh ();
-			if (reportableMouseEvents.HasFlag (Curses.Event.ReportMousePosition))
-				StartReportingMouseMoves ();
+			StartReportingMouseMoves ();
 		}
 
 		public override void StartReportingMouseMoves ()
 		{
-			Console.Out.Write ("\x1b[?1003h");
-			Console.Out.Flush ();
+			Console.Out.Write (EscSeqUtils.EnableMouseEvents);
 		}
 
 		public override void StopReportingMouseMoves ()
 		{
-			Console.Out.Write ("\x1b[?1003l");
-			Console.Out.Flush ();
+			Console.Out.Write (EscSeqUtils.DisableMouseEvents);
 		}
 
 		//int lastMouseInterval;
@@ -1126,7 +814,6 @@ namespace Terminal.Gui {
 
 			if (visibility != CursorVisibility.Invisible) {
 				Console.Out.Write ("\x1b[{0} q", ((int)visibility >> 24) & 0xFF);
-				Console.Out.Flush ();
 			}
 
 			currentCursorVisibility = visibility;
@@ -1191,8 +878,8 @@ namespace Terminal.Gui {
 			background = default;
 			int back = -1;
 			IEnumerable<int> values = Enum.GetValues (typeof (ConsoleColor))
-			      .OfType<ConsoleColor> ()
-			      .Select (s => (int)s);
+				.OfType<ConsoleColor> ()
+				.Select (s => (int)s);
 			if (values.Contains ((value >> 12) & 0xffff)) {
 				hasColor = true;
 				back = (value >> 12) & 0xffff;
@@ -1285,6 +972,7 @@ namespace Terminal.Gui {
 
 		bool CheckSupport ()
 		{
+#pragma warning disable RCS1075 // Avoid empty catch clause that catches System.Exception.
 			try {
 				var (exitCode, result) = ClipboardProcessRunner.Bash ("which xclip", waitForOutput: true);
 				if (exitCode == 0 && result.FileExists ()) {
@@ -1294,6 +982,7 @@ namespace Terminal.Gui {
 			} catch (Exception) {
 				// Permissions issue.
 			}
+#pragma warning restore RCS1075 // Avoid empty catch clause that catches System.Exception.
 			return false;
 		}
 

+ 3 - 27
Terminal.Gui/ConsoleDrivers/CursesDriver/UnixMainLoop.cs

@@ -1,30 +1,6 @@
 //
 // mainloop.cs: Simple managed mainloop implementation.
 //
-// Authors:
-//   Miguel de Icaza ([email protected])
-//
-// Copyright (C) 2011 Novell (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
 using System;
 using System.Collections.Generic;
 using System.Runtime.InteropServices;
@@ -52,7 +28,7 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		///   Condition on which to wake up from file descriptor activity.  These match the Linux/BSD poll definitions.
+		///	Condition on which to wake up from file descriptor activity.  These match the Linux/BSD poll definitions.
 		/// </summary>
 		[Flags]
 		public enum Condition : short {
@@ -127,10 +103,10 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		///   Removes an active watch from the mainloop.
+		///	Removes an active watch from the mainloop.
 		/// </summary>
 		/// <remarks>
-		///   The token parameter is the value returned from AddWatch
+		///	The token parameter is the value returned from AddWatch
 		/// </remarks>
 		public void RemoveWatch (object token)
 		{

+ 14 - 21
Terminal.Gui/ConsoleDrivers/CursesDriver/UnmanagedLibrary.cs

@@ -6,7 +6,7 @@
 // you may not use this file except in compliance with the License.
 // You may obtain a copy of the License at
 //
-//     http://www.apache.org/licenses/LICENSE-2.0
+//	 http://www.apache.org/licenses/LICENSE-2.0
 //
 // Unless required by applicable law or agreed to in writing, software
 // distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,8 +21,6 @@ using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Threading;
 
-
-
 namespace Unix.Terminal {
 	/// <summary>
 	/// Represents a dynamically loaded unmanaged library in a (partially) platform independent manner.
@@ -45,7 +43,7 @@ namespace Unix.Terminal {
 		static bool IsNetCore;
 
 		public static bool IsMacOSPlatform => IsMacOS;
-		
+
 		[DllImport ("libc")]
 		static extern int uname (IntPtr buf);
 
@@ -105,11 +103,11 @@ namespace Unix.Terminal {
 		//
 		public UnmanagedLibrary (string [] libraryPathAlternatives, bool isFullPath)
 		{
-			if (isFullPath){
+			if (isFullPath) {
 				this.libraryPath = FirstValidLibraryPath (libraryPathAlternatives);
 				this.handle = PlatformSpecificLoadLibrary (this.libraryPath);
 			} else {
-				foreach (var lib in libraryPathAlternatives){
+				foreach (var lib in libraryPathAlternatives) {
 					this.handle = PlatformSpecificLoadLibrary (lib);
 					if (this.handle != IntPtr.Zero)
 						break;
@@ -164,13 +162,13 @@ namespace Unix.Terminal {
 		}
 
 		public T GetNativeMethodDelegate<T> (string methodName)
-		    where T : class
+			where T : class
 		{
 			var ptr = LoadSymbol (methodName);
 			if (ptr == IntPtr.Zero) {
 				throw new MissingMethodException (string.Format ("The native method \"{0}\" does not exist", methodName));
 			}
-			return Marshal.GetDelegateForFunctionPointer<T>(ptr);  // non-generic version is obsolete
+			return Marshal.GetDelegateForFunctionPointer<T> (ptr);  // non-generic version is obsolete
 		}
 
 		/// <summary>
@@ -209,12 +207,11 @@ namespace Unix.Terminal {
 				}
 			}
 			throw new FileNotFoundException (
-			    String.Format ("Error loading native library. Not found in any of the possible locations: {0}",
+				String.Format ("Error loading native library. Not found in any of the possible locations: {0}",
 				string.Join (",", libraryPathAlternatives)));
 		}
 
-		static class Windows
-		{
+		static class Windows {
 			[DllImport ("kernel32.dll")]
 			internal static extern IntPtr LoadLibrary (string filename);
 
@@ -222,8 +219,7 @@ namespace Unix.Terminal {
 			internal static extern IntPtr GetProcAddress (IntPtr hModule, string procName);
 		}
 
-		static class Linux
-		{
+		static class Linux {
 			[DllImport ("libdl.so")]
 			internal static extern IntPtr dlopen (string filename, int flags);
 
@@ -231,8 +227,7 @@ namespace Unix.Terminal {
 			internal static extern IntPtr dlsym (IntPtr handle, string symbol);
 		}
 
-		static class MacOSX
-		{
+		static class MacOSX {
 			[DllImport ("libSystem.dylib")]
 			internal static extern IntPtr dlopen (string filename, int flags);
 
@@ -247,8 +242,7 @@ namespace Unix.Terminal {
 		/// dlopen and dlsym from the current process as on Linux
 		/// Mono sure is linked against these symbols.
 		/// </summary>
-		static class Mono
-		{
+		static class Mono {
 			[DllImport ("__Internal")]
 			internal static extern IntPtr dlopen (string filename, int flags);
 
@@ -261,13 +255,12 @@ namespace Unix.Terminal {
 		/// dlopen and dlsym from the "libcoreclr.so",
 		/// to avoid the dependency on libc-dev Linux.
 		/// </summary>
-		static class CoreCLR
-		{
+		static class CoreCLR {
 #if NET6_0
 			// Custom resolver to support true single-file apps
 			// (those which run directly from bundle; in-memory).
-			//     -1 on Unix means self-referencing binary (libcoreclr.so)
-			//     0 means fallback to CoreCLR's internal resolution
+			//	 -1 on Unix means self-referencing binary (libcoreclr.so)
+			//	 0 means fallback to CoreCLR's internal resolution
 			// Note: meaning of -1 stay the same even for non-single-file form factors.
 			static CoreCLR() =>  NativeLibrary.SetDllImportResolver(typeof(CoreCLR).Assembly,
 				(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) =>

+ 0 - 5
Terminal.Gui/ConsoleDrivers/CursesDriver/binding.cs

@@ -145,11 +145,6 @@ namespace Unix.Terminal {
 			if (l == 1 || l != lines || c != cols) {
 				lines = l;
 				cols = c;
-				//if (l <= 0 || c <= 0) {
-				//	Console.Out.Write ($"\x1b[8;50;{c}t");
-				//	Console.Out.Flush ();
-				//	return false;
-				//}
 				return true;
 			}
 			return false;

+ 2 - 2
Terminal.Gui/ConsoleDrivers/CursesDriver/constants.cs

@@ -53,7 +53,6 @@ namespace Unix.Terminal {
 		public const int COLOR_WHITE = unchecked((int)0x7);
 		public const int COLOR_GRAY = unchecked((int)0x8);
 		public const int KEY_CODE_YES = unchecked((int)0x100);
-		public const int KEY_CODE_SEQ = unchecked((int)0x5b);
 		public const int ERR = unchecked((int)0xffffffff);
 		public const int TIOCGWINSZ  = unchecked((int)0x5413);
 		public const int TIOCGWINSZ_MAC  = unchecked((int)0x40087468);
@@ -69,7 +68,7 @@ namespace Unix.Terminal {
 			Button2Released = unchecked((int)0x20),
 			Button2Clicked = unchecked((int)0x80),
 			Button2DoubleClicked = unchecked((int)0x100),
-			Button2TrippleClicked = unchecked((int)0x200),
+			Button2TripleClicked = unchecked((int)0x200),
 			Button3Pressed = unchecked((int)0x800),
 			Button3Released = unchecked((int)0x400),
 			Button3Clicked = unchecked((int)0x1000),
@@ -106,6 +105,7 @@ namespace Unix.Terminal {
 		public const int KeyPPage = unchecked((int)0x153);
 		public const int KeyHome = unchecked((int)0x106);
 		public const int KeyMouse = unchecked((int)0x199);
+		public const int KeyCSI = unchecked((int)0x5b);
 		public const int KeyEnd = unchecked((int)0x168);
 		public const int KeyDeleteChar = unchecked((int)0x14a);
 		public const int KeyInsertChar = unchecked((int)0x14b);

File diff suppressed because it is too large
+ 284 - 289
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeConsole.cs


+ 14 - 12
Terminal.Gui/ConsoleDrivers/FakeDriver/FakeDriver.cs

@@ -1,9 +1,6 @@
 //
 // FakeDriver.cs: A fake ConsoleDriver for unit tests. 
 //
-// Authors:
-//   Charlie Kindel (github.com/tig)
-//
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
@@ -48,7 +45,12 @@ namespace Terminal.Gui {
 		// Only handling left here because not all terminals has a horizontal scroll bar.
 		public override int Left => 0;
 		public override int Top => 0;
-		public override bool HeightAsBuffer { get; set; }
+		public override bool EnableConsoleScrolling { get; set; }
+		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
+		public override bool HeightAsBuffer {
+			get => EnableConsoleScrolling;
+			set => EnableConsoleScrolling = value;
+		}
 		private IClipboard clipboard = null;
 		public override IClipboard Clipboard => clipboard;
 
@@ -245,8 +247,8 @@ namespace Terminal.Gui {
 		{
 			redrawColor = color;
 			IEnumerable<int> values = Enum.GetValues (typeof (ConsoleColor))
-			      .OfType<ConsoleColor> ()
-			      .Select (s => (int)s);
+				.OfType<ConsoleColor> ()
+				.Select (s => (int)s);
 			if (values.Contains (color & 0xffff)) {
 				FakeConsole.BackgroundColor = (ConsoleColor)(color & 0xffff);
 			}
@@ -535,7 +537,7 @@ namespace Terminal.Gui {
 			FakeConsole.SetBufferSize (width, height);
 			cols = width;
 			rows = height;
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				SetWindowSize (width, height);
 			}
 			ProcessResize ();
@@ -544,7 +546,7 @@ namespace Terminal.Gui {
 		public void SetWindowSize (int width, int height)
 		{
 			FakeConsole.SetWindowSize (width, height);
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				if (width != cols || height != rows) {
 					SetBufferSize (width, height);
 					cols = width;
@@ -556,7 +558,7 @@ namespace Terminal.Gui {
 
 		public void SetWindowPosition (int left, int top)
 		{
-			if (HeightAsBuffer) {
+			if (EnableConsoleScrolling) {
 				this.left = Math.Max (Math.Min (left, Cols - FakeConsole.WindowWidth), 0);
 				this.top = Math.Max (Math.Min (top, Rows - FakeConsole.WindowHeight), 0);
 			} else if (this.left > 0 || this.top > 0) {
@@ -575,7 +577,7 @@ namespace Terminal.Gui {
 
 		public override void ResizeScreen ()
 		{
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				if (FakeConsole.WindowHeight > 0) {
 					// Can raise an exception while is still resizing.
 					try {
@@ -629,8 +631,8 @@ namespace Terminal.Gui {
 			foreground = default;
 			background = default;
 			IEnumerable<int> values = Enum.GetValues (typeof (ConsoleColor))
-			      .OfType<ConsoleColor> ()
-			      .Select (s => (int)s);
+				.OfType<ConsoleColor> ()
+				.Select (s => (int)s);
 			if (values.Contains (value & 0xffff)) {
 				hasColor = true;
 				background = (Color)(ConsoleColor)(value & 0xffff);

File diff suppressed because it is too large
+ 258 - 828
Terminal.Gui/ConsoleDrivers/NetDriver.cs


+ 56 - 36
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -1,30 +1,6 @@
 //
 // WindowsDriver.cs: Windows specific driver
 //
-// Authors:
-//   Miguel de Icaza ([email protected])
-//   Nick Van Dyck ([email protected])
-//
-// Copyright (c) 2018
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-//
 using NStack;
 using System;
 using System.Collections.Generic;
@@ -646,7 +622,7 @@ namespace Terminal.Gui {
 			}
 		}
 
-#if false      // Not needed on the constructor. Perhaps could be used on resizing. To study.
+#if false      // Not needed on the constructor. Perhaps could be used on resizing. To study.                                                                                     
 		[DllImport ("kernel32.dll", ExactSpelling = true)]
 		static extern IntPtr GetConsoleWindow ();
 
@@ -739,7 +715,12 @@ namespace Terminal.Gui {
 		public override int Rows => rows;
 		public override int Left => left;
 		public override int Top => top;
-		public override bool HeightAsBuffer { get; set; }
+		public override bool EnableConsoleScrolling { get; set; }
+		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
+		public override bool HeightAsBuffer {
+			get => EnableConsoleScrolling;
+			set => EnableConsoleScrolling = value;
+		}
 		public override IClipboard Clipboard => clipboard;
 		public override int [,,] Contents => contents;
 
@@ -774,7 +755,7 @@ namespace Terminal.Gui {
 
 		private void ChangeWin (Size e)
 		{
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				var w = e.Width;
 				if (w == cols - 3 && e.Height < rows) {
 					w += 3;
@@ -915,8 +896,12 @@ namespace Terminal.Gui {
 				left = pos.X;
 				top = pos.Y;
 				cols = inputEvent.WindowBufferSizeEvent.size.X;
-				rows = inputEvent.WindowBufferSizeEvent.size.Y;
-				//System.Diagnostics.Debug.WriteLine ($"{HeightAsBuffer},{cols},{rows}");
+				if (EnableConsoleScrolling) {
+					rows = Math.Max (inputEvent.WindowBufferSizeEvent.size.Y, rows);
+				} else {
+					rows = inputEvent.WindowBufferSizeEvent.size.Y;
+				}
+				//System.Diagnostics.Debug.WriteLine ($"{EnableConsoleScrolling},{cols},{rows}");
 				ResizeScreen ();
 				UpdateOffScreen ();
 				TerminalResized?.Invoke ();
@@ -1459,6 +1444,19 @@ namespace Terminal.Gui {
 			TerminalResized = terminalResized;
 
 			try {
+				// Needed for Windows Terminal
+				// ESC [ ? 1047 h  Activate xterm alternative buffer (no backscroll)
+				// ESC [ ? 1047 l  Restore xterm working buffer (with backscroll)
+				// ESC [ ? 1048 h  Save cursor position
+				// ESC [ ? 1048 l  Restore cursor position
+				// ESC [ ? 1049 h  Save cursor position and activate xterm alternative buffer (no backscroll)
+				// ESC [ ? 1049 l  Restore cursor position and restore xterm working buffer (with backscroll)
+				// Per Issue #2264 using the alterantive screen buffer is required for Windows Terminal to not 
+				// wipe out the backscroll buffer when the application exits.
+				Console.Out.Write ("\x1b[?1047h");
+
+				// Console.Out.Flush () is not needed. See https://stackoverflow.com/a/20450486/297526
+
 				var winSize = WinConsole.GetConsoleOutputWindow (out Point pos);
 				cols = winSize.Width;
 				rows = winSize.Height;
@@ -1467,6 +1465,9 @@ namespace Terminal.Gui {
 				CurrentAttribute = MakeColor (Color.White, Color.Black);
 				InitalizeColorSchemes ();
 
+				CurrentAttribute = MakeColor (Color.White, Color.Black);
+				InitalizeColorSchemes ();
+
 				ResizeScreen ();
 				UpdateOffScreen ();
 			} catch (Win32Exception e) {
@@ -1485,8 +1486,15 @@ namespace Terminal.Gui {
 				Right = (short)Cols
 			};
 			WinConsole.ForceRefreshCursorVisibility ();
-			Console.Out.Write ("\x1b[3J");
-			Console.Out.Flush ();
+			if (!EnableConsoleScrolling) {
+				// ANSI ESC "[xJ" Clears part of the screen.
+				// If n is 0 (or missing), clear from cursor to end of screen.
+				// If n is 1, clear from cursor to beginning of the screen.
+				// If n is 2, clear entire screen (and moves cursor to upper left on DOS ANSI.SYS).
+				// If n is 3, clear entire screen and delete all lines saved in the scrollback buffer
+				// DO NOT USE 3J - even with the alternate screen buffer, it clears the entire scrollback buffer
+				Console.Out.Write ("\x1b[3J");
+			}
 		}
 
 		public override void UpdateOffScreen ()
@@ -1653,7 +1661,7 @@ namespace Terminal.Gui {
 			if (damageRegion.Left == -1)
 				return;
 
-			if (!HeightAsBuffer) {
+			if (!EnableConsoleScrolling) {
 				var windowSize = WinConsole.GetConsoleBufferWindow (out _);
 				if (!windowSize.IsEmpty && (windowSize.Width != Cols || windowSize.Height != Rows))
 					return;
@@ -1700,6 +1708,18 @@ namespace Terminal.Gui {
 		{
 			WinConsole.Cleanup ();
 			WinConsole = null;
+
+			// Needed for Windows Terminal
+			// Clear the alternative screen buffer from the cursor to the
+			// end of the screen.
+			// Note, [3J causes Windows Terminal to wipe out the entire NON ALTERNATIVE
+			// backbuffer! So we need to use [0J instead.
+			Console.Out.Write ("\x1b[0J");
+
+			// Disable alternative screen buffer.
+			Console.Out.Write ("\x1b[?1047l");
+
+			// Console.Out.Flush () is not needed. See https://stackoverflow.com/a/20450486/297526
 		}
 
 		/// <inheritdoc/>
@@ -1780,8 +1800,8 @@ namespace Terminal.Gui {
 			foreground = default;
 			background = default;
 			IEnumerable<int> values = Enum.GetValues (typeof (ConsoleColor))
-			      .OfType<ConsoleColor> ()
-			      .Select (s => (int)s);
+				.OfType<ConsoleColor> ()
+				.Select (s => (int)s);
 			if (values.Contains ((value >> 4) & 0xffff)) {
 				hasColor = true;
 				background = (Color)(ConsoleColor)((value >> 4) & 0xffff);
@@ -1897,9 +1917,9 @@ namespace Terminal.Gui {
 		{
 			while (true) {
 				Thread.Sleep (100);
-				if (!consoleDriver.HeightAsBuffer) {
+				if (!consoleDriver.EnableConsoleScrolling) {
 					windowSize = winConsole.GetConsoleBufferWindow (out _);
-					//System.Diagnostics.Debug.WriteLine ($"{consoleDriver.HeightAsBuffer},{windowSize.Width},{windowSize.Height}");
+					//System.Diagnostics.Debug.WriteLine ($"{consoleDriver.EnableConsoleScrolling},{windowSize.Width},{windowSize.Height}");
 					if (windowSize != Size.Empty && windowSize.Width != consoleDriver.Cols
 						|| windowSize.Height != consoleDriver.Rows) {
 						return;

+ 35 - 13
Terminal.Gui/Core/Application.cs

@@ -114,30 +114,51 @@ namespace Terminal.Gui {
 		/// </summary>
 		public static View WantContinuousButtonPressedView { get; private set; }
 
-		private static bool? _heightAsBuffer;
+		private static bool? _enableConsoleScrolling;
 
 		/// <summary>
-		/// The current <see cref="ConsoleDriver.HeightAsBuffer"/> used in the terminal.
+		/// The current <see cref="ConsoleDriver.EnableConsoleScrolling"/> used in the terminal.
 		/// </summary>
-		/// 
+		/// <remarks>
+		/// <para>
+		/// If <see langword="false"/> (the default) the height of the Terminal.Gui application (<see cref="ConsoleDriver.Rows"/>) 
+		/// tracks to the height of the visible console view when the console is resized. In this case 
+		/// scrolling in the console will be disabled and all <see cref="ConsoleDriver.Rows"/> will remain visible.
+		/// </para>
+		/// <para>
+		/// If <see langword="true"/> then height of the Terminal.Gui application <see cref="ConsoleDriver.Rows"/> only tracks 
+		/// the height of the visible console view when the console is made larger (the application will only grow in height, never shrink). 
+		/// In this case console scrolling is enabled and the contents (<see cref="ConsoleDriver.Rows"/> high) will scroll
+		/// as the console scrolls. 
+		/// </para>
+		/// This API was previously named 'HeightAsBuffer` but was renamed to make its purpose more clear.
+		/// </remarks>
 		[SerializableConfigurationProperty (Scope = typeof(SettingsScope))]
-		public static bool HeightAsBuffer {
+		public static bool EnableConsoleScrolling {
 			get {
 				if (Driver == null) {
-					return _heightAsBuffer.HasValue && _heightAsBuffer.Value;
+					return _enableConsoleScrolling.HasValue && _enableConsoleScrolling.Value;
 				}
-				return Driver.HeightAsBuffer;
+				return Driver.EnableConsoleScrolling;
 			}
 			set {
-				_heightAsBuffer = value;
+				_enableConsoleScrolling = value;
 				if (Driver == null) {
 					return;
 				}
-
-				Driver.HeightAsBuffer = _heightAsBuffer.Value;
+				Driver.EnableConsoleScrolling = value;
 			}
 		}
 
+		/// <summary>
+		/// This API is deprecated; use <see cref="EnableConsoleScrolling"/> instead.
+		/// </summary>
+		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
+		public static bool HeightAsBuffer {
+			get => EnableConsoleScrolling;
+			set => EnableConsoleScrolling = value;
+		}
+
 		static Key alternateForwardKey = Key.PageDown | Key.CtrlMask;
 
 		/// <summary>
@@ -157,7 +178,7 @@ namespace Terminal.Gui {
 
 		static void OnAlternateForwardKeyChanged (Key oldKey)
 		{
-			foreach (var top in toplevels.ToArray()) {
+			foreach (var top in toplevels.ToArray ()) {
 				top.OnAlternateForwardKeyChanged (oldKey);
 			}
 		}
@@ -181,7 +202,7 @@ namespace Terminal.Gui {
 
 		static void OnAlternateBackwardKeyChanged (Key oldKey)
 		{
-			foreach (var top in toplevels.ToArray()) {
+			foreach (var top in toplevels.ToArray ()) {
 				top.OnAlternateBackwardKeyChanged (oldKey);
 			}
 		}
@@ -213,7 +234,7 @@ namespace Terminal.Gui {
 		static void OnQuitKeyChanged (Key oldKey)
 		{
 			// Duplicate the list so if it changes during enumeration we're safe
-			foreach (var top in toplevels.ToArray()) {
+			foreach (var top in toplevels.ToArray ()) {
 				top.OnQuitKeyChanged (oldKey);
 			}
 		}
@@ -445,7 +466,7 @@ namespace Terminal.Gui {
 			MainLoop = new MainLoop (mainLoopDriver);
 
 			try {
-				Driver.HeightAsBuffer = HeightAsBuffer;
+				Driver.EnableConsoleScrolling = EnableConsoleScrolling;
 				Driver.Init (TerminalResized);
 			} catch (InvalidOperationException ex) {
 				// This is a case where the driver is unable to initialize the console.
@@ -1121,6 +1142,7 @@ namespace Terminal.Gui {
 			NotifyStopRunState = null;
 			_initialized = false;
 			mouseGrabView = null;
+			_enableConsoleScrolling = false;
 
 			// Reset synchronization context to allow the user to run async/await,
 			// as the main loop has been ended, the synchronization context from 

+ 2 - 2
Terminal.Gui/Core/Border.cs

@@ -335,7 +335,7 @@ namespace Terminal.Gui {
 		/// <summary>
 		/// Specifies the <see cref="Gui.BorderStyle"/> for a view.
 		/// </summary>
-		[JsonInclude, JsonConverter (typeof(JsonStringEnumConverter))]
+		[JsonInclude, JsonConverter (typeof (JsonStringEnumConverter))]
 		public BorderStyle BorderStyle {
 			get => borderStyle;
 			set {
@@ -1034,4 +1034,4 @@ namespace Terminal.Gui {
 			BorderChanged?.Invoke (this);
 		}
 	}
-}
+}

+ 24 - 71
Terminal.Gui/Core/ConsoleDriver.cs

@@ -89,7 +89,7 @@ namespace Terminal.Gui {
 	}
 
 	/// <summary>
-	/// 
+	/// Indicates the RGB for true colors.
 	/// </summary>
 	public class TrueColor {
 		/// <summary>
@@ -119,7 +119,7 @@ namespace Terminal.Gui {
 		}
 
 		/// <summary>
-		/// 
+		/// Converts true color to console color.
 		/// </summary>
 		/// <returns></returns>
 		public Color ToConsoleColor ()
@@ -504,7 +504,7 @@ namespace Terminal.Gui {
 			public bool Equals (string x, string y)
 			{
 				if (x != null && y != null) {
-					return x.ToLowerInvariant () == y.ToLowerInvariant ();
+					return string.Equals (x, y, StringComparison.InvariantCultureIgnoreCase);
 				}
 				return false;
 			}
@@ -659,72 +659,7 @@ namespace Terminal.Gui {
 		/// <remarks>Works under Xterm-like terminal otherwise this is equivalent to <see ref="Block"/></remarks>
 		BoxFix = 0x02020164,
 	}
-
-	///// <summary>
-	///// Special characters that can be drawn with 
-	///// </summary>
-	//public enum SpecialChar {
-	//	/// <summary>
-	//	/// Horizontal line character.
-	//	/// </summary>
-	//	HLine,
-
-	//	/// <summary>
-	//	/// Vertical line character.
-	//	/// </summary>
-	//	VLine,
-
-	//	/// <summary>
-	//	/// Stipple pattern
-	//	/// </summary>
-	//	Stipple,
-
-	//	/// <summary>
-	//	/// Diamond character
-	//	/// </summary>
-	//	Diamond,
-
-	//	/// <summary>
-	//	/// Upper left corner
-	//	/// </summary>
-	//	ULCorner,
-
-	//	/// <summary>
-	//	/// Lower left corner
-	//	/// </summary>
-	//	LLCorner,
-
-	//	/// <summary>
-	//	/// Upper right corner
-	//	/// </summary>
-	//	URCorner,
-
-	//	/// <summary>
-	//	/// Lower right corner
-	//	/// </summary>
-	//	LRCorner,
-
-	//	/// <summary>
-	//	/// Left tee
-	//	/// </summary>
-	//	LeftTee,
-
-	//	/// <summary>
-	//	/// Right tee
-	//	/// </summary>
-	//	RightTee,
-
-	//	/// <summary>
-	//	/// Top tee
-	//	/// </summary>
-	//	TopTee,
-
-	//	/// <summary>
-	//	/// The bottom tee.
-	//	/// </summary>
-	//	BottomTee,
-	//}
-
+	
 	/// <summary>
 	/// ConsoleDriver is an abstract class that defines the requirements for a console driver.  
 	/// There are currently three implementations: <see cref="CursesDriver"/> (for Unix and Mac), <see cref="WindowsDriver"/>, and <see cref="NetDriver"/> that uses the .NET Console API.
@@ -761,9 +696,27 @@ namespace Terminal.Gui {
 		public abstract IClipboard Clipboard { get; }
 
 		/// <summary>
-		/// If false height is measured by the window height and thus no scrolling.
-		/// If true then height is measured by the buffer height, enabling scrolling.
+		/// <para>
+		/// If <see langword="false"/> (the default) the height of the Terminal.Gui application (<see cref="Rows"/>) 
+		/// tracks to the height of the visible console view when the console is resized. In this case 
+		/// scrolling in the console will be disabled and all <see cref="Rows"/> will remain visible.
+		/// </para>
+		/// <para>
+		/// If <see langword="true"/> then height of the Terminal.Gui application <see cref="Rows"/> only tracks 
+		/// the height of the visible console view when the console is made larger (the application will only grow in height, never shrink). 
+		/// In this case console scrolling is enabled and the contents (<see cref="Rows"/> high) will scroll
+		/// as the console scrolls. 
+		/// </para>
+		/// </summary>
+		/// <remarks>
+		/// NOTE: This functionaliy is currently broken on Windows Terminal.
+		/// </remarks>
+		public abstract bool EnableConsoleScrolling { get; set; }
+
+		/// <summary>
+		/// This API is deprecated; use <see cref="EnableConsoleScrolling"/> instead.
 		/// </summary>
+		[Obsolete ("This API is deprecated; use EnableConsoleScrolling instead.", false)]
 		public abstract bool HeightAsBuffer { get; set; }
 
 		/// <summary>

+ 19 - 0
Terminal.Gui/Core/ConsoleKeyMapping.cs

@@ -334,6 +334,25 @@ namespace Terminal.Gui {
 			return (Key)consoleKey;
 		}
 
+		/// <summary>
+		/// Maps a <see cref="ConsoleKeyInfo"/> to a <see cref="Key"/>.
+		/// </summary>
+		/// <param name="keyInfo">The console key info.</param>
+		/// <param name="key">The key.</param>
+		/// <returns>The <see cref="Key"/> with <see cref="ConsoleModifiers"/> or the <paramref name="key"/></returns>
+		public static Key MapKeyModifiers (ConsoleKeyInfo keyInfo, Key key)
+		{
+			Key keyMod = new Key ();
+			if ((keyInfo.Modifiers & ConsoleModifiers.Shift) != 0)
+				keyMod = Key.ShiftMask;
+			if ((keyInfo.Modifiers & ConsoleModifiers.Control) != 0)
+				keyMod |= Key.CtrlMask;
+			if ((keyInfo.Modifiers & ConsoleModifiers.Alt) != 0)
+				keyMod |= Key.AltMask;
+
+			return keyMod != Key.Null ? keyMod | key : key;
+		}
+
 		private static HashSet<ScanCodeMapping> scanCodes = new HashSet<ScanCodeMapping> {
 			new ScanCodeMapping (1,27,0,27),	// Escape
 			new ScanCodeMapping (1,27,ConsoleModifiers.Shift,27),

+ 109 - 0
Terminal.Gui/Core/EscSeqUtils/EscSeqReq.cs

@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Represents the state of an ANSI escape sequence request.
+	/// </summary>
+	/// <remarks>
+	/// This is needed because there are some escape sequence requests responses that are equal
+	/// with some normal escape sequences and thus, will be only considered the responses to the
+	/// requests that were registered with this object.
+	/// </remarks>
+	public class EscSeqReqStatus {
+		/// <summary>
+		/// Gets the terminating.
+		/// </summary>
+		public string Terminating { get; }
+		/// <summary>
+		/// Gets the number of requests.
+		/// </summary>
+		public int NumRequests { get; }
+		/// <summary>
+		/// Gets information about unfinished requests.
+		/// </summary>
+		public int NumOutstanding { get; set; }
+
+		/// <summary>
+		/// Creates a new state of escape sequence request.
+		/// </summary>
+		/// <param name="terminating">The terminating.</param>
+		/// <param name="numOfReq">The number of requests.</param>
+		public EscSeqReqStatus (string terminating, int numOfReq)
+		{
+			Terminating = terminating;
+			NumRequests = NumOutstanding = numOfReq;
+		}
+	}
+
+	/// <summary>
+	/// Manages a list of <see cref="EscSeqReqStatus"/>.
+	/// </summary>
+	public class EscSeqReqProc {
+		/// <summary>
+		/// Gets the <see cref="EscSeqReqStatus"/> list.
+		/// </summary>
+		public List<EscSeqReqStatus> EscSeqReqStats { get; } = new List<EscSeqReqStatus> ();
+
+		/// <summary>
+		/// Adds a new <see cref="EscSeqReqStatus"/> instance to the <see cref="EscSeqReqStats"/> list.
+		/// </summary>
+		/// <param name="terminating">The terminating.</param>
+		/// <param name="numOfReq">The number of requests.</param>
+		public void Add (string terminating, int numOfReq = 1)
+		{
+			lock (EscSeqReqStats) {
+				var found = EscSeqReqStats.Find (x => x.Terminating == terminating);
+				if (found == null) {
+					EscSeqReqStats.Add (new EscSeqReqStatus (terminating, numOfReq));
+				} else if (found != null && found.NumOutstanding < found.NumRequests) {
+					found.NumOutstanding = Math.Min (found.NumOutstanding + numOfReq, found.NumRequests);
+				}
+			}
+		}
+
+		/// <summary>
+		/// Removes a <see cref="EscSeqReqStatus"/> instance from the <see cref="EscSeqReqStats"/> list.
+		/// </summary>
+		/// <param name="terminating">The terminating string.</param>
+		public void Remove (string terminating)
+		{
+			lock (EscSeqReqStats) {
+				var found = EscSeqReqStats.Find (x => x.Terminating == terminating);
+				if (found == null) {
+					return;
+				}
+				if (found != null && found.NumOutstanding == 0) {
+					EscSeqReqStats.Remove (found);
+				} else if (found != null && found.NumOutstanding > 0) {
+					found.NumOutstanding--;
+					if (found.NumOutstanding == 0) {
+						EscSeqReqStats.Remove (found);
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// Indicates if a <see cref="EscSeqReqStatus"/> with the <paramref name="terminating"/> exist
+		/// in the <see cref="EscSeqReqStats"/> list.
+		/// </summary>
+		/// <param name="terminating"></param>
+		/// <returns><see langword="true"/> if exist, <see langword="false"/> otherwise.</returns>
+		public bool Requested (string terminating)
+		{
+			lock (EscSeqReqStats) {
+				var found = EscSeqReqStats.Find (x => x.Terminating == terminating);
+				if (found == null) {
+					return false;
+				}
+				if (found != null && found.NumOutstanding > 0) {
+					return true;
+				} else {
+					EscSeqReqStats.Remove (found);
+				}
+				return false;
+			}
+		}
+	}
+}

+ 907 - 0
Terminal.Gui/Core/EscSeqUtils/EscSeqUtils.cs

@@ -0,0 +1,907 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Management;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+
+namespace Terminal.Gui {
+	/// <summary>
+	/// Provides a platform-independent API for managing ANSI escape sequence codes.
+	/// </summary>
+	public static class EscSeqUtils {
+		/// <summary>
+		/// Represents the escape key.
+		/// </summary>
+		public static readonly char KeyEsc = (char)Key.Esc;
+		/// <summary>
+		/// Represents the CSI (Control Sequence Introducer).
+		/// </summary>
+		public static readonly string KeyCSI = $"{KeyEsc}[";
+		/// <summary>
+		/// Represents the CSI for enable any mouse event tracking.
+		/// </summary>
+		public static readonly string CSI_EnableAnyEventMouse = KeyCSI + "?1003h";
+		/// <summary>
+		/// Represents the CSI for enable SGR (Select Graphic Rendition).
+		/// </summary>
+		public static readonly string CSI_EnableSgrExtModeMouse = KeyCSI + "?1006h";
+		/// <summary>
+		/// Represents the CSI for enable URXVT (Unicode Extended Virtual Terminal).
+		/// </summary>
+		public static readonly string CSI_EnableUrxvtExtModeMouse = KeyCSI + "?1015h";
+		/// <summary>
+		/// Represents the CSI for disable any mouse event tracking.
+		/// </summary>
+		public static readonly string CSI_DisableAnyEventMouse = KeyCSI + "?1003l";
+		/// <summary>
+		/// Represents the CSI for disable SGR (Select Graphic Rendition).
+		/// </summary>
+		public static readonly string CSI_DisableSgrExtModeMouse = KeyCSI + "?1006l";
+		/// <summary>
+		/// Represents the CSI for disable URXVT (Unicode Extended Virtual Terminal).
+		/// </summary>
+		public static readonly string CSI_DisableUrxvtExtModeMouse = KeyCSI + "?1015l";
+
+		/// <summary>
+		/// Control sequence for enable mouse events.
+		/// </summary>
+		public static string EnableMouseEvents { get; set; } =
+			CSI_EnableAnyEventMouse + CSI_EnableUrxvtExtModeMouse + CSI_EnableSgrExtModeMouse;
+		/// <summary>
+		/// Control sequence for disable mouse events.
+		/// </summary>
+		public static string DisableMouseEvents { get; set; } =
+			CSI_DisableAnyEventMouse + CSI_DisableUrxvtExtModeMouse + CSI_DisableSgrExtModeMouse;
+
+		/// <summary>
+		/// Ensures a console key is mapped to one that works correctly with ANSI escape sequences.
+		/// </summary>
+		/// <param name="consoleKeyInfo">The <see cref="ConsoleKeyInfo"/>.</param>
+		/// <returns>The <see cref="ConsoleKeyInfo"/> modified.</returns>
+		public static ConsoleKeyInfo GetConsoleInputKey (ConsoleKeyInfo consoleKeyInfo)
+		{
+			ConsoleKeyInfo newConsoleKeyInfo = consoleKeyInfo;
+			ConsoleKey key;
+			var keyChar = consoleKeyInfo.KeyChar;
+			switch ((uint)keyChar) {
+			case 0:
+				if (consoleKeyInfo.Key == (ConsoleKey)64) {    // Ctrl+Space in Windows.
+					newConsoleKeyInfo = new ConsoleKeyInfo (' ', ConsoleKey.Spacebar,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0);
+				}
+				break;
+			case uint n when (n >= '\u0001' && n <= '\u001a'):
+				if (consoleKeyInfo.Key == 0 && consoleKeyInfo.KeyChar == '\r') {
+					key = ConsoleKey.Enter;
+					newConsoleKeyInfo = new ConsoleKeyInfo (consoleKeyInfo.KeyChar,
+						key,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0);
+				} else if (consoleKeyInfo.Key == 0) {
+					key = (ConsoleKey)(char)(consoleKeyInfo.KeyChar + (uint)ConsoleKey.A - 1);
+					newConsoleKeyInfo = new ConsoleKeyInfo ((char)key,
+						key,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
+						(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
+						true);
+				}
+				break;
+			case 127:
+				newConsoleKeyInfo = new ConsoleKeyInfo (consoleKeyInfo.KeyChar, ConsoleKey.Backspace,
+					(consoleKeyInfo.Modifiers & ConsoleModifiers.Shift) != 0,
+					(consoleKeyInfo.Modifiers & ConsoleModifiers.Alt) != 0,
+					(consoleKeyInfo.Modifiers & ConsoleModifiers.Control) != 0);
+				break;
+			default:
+				newConsoleKeyInfo = consoleKeyInfo;
+				break;
+			}
+
+			return newConsoleKeyInfo;
+		}
+
+		/// <summary>
+		/// A helper to resize the <see cref="ConsoleKeyInfo"/> as needed.
+		/// </summary>
+		/// <param name="consoleKeyInfo">The <see cref="ConsoleKeyInfo"/>.</param>
+		/// <param name="cki">The <see cref="ConsoleKeyInfo"/> array to resize.</param>
+		/// <returns>The <see cref="ConsoleKeyInfo"/> resized.</returns>
+		public static ConsoleKeyInfo [] ResizeArray (ConsoleKeyInfo consoleKeyInfo, ConsoleKeyInfo [] cki)
+		{
+			Array.Resize (ref cki, cki == null ? 1 : cki.Length + 1);
+			cki [cki.Length - 1] = consoleKeyInfo;
+			return cki;
+		}
+
+		/// <summary>
+		/// Decodes a escape sequence to been processed in the appropriate manner.
+		/// </summary>
+		/// <param name="escSeqReqProc">The <see cref="EscSeqReqProc"/> which may contain a request.</param>
+		/// <param name="newConsoleKeyInfo">The <see cref="ConsoleKeyInfo"/> which may changes.</param>
+		/// <param name="key">The <see cref="ConsoleKey"/> which may changes.</param>
+		/// <param name="cki">The <see cref="ConsoleKeyInfo"/> array.</param>
+		/// <param name="mod">The <see cref="ConsoleModifiers"/> which may changes.</param>
+		/// <param name="c1Control">The control returned by the <see cref="GetC1ControlChar(char)"/> method.</param>
+		/// <param name="code">The code returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
+		/// <param name="values">The values returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
+		/// <param name="terminating">The terminating returned by the <see cref="GetEscapeResult(char[])"/> method.</param>
+		/// <param name="isKeyMouse">Indicates if the escape sequence is a mouse key.</param>
+		/// <param name="buttonState">The <see cref="MouseFlags"/> button state.</param>
+		/// <param name="pos">The <see cref="MouseFlags"/> position.</param>
+		/// <param name="isReq">Indicates if the escape sequence is a response to a request.</param>
+		/// <param name="continuousButtonPressedHandler">The handler that will process the event.</param>
+		public static void DecodeEscSeq (EscSeqReqProc escSeqReqProc, ref ConsoleKeyInfo newConsoleKeyInfo, ref ConsoleKey key, ConsoleKeyInfo [] cki, ref ConsoleModifiers mod, out string c1Control, out string code, out string [] values, out string terminating, out bool isKeyMouse, out List<MouseFlags> buttonState, out Point pos, out bool isReq, Action<MouseFlags, Point> continuousButtonPressedHandler)
+		{
+			char [] kChars = GetKeyCharArray (cki);
+			(c1Control, code, values, terminating) = GetEscapeResult (kChars);
+			isKeyMouse = false;
+			buttonState = new List<MouseFlags> () { 0 };
+			pos = default;
+			isReq = false;
+			switch (c1Control) {
+			case "ESC":
+				if (values == null && string.IsNullOrEmpty (terminating)) {
+					key = ConsoleKey.Escape;
+					newConsoleKeyInfo = new ConsoleKeyInfo (cki [0].KeyChar, key,
+						(mod & ConsoleModifiers.Shift) != 0,
+						(mod & ConsoleModifiers.Alt) != 0,
+						(mod & ConsoleModifiers.Control) != 0);
+				} else if ((uint)cki [1].KeyChar >= 1 && (uint)cki [1].KeyChar <= 26) {
+					key = (ConsoleKey)(char)(cki [1].KeyChar + (uint)ConsoleKey.A - 1);
+					newConsoleKeyInfo = new ConsoleKeyInfo (cki [1].KeyChar,
+						key,
+						false,
+						true,
+						true);
+				} else {
+					if (cki [1].KeyChar >= 97 && cki [1].KeyChar <= 122) {
+						key = (ConsoleKey)cki [1].KeyChar.ToString ().ToUpper () [0];
+					} else {
+						key = (ConsoleKey)cki [1].KeyChar;
+					}
+					newConsoleKeyInfo = new ConsoleKeyInfo ((char)key,
+						(ConsoleKey)Math.Min ((uint)key, 255),
+						false,
+						true,
+						false);
+				}
+				break;
+			case "SS3":
+				key = GetConsoleKey (terminating [0], values [0], ref mod);
+				newConsoleKeyInfo = new ConsoleKeyInfo ('\0',
+					key,
+					(mod & ConsoleModifiers.Shift) != 0,
+					(mod & ConsoleModifiers.Alt) != 0,
+					(mod & ConsoleModifiers.Control) != 0);
+				break;
+			case "CSI":
+				if (!string.IsNullOrEmpty (code) && code == "<") {
+					GetMouse (cki, out buttonState, out pos, continuousButtonPressedHandler);
+					isKeyMouse = true;
+					return;
+				} else if (escSeqReqProc != null && escSeqReqProc.Requested (terminating)) {
+					isReq = true;
+					escSeqReqProc.Remove (terminating);
+					return;
+				}
+				key = GetConsoleKey (terminating [0], values [0], ref mod);
+				if (key != 0 && values.Length > 1) {
+					mod |= GetConsoleModifiers (values [1]);
+				}
+				newConsoleKeyInfo = new ConsoleKeyInfo ('\0',
+					key,
+					(mod & ConsoleModifiers.Shift) != 0,
+					(mod & ConsoleModifiers.Alt) != 0,
+					(mod & ConsoleModifiers.Control) != 0);
+				break;
+			}
+		}
+
+		/// <summary>
+		/// Gets all the needed information about a escape sequence.
+		/// </summary>
+		/// <param name="kChar">The array with all chars.</param>
+		/// <returns>
+		/// The c1Control returned by <see cref="GetC1ControlChar(char)"/>, code, values and terminating.
+		/// </returns>
+		public static (string c1Control, string code, string [] values, string terminating) GetEscapeResult (char [] kChar)
+		{
+			if (kChar == null || kChar.Length == 0) {
+				return (null, null, null, null);
+			}
+			if (kChar [0] != '\x1b') {
+				throw new InvalidOperationException ("Invalid escape character!");
+			}
+			if (kChar.Length == 1) {
+				return ("ESC", null, null, null);
+			}
+			if (kChar.Length == 2) {
+				return ("ESC", null, null, kChar [1].ToString ());
+			}
+			string c1Control = GetC1ControlChar (kChar [1]);
+			string code = null;
+			int nSep = kChar.Count (x => x == ';') + 1;
+			string [] values = new string [nSep];
+			int valueIdx = 0;
+			string terminating = "";
+			for (int i = 2; i < kChar.Length; i++) {
+				var c = kChar [i];
+				if (char.IsDigit (c)) {
+					values [valueIdx] += c.ToString ();
+				} else if (c == ';') {
+					valueIdx++;
+				} else if (valueIdx == nSep - 1 || i == kChar.Length - 1) {
+					terminating += c.ToString ();
+				} else {
+					code += c.ToString ();
+				}
+			}
+
+			return (c1Control, code, values, terminating);
+		}
+
+		/// <summary>
+		/// Gets the c1Control used in the called escape sequence.
+		/// </summary>
+		/// <param name="c">The char used.</param>
+		/// <returns>The c1Control.</returns>
+		public static string GetC1ControlChar (char c)
+		{
+			// These control characters are used in the vtXXX emulation.
+			switch (c) {
+			case 'D':
+				return "IND"; // Index
+			case 'E':
+				return "NEL"; // Next Line
+			case 'H':
+				return "HTS"; // Tab Set
+			case 'M':
+				return "RI"; // Reverse Index
+			case 'N':
+				return "SS2"; // Single Shift Select of G2 Character Set: affects next character only
+			case 'O':
+				return "SS3"; // Single Shift Select of G3 Character Set: affects next character only
+			case 'P':
+				return "DCS"; // Device Control String
+			case 'V':
+				return "SPA"; // Start of Guarded Area
+			case 'W':
+				return "EPA"; // End of Guarded Area
+			case 'X':
+				return "SOS"; // Start of String
+			case 'Z':
+				return "DECID"; // Return Terminal ID Obsolete form of CSI c (DA)
+			case '[':
+				return "CSI"; // Control Sequence Introducer
+			case '\\':
+				return "ST"; // String Terminator
+			case ']':
+				return "OSC"; // Operating System Command
+			case '^':
+				return "PM"; // Privacy Message
+			case '_':
+				return "APC"; // Application Program Command
+			default:
+				return ""; // Not supported
+			}
+		}
+
+		/// <summary>
+		/// Gets the <see cref="ConsoleModifiers"/> from the value.
+		/// </summary>
+		/// <param name="value">The value.</param>
+		/// <returns>The <see cref="ConsoleModifiers"/> or zero.</returns>
+		public static ConsoleModifiers GetConsoleModifiers (string value)
+		{
+			switch (value) {
+			case "2":
+				return ConsoleModifiers.Shift;
+			case "3":
+				return ConsoleModifiers.Alt;
+			case "4":
+				return ConsoleModifiers.Shift | ConsoleModifiers.Alt;
+			case "5":
+				return ConsoleModifiers.Control;
+			case "6":
+				return ConsoleModifiers.Shift | ConsoleModifiers.Control;
+			case "7":
+				return ConsoleModifiers.Alt | ConsoleModifiers.Control;
+			case "8":
+				return ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control;
+			default:
+				return 0;
+			}
+		}
+
+		/// <summary>
+		/// Gets the <see cref="ConsoleKey"/> depending on terminating and value.
+		/// </summary>
+		/// <param name="terminating">The terminating.</param>
+		/// <param name="value">The value.</param>
+		/// <param name="mod">The <see cref="ConsoleModifiers"/> which may changes.</param>
+		/// <returns>The <see cref="ConsoleKey"/> and probably the <see cref="ConsoleModifiers"/>.</returns>
+		public static ConsoleKey GetConsoleKey (char terminating, string value, ref ConsoleModifiers mod)
+		{
+			ConsoleKey key;
+			switch (terminating) {
+			case 'A':
+				key = ConsoleKey.UpArrow;
+				break;
+			case 'B':
+				key = ConsoleKey.DownArrow;
+				break;
+			case 'C':
+				key = ConsoleKey.RightArrow;
+				break;
+			case 'D':
+				key = ConsoleKey.LeftArrow;
+				break;
+			case 'F':
+				key = ConsoleKey.End;
+				break;
+			case 'H':
+				key = ConsoleKey.Home;
+				break;
+			case 'P':
+				key = ConsoleKey.F1;
+				break;
+			case 'Q':
+				key = ConsoleKey.F2;
+				break;
+			case 'R':
+				key = ConsoleKey.F3;
+				break;
+			case 'S':
+				key = ConsoleKey.F4;
+				break;
+			case 'Z':
+				key = ConsoleKey.Tab;
+				mod |= ConsoleModifiers.Shift;
+				break;
+			case '~':
+				switch (value) {
+				case "2":
+					key = ConsoleKey.Insert;
+					break;
+				case "3":
+					key = ConsoleKey.Delete;
+					break;
+				case "5":
+					key = ConsoleKey.PageUp;
+					break;
+				case "6":
+					key = ConsoleKey.PageDown;
+					break;
+				case "15":
+					key = ConsoleKey.F5;
+					break;
+				case "17":
+					key = ConsoleKey.F6;
+					break;
+				case "18":
+					key = ConsoleKey.F7;
+					break;
+				case "19":
+					key = ConsoleKey.F8;
+					break;
+				case "20":
+					key = ConsoleKey.F9;
+					break;
+				case "21":
+					key = ConsoleKey.F10;
+					break;
+				case "23":
+					key = ConsoleKey.F11;
+					break;
+				case "24":
+					key = ConsoleKey.F12;
+					break;
+				default:
+					key = 0;
+					break;
+				}
+				break;
+			default:
+				key = 0;
+				break;
+			}
+
+			return key;
+		}
+
+		/// <summary>
+		/// A helper to get only the <see cref="ConsoleKeyInfo.KeyChar"/> from the <see cref="ConsoleKeyInfo"/> array.
+		/// </summary>
+		/// <param name="cki"></param>
+		/// <returns>The char array of the escape sequence.</returns>
+		public static char [] GetKeyCharArray (ConsoleKeyInfo [] cki)
+		{
+			char [] kChar = new char [] { };
+			var length = 0;
+			foreach (var kc in cki) {
+				length++;
+				Array.Resize (ref kChar, length);
+				kChar [length - 1] = kc.KeyChar;
+			}
+
+			return kChar;
+		}
+
+		private static MouseFlags? lastMouseButtonPressed;
+		//private static MouseFlags? lastMouseButtonReleased;
+		private static bool isButtonPressed;
+		//private static bool isButtonReleased;
+		private static bool isButtonClicked;
+		private static bool isButtonDoubleClicked;
+		private static bool isButtonTripleClicked;
+		private static Point point;
+
+		/// <summary>
+		/// Gets the <see cref="MouseFlags"/> mouse button flags and the position.
+		/// </summary>
+		/// <param name="cki">The <see cref="ConsoleKeyInfo"/> array.</param>
+		/// <param name="mouseFlags">The mouse button flags.</param>
+		/// <param name="pos">The mouse position.</param>
+		/// <param name="continuousButtonPressedHandler">The handler that will process the event.</param>
+		public static void GetMouse (ConsoleKeyInfo [] cki, out List<MouseFlags> mouseFlags, out Point pos, Action<MouseFlags, Point> continuousButtonPressedHandler)
+		{
+			MouseFlags buttonState = 0;
+			pos = new Point ();
+			int buttonCode = 0;
+			bool foundButtonCode = false;
+			int foundPoint = 0;
+			string value = "";
+			var kChar = GetKeyCharArray (cki);
+			//System.Diagnostics.Debug.WriteLine ($"kChar: {new string (kChar)}");
+			for (int i = 0; i < kChar.Length; i++) {
+				var c = kChar [i];
+				if (c == '<') {
+					foundButtonCode = true;
+				} else if (foundButtonCode && c != ';') {
+					value += c.ToString ();
+				} else if (c == ';') {
+					if (foundButtonCode) {
+						foundButtonCode = false;
+						buttonCode = int.Parse (value);
+					}
+					if (foundPoint == 1) {
+						pos.X = int.Parse (value) - 1;
+					}
+					value = "";
+					foundPoint++;
+				} else if (foundPoint > 0 && c != 'm' && c != 'M') {
+					value += c.ToString ();
+				} else if (c == 'm' || c == 'M') {
+					//pos.Y = int.Parse (value) + Console.WindowTop - 1;
+					pos.Y = int.Parse (value) - 1;
+
+					switch (buttonCode) {
+					case 0:
+					case 8:
+					case 16:
+					case 24:
+					case 32:
+					case 36:
+					case 40:
+					case 48:
+					case 56:
+						buttonState = c == 'M' ? MouseFlags.Button1Pressed
+							: MouseFlags.Button1Released;
+						break;
+					case 1:
+					case 9:
+					case 17:
+					case 25:
+					case 33:
+					case 37:
+					case 41:
+					case 45:
+					case 49:
+					case 53:
+					case 57:
+					case 61:
+						buttonState = c == 'M' ? MouseFlags.Button2Pressed
+							: MouseFlags.Button2Released;
+						break;
+					case 2:
+					case 10:
+					case 14:
+					case 18:
+					case 22:
+					case 26:
+					case 30:
+					case 34:
+					case 42:
+					case 46:
+					case 50:
+					case 54:
+					case 58:
+					case 62:
+						buttonState = c == 'M' ? MouseFlags.Button3Pressed
+							: MouseFlags.Button3Released;
+						break;
+					case 35:
+					//// Needed for Windows OS
+					//if (isButtonPressed && c == 'm'
+					//	&& (lastMouseEvent.ButtonState == MouseFlags.Button1Pressed
+					//	|| lastMouseEvent.ButtonState == MouseFlags.Button2Pressed
+					//	|| lastMouseEvent.ButtonState == MouseFlags.Button3Pressed)) {
+
+					//	switch (lastMouseEvent.ButtonState) {
+					//	case MouseFlags.Button1Pressed:
+					//		buttonState = MouseFlags.Button1Released;
+					//		break;
+					//	case MouseFlags.Button2Pressed:
+					//		buttonState = MouseFlags.Button2Released;
+					//		break;
+					//	case MouseFlags.Button3Pressed:
+					//		buttonState = MouseFlags.Button3Released;
+					//		break;
+					//	}
+					//} else {
+					//	buttonState = MouseFlags.ReportMousePosition;
+					//}
+					//break;
+					case 39:
+					case 43:
+					case 47:
+					case 51:
+					case 55:
+					case 59:
+					case 63:
+						buttonState = MouseFlags.ReportMousePosition;
+						break;
+					case 64:
+						buttonState = MouseFlags.WheeledUp;
+						break;
+					case 65:
+						buttonState = MouseFlags.WheeledDown;
+						break;
+					case 68:
+					case 72:
+					case 80:
+						buttonState = MouseFlags.WheeledLeft;       // Shift/Ctrl+WheeledUp
+						break;
+					case 69:
+					case 73:
+					case 81:
+						buttonState = MouseFlags.WheeledRight;      // Shift/Ctrl+WheeledDown
+						break;
+					}
+					// Modifiers.
+					switch (buttonCode) {
+					case 8:
+					case 9:
+					case 10:
+					case 43:
+						buttonState |= MouseFlags.ButtonAlt;
+						break;
+					case 14:
+					case 47:
+						buttonState |= MouseFlags.ButtonAlt | MouseFlags.ButtonShift;
+						break;
+					case 16:
+					case 17:
+					case 18:
+					case 51:
+						buttonState |= MouseFlags.ButtonCtrl;
+						break;
+					case 22:
+					case 55:
+						buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonShift;
+						break;
+					case 24:
+					case 25:
+					case 26:
+					case 59:
+						buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonAlt;
+						break;
+					case 30:
+					case 63:
+						buttonState |= MouseFlags.ButtonCtrl | MouseFlags.ButtonShift | MouseFlags.ButtonAlt;
+						break;
+					case 32:
+					case 33:
+					case 34:
+						buttonState |= MouseFlags.ReportMousePosition;
+						break;
+					case 36:
+					case 37:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonShift;
+						break;
+					case 39:
+					case 68:
+					case 69:
+						buttonState |= MouseFlags.ButtonShift;
+						break;
+					case 40:
+					case 41:
+					case 42:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonAlt;
+						break;
+					case 45:
+					case 46:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonAlt | MouseFlags.ButtonShift;
+						break;
+					case 48:
+					case 49:
+					case 50:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl;
+						break;
+					case 53:
+					case 54:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonShift;
+						break;
+					case 56:
+					case 57:
+					case 58:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonAlt;
+						break;
+					case 61:
+					case 62:
+						buttonState |= MouseFlags.ReportMousePosition | MouseFlags.ButtonCtrl | MouseFlags.ButtonShift | MouseFlags.ButtonAlt;
+						break;
+					}
+				}
+			}
+
+			mouseFlags = new List<MouseFlags> () { MouseFlags.AllEvents };
+
+			if (lastMouseButtonPressed != null && !isButtonPressed && !buttonState.HasFlag (MouseFlags.ReportMousePosition)
+				&& !buttonState.HasFlag (MouseFlags.Button1Released)
+				&& !buttonState.HasFlag (MouseFlags.Button2Released)
+				&& !buttonState.HasFlag (MouseFlags.Button3Released)
+				&& !buttonState.HasFlag (MouseFlags.Button4Released)) {
+
+				lastMouseButtonPressed = null;
+				isButtonPressed = false;
+			}
+
+			if (!isButtonClicked && !isButtonDoubleClicked && ((buttonState == MouseFlags.Button1Pressed || buttonState == MouseFlags.Button2Pressed ||
+				  buttonState == MouseFlags.Button3Pressed || buttonState == MouseFlags.Button4Pressed) && lastMouseButtonPressed == null) ||
+				  isButtonPressed && lastMouseButtonPressed != null && buttonState.HasFlag (MouseFlags.ReportMousePosition)) {
+
+				mouseFlags [0] = buttonState;
+				lastMouseButtonPressed = buttonState;
+				isButtonPressed = true;
+
+				if ((mouseFlags [0] & MouseFlags.ReportMousePosition) == 0) {
+					point = new Point () {
+						X = pos.X,
+						Y = pos.Y
+					};
+
+					Application.MainLoop.AddIdle (() => {
+						Task.Run (async () => await ProcessContinuousButtonPressedAsync (buttonState, continuousButtonPressedHandler));
+						return false;
+					});
+				} else if (mouseFlags [0] == MouseFlags.ReportMousePosition) {
+					isButtonPressed = false;
+				}
+
+			} else if (isButtonDoubleClicked && (buttonState == MouseFlags.Button1Pressed || buttonState == MouseFlags.Button2Pressed ||
+				buttonState == MouseFlags.Button3Pressed || buttonState == MouseFlags.Button4Pressed)) {
+
+				mouseFlags [0] = GetButtonTripleClicked (buttonState);
+				isButtonDoubleClicked = false;
+				isButtonTripleClicked = true;
+
+			} else if (isButtonClicked && (buttonState == MouseFlags.Button1Pressed || buttonState == MouseFlags.Button2Pressed ||
+				buttonState == MouseFlags.Button3Pressed || buttonState == MouseFlags.Button4Pressed)) {
+
+				mouseFlags [0] = GetButtonDoubleClicked (buttonState);
+				isButtonClicked = false;
+				isButtonDoubleClicked = true;
+				Application.MainLoop.AddIdle (() => {
+					Task.Run (async () => await ProcessButtonDoubleClickedAsync ());
+					return false;
+				});
+
+			}
+			//else if (isButtonReleased && !isButtonClicked && buttonState == MouseFlags.ReportMousePosition) {
+			//	mouseFlag [0] = GetButtonClicked ((MouseFlags)lastMouseButtonReleased);
+			//	lastMouseButtonReleased = null;
+			//	isButtonReleased = false;
+			//	isButtonClicked = true;
+			//	Application.MainLoop.AddIdle (() => {
+			//		Task.Run (async () => await ProcessButtonClickedAsync ());
+			//		return false;
+			//	});
+
+			//} 
+			else if (!isButtonClicked && !isButtonDoubleClicked && (buttonState == MouseFlags.Button1Released || buttonState == MouseFlags.Button2Released ||
+				  buttonState == MouseFlags.Button3Released || buttonState == MouseFlags.Button4Released)) {
+
+				mouseFlags [0] = buttonState;
+				isButtonPressed = false;
+
+				if (isButtonTripleClicked) {
+					isButtonTripleClicked = false;
+				} else if (pos.X == point.X && pos.Y == point.Y) {
+					mouseFlags.Add (GetButtonClicked (buttonState));
+					isButtonClicked = true;
+					Application.MainLoop.AddIdle (() => {
+						Task.Run (async () => await ProcessButtonClickedAsync ());
+						return false;
+					});
+				}
+
+				point = pos;
+
+				//if ((lastMouseButtonPressed & MouseFlags.ReportMousePosition) == 0) {
+				//	lastMouseButtonReleased = buttonState;
+				//	isButtonPressed = false;
+				//	isButtonReleased = true;
+				//} else {
+				//	lastMouseButtonPressed = null;
+				//	isButtonPressed = false;
+				//}
+
+			} else if (buttonState == MouseFlags.WheeledUp) {
+
+				mouseFlags [0] = MouseFlags.WheeledUp;
+
+			} else if (buttonState == MouseFlags.WheeledDown) {
+
+				mouseFlags [0] = MouseFlags.WheeledDown;
+
+			} else if (buttonState == MouseFlags.WheeledLeft) {
+
+				mouseFlags [0] = MouseFlags.WheeledLeft;
+
+			} else if (buttonState == MouseFlags.WheeledRight) {
+
+				mouseFlags [0] = MouseFlags.WheeledRight;
+
+			} else if (buttonState == MouseFlags.ReportMousePosition) {
+				mouseFlags [0] = MouseFlags.ReportMousePosition;
+
+			} else {
+				mouseFlags [0] = buttonState;
+				//foreach (var flag in buttonState.GetUniqueFlags()) {
+				//	mouseFlag [0] |= flag;
+				//}
+			}
+
+			mouseFlags [0] = SetControlKeyStates (buttonState, mouseFlags [0]);
+			//buttonState = mouseFlags;
+
+			//System.Diagnostics.Debug.WriteLine ($"buttonState: {buttonState} X: {pos.X} Y: {pos.Y}");
+			//foreach (var mf in mouseFlags) {
+			//	System.Diagnostics.Debug.WriteLine ($"mouseFlags: {mf} X: {pos.X} Y: {pos.Y}");
+			//}
+		}
+
+		private static async Task ProcessContinuousButtonPressedAsync (MouseFlags mouseFlag, Action<MouseFlags, Point> continuousButtonPressedHandler)
+		{
+			while (isButtonPressed) {
+				await Task.Delay (100);
+				//var me = new MouseEvent () {
+				//	X = point.X,
+				//	Y = point.Y,
+				//	Flags = mouseFlag
+				//};
+
+				var view = Application.WantContinuousButtonPressedView;
+				if (view == null)
+					break;
+				if (isButtonPressed && lastMouseButtonPressed != null && (mouseFlag & MouseFlags.ReportMousePosition) == 0) {
+					Application.MainLoop.Invoke (() => continuousButtonPressedHandler (mouseFlag, point));
+				}
+			}
+		}
+
+		private static async Task ProcessButtonClickedAsync ()
+		{
+			await Task.Delay (300);
+			isButtonClicked = false;
+		}
+
+		private static async Task ProcessButtonDoubleClickedAsync ()
+		{
+			await Task.Delay (300);
+			isButtonDoubleClicked = false;
+		}
+
+		private static MouseFlags GetButtonClicked (MouseFlags mouseFlag)
+		{
+			MouseFlags mf = default;
+			switch (mouseFlag) {
+			case MouseFlags.Button1Released:
+				mf = MouseFlags.Button1Clicked;
+				break;
+
+			case MouseFlags.Button2Released:
+				mf = MouseFlags.Button2Clicked;
+				break;
+
+			case MouseFlags.Button3Released:
+				mf = MouseFlags.Button3Clicked;
+				break;
+			}
+			return mf;
+		}
+
+		private static MouseFlags GetButtonDoubleClicked (MouseFlags mouseFlag)
+		{
+			MouseFlags mf = default;
+			switch (mouseFlag) {
+			case MouseFlags.Button1Pressed:
+				mf = MouseFlags.Button1DoubleClicked;
+				break;
+
+			case MouseFlags.Button2Pressed:
+				mf = MouseFlags.Button2DoubleClicked;
+				break;
+
+			case MouseFlags.Button3Pressed:
+				mf = MouseFlags.Button3DoubleClicked;
+				break;
+			}
+			return mf;
+		}
+
+		private static MouseFlags GetButtonTripleClicked (MouseFlags mouseFlag)
+		{
+			MouseFlags mf = default;
+			switch (mouseFlag) {
+			case MouseFlags.Button1Pressed:
+				mf = MouseFlags.Button1TripleClicked;
+				break;
+
+			case MouseFlags.Button2Pressed:
+				mf = MouseFlags.Button2TripleClicked;
+				break;
+
+			case MouseFlags.Button3Pressed:
+				mf = MouseFlags.Button3TripleClicked;
+				break;
+			}
+			return mf;
+		}
+
+		private static MouseFlags SetControlKeyStates (MouseFlags buttonState, MouseFlags mouseFlag)
+		{
+			if ((buttonState & MouseFlags.ButtonCtrl) != 0 && (mouseFlag & MouseFlags.ButtonCtrl) == 0)
+				mouseFlag |= MouseFlags.ButtonCtrl;
+
+			if ((buttonState & MouseFlags.ButtonShift) != 0 && (mouseFlag & MouseFlags.ButtonShift) == 0)
+				mouseFlag |= MouseFlags.ButtonShift;
+
+			if ((buttonState & MouseFlags.ButtonAlt) != 0 && (mouseFlag & MouseFlags.ButtonAlt) == 0)
+				mouseFlag |= MouseFlags.ButtonAlt;
+			return mouseFlag;
+		}
+
+		/// <summary>
+		/// Get the terminal that holds the console driver.
+		/// </summary>
+		/// <param name="process">The process.</param>
+		/// <returns>If supported the executable console process, null otherwise.</returns>
+		public static Process GetParentProcess (Process process)
+		{
+			if (!RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
+				return null;
+			}
+
+			string query = "SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = " + process.Id;
+			using (ManagementObjectSearcher mos = new ManagementObjectSearcher (query)) {
+				foreach (ManagementObject mo in mos.Get ()) {
+					if (mo ["ParentProcessId"] != null) {
+						try {
+							var id = Convert.ToInt32 (mo ["ParentProcessId"]);
+							return Process.GetProcessById (id);
+						} catch {
+						}
+					}
+				}
+			}
+			return null;
+		}
+	}
+}

+ 1 - 1
Terminal.Gui/Core/Event.cs

@@ -749,7 +749,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		WheeledUp = unchecked((int)0x10000000),
 		/// <summary>
-		/// Vertical button wheeled up.
+		/// Vertical button wheeled down.
 		/// </summary>
 		WheeledDown = unchecked((int)0x20000000),
 		/// <summary>

+ 7 - 12
Terminal.Gui/Core/Window.cs

@@ -38,6 +38,9 @@ namespace Terminal.Gui {
 				if (!OnTitleChanging (title, value)) {
 					var old = title;
 					title = value;
+					if (Border != null) {
+						Border.Title = title;
+					}
 					OnTitleChanged (old, title);
 				}
 				SetNeedsDisplay ();
@@ -192,10 +195,13 @@ namespace Terminal.Gui {
 				Border = new Border () {
 					BorderStyle = DefaultBorderStyle,
 					Padding = new Thickness (padding),
-					BorderBrush = ColorScheme.Normal.Background
+					Title = title
 				};
 			} else {
 				Border = border;
+				if (ustring.IsNullOrEmpty (border.Title)) {
+					border.Title = title;
+				}
 			}
 			AdjustContentView (frame);
 		}
@@ -287,9 +293,6 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		public override void Redraw (Rect bounds)
 		{
-			var padding = Border.GetSumThickness ();
-			var scrRect = ViewToScreen (new Rect (0, 0, Frame.Width, Frame.Height));
-
 			if (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded) {
 				Driver.SetAttribute (GetNormalColor ());
 				Clear ();
@@ -298,7 +301,6 @@ namespace Terminal.Gui {
 			var savedClip = contentView.ClipToBounds ();
 
 			// Redraw our contentView
-			// DONE: smartly constrict contentView.Bounds to just be what intersects with the 'bounds' we were passed
 			contentView.Redraw (!NeedDisplay.IsEmpty || ChildNeedsDisplay || LayoutNeeded ? contentView.Bounds : bounds);
 			Driver.Clip = savedClip;
 
@@ -306,14 +308,7 @@ namespace Terminal.Gui {
 			ClearNeedsDisplay ();
 
 			Driver.SetAttribute (GetNormalColor ());
-			//Driver.DrawWindowFrame (scrRect, padding.Left + borderLength, padding.Top + borderLength, padding.Right + borderLength, padding.Bottom + borderLength,
-			//	Border.BorderStyle != BorderStyle.None, fill: true, Border.BorderStyle);
 			Border.DrawContent (this, false);
-			if (HasFocus)
-				Driver.SetAttribute (ColorScheme.HotNormal);
-			if (Border.DrawMarginFrame)
-				Driver.DrawWindowTitle (scrRect, Title, padding.Left, padding.Top, padding.Right, padding.Bottom);
-			Driver.SetAttribute (GetNormalColor ());
 		}
 
 		/// <inheritdoc/>

+ 1 - 1
Terminal.Gui/Resources/config.json

@@ -23,7 +23,7 @@
       "Ctrl"
     ]
   },
-  "Application.HeightAsBuffer": false,
+  "Application.EnableConsoleScrolling": false,
   "Application.QuitKey": {
     "Key": "Q",
     "Modifiers": [

+ 4 - 5
Terminal.Gui/Terminal.Gui.csproj

@@ -22,9 +22,13 @@
     <EmbeddedResource Include="Resources\config.json" />
   </ItemGroup>
   <ItemGroup>
+    <!-- Enable Nuget Source Link for github -->
+    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
     <PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
     <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
     <PackageReference Include="NStack.Core" Version="1.0.7" />
+    <PackageReference Include="System.Text.Json" Version="7.0.1" />
+    <PackageReference Include="System.Management" Version="7.0.0" />
     <InternalsVisibleTo Include="UnitTests" />
   </ItemGroup>
   <!-- Uncomment the RestoreSources element to have dotnet restore pull NStack from a local dir for testing -->
@@ -56,11 +60,6 @@
       <LastGenOutput>Strings.Designer.cs</LastGenOutput>
     </EmbeddedResource>
   </ItemGroup>
-  <!-- Enable Nuget Source Link for github -->
-  <ItemGroup>
-    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
-    <PackageReference Include="System.Text.Json" Version="7.0.1" />
-  </ItemGroup>
   <PropertyGroup>
     <TargetFrameworks>net472;netstandard2.0;net6.0</TargetFrameworks>
     <LangVersion>9</LangVersion>

+ 7 - 1
Terminal.Gui/Views/FrameView.cs

@@ -67,6 +67,9 @@ namespace Terminal.Gui {
 			get => title;
 			set {
 				title = value;
+				if (Border != null) {
+					Border.Title = title;
+				}
 				SetNeedsDisplay ();
 			}
 		}
@@ -163,6 +166,9 @@ namespace Terminal.Gui {
 				};
 			} else {
 				Border = border;
+				if (ustring.IsNullOrEmpty (border.Title)) {
+					border.Title = title;
+				}
 			}
 			AdjustContentView (frame, views);
 		}
@@ -310,7 +316,7 @@ namespace Terminal.Gui {
 				foreach (var p in lc.GenerateImage (bounds)) {
 					this.AddRune (p.Key.X, p.Key.Y, p.Value);
 				}
-				
+
 				// Redraw the lines so that focus/drag symbol renders
 				foreach (var subview in contentView.Subviews) {
 					//	line.DrawSplitterSymbol ();

+ 6 - 4
UICatalog/Properties/launchSettings.json

@@ -3,6 +3,12 @@
     "UICatalog": {
       "commandName": "Project"
     },
+    "WSL : UICatalog": {
+      "commandName": "Executable",
+      "executablePath": "wsl",
+      "commandLineArgs": "dotnet UICatalog.dll",
+      "distributionName": ""
+    },
     "UICatalog -usc": {
       "commandName": "Project",
       "commandLineArgs": "-usc"
@@ -29,10 +35,6 @@
       "commandName": "Project",
       "commandLineArgs": "WizardAsView"
     },
-    "VkeyPacketSimulator": {
-      "commandName": "Project",
-      "commandLineArgs": "VkeyPacketSimulator"
-    },
     "CollectionNavigatorTester": {
       "commandName": "Project",
       "commandLineArgs": "\"Search Collection Nav\""

+ 3 - 2
UICatalog/Scenarios/BordersComparisons.cs

@@ -12,9 +12,10 @@ namespace UICatalog.Scenarios {
 			var borderStyle = BorderStyle.Double;
 			var drawMarginFrame = false;
 			var borderThickness = new Thickness (1, 2, 3, 4);
-			var borderBrush = Colors.Base.HotFocus.Foreground;
+			var borderBrush = Color.BrightMagenta;
+			;
 			var padding = new Thickness (1, 2, 3, 4);
-			var background = Colors.Base.HotNormal.Foreground;
+			var background = Color.Cyan;
 			var effect3D = true;
 
 			var win = new Window (new Rect (5, 5, 40, 20), "Test", 8,

+ 15 - 13
UICatalog/UICatalog.cs

@@ -192,6 +192,9 @@ namespace UICatalog {
 			// Run UI Catalog UI. When it exits, if _selectedScenario is != null then
 			// a Scenario was selected. Otherwise, the user wants to exit UI Catalog.
 			Application.Init ();
+			
+			//Application.EnableConsoleScrolling = _enableConsoleScrolling;
+			
 			Application.Run<UICatalogTopLevel> ();
 			Application.Shutdown ();
 
@@ -225,7 +228,7 @@ namespace UICatalog {
 		/// </summary>
 		public class UICatalogTopLevel : Toplevel {
 			public MenuItem miIsMouseDisabled;
-			public MenuItem miHeightAsBuffer;
+			public MenuItem miEnableConsoleScrolling;
 
 			public TileView ContentPane;
 			public ListView CategoryListView;
@@ -406,7 +409,7 @@ namespace UICatalog {
 				List<MenuItem []> menuItems = new List<MenuItem []> {
 					CreateDiagnosticFlagsMenuItems (),
 					new MenuItem [] { null },
-					CreateHeightAsBufferMenuItems (),
+					CreateEnableConsoleScrollingMenuItems (),
 					CreateDisabledEnabledMouseItems (),
 					CreateKeybindingsMenuItems ()
 				};
@@ -447,19 +450,18 @@ namespace UICatalog {
 				return menuItems.ToArray ();
 			}
 
-			MenuItem [] CreateHeightAsBufferMenuItems ()
+			MenuItem [] CreateEnableConsoleScrollingMenuItems ()
 			{
 				List<MenuItem> menuItems = new List<MenuItem> ();
-				miHeightAsBuffer = new MenuItem {
-					Title = "_Height As Buffer"
-				};
-				miHeightAsBuffer.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miHeightAsBuffer.Title.ToString ().Substring (1, 1) [0];
-				miHeightAsBuffer.CheckType |= MenuItemCheckStyle.Checked;
-				miHeightAsBuffer.Action += () => {
-					miHeightAsBuffer.Checked = !miHeightAsBuffer.Checked;
-					Application.HeightAsBuffer = (bool)miHeightAsBuffer.Checked;
+				miEnableConsoleScrolling = new MenuItem ();
+				miEnableConsoleScrolling.Title = "_Enable Console Scrolling";
+				miEnableConsoleScrolling.Shortcut = Key.CtrlMask | Key.AltMask | (Key)miEnableConsoleScrolling.Title.ToString ().Substring (1, 1) [0];
+				miEnableConsoleScrolling.CheckType |= MenuItemCheckStyle.Checked;
+				miEnableConsoleScrolling.Action += () => {
+					miEnableConsoleScrolling.Checked = !miEnableConsoleScrolling.Checked;
+					Application.EnableConsoleScrolling = (bool)miEnableConsoleScrolling.Checked;
 				};
-				menuItems.Add (miHeightAsBuffer);
+				menuItems.Add (miEnableConsoleScrolling);
 
 				return menuItems.ToArray ();
 			}
@@ -634,7 +636,7 @@ namespace UICatalog {
 				StatusBar.Items [0].Title = $"~{Application.QuitKey} to quit";
 
 				miIsMouseDisabled.Checked = Application.IsMouseDisabled;
-				miHeightAsBuffer.Checked = Application.HeightAsBuffer;
+				miEnableConsoleScrolling.Checked = Application.EnableConsoleScrolling;
 
 				var height = (UICatalogApp.ShowStatusBar ? 1 : 0);// + (MenuBar.Visible ? 1 : 0);
 				ContentPane.Height = Dim.Fill (height);

+ 6 - 7
UnitTests/Application/ApplicationTests.cs

@@ -24,8 +24,7 @@ namespace Terminal.Gui.ApplicationTests {
 			Assert.Null (Application.Driver);
 			Assert.Null (Application.Top);
 			Assert.Null (Application.Current);
-			// removed below as HeightAsBuffer now works without a driver loaded
-			//Assert.Throws<ArgumentNullException> (() => Application.HeightAsBuffer == true);
+			Assert.False (Application.EnableConsoleScrolling);
 			Assert.Null (Application.MainLoop);
 			Assert.Null (Application.Iteration);
 			Assert.Null (Application.RootMouseEvent);
@@ -37,7 +36,7 @@ namespace Terminal.Gui.ApplicationTests {
 			Assert.NotNull (Application.Driver);
 			Assert.NotNull (Application.Top);
 			Assert.NotNull (Application.Current);
-			Assert.False (Application.HeightAsBuffer);
+			Assert.False (Application.EnableConsoleScrolling);
 			Assert.NotNull (Application.MainLoop);
 			Assert.Null (Application.Iteration);
 			Assert.Null (Application.RootMouseEvent);
@@ -314,7 +313,7 @@ namespace Terminal.Gui.ApplicationTests {
 		public void Run_T_Init_Driver_Cleared_with_TestTopLevel_Throws ()
 		{
 			Init ();
-			
+
 			Application.Driver = null;
 
 			Application.Iteration = () => {
@@ -334,8 +333,8 @@ namespace Terminal.Gui.ApplicationTests {
 		[Fact]
 		public void Run_T_NoInit_DoesNotThrow ()
 		{
-			Application.ForceFakeConsole = true; 
-			
+			Application.ForceFakeConsole = true;
+
 			Application.Iteration = () => {
 				Application.RequestStop ();
 			};
@@ -431,7 +430,7 @@ namespace Terminal.Gui.ApplicationTests {
 		}
 
 		// TODO: Add tests for Run that test errorHandler
-		
+
 		#endregion
 
 		#region ShutdownTests

+ 4 - 4
UnitTests/Configuration/ConfigurationMangerTests.cs

@@ -235,7 +235,7 @@ namespace Terminal.Gui.ConfigurationTests {
 			Assert.Equal (Key.B, Application.AlternateBackwardKey);
 			Assert.True (Application.UseSystemConsole);
 			Assert.True (Application.IsMouseDisabled);
-			Assert.True (Application.HeightAsBuffer);
+			Assert.True (Application.EnableConsoleScrolling);
 
 			//act
 			ConfigurationManager.Reset ();
@@ -248,7 +248,7 @@ namespace Terminal.Gui.ConfigurationTests {
 			Assert.Equal (Key.PageUp | Key.CtrlMask, Application.AlternateBackwardKey);
 			Assert.False (Application.UseSystemConsole);
 			Assert.False (Application.IsMouseDisabled);
-			Assert.False (Application.HeightAsBuffer);
+			Assert.False (Application.EnableConsoleScrolling);
 
 			// arrange
 			ConfigurationManager.Settings ["Application.QuitKey"].PropertyValue = Key.Q;
@@ -274,7 +274,7 @@ namespace Terminal.Gui.ConfigurationTests {
 			Assert.Equal (Key.PageUp | Key.CtrlMask, Application.AlternateBackwardKey);
 			Assert.False (Application.UseSystemConsole);
 			Assert.False (Application.IsMouseDisabled);
-			Assert.False (Application.HeightAsBuffer);
+			Assert.False (Application.EnableConsoleScrolling);
 
 		}
 
@@ -810,7 +810,7 @@ namespace Terminal.Gui.ConfigurationTests {
 				Assert.Equal (Key.B, Application.AlternateBackwardKey);
 				Assert.True (Application.UseSystemConsole);
 				Assert.True (Application.IsMouseDisabled);
-				Assert.True (Application.HeightAsBuffer);
+				Assert.True (Application.EnableConsoleScrolling);
 			}
 
 			// act

+ 1 - 1
UnitTests/Configuration/SettingsScopeTests.cs

@@ -63,7 +63,7 @@ namespace Terminal.Gui.ConfigurationTests {
 			Assert.Equal (Key.B, Application.AlternateBackwardKey);
 			Assert.True (Application.UseSystemConsole);
 			Assert.True (Application.IsMouseDisabled);
-			Assert.True (Application.HeightAsBuffer);
+			Assert.True (Application.EnableConsoleScrolling);
 		}
 
 		[Fact, AutoInitShutdown]

+ 12 - 2
UnitTests/Core/BorderTests.cs

@@ -226,7 +226,12 @@ namespace Terminal.Gui.CoreTests {
 
 					var color = (Attribute)driver.Contents [r, c, 1];
 					var rune = (Rune)driver.Contents [r, c, 0];
-					Assert.Equal (Color.Black, color.Background);
+					if (r == frame.Y - drawMarginFrame || r == frame.Bottom + drawMarginFrame - 1
+						|| c == frame.X - drawMarginFrame || c == frame.Right + drawMarginFrame - 1) {
+						Assert.Equal (Color.BrightGreen, color.Background);
+					} else {
+						Assert.Equal (Color.Black, color.Background);
+					}
 					if (c == frame.X - drawMarginFrame && r == frame.Y - drawMarginFrame) {
 						Assert.Equal (uLCorner, rune);
 					} else if (c == frame.Right && r == frame.Y - drawMarginFrame) {
@@ -456,7 +461,12 @@ namespace Terminal.Gui.CoreTests {
 
 					var color = (Attribute)driver.Contents [r, c, 1];
 					var rune = (Rune)driver.Contents [r, c, 0];
-					Assert.Equal (Color.Black, color.Background);
+					if (r == frame.Y + sumThickness.Top || r == frame.Bottom - sumThickness.Bottom - 1
+						|| c == frame.X + sumThickness.Left || c == frame.Right - sumThickness.Right - 1) {
+						Assert.Equal (Color.BrightGreen, color.Background);
+					} else {
+						Assert.Equal (Color.Black, color.Background);
+					}
 					if (c == frame.X + sumThickness.Left && r == frame.Y + sumThickness.Top) {
 						Assert.Equal (uLCorner, rune);
 					} else if (c == frame.Right - drawMarginFrame - sumThickness.Right

+ 78 - 0
UnitTests/Core/EscSeqReqTests.cs

@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Terminal.Gui.CoreTests {
+	public class EscSeqReqTests {
+		[Fact]
+		public void Constructor_Defaults ()
+		{
+			var escSeqReq = new EscSeqReqProc ();
+			Assert.NotNull (escSeqReq.EscSeqReqStats);
+			Assert.Empty (escSeqReq.EscSeqReqStats);
+		}
+
+		[Fact]
+		public void Add_Tests ()
+		{
+			var escSeqReq = new EscSeqReqProc ();
+			escSeqReq.Add ("t");
+			Assert.Single (escSeqReq.EscSeqReqStats);
+			Assert.Equal ("t", escSeqReq.EscSeqReqStats [^1].Terminating);
+			Assert.Equal (1, escSeqReq.EscSeqReqStats [^1].NumRequests);
+			Assert.Equal (1, escSeqReq.EscSeqReqStats [^1].NumOutstanding);
+
+			escSeqReq.Add ("t", 2);
+			Assert.Single (escSeqReq.EscSeqReqStats);
+			Assert.Equal ("t", escSeqReq.EscSeqReqStats [^1].Terminating);
+			Assert.Equal (1, escSeqReq.EscSeqReqStats [^1].NumRequests);
+			Assert.Equal (1, escSeqReq.EscSeqReqStats [^1].NumOutstanding);
+
+			escSeqReq = new EscSeqReqProc ();
+			escSeqReq.Add ("t", 2);
+			Assert.Single (escSeqReq.EscSeqReqStats);
+			Assert.Equal ("t", escSeqReq.EscSeqReqStats [^1].Terminating);
+			Assert.Equal (2, escSeqReq.EscSeqReqStats [^1].NumRequests);
+			Assert.Equal (2, escSeqReq.EscSeqReqStats [^1].NumOutstanding);
+
+			escSeqReq.Add ("t", 3);
+			Assert.Single (escSeqReq.EscSeqReqStats);
+			Assert.Equal ("t", escSeqReq.EscSeqReqStats [^1].Terminating);
+			Assert.Equal (2, escSeqReq.EscSeqReqStats [^1].NumRequests);
+			Assert.Equal (2, escSeqReq.EscSeqReqStats [^1].NumOutstanding);
+		}
+
+		[Fact]
+		public void Remove_Tests ()
+		{
+			var escSeqReq = new EscSeqReqProc ();
+			escSeqReq.Add ("t");
+			escSeqReq.Remove ("t");
+			Assert.Empty (escSeqReq.EscSeqReqStats);
+
+			escSeqReq.Add ("t", 2);
+			escSeqReq.Remove ("t");
+			Assert.Single (escSeqReq.EscSeqReqStats);
+			Assert.Equal ("t", escSeqReq.EscSeqReqStats [^1].Terminating);
+			Assert.Equal (2, escSeqReq.EscSeqReqStats [^1].NumRequests);
+			Assert.Equal (1, escSeqReq.EscSeqReqStats [^1].NumOutstanding);
+
+			escSeqReq.Remove ("t");
+			Assert.Empty (escSeqReq.EscSeqReqStats);
+		}
+
+		[Fact]
+		public void Requested_Tests ()
+		{
+			var escSeqReq = new EscSeqReqProc ();
+			Assert.False (escSeqReq.Requested ("t"));
+
+			escSeqReq.Add ("t");
+			Assert.False (escSeqReq.Requested ("r"));
+			Assert.True (escSeqReq.Requested ("t"));
+		}
+	}
+}

+ 870 - 0
UnitTests/Core/EscSeqUtilsTests.cs

@@ -0,0 +1,870 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Xunit;
+
+namespace Terminal.Gui.CoreTests {
+	public class EscSeqUtilsTests {
+		[Fact]
+		public void Defaults_Values ()
+		{
+			Assert.Equal ('\x1b', EscSeqUtils.KeyEsc);
+			Assert.Equal ("\x1b[", EscSeqUtils.KeyCSI);
+			Assert.Equal ("\x1b[?1003h", EscSeqUtils.CSI_EnableAnyEventMouse);
+			Assert.Equal ("\x1b[?1006h", EscSeqUtils.CSI_EnableSgrExtModeMouse);
+			Assert.Equal ("\x1b[?1015h", EscSeqUtils.CSI_EnableUrxvtExtModeMouse);
+			Assert.Equal ("\x1b[?1003l", EscSeqUtils.CSI_DisableAnyEventMouse);
+			Assert.Equal ("\x1b[?1006l", EscSeqUtils.CSI_DisableSgrExtModeMouse);
+			Assert.Equal ("\x1b[?1015l", EscSeqUtils.CSI_DisableUrxvtExtModeMouse);
+			Assert.Equal ("\x1b[?1003h\x1b[?1015h\u001b[?1006h", EscSeqUtils.EnableMouseEvents);
+			Assert.Equal ("\x1b[?1003l\x1b[?1015l\u001b[?1006l", EscSeqUtils.DisableMouseEvents);
+		}
+
+		[Fact]
+		public void GetConsoleInputKey_ConsoleKeyInfo ()
+		{
+			var cki = new ConsoleKeyInfo ('r', 0, false, false, false);
+			var expectedCki = new ConsoleKeyInfo ('r', 0, false, false, false);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('r', 0, true, false, false);
+			expectedCki = new ConsoleKeyInfo ('r', 0, true, false, false);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('r', 0, false, true, false);
+			expectedCki = new ConsoleKeyInfo ('r', 0, false, true, false);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('r', 0, false, false, true);
+			expectedCki = new ConsoleKeyInfo ('r', 0, false, false, true);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('r', 0, true, true, false);
+			expectedCki = new ConsoleKeyInfo ('r', 0, true, true, false);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('r', 0, false, true, true);
+			expectedCki = new ConsoleKeyInfo ('r', 0, false, true, true);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('r', 0, true, true, true);
+			expectedCki = new ConsoleKeyInfo ('r', 0, true, true, true);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('\u0012', 0, false, false, false);
+			expectedCki = new ConsoleKeyInfo ('R', ConsoleKey.R, false, false, true);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('\0', (ConsoleKey)64, false, false, true);
+			expectedCki = new ConsoleKeyInfo (' ', ConsoleKey.Spacebar, false, false, true);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('\r', 0, false, false, false);
+			expectedCki = new ConsoleKeyInfo ('\r', ConsoleKey.Enter, false, false, false);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('\u007f', 0, false, false, false);
+			expectedCki = new ConsoleKeyInfo ('\u007f', ConsoleKey.Backspace, false, false, false);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+
+			cki = new ConsoleKeyInfo ('R', 0, false, false, false);
+			expectedCki = new ConsoleKeyInfo ('R', 0, false, false, false);
+			Assert.Equal (expectedCki, EscSeqUtils.GetConsoleInputKey (cki));
+		}
+
+		[Fact]
+		public void ResizeArray_ConsoleKeyInfo ()
+		{
+			ConsoleKeyInfo [] expectedCkInfos = null;
+			var cki = new ConsoleKeyInfo ('\u001b', ConsoleKey.Escape, false, false, false);
+			expectedCkInfos = EscSeqUtils.ResizeArray (cki, expectedCkInfos);
+			Assert.Single (expectedCkInfos);
+			Assert.Equal (cki, expectedCkInfos [0]);
+		}
+
+		private EscSeqReqProc escSeqReqProc;
+		private ConsoleKeyInfo newConsoleKeyInfo;
+		private ConsoleKey key;
+		private ConsoleKeyInfo [] cki;
+		private ConsoleModifiers mod;
+		private string c1Control, code, terminating;
+		private string [] values;
+		private bool isKeyMouse;
+		private bool isReq;
+		private List<MouseFlags> mouseFlags;
+		Point pos;
+		private MouseFlags arg1;
+		private Point arg2;
+		private bool actionStarted;
+
+		[Fact, AutoInitShutdown]
+		public void DecodeEscSeq_Tests ()
+		{
+			// ESC
+			cki = new ConsoleKeyInfo [] { new ConsoleKeyInfo ('\u001b', 0, false, false, false) };
+			var expectedCki = new ConsoleKeyInfo ('\u001b', ConsoleKey.Escape, false, false, false);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.Escape, key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("ESC", c1Control);
+			Assert.Null (code);
+			Assert.Null (values);
+			Assert.Null (terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('\u0012', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\u0012', ConsoleKey.R, false, true, true);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.R, key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("ESC", c1Control);
+			Assert.Null (code);
+			Assert.Null (values);
+			Assert.Equal ("\u0012", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('r', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('R', ConsoleKey.R, false, true, false);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.R, key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("ESC", c1Control);
+			Assert.Null (code);
+			Assert.Null (values);
+			Assert.Equal ("r", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			// SS3
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('O', 0, false, false, false),
+				new ConsoleKeyInfo ('R', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\0', ConsoleKey.F3, false, false, false);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.F3, key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("SS3", c1Control);
+			Assert.Null (code);
+			Assert.Single (values);
+			Assert.Null (values [0]);
+			Assert.Equal ("R", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			// CSI
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('1', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo ('R', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\0', ConsoleKey.F3, true, false, false);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.F3, key);
+			Assert.Equal (ConsoleModifiers.Shift, mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (2, values.Length);
+			Assert.Equal ("1", values [0]);
+			Assert.Equal ("2", values [^1]);
+			Assert.Equal ("R", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('1', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('R', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\0', ConsoleKey.F3, false, true, false);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.F3, key);
+			Assert.Equal (ConsoleModifiers.Alt, mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (2, values.Length);
+			Assert.Equal ("1", values [0]);
+			Assert.Equal ("3", values [^1]);
+			Assert.Equal ("R", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('1', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('4', 0, false, false, false),
+				new ConsoleKeyInfo ('R', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\0', ConsoleKey.F3, true, true, false);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.F3, key);
+			Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt, mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (2, values.Length);
+			Assert.Equal ("1", values [0]);
+			Assert.Equal ("4", values [^1]);
+			Assert.Equal ("R", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('1', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('5', 0, false, false, false),
+				new ConsoleKeyInfo ('R', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\0', ConsoleKey.F3, false, false, true);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.F3, key);
+			Assert.Equal (ConsoleModifiers.Control, mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (2, values.Length);
+			Assert.Equal ("1", values [0]);
+			Assert.Equal ("5", values [^1]);
+			Assert.Equal ("R", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('1', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('6', 0, false, false, false),
+				new ConsoleKeyInfo ('R', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\0', ConsoleKey.F3, true, false, true);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.F3, key);
+			Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Control, mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (2, values.Length);
+			Assert.Equal ("1", values [0]);
+			Assert.Equal ("6", values [^1]);
+			Assert.Equal ("R", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('1', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('7', 0, false, false, false),
+				new ConsoleKeyInfo ('R', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\0', ConsoleKey.F3, false, true, true);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.F3, key);
+			Assert.Equal (ConsoleModifiers.Alt | ConsoleModifiers.Control, mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (2, values.Length);
+			Assert.Equal ("1", values [0]);
+			Assert.Equal ("7", values [^1]);
+			Assert.Equal ("R", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('1', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('8', 0, false, false, false),
+				new ConsoleKeyInfo ('R', 0, false, false, false)
+			};
+			expectedCki = new ConsoleKeyInfo ('\0', ConsoleKey.F3, true, true, true);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (ConsoleKey.F3, key);
+			Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control, mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (2, values.Length);
+			Assert.Equal ("1", values [0]);
+			Assert.Equal ("8", values [^1]);
+			Assert.Equal ("R", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('M', 0, false, false, false)
+			};
+			expectedCki = default;
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (0, (int)key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Equal ("<", code);
+			Assert.Equal (3, values.Length);
+			Assert.Equal ("0", values [0]);
+			Assert.Equal ("2", values [1]);
+			Assert.Equal ("3", values [^1]);
+			Assert.Equal ("M", terminating);
+			Assert.True (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1Pressed }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('m', 0, false, false, false)
+			};
+			expectedCki = default;
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (0, (int)key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Equal ("<", code);
+			Assert.Equal (3, values.Length);
+			Assert.Equal ("0", values [0]);
+			Assert.Equal ("2", values [1]);
+			Assert.Equal ("3", values [^1]);
+			Assert.Equal ("m", terminating);
+			Assert.True (isKeyMouse);
+			Assert.Equal (2, mouseFlags.Count);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1Released, MouseFlags.Button1Clicked }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('M', 0, false, false, false)
+			};
+			expectedCki = default;
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (0, (int)key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Equal ("<", code);
+			Assert.Equal (3, values.Length);
+			Assert.Equal ("0", values [0]);
+			Assert.Equal ("2", values [1]);
+			Assert.Equal ("3", values [^1]);
+			Assert.Equal ("M", terminating);
+			Assert.True (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1DoubleClicked }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+			Assert.False (isReq);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('M', 0, false, false, false)
+			};
+			expectedCki = default;
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (0, (int)key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Equal ("<", code);
+			Assert.Equal (3, values.Length);
+			Assert.Equal ("0", values [0]);
+			Assert.Equal ("2", values [1]);
+			Assert.Equal ("3", values [^1]);
+			Assert.Equal ("M", terminating);
+			Assert.True (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1TripleClicked }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+			Assert.False (isReq);
+
+			var view = new View () {
+				Width = Dim.Fill (),
+				Height = Dim.Fill (),
+				WantContinuousButtonPressed = true
+			};
+			Application.Top.Add (view);
+			Application.Begin (Application.Top);
+
+			ReflectionTools.InvokePrivate (
+				typeof (Application),
+				"ProcessMouseEvent",
+				new MouseEvent () {
+					X = 0,
+					Y = 0,
+					Flags = 0
+				});
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('M', 0, false, false, false)
+			};
+			expectedCki = default;
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (0, (int)key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Equal ("<", code);
+			Assert.Equal (3, values.Length);
+			Assert.Equal ("0", values [0]);
+			Assert.Equal ("2", values [1]);
+			Assert.Equal ("3", values [^1]);
+			Assert.Equal ("M", terminating);
+			Assert.True (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1Pressed }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+			Assert.False (isReq);
+
+			Application.Iteration += () => {
+				if (actionStarted) {
+					// set Application.WantContinuousButtonPressedView to null
+					view.WantContinuousButtonPressed = false;
+					ReflectionTools.InvokePrivate (
+						typeof (Application),
+						"ProcessMouseEvent",
+						new MouseEvent () {
+							X = 0,
+							Y = 0,
+							Flags = 0
+						});
+
+					Application.RequestStop ();
+				}
+			};
+
+			Application.Run ();
+
+			Assert.Null (Application.WantContinuousButtonPressedView);
+
+			Assert.Equal (MouseFlags.Button1Pressed, arg1);
+			Assert.Equal (new Point (1, 2), arg2);
+
+			ClearAll ();
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('m', 0, false, false, false)
+			};
+			expectedCki = default;
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Null (escSeqReqProc);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (0, (int)key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Equal ("<", code);
+			Assert.Equal (3, values.Length);
+			Assert.Equal ("0", values [0]);
+			Assert.Equal ("2", values [1]);
+			Assert.Equal ("3", values [^1]);
+			Assert.Equal ("m", terminating);
+			Assert.True (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1Released }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+			Assert.False (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+
+			ClearAll ();
+
+			Assert.Null (escSeqReqProc);
+			escSeqReqProc = new EscSeqReqProc ();
+			escSeqReqProc.Add ("t");
+
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('8', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('1', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo ('t', 0, false, false, false)
+			};
+			expectedCki = default;
+			Assert.Single (escSeqReqProc.EscSeqReqStats);
+			Assert.Equal ("t", escSeqReqProc.EscSeqReqStats [^1].Terminating);
+			EscSeqUtils.DecodeEscSeq (escSeqReqProc, ref newConsoleKeyInfo, ref key, cki, ref mod, out c1Control, out code, out values, out terminating, out isKeyMouse, out mouseFlags, out pos, out isReq, ProcessContinuousButtonPressed);
+			Assert.Empty (escSeqReqProc.EscSeqReqStats);
+			Assert.Equal (expectedCki, newConsoleKeyInfo);
+			Assert.Equal (0, (int)key);
+			Assert.Equal (0, (int)mod);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (3, values.Length);
+			Assert.Equal ("8", values [0]);
+			Assert.Equal ("10", values [1]);
+			Assert.Equal ("20", values [^1]);
+			Assert.Equal ("t", terminating);
+			Assert.False (isKeyMouse);
+			Assert.Equal (new List<MouseFlags> () { 0 }, mouseFlags);
+			Assert.Equal (Point.Empty, pos);
+			Assert.True (isReq);
+			Assert.Equal (0, (int)arg1);
+			Assert.Equal (Point.Empty, arg2);
+		}
+
+		private void ClearAll ()
+		{
+			escSeqReqProc = default;
+			newConsoleKeyInfo = default;
+			key = default;
+			cki = default;
+			mod = default;
+			c1Control = default;
+			code = default;
+			terminating = default;
+			values = default;
+			isKeyMouse = default;
+			isReq = default;
+			mouseFlags = default;
+			pos = default;
+			arg1 = default;
+			arg2 = default;
+		}
+
+		private void ProcessContinuousButtonPressed (MouseFlags arg1, Point arg2)
+		{
+			this.arg1 = arg1;
+			this.arg2 = arg2;
+			actionStarted = true;
+		}
+
+		[Fact]
+		public void GetEscapeResult_Tests ()
+		{
+			char [] kChars = new char [] { '\u001b', '[', '5', ';', '1', '0', 'r' };
+			(c1Control, code, values, terminating) = EscSeqUtils.GetEscapeResult (kChars);
+			Assert.Equal ("CSI", c1Control);
+			Assert.Null (code);
+			Assert.Equal (2, values.Length);
+			Assert.Equal ("5", values [0]);
+			Assert.Equal ("10", values [^1]);
+			Assert.Equal ("r", terminating);
+		}
+
+		[Fact]
+		public void GetC1ControlChar_Tests ()
+		{
+			Assert.Equal ("IND", EscSeqUtils.GetC1ControlChar ('D'));
+			Assert.Equal ("NEL", EscSeqUtils.GetC1ControlChar ('E'));
+			Assert.Equal ("HTS", EscSeqUtils.GetC1ControlChar ('H'));
+			Assert.Equal ("RI", EscSeqUtils.GetC1ControlChar ('M'));
+			Assert.Equal ("SS2", EscSeqUtils.GetC1ControlChar ('N'));
+			Assert.Equal ("SS3", EscSeqUtils.GetC1ControlChar ('O'));
+			Assert.Equal ("DCS", EscSeqUtils.GetC1ControlChar ('P'));
+			Assert.Equal ("SPA", EscSeqUtils.GetC1ControlChar ('V'));
+			Assert.Equal ("EPA", EscSeqUtils.GetC1ControlChar ('W'));
+			Assert.Equal ("SOS", EscSeqUtils.GetC1ControlChar ('X'));
+			Assert.Equal ("DECID", EscSeqUtils.GetC1ControlChar ('Z'));
+			Assert.Equal ("CSI", EscSeqUtils.GetC1ControlChar ('['));
+			Assert.Equal ("ST", EscSeqUtils.GetC1ControlChar ('\\'));
+			Assert.Equal ("OSC", EscSeqUtils.GetC1ControlChar (']'));
+			Assert.Equal ("PM", EscSeqUtils.GetC1ControlChar ('^'));
+			Assert.Equal ("APC", EscSeqUtils.GetC1ControlChar ('_'));
+			Assert.Equal ("", EscSeqUtils.GetC1ControlChar ('\0'));
+		}
+
+		[Fact]
+		public void GetConsoleModifiers_Tests ()
+		{
+			Assert.Equal (ConsoleModifiers.Shift, EscSeqUtils.GetConsoleModifiers ("2"));
+			Assert.Equal (ConsoleModifiers.Alt, EscSeqUtils.GetConsoleModifiers ("3"));
+			Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt, EscSeqUtils.GetConsoleModifiers ("4"));
+			Assert.Equal (ConsoleModifiers.Control, EscSeqUtils.GetConsoleModifiers ("5"));
+			Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Control, EscSeqUtils.GetConsoleModifiers ("6"));
+			Assert.Equal (ConsoleModifiers.Alt | ConsoleModifiers.Control, EscSeqUtils.GetConsoleModifiers ("7"));
+			Assert.Equal (ConsoleModifiers.Shift | ConsoleModifiers.Alt | ConsoleModifiers.Control, EscSeqUtils.GetConsoleModifiers ("8"));
+			Assert.Equal (0, (int)EscSeqUtils.GetConsoleModifiers (""));
+		}
+
+		[Fact]
+		public void GetConsoleKey_Tests ()
+		{
+			ConsoleModifiers mod = 0;
+			Assert.Equal (ConsoleKey.UpArrow, EscSeqUtils.GetConsoleKey ('A', "", ref mod));
+			Assert.Equal (ConsoleKey.DownArrow, EscSeqUtils.GetConsoleKey ('B', "", ref mod));
+			Assert.Equal (key = ConsoleKey.RightArrow, EscSeqUtils.GetConsoleKey ('C', "", ref mod));
+			Assert.Equal (ConsoleKey.LeftArrow, EscSeqUtils.GetConsoleKey ('D', "", ref mod));
+			Assert.Equal (ConsoleKey.End, EscSeqUtils.GetConsoleKey ('F', "", ref mod));
+			Assert.Equal (ConsoleKey.Home, EscSeqUtils.GetConsoleKey ('H', "", ref mod));
+			Assert.Equal (ConsoleKey.F1, EscSeqUtils.GetConsoleKey ('P', "", ref mod));
+			Assert.Equal (ConsoleKey.F2, EscSeqUtils.GetConsoleKey ('Q', "", ref mod));
+			Assert.Equal (ConsoleKey.F3, EscSeqUtils.GetConsoleKey ('R', "", ref mod));
+			Assert.Equal (ConsoleKey.F4, EscSeqUtils.GetConsoleKey ('S', "", ref mod));
+			Assert.Equal (ConsoleKey.Tab, EscSeqUtils.GetConsoleKey ('Z', "", ref mod));
+			Assert.Equal (ConsoleModifiers.Shift, mod);
+			Assert.Equal (0, (int)EscSeqUtils.GetConsoleKey ('\0', "", ref mod));
+			Assert.Equal (ConsoleKey.Insert, EscSeqUtils.GetConsoleKey ('~', "2", ref mod));
+			Assert.Equal (ConsoleKey.Delete, EscSeqUtils.GetConsoleKey ('~', "3", ref mod));
+			Assert.Equal (ConsoleKey.PageUp, EscSeqUtils.GetConsoleKey ('~', "5", ref mod));
+			Assert.Equal (ConsoleKey.PageDown, EscSeqUtils.GetConsoleKey ('~', "6", ref mod));
+			Assert.Equal (ConsoleKey.F5, EscSeqUtils.GetConsoleKey ('~', "15", ref mod));
+			Assert.Equal (ConsoleKey.F6, EscSeqUtils.GetConsoleKey ('~', "17", ref mod));
+			Assert.Equal (ConsoleKey.F7, EscSeqUtils.GetConsoleKey ('~', "18", ref mod));
+			Assert.Equal (ConsoleKey.F8, EscSeqUtils.GetConsoleKey ('~', "19", ref mod));
+			Assert.Equal (ConsoleKey.F9, EscSeqUtils.GetConsoleKey ('~', "20", ref mod));
+			Assert.Equal (ConsoleKey.F10, EscSeqUtils.GetConsoleKey ('~', "21", ref mod));
+			Assert.Equal (ConsoleKey.F11, EscSeqUtils.GetConsoleKey ('~', "23", ref mod));
+			Assert.Equal (ConsoleKey.F12, EscSeqUtils.GetConsoleKey ('~', "24", ref mod));
+			Assert.Equal (0, (int)EscSeqUtils.GetConsoleKey ('~', "", ref mod));
+		}
+
+		[Fact]
+		public void GetKeyCharArray_Tests ()
+		{
+			var cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo('[', 0, false, false, false),
+				new ConsoleKeyInfo('5', 0, false, false, false),
+				new ConsoleKeyInfo(';', 0, false, false, false),
+				new ConsoleKeyInfo('1', 0, false, false, false),
+				new ConsoleKeyInfo('0', 0, false, false, false),
+				new ConsoleKeyInfo('r', 0, false, false, false),
+			};
+
+			Assert.Equal (new char [] { '\u001b', '[', '5', ';', '1', '0', 'r' }, EscSeqUtils.GetKeyCharArray (cki));
+		}
+
+		[Fact, AutoInitShutdown]
+		public void GetMouse_Tests ()
+		{
+			var cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('M', 0, false, false, false)
+			};
+			EscSeqUtils.GetMouse (cki, out List<MouseFlags> mouseFlags, out Point pos, ProcessContinuousButtonPressed);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1Pressed }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('m', 0, false, false, false)
+			};
+			EscSeqUtils.GetMouse (cki, out mouseFlags, out pos, ProcessContinuousButtonPressed);
+			Assert.Equal (2, mouseFlags.Count);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1Released, MouseFlags.Button1Clicked }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('M', 0, false, false, false)
+			};
+			EscSeqUtils.GetMouse (cki, out mouseFlags, out pos, ProcessContinuousButtonPressed);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1DoubleClicked }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('M', 0, false, false, false)
+			};
+			EscSeqUtils.GetMouse (cki, out mouseFlags, out pos, ProcessContinuousButtonPressed);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1TripleClicked }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+
+			cki = new ConsoleKeyInfo [] {
+				new ConsoleKeyInfo ('\u001b', 0, false, false, false),
+				new ConsoleKeyInfo ('[', 0, false, false, false),
+				new ConsoleKeyInfo ('<', 0, false, false, false),
+				new ConsoleKeyInfo ('0', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('2', 0, false, false, false),
+				new ConsoleKeyInfo (';', 0, false, false, false),
+				new ConsoleKeyInfo ('3', 0, false, false, false),
+				new ConsoleKeyInfo ('m', 0, false, false, false)
+			};
+			EscSeqUtils.GetMouse (cki, out mouseFlags, out pos, ProcessContinuousButtonPressed);
+			Assert.Equal (new List<MouseFlags> () { MouseFlags.Button1Released }, mouseFlags);
+			Assert.Equal (new Point (1, 2), pos);
+		}
+
+		[Fact]
+		public void GetParentProcess_Tests ()
+		{
+			if (RuntimeInformation.IsOSPlatform (OSPlatform.Windows)) {
+				Assert.NotNull (EscSeqUtils.GetParentProcess (Process.GetCurrentProcess ()));
+			} else {
+				Assert.Null (EscSeqUtils.GetParentProcess (Process.GetCurrentProcess ()));
+			}
+		}
+	}
+}

+ 15 - 15
UnitTests/Drivers/ConsoleDriverTests.cs

@@ -171,7 +171,7 @@ namespace Terminal.Gui.DriverTests {
 
 			// MockDriver will still be 120x40
 			wasTerminalResized = false;
-			Application.HeightAsBuffer = true;
+			Application.EnableConsoleScrolling = true;
 			driver.SetWindowSize (40, 20);
 			Assert.Equal (120, Application.Driver.Cols);
 			Assert.Equal (40, Application.Driver.Rows);
@@ -186,12 +186,12 @@ namespace Terminal.Gui.DriverTests {
 
 		[Theory]
 		[InlineData (typeof (FakeDriver))]
-		public void HeightAsBuffer_Is_False_Left_And_Top_Is_Always_Zero (Type driverType)
+		public void EnableConsoleScrolling_Is_False_Left_And_Top_Is_Always_Zero (Type driverType)
 		{
 			var driver = (FakeDriver)Activator.CreateInstance (driverType);
 			Application.Init (driver);
 
-			Assert.False (Application.HeightAsBuffer);
+			Assert.False (Application.EnableConsoleScrolling);
 			Assert.Equal (0, Console.WindowLeft);
 			Assert.Equal (0, Console.WindowTop);
 
@@ -204,13 +204,13 @@ namespace Terminal.Gui.DriverTests {
 
 		[Theory]
 		[InlineData (typeof (FakeDriver))]
-		public void HeightAsBuffer_Is_True_Left_Cannot_Be_Greater_Than_WindowWidth (Type driverType)
+		public void EnableConsoleScrolling_Is_True_Left_Cannot_Be_Greater_Than_WindowWidth (Type driverType)
 		{
 			var driver = (FakeDriver)Activator.CreateInstance (driverType);
 			Application.Init (driver);
 
-			Application.HeightAsBuffer = true;
-			Assert.True (Application.HeightAsBuffer);
+			Application.EnableConsoleScrolling = true;
+			Assert.True (Application.EnableConsoleScrolling);
 
 			driver.SetWindowPosition (81, 25);
 			Assert.Equal (0, Console.WindowLeft);
@@ -221,13 +221,13 @@ namespace Terminal.Gui.DriverTests {
 
 		[Theory]
 		[InlineData (typeof (FakeDriver))]
-		public void HeightAsBuffer_Is_True_Left_Cannot_Be_Greater_Than_BufferWidth_Minus_WindowWidth (Type driverType)
+		public void EnableConsoleScrolling_Is_True_Left_Cannot_Be_Greater_Than_BufferWidth_Minus_WindowWidth (Type driverType)
 		{
 			var driver = (FakeDriver)Activator.CreateInstance (driverType);
 			Application.Init (driver);
 
-			Application.HeightAsBuffer = true;
-			Assert.True (Application.HeightAsBuffer);
+			Application.EnableConsoleScrolling = true;
+			Assert.True (Application.EnableConsoleScrolling);
 
 			driver.SetWindowPosition (81, 25);
 			Assert.Equal (0, Console.WindowLeft);
@@ -261,13 +261,13 @@ namespace Terminal.Gui.DriverTests {
 
 		[Theory]
 		[InlineData (typeof (FakeDriver))]
-		public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_WindowHeight (Type driverType)
+		public void EnableConsoleScrolling_Is_True_Top_Cannot_Be_Greater_Than_WindowHeight (Type driverType)
 		{
 			var driver = (FakeDriver)Activator.CreateInstance (driverType);
 			Application.Init (driver);
 
-			Application.HeightAsBuffer = true;
-			Assert.True (Application.HeightAsBuffer);
+			Application.EnableConsoleScrolling = true;
+			Assert.True (Application.EnableConsoleScrolling);
 
 			driver.SetWindowPosition (80, 26);
 			Assert.Equal (0, Console.WindowLeft);
@@ -278,13 +278,13 @@ namespace Terminal.Gui.DriverTests {
 
 		[Theory]
 		[InlineData (typeof (FakeDriver))]
-		public void HeightAsBuffer_Is_True_Top_Cannot_Be_Greater_Than_BufferHeight_Minus_WindowHeight (Type driverType)
+		public void EnableConsoleScrolling_Is_True_Top_Cannot_Be_Greater_Than_BufferHeight_Minus_WindowHeight (Type driverType)
 		{
 			var driver = (FakeDriver)Activator.CreateInstance (driverType);
 			Application.Init (driver);
 
-			Application.HeightAsBuffer = true;
-			Assert.True (Application.HeightAsBuffer);
+			Application.EnableConsoleScrolling = true;
+			Assert.True (Application.EnableConsoleScrolling);
 
 			driver.SetWindowPosition (80, 26);
 			Assert.Equal (0, Console.WindowLeft);

+ 2 - 2
UnitTests/UnitTests.csproj

@@ -21,8 +21,8 @@
     <DefineConstants>TRACE;DEBUG_IDISPOSABLE</DefineConstants>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
-    <PackageReference Include="ReportGenerator" Version="5.1.12" />
+    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
+    <PackageReference Include="ReportGenerator" Version="5.1.17" />
     <PackageReference Include="System.Collections" Version="4.3.0" />
     <PackageReference Include="xunit" Version="2.4.2" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">

Some files were not shown because too many files changed in this diff