using System; using System.Threading; // Wrapper class for the console allowing concurrent read and write operations public class Terminal { private Object TerminalLock = new Object (); private Object ReadLineLock = new Object (); private AutoResetEvent ResetEvent = new AutoResetEvent (false); private String InputBuffer = ""; private bool AcceptInput = false; private int OutLinePos; private Thread catchInputThread; public Terminal () { OutLinePos = Console.CursorTop; catchInputThread = new Thread (new ThreadStart (this.CatchInput)); catchInputThread.Start (); } private void CatchInput () { while (true) { ConsoleKeyInfo key = Console.ReadKey (false); lock (TerminalLock) { if (!AcceptInput) { Console.CursorLeft--; Console.Write (" "); Console.CursorLeft--; continue; } if (key.Key == ConsoleKey.Backspace) { if (InputBuffer.Length == 0) continue; InputBuffer = InputBuffer.Substring (0, InputBuffer.Length - 1); ClearInputLine (); Console.Write (InputBuffer); } else if (key.Key == ConsoleKey.Enter) { AcceptInput = false; ResetEvent.Set (); OutLinePos = Console.CursorTop; } else { InputBuffer += key.KeyChar; ClearInputLine (); Console.Write (InputBuffer); } } } } public void PrintLine (String s) { lock (TerminalLock) { ClearInputLine (); Console.WriteLine (s); OutLinePos = Console.CursorTop; Console.Write (InputBuffer); } } public String ReadLine () { lock (ReadLineLock) { try { String result; AcceptInput = true; ResetEvent.WaitOne (); result = InputBuffer; InputBuffer = ""; return result; } catch (ThreadAbortException e) { lock (TerminalLock) { AcceptInput = false; InputBuffer = ""; ClearInputLine (); } throw e; } } } public void ClearInputLine () { lock (TerminalLock) { int top = Console.CursorTop; int left = Console.CursorLeft; Console.SetCursorPosition (0, OutLinePos); while (left != Console.CursorLeft || top != Console.CursorTop) { Console.Write (" "); } Console.SetCursorPosition (0, OutLinePos); } } public void Close () { catchInputThread.Abort(); } }