Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #3518. v1 NetDriver throws System.InvalidOperationException when a key is pressed. #3519

Merged
merged 6 commits into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Terminal.Gui/ConsoleDrivers/CursesDriver/CursesDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -752,9 +752,9 @@ public override void UpdateOffScreen ()
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;
Expand Down
124 changes: 83 additions & 41 deletions Terminal.Gui/ConsoleDrivers/NetDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ internal class NetEvents {
ConsoleDriver consoleDriver;
volatile ConsoleKeyInfo [] cki = null;
static volatile bool isEscSeq;
bool stopTasks;

internal CancellationTokenSource TokenSource = new CancellationTokenSource ();

#if PROCESS_REQUEST
bool neededProcessRequest;
#endif
Expand All @@ -125,21 +127,13 @@ public NetEvents (ConsoleDriver consoleDriver)
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 ();

Expand All @@ -154,11 +148,13 @@ internal void StopTasks ()
return inputResultQueue.Dequeue ();
}
}

return null;
}

void ProcessInputResultQueue ()
{
while (true) {
while (!TokenSource.IsCancellationRequested) {
waitForStart.Wait ();
waitForStart.Reset ();

Expand All @@ -176,8 +172,23 @@ void GetConsoleKey ()
ConsoleModifiers mod = 0;
ConsoleKeyInfo newConsoleKeyInfo = default;

while (true) {
ConsoleKeyInfo consoleKeyInfo = Console.ReadKey (true);
while (!TokenSource.IsCancellationRequested) {
ConsoleKeyInfo consoleKeyInfo = default;

try {
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;
}

if ((consoleKeyInfo.KeyChar == (char)Key.Esc && !isEscSeq)
|| (consoleKeyInfo.KeyChar != (char)Key.Esc && isEscSeq)) {
if (cki == null && consoleKeyInfo.KeyChar != (char)Key.Esc && isEscSeq) {
Expand All @@ -201,18 +212,19 @@ void GetConsoleKey ()
}
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 ();
Expand All @@ -222,13 +234,16 @@ void CheckWinChange ()

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);
Expand Down Expand Up @@ -691,7 +706,7 @@ public override void AddStr (ustring str)

public override void End ()
{
mainLoop.netEvents.StopTasks ();
mainLoop.Dispose ();

if (IsWinPlatform) {
NetWinConsole.Cleanup ();
Expand Down Expand Up @@ -1019,8 +1034,28 @@ public override void StopReportingMouseMoves ()

public override void Suspend ()
{
}
if (Environment.OSVersion.Platform != PlatformID.Unix) {
return;
}

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)
{
Expand Down Expand Up @@ -1343,7 +1378,11 @@ public override bool GetCursorVisibility (out CursorVisibility visibility)
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;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -1423,7 +1462,7 @@ public override void UncookMouse ()
/// <remarks>
/// This implementation is used for NetDriver.
/// </remarks>
internal class NetMainLoop : IMainLoopDriver {
internal class NetMainLoop : IMainLoopDriver, IDisposable {
ManualResetEventSlim keyReady = new ManualResetEventSlim (false);
ManualResetEventSlim waitForProbe = new ManualResetEventSlim (false);
Queue<NetEvents.InputResult?> inputResult = new Queue<NetEvents.InputResult?> ();
Expand Down Expand Up @@ -1453,27 +1492,25 @@ public NetMainLoop (ConsoleDriver consoleDriver = null)

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 ()
Expand Down Expand Up @@ -1503,8 +1540,7 @@ bool IMainLoopDriver.EventsPending (bool wait)
return inputResult.Count > 0 || CheckTimers (wait, out _);
}

tokenSource.Dispose ();
tokenSource = new CancellationTokenSource ();
tokenSource.Token.ThrowIfCancellationRequested ();
return true;
}

Expand Down Expand Up @@ -1537,5 +1573,11 @@ void IMainLoopDriver.MainIteration ()
ProcessInput?.Invoke (inputResult.Dequeue ().Value);
}
}

public void Dispose ()
{
tokenSource.Cancel ();
netEvents.TokenSource.Cancel ();
}
}
}
2 changes: 1 addition & 1 deletion Terminal.Gui/Core/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,9 +1133,9 @@ static void ResetState ()

// BUGBUG: MdiTop is not cleared here, but it should be?

MainLoop = null;
Driver?.End ();
Driver = null;
MainLoop = null;
Iteration = null;
RootMouseEvent = null;
RootKeyEvent = null;
Expand Down
Loading