tgstation-server  4.3.2
The /tg/station 13 server suite
Console.cs
Go to the documentation of this file.
1 using System;
2 using System.Text;
3 using System.Threading;
4 using System.Threading.Tasks;
5 
6 namespace Tgstation.Server.Host.IO
7 {
9  sealed class Console : IConsole, IDisposable
10  {
12  public bool Available => Environment.UserInteractive;
13 
15  public CancellationToken CancelKeyPress => cancelKeyCts.Token;
16 
20  readonly CancellationTokenSource cancelKeyCts;
21 
25  bool disposed;
26 
30  public Console()
31  {
32  cancelKeyCts = new CancellationTokenSource();
33  global::System.Console.CancelKeyPress += (sender, e) =>
34  {
35  lock (cancelKeyCts)
36  {
37  if (!disposed)
38  cancelKeyCts.Cancel();
39  }
40  };
41  }
42 
44  public void Dispose()
45  {
46  lock (cancelKeyCts)
47  {
48  cancelKeyCts.Dispose();
49  disposed = true;
50  }
51  }
52 
54  {
55  if (!Available)
56  throw new InvalidOperationException("Console unavailable");
57  }
58 
60  public Task PressAnyKeyAsync(CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
61  {
62  CheckAvailable();
63  global::System.Console.Read();
64  }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
65 
67  public Task<string> ReadLineAsync(bool usePasswordChar, CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
68  {
69  // TODO: Make this better: https://stackoverflow.com/questions/9479573/how-to-interrupt-console-readline
70  CheckAvailable();
71  if (!usePasswordChar)
72  return global::System.Console.ReadLine();
73 
74  var passwordBuilder = new StringBuilder();
75  do
76  {
77  var keyDescription = global::System.Console.ReadKey(true);
78  if (keyDescription.Key == ConsoleKey.Enter)
79  break;
80  else if (keyDescription.Key == ConsoleKey.Backspace)
81  {
82  if (passwordBuilder.Length > 0)
83  {
84  --passwordBuilder.Length;
85  global::System.Console.Write("\b \b");
86  }
87  }
88  else if (keyDescription.KeyChar != '\u0000')
89  {
90  // KeyChar == '\u0000' if the key pressed does not correspond to a printable character, e.g. F1, Pause-Break, etc
91  passwordBuilder.Append(keyDescription.KeyChar);
92  global::System.Console.Write('*');
93  }
94  }
95  while (!cancellationToken.IsCancellationRequested);
96 
97  cancellationToken.ThrowIfCancellationRequested();
98  global::System.Console.WriteLine();
99  return passwordBuilder.ToString();
100  }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
101 
103  public Task WriteAsync(string text, bool newLine, CancellationToken cancellationToken) => Task.Factory.StartNew(() =>
104  {
105  CheckAvailable();
106  if (text == null)
107  {
108  if (!newLine)
109  throw new InvalidOperationException("Cannot write null text without a new line!");
110  global::System.Console.WriteLine();
111  }
112  else if (newLine)
113  global::System.Console.WriteLine(text);
114  else
115  global::System.Console.Write(text);
116  }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);
117  }
118 }
readonly CancellationTokenSource cancelKeyCts
The CancellationTokenSource for CancelKeyPress.
Definition: Console.cs:20
Abstraction for global::System.Console
Definition: IConsole.cs:9
bool disposed
If the Console was disposed;
Definition: Console.cs:25
Console()
Initializes a new instance of the Console .
Definition: Console.cs:30