From dee29b50b1f9cbb311e1da5d7e4561ee180ab8a0 Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 30 May 2024 21:50:17 +0100 Subject: [PATCH 1/6] Fixes #3518. v1 NetDriver throws System.InvalidOperationException when a key is pressed. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 811426f44..156c08f9d 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -177,7 +177,15 @@ namespace Terminal.Gui { ConsoleKeyInfo newConsoleKeyInfo = default; while (true) { - ConsoleKeyInfo consoleKeyInfo = Console.ReadKey (true); + ConsoleKeyInfo consoleKeyInfo; + + try { + consoleKeyInfo = Console.ReadKey (true); + } catch (InvalidOperationException ex) { + + return; + } + if ((consoleKeyInfo.KeyChar == (char)Key.Esc && !isEscSeq) || (consoleKeyInfo.KeyChar != (char)Key.Esc && isEscSeq)) { if (cki == null && consoleKeyInfo.KeyChar != (char)Key.Esc && isEscSeq) { From 322948cfaa661f5357989df594f012cf52b46cdd Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 30 May 2024 21:54:12 +0100 Subject: [PATCH 2/6] Ensures cursor visibility when cursor is visible. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 156c08f9d..69ccc22b0 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1351,7 +1351,11 @@ namespace Terminal.Gui { public override bool SetCursorVisibility (CursorVisibility visibility) { savedCursorVisibility = visibility; - return Console.CursorVisible = visibility == CursorVisibility.Default; + Console.Out.Write (visibility == CursorVisibility.Default + ? "\x1b[?25h" + : "\x1b[?25l"); + + return visibility == CursorVisibility.Default; } /// From 78de7b116ae7bd56bb18406492768f20355a0c0b Mon Sep 17 00:00:00 2001 From: BDisp Date: Thu, 30 May 2024 22:12:22 +0100 Subject: [PATCH 3/6] Add support for Suspend. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 69ccc22b0..af10b8b09 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1027,6 +1027,16 @@ namespace Terminal.Gui { public override void Suspend () { + if (Environment.OSVersion.Platform != PlatformID.Unix) { + return; + } + + StopReportingMouseMoves (); + Console.ResetColor (); + Console.Clear (); + Platform.Suspend (); + Application.Refresh (); + StartReportingMouseMoves (); } From 5b4195ed61f1271e68a3e610978aa5d9bc03ffa6 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sat, 1 Jun 2024 15:21:06 +0100 Subject: [PATCH 4/6] Restore buffer and cursor during suspend. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index af10b8b09..7d6ed0d69 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -1034,12 +1034,22 @@ namespace Terminal.Gui { StopReportingMouseMoves (); Console.ResetColor (); Console.Clear (); + + //Disable alternative screen buffer. + Console.Out.Write ("\x1b[?1049l"); + + //Set cursor key to cursor. + Console.Out.Write ("\x1b[?25h"); + Platform.Suspend (); + + //Enable alternative screen buffer. + Console.Out.Write ("\x1b[?1049h"); + Application.Refresh (); StartReportingMouseMoves (); } - public override void SetAttribute (Attribute c) { base.SetAttribute (c); From f749eef8e9c28d8df34cf2d98b81381246ea8b62 Mon Sep 17 00:00:00 2001 From: BDisp Date: Sun, 2 Jun 2024 20:03:29 +0100 Subject: [PATCH 5/6] Remove InvalidOperationException and use Task.Delay with CancellationTokenSource. --- Terminal.Gui/ConsoleDrivers/NetDriver.cs | 92 +++++++++++++----------- Terminal.Gui/Core/Application.cs | 2 +- 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/NetDriver.cs b/Terminal.Gui/ConsoleDrivers/NetDriver.cs index 7d6ed0d69..1e02a03ae 100644 --- a/Terminal.Gui/ConsoleDrivers/NetDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/NetDriver.cs @@ -113,7 +113,9 @@ namespace Terminal.Gui { ConsoleDriver consoleDriver; volatile ConsoleKeyInfo [] cki = null; static volatile bool isEscSeq; - bool stopTasks; + + internal CancellationTokenSource TokenSource = new CancellationTokenSource (); + #if PROCESS_REQUEST bool neededProcessRequest; #endif @@ -125,21 +127,13 @@ namespace Terminal.Gui { throw new ArgumentNullException ("Console driver instance must be provided."); } this.consoleDriver = consoleDriver; - Task.Run (ProcessInputResultQueue); - Task.Run (CheckWinChange); - } - - internal void StopTasks () - { - stopTasks = true; + Task.Run (ProcessInputResultQueue, TokenSource.Token); + Task.Run (CheckWinChange, TokenSource.Token); } public InputResult? ReadConsoleInput () { - while (true) { - if (stopTasks) { - return null; - } + while (!TokenSource.IsCancellationRequested) { waitForStart.Set (); winChange.Set (); @@ -154,11 +148,13 @@ namespace Terminal.Gui { return inputResultQueue.Dequeue (); } } + + return null; } void ProcessInputResultQueue () { - while (true) { + while (!TokenSource.IsCancellationRequested) { waitForStart.Wait (); waitForStart.Reset (); @@ -176,12 +172,19 @@ namespace Terminal.Gui { ConsoleModifiers mod = 0; ConsoleKeyInfo newConsoleKeyInfo = default; - while (true) { - ConsoleKeyInfo consoleKeyInfo; + while (!TokenSource.IsCancellationRequested) { + ConsoleKeyInfo consoleKeyInfo = default; try { - consoleKeyInfo = Console.ReadKey (true); - } catch (InvalidOperationException ex) { + if (Console.KeyAvailable) { + consoleKeyInfo = Console.ReadKey (true); + } else { + Task.Delay (100, TokenSource.Token).Wait (TokenSource.Token); + if (Console.KeyAvailable) { + consoleKeyInfo = Console.ReadKey (true); + } + } + } catch (OperationCanceledException) { return; } @@ -209,18 +212,19 @@ namespace Terminal.Gui { } break; } else { - GetConsoleInputType (consoleKeyInfo); - break; + if (consoleKeyInfo != default) { + GetConsoleInputType (consoleKeyInfo); + break; + } } + + TokenSource.Token.ThrowIfCancellationRequested (); } } void CheckWinChange () { - while (true) { - if (stopTasks) { - return; - } + while (!TokenSource.IsCancellationRequested) { winChange.Wait (); winChange.Reset (); WaitWinChange (); @@ -230,13 +234,16 @@ namespace Terminal.Gui { void WaitWinChange () { - while (true) { - // Wait for a while then check if screen has changed sizes - Task.Delay (500).Wait (); + while (!TokenSource.IsCancellationRequested) { + try { + // Wait for a while then check if screen has changed sizes + Task.Delay (500, TokenSource.Token).Wait (TokenSource.Token); + + } catch (OperationCanceledException) { - if (stopTasks) { return; } + int buffHeight, buffWidth; if (((NetDriver)consoleDriver).IsWinPlatform) { buffHeight = Math.Max (Console.BufferHeight, 0); @@ -699,7 +706,7 @@ namespace Terminal.Gui { public override void End () { - mainLoop.netEvents.StopTasks (); + mainLoop.Dispose (); if (IsWinPlatform) { NetWinConsole.Cleanup (); @@ -1455,7 +1462,7 @@ namespace Terminal.Gui { /// /// This implementation is used for NetDriver. /// - internal class NetMainLoop : IMainLoopDriver { + internal class NetMainLoop : IMainLoopDriver, IDisposable { ManualResetEventSlim keyReady = new ManualResetEventSlim (false); ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false); Queue inputResult = new Queue (); @@ -1485,27 +1492,25 @@ namespace Terminal.Gui { void NetInputHandler () { - while (true) { + while (!tokenSource.IsCancellationRequested) { waitForProbe.Wait (); waitForProbe.Reset (); if (inputResult.Count == 0) { inputResult.Enqueue (netEvents.ReadConsoleInput ()); } - try { - while (inputResult.Peek () == null) { - inputResult.Dequeue (); - } - if (inputResult.Count > 0) { - keyReady.Set (); - } - } catch (InvalidOperationException) { } + while (inputResult.Count > 0 && inputResult.Peek () == null) { + inputResult.Dequeue (); + } + if (inputResult.Count > 0) { + keyReady.Set (); + } } } void IMainLoopDriver.Setup (MainLoop mainLoop) { this.mainLoop = mainLoop; - Task.Run (NetInputHandler); + Task.Run (NetInputHandler, tokenSource.Token); } void IMainLoopDriver.Wakeup () @@ -1535,8 +1540,7 @@ namespace Terminal.Gui { return inputResult.Count > 0 || CheckTimers (wait, out _); } - tokenSource.Dispose (); - tokenSource = new CancellationTokenSource (); + tokenSource.Token.ThrowIfCancellationRequested (); return true; } @@ -1569,5 +1573,11 @@ namespace Terminal.Gui { ProcessInput?.Invoke (inputResult.Dequeue ().Value); } } + + public void Dispose () + { + tokenSource.Cancel (); + netEvents.TokenSource.Cancel (); + } } } \ No newline at end of file diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index 52343079b..9e981ce0d 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -1133,9 +1133,9 @@ namespace Terminal.Gui { // BUGBUG: MdiTop is not cleared here, but it should be? - MainLoop = null; Driver?.End (); Driver = null; + MainLoop = null; Iteration = null; RootMouseEvent = null; RootKeyEvent = null; From 7d8c5a2e5486c683c8c883285a32ac0e94f095fb Mon Sep 17 00:00:00 2001 From: BDisp Date: Mon, 3 Jun 2024 01:52:07 +0100 Subject: [PATCH 6/6] Fixes #3527. v1 CursesDriver isn't updating the buffer on the UpdateOffScreen method. --- Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs index 0247b5671..fb5fa1c8c 100644 --- a/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs +++ b/Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs @@ -752,9 +752,9 @@ namespace Terminal.Gui { contents = new int [Rows, Cols, 3]; for (int row = 0; row < Rows; row++) { for (int col = 0; col < Cols; col++) { - //Curses.move (row, col); - //Curses.attrset (Colors.TopLevel.Normal); - //Curses.addch ((int)(uint)' '); + Curses.move (row, col); + Curses.attrset (Colors.TopLevel.Normal); + Curses.addch ((int)(uint)' '); contents [row, col, 0] = ' '; contents [row, col, 1] = Colors.TopLevel.Normal; contents [row, col, 2] = 0;