using System; using System.Collections.Generic; namespace Unosquare.Swan { /// /// A console terminal helper to create nicer output and receive input from the user /// This class is thread-safe :). /// public static partial class Terminal { #region ReadKey /// /// Reads a key from the Terminal. This is the closest equivalent to Console.ReadKey. /// /// if set to true the pressed key will not be rendered to the output. /// if set to true the output will continue to be shown. /// This is useful for services and daemons that are running as console applications and wait for a key to exit the program. /// The console key information. public static ConsoleKeyInfo ReadKey(Boolean intercept, Boolean disableLocking = false) { if(IsConsolePresent == false) { return default; } if(disableLocking) { return Console.ReadKey(intercept); } lock(SyncLock) { Flush(); InputDone.Reset(); try { Console.CursorVisible = true; return Console.ReadKey(intercept); } finally { Console.CursorVisible = false; InputDone.Set(); } } } /// /// Reads a key from the Terminal. /// /// The prompt. /// if set to true [prevent echo]. /// The console key information. public static ConsoleKeyInfo ReadKey(this String prompt, Boolean preventEcho) { if(IsConsolePresent == false) { return default; } lock(SyncLock) { if(prompt != null) { ($" {(String.IsNullOrWhiteSpace(Settings.LoggingTimeFormat) ? String.Empty : DateTime.Now.ToString(Settings.LoggingTimeFormat) + " ")}" + $"{Settings.UserInputPrefix} << {prompt} ").Write(ConsoleColor.White); } ConsoleKeyInfo input = ReadKey(true); String echo = preventEcho ? String.Empty : input.Key.ToString(); echo.WriteLine(); return input; } } /// /// Reads a key from the terminal preventing the key from being echoed. /// /// The prompt. /// A value that identifies the console key. public static ConsoleKeyInfo ReadKey(this String prompt) => prompt.ReadKey(true); #endregion #region Other Terminal Read Methods /// /// Reads a line of text from the console. /// /// The read line. public static String ReadLine() { if(IsConsolePresent == false) { return default; } lock(SyncLock) { Flush(); InputDone.Reset(); try { Console.CursorVisible = true; return Console.ReadLine(); } finally { Console.CursorVisible = false; InputDone.Set(); } } } /// /// Reads a number from the input. If unable to parse, it returns the default number. /// /// The prompt. /// The default number. /// /// Conversions of string representation of a number to its 32-bit signed integer equivalent. /// public static Int32 ReadNumber(this String prompt, Int32 defaultNumber) { if(IsConsolePresent == false) { return defaultNumber; } lock(SyncLock) { $" {DateTime.Now:HH:mm:ss} USR << {prompt} (default is {defaultNumber}): ".Write(ConsoleColor.White); String input = ReadLine(); return Int32.TryParse(input, out Int32 parsedInt) ? parsedInt : defaultNumber; } } /// /// Creates a table prompt where the user can enter an option based on the options dictionary provided. /// /// The title. /// The options. /// Any key option. /// A value that identifies the console key that was pressed. public static ConsoleKeyInfo ReadPrompt(this String title, Dictionary options, String anyKeyOption) { if(IsConsolePresent == false) { return default; } const ConsoleColor textColor = ConsoleColor.White; Int32 lineLength = Console.BufferWidth; Int32 lineAlign = -(lineLength - 2); String textFormat = "{0," + lineAlign + "}"; // lock the output as an atomic operation lock(SyncLock) { { // Top border Table.TopLeft(); Table.Horizontal(-lineAlign); Table.TopRight(); } { // Title Table.Vertical(); String titleText = String.Format( textFormat, String.IsNullOrWhiteSpace(title) ? " Select an option from the list below." : $" {title}"); titleText.Write(textColor); Table.Vertical(); } { // Title Bottom Table.LeftTee(); Table.Horizontal(lineLength - 2); Table.RightTee(); } // Options foreach(KeyValuePair kvp in options) { Table.Vertical(); String.Format(textFormat, $" {"[ " + kvp.Key + " ]",-10} {kvp.Value}").Write(textColor); Table.Vertical(); } // Any Key Options if(String.IsNullOrWhiteSpace(anyKeyOption) == false) { Table.Vertical(); String.Format(textFormat, " ").Write(ConsoleColor.Gray); Table.Vertical(); Table.Vertical(); String.Format(textFormat, $" {" ",-10} {anyKeyOption}").Write(ConsoleColor.Gray); Table.Vertical(); } { // Input section Table.LeftTee(); Table.Horizontal(lineLength - 2); Table.RightTee(); Table.Vertical(); String.Format(textFormat, Settings.UserOptionText).Write(ConsoleColor.Green); Table.Vertical(); Table.BottomLeft(); Table.Horizontal(lineLength - 2); Table.BottomRight(); } } Int32 inputLeft = Settings.UserOptionText.Length + 3; SetCursorPosition(inputLeft, CursorTop - 2); ConsoleKeyInfo userInput = ReadKey(true); userInput.Key.ToString().Write(ConsoleColor.Gray); SetCursorPosition(0, CursorTop + 2); return userInput; } #endregion } }