问题
I want to read an users input into a string while still reacting on ESC press at any time, but without defining a system wide hotkey.
So when the user types e. g. "Test Name" but instead of confirming with ENTER presses ESC he should be led back into main menu.
Console.Write("Enter name: ")
if (Console.ReadLine().Contains(ConsoleKey.Escape.ToString()))
{
goto MainMenu;
}
return Console.ReadLine();
Thats the simplest way I could think of, but since ESC is not seen by Console.ReadLine()
it is not working.
Found a rather complex way to react on ESC when pressed before starting to enter text here, but I want it to work at any time.
回答1:
You will probably have to forego the use of ReadLine
and roll your own using ReadKey
:
static void Main(string[] args)
{
Console.Clear();
Console.Write("Enter your name and press ENTER. (ESC to cancel): ");
string name = readLineWithCancel();
Console.WriteLine("\r\n{0}", name == null ? "Cancelled" : name);
Console.ReadLine();
}
//Returns null if ESC key pressed during input.
private static string readLineWithCancel()
{
string result = null;
StringBuilder buffer = new StringBuilder();
//The key is read passing true for the intercept argument to prevent
//any characters from displaying when the Escape key is pressed.
ConsoleKeyInfo info = Console.ReadKey(true);
while (info.Key != ConsoleKey.Enter && info.Key != ConsoleKey.Escape)
{
Console.Write(info.KeyChar);
buffer.Append(info.KeyChar);
info = Console.ReadKey(true);
}
if (info.Key == ConsoleKey.Enter)
{
result = buffer.ToString();
}
return result;
}
This code is not complete and may require work to make it robust, but it should give you some ideas.
回答2:
A bit improved version of Chris Dunaway's one :
public static bool CancelableReadLine(out string value)
{
value = string.Empty;
var buffer = new StringBuilder();
var key = Console.ReadKey(true);
while (key.Key != ConsoleKey.Enter && key.Key != ConsoleKey.Escape)
{
if (key.Key == ConsoleKey.Backspace && Console.CursorLeft > 0)
{
var cli = --Console.CursorLeft;
buffer.Remove(cli, 1);
Console.CursorLeft = 0;
Console.Write(new String(Enumerable.Range(0, buffer.Length + 1).Select(o => ' ').ToArray()));
Console.CursorLeft = 0;
Console.Write(buffer.ToString());
Console.CursorLeft = cli;
key = Console.ReadKey(true);
}
else if (Char.IsLetterOrDigit(key.KeyChar) || Char.IsWhiteSpace(key.KeyChar))
{
var cli = Console.CursorLeft;
buffer.Insert(cli, key.KeyChar);
Console.CursorLeft = 0;
Console.Write(buffer.ToString());
Console.CursorLeft = cli + 1;
key = Console.ReadKey(true);
}
else if (key.Key == ConsoleKey.LeftArrow && Console.CursorLeft > 0)
{
Console.CursorLeft--;
key = Console.ReadKey(true);
}
else if (key.Key == ConsoleKey.RightArrow && Console.CursorLeft < buffer.Length)
{
Console.CursorLeft++;
key = Console.ReadKey(true);
}
else
{
key = Console.ReadKey(true);
}
}
if (key.Key == ConsoleKey.Enter)
{
Console.WriteLine();
value = buffer.ToString();
return true;
}
return false;
}
}
I didn't test it much, but at least works for me.
回答3:
In case someone has the same problem. Found an solution by my own. Could be a little shorter, but at least it works:
string name;
char CurrentChar = ' ';
do
{
CurrentChar = Console.ReadKey().KeyChar;
if (CurrentChar != '\b')
{
name = name + CurrentChar;
if (CurrentChar == (char)13)
{
return name;
}
}
else if (Console.CursorLeft >= 14)
{
name = name.Remove(name.Length - 1);
Console.Write(" \b");
}
else
{
Console.CursorLeft = 14;
}
} while (CurrentChar != (char)27);
回答4:
This is the simplest way:
Console.WriteLine("Press ESC to go to Main Menu");
while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape))
{
// your code here
}
goto MainMenu;
来源:https://stackoverflow.com/questions/31996519/listen-on-esc-while-reading-console-line