@@ -113,7 +113,9 @@ internal class NetEvents {
113113 ConsoleDriver consoleDriver ;
114114 volatile ConsoleKeyInfo [ ] cki = null ;
115115 static volatile bool isEscSeq ;
116- bool stopTasks ;
116+
117+ internal CancellationTokenSource TokenSource = new CancellationTokenSource ( ) ;
118+
117119#if PROCESS_REQUEST
118120 bool neededProcessRequest ;
119121#endif
@@ -125,21 +127,13 @@ public NetEvents (ConsoleDriver consoleDriver)
125127 throw new ArgumentNullException ( "Console driver instance must be provided." ) ;
126128 }
127129 this . consoleDriver = consoleDriver ;
128- Task . Run ( ProcessInputResultQueue ) ;
129- Task . Run ( CheckWinChange ) ;
130- }
131-
132- internal void StopTasks ( )
133- {
134- stopTasks = true ;
130+ Task . Run ( ProcessInputResultQueue , TokenSource . Token ) ;
131+ Task . Run ( CheckWinChange , TokenSource . Token ) ;
135132 }
136133
137134 public InputResult ? ReadConsoleInput ( )
138135 {
139- while ( true ) {
140- if ( stopTasks ) {
141- return null ;
142- }
136+ while ( ! TokenSource . IsCancellationRequested ) {
143137 waitForStart . Set ( ) ;
144138 winChange . Set ( ) ;
145139
@@ -154,11 +148,13 @@ internal void StopTasks ()
154148 return inputResultQueue . Dequeue ( ) ;
155149 }
156150 }
151+
152+ return null ;
157153 }
158154
159155 void ProcessInputResultQueue ( )
160156 {
161- while ( true ) {
157+ while ( ! TokenSource . IsCancellationRequested ) {
162158 waitForStart . Wait ( ) ;
163159 waitForStart . Reset ( ) ;
164160
@@ -176,8 +172,23 @@ void GetConsoleKey ()
176172 ConsoleModifiers mod = 0 ;
177173 ConsoleKeyInfo newConsoleKeyInfo = default ;
178174
179- while ( true ) {
180- ConsoleKeyInfo consoleKeyInfo = Console . ReadKey ( true ) ;
175+ while ( ! TokenSource . IsCancellationRequested ) {
176+ ConsoleKeyInfo consoleKeyInfo = default ;
177+
178+ try {
179+ if ( Console . KeyAvailable ) {
180+ consoleKeyInfo = Console . ReadKey ( true ) ;
181+ } else {
182+ Task . Delay ( 100 , TokenSource . Token ) . Wait ( TokenSource . Token ) ;
183+ if ( Console . KeyAvailable ) {
184+ consoleKeyInfo = Console . ReadKey ( true ) ;
185+ }
186+ }
187+ } catch ( OperationCanceledException ) {
188+
189+ return ;
190+ }
191+
181192 if ( ( consoleKeyInfo . KeyChar == ( char ) Key . Esc && ! isEscSeq )
182193 || ( consoleKeyInfo . KeyChar != ( char ) Key . Esc && isEscSeq ) ) {
183194 if ( cki == null && consoleKeyInfo . KeyChar != ( char ) Key . Esc && isEscSeq ) {
@@ -201,18 +212,19 @@ void GetConsoleKey ()
201212 }
202213 break ;
203214 } else {
204- GetConsoleInputType ( consoleKeyInfo ) ;
205- break ;
215+ if ( consoleKeyInfo != default ) {
216+ GetConsoleInputType ( consoleKeyInfo ) ;
217+ break ;
218+ }
206219 }
220+
221+ TokenSource . Token . ThrowIfCancellationRequested ( ) ;
207222 }
208223 }
209224
210225 void CheckWinChange ( )
211226 {
212- while ( true ) {
213- if ( stopTasks ) {
214- return ;
215- }
227+ while ( ! TokenSource . IsCancellationRequested ) {
216228 winChange . Wait ( ) ;
217229 winChange . Reset ( ) ;
218230 WaitWinChange ( ) ;
@@ -222,13 +234,16 @@ void CheckWinChange ()
222234
223235 void WaitWinChange ( )
224236 {
225- while ( true ) {
226- // Wait for a while then check if screen has changed sizes
227- Task . Delay ( 500 ) . Wait ( ) ;
237+ while ( ! TokenSource . IsCancellationRequested ) {
238+ try {
239+ // Wait for a while then check if screen has changed sizes
240+ Task . Delay ( 500 , TokenSource . Token ) . Wait ( TokenSource . Token ) ;
241+
242+ } catch ( OperationCanceledException ) {
228243
229- if ( stopTasks ) {
230244 return ;
231245 }
246+
232247 int buffHeight , buffWidth ;
233248 if ( ( ( NetDriver ) consoleDriver ) . IsWinPlatform ) {
234249 buffHeight = Math . Max ( Console . BufferHeight , 0 ) ;
@@ -691,7 +706,7 @@ public override void AddStr (ustring str)
691706
692707 public override void End ( )
693708 {
694- mainLoop . netEvents . StopTasks ( ) ;
709+ mainLoop . Dispose ( ) ;
695710
696711 if ( IsWinPlatform ) {
697712 NetWinConsole . Cleanup ( ) ;
@@ -1019,8 +1034,28 @@ public override void StopReportingMouseMoves ()
10191034
10201035 public override void Suspend ( )
10211036 {
1022- }
1037+ if ( Environment . OSVersion . Platform != PlatformID . Unix ) {
1038+ return ;
1039+ }
1040+
1041+ StopReportingMouseMoves ( ) ;
1042+ Console . ResetColor ( ) ;
1043+ Console . Clear ( ) ;
1044+
1045+ //Disable alternative screen buffer.
1046+ Console . Out . Write ( "\x1b [?1049l" ) ;
1047+
1048+ //Set cursor key to cursor.
1049+ Console . Out . Write ( "\x1b [?25h" ) ;
1050+
1051+ Platform . Suspend ( ) ;
1052+
1053+ //Enable alternative screen buffer.
1054+ Console . Out . Write ( "\x1b [?1049h" ) ;
10231055
1056+ Application . Refresh ( ) ;
1057+ StartReportingMouseMoves ( ) ;
1058+ }
10241059
10251060 public override void SetAttribute ( Attribute c )
10261061 {
@@ -1343,7 +1378,11 @@ public override bool GetCursorVisibility (out CursorVisibility visibility)
13431378 public override bool SetCursorVisibility ( CursorVisibility visibility )
13441379 {
13451380 savedCursorVisibility = visibility ;
1346- return Console . CursorVisible = visibility == CursorVisibility . Default ;
1381+ Console . Out . Write ( visibility == CursorVisibility . Default
1382+ ? "\x1b [?25h"
1383+ : "\x1b [?25l" ) ;
1384+
1385+ return visibility == CursorVisibility . Default ;
13471386 }
13481387
13491388 /// <inheritdoc/>
@@ -1423,7 +1462,7 @@ public override void UncookMouse ()
14231462 /// <remarks>
14241463 /// This implementation is used for NetDriver.
14251464 /// </remarks>
1426- internal class NetMainLoop : IMainLoopDriver {
1465+ internal class NetMainLoop : IMainLoopDriver , IDisposable {
14271466 ManualResetEventSlim keyReady = new ManualResetEventSlim ( false ) ;
14281467 ManualResetEventSlim waitForProbe = new ManualResetEventSlim ( false ) ;
14291468 Queue < NetEvents . InputResult ? > inputResult = new Queue < NetEvents . InputResult ? > ( ) ;
@@ -1453,27 +1492,25 @@ public NetMainLoop (ConsoleDriver consoleDriver = null)
14531492
14541493 void NetInputHandler ( )
14551494 {
1456- while ( true ) {
1495+ while ( ! tokenSource . IsCancellationRequested ) {
14571496 waitForProbe . Wait ( ) ;
14581497 waitForProbe . Reset ( ) ;
14591498 if ( inputResult . Count == 0 ) {
14601499 inputResult . Enqueue ( netEvents . ReadConsoleInput ( ) ) ;
14611500 }
1462- try {
1463- while ( inputResult . Peek ( ) == null ) {
1464- inputResult . Dequeue ( ) ;
1465- }
1466- if ( inputResult . Count > 0 ) {
1467- keyReady . Set ( ) ;
1468- }
1469- } catch ( InvalidOperationException ) { }
1501+ while ( inputResult . Count > 0 && inputResult . Peek ( ) == null ) {
1502+ inputResult . Dequeue ( ) ;
1503+ }
1504+ if ( inputResult . Count > 0 ) {
1505+ keyReady . Set ( ) ;
1506+ }
14701507 }
14711508 }
14721509
14731510 void IMainLoopDriver . Setup ( MainLoop mainLoop )
14741511 {
14751512 this . mainLoop = mainLoop ;
1476- Task . Run ( NetInputHandler ) ;
1513+ Task . Run ( NetInputHandler , tokenSource . Token ) ;
14771514 }
14781515
14791516 void IMainLoopDriver . Wakeup ( )
@@ -1503,8 +1540,7 @@ bool IMainLoopDriver.EventsPending (bool wait)
15031540 return inputResult . Count > 0 || CheckTimers ( wait , out _ ) ;
15041541 }
15051542
1506- tokenSource . Dispose ( ) ;
1507- tokenSource = new CancellationTokenSource ( ) ;
1543+ tokenSource . Token . ThrowIfCancellationRequested ( ) ;
15081544 return true ;
15091545 }
15101546
@@ -1537,5 +1573,11 @@ void IMainLoopDriver.MainIteration ()
15371573 ProcessInput ? . Invoke ( inputResult . Dequeue ( ) . Value ) ;
15381574 }
15391575 }
1576+
1577+ public void Dispose ( )
1578+ {
1579+ tokenSource . Cancel ( ) ;
1580+ netEvents . TokenSource . Cancel ( ) ;
1581+ }
15401582 }
15411583}
0 commit comments