![](/img/trans.png)
[英]I'm trying to to use ReadLine(), or Read() or ReadKey to read in integers using C#
[英]Using Readline() and ReadKey() Simultaneously
有没有办法同时检测 Readline 和 ReadKey,以便在大多数情况下它的行为就像一个 readline,除了一些应该检测的特殊键输入?
我需要一些“并行”实现来引入同时性。 下面的代码是同步的,不符合我的需要
while ((line = Console.ReadLine()) != "x")
{
if (line == "BLABLA")
{
//Stuff
}
else
{
//Stuff
}
ConsoleKeyInfo ki = Console.ReadKey(true);
if ((ki.Key == ConsoleKey.V) && (ki.Modifiers == ConsoleModifiers.Control))
{
//Stuff
}
}
这是我刚才做的一个功能。
现在它只处理退格,输入和Esc,但如果你认为有必要,可以很容易地修改它来处理其他键。
// returns null if user pressed Escape, or the contents of the line if they pressed Enter.
private static string ReadLineOrEsc()
{
string retString = "";
int curIndex = 0;
do
{
ConsoleKeyInfo readKeyResult = Console.ReadKey(true);
// handle Esc
if (readKeyResult.Key == ConsoleKey.Escape)
{
Console.WriteLine();
return null;
}
// handle Enter
if (readKeyResult.Key == ConsoleKey.Enter)
{
Console.WriteLine();
return retString;
}
// handle backspace
if (readKeyResult.Key == ConsoleKey.Backspace)
{
if (curIndex > 0)
{
retString = retString.Remove(retString.Length - 1);
Console.Write(readKeyResult.KeyChar);
Console.Write(' ');
Console.Write(readKeyResult.KeyChar);
curIndex--;
}
}
else
// handle all other keypresses
{
retString += readKeyResult.KeyChar;
Console.Write(readKeyResult.KeyChar);
curIndex++;
}
}
while (true);
}
不,不是这样的。 两种方法都会阻塞,直到用户在控制台上输入内容。 因此,即使你找到了一种让两者并行运行的方法,也不确定哪一个获得第一枪。
有一个(不明显的)类似问题:如何在没有用户输入的情况下在一定时间后使Console.ReadLine()
中止/中断。
这里有多次尝试解决这个问题:
大多数都建模为创建自己的ReadLine
函数版本,增加超时(或在您的情况下特殊处理某些字符(代码))或使用某种线程。
这两种方式都是非平凡的或有自己的问题(确保您审查评论,即使是已接受的答案)。
简而言之,我认为您需要根据Console.ReadKey
推出自己的ReadLine版本,包括您的特殊处理以及您需要的大部分真正的Console.ReadLine
行为。 请注意,这甚至包括RETURN,ARROW KEYS,BACKSPACE处理等基本功能。
更新 : Mono项目中有getline.cs代码,它实现了一些行编辑功能,就像它由一些古老的UNIX shell(EMACS模式,如果你关心的话)提供的那样。 为此,我相信它需要实现某种ReadLine替换,尽管我还没有检查过。 也许你可以用它作为起点。
为响应@Overlord Zurd ,我改进了用户提供的代码。
public class ConsoleOutput
{
private ConsoleOutputType OutputType { get; set; }
private object MyObject { get; }
private static bool IsInserting { get; set; }
public string KeyName => IsKey() && (ConsoleKeyInfo)MyObject != null ? ((ConsoleKeyInfo)MyObject).Key.ToString() : "Null";
public string OutputString => !IsKey() && MyObject != null ? (string)MyObject : string.Empty;
public static event Action<string> ReadInput = delegate { };
public static event Action<ConsoleKeyInfo> ReadKey = delegate { };
private ConsoleOutput()
{
}
public ConsoleOutput(object obj)
{
MyObject = obj;
OutputType = obj is ConsoleKeyInfo ? ConsoleOutputType.Key : ConsoleOutputType.Value;
}
public bool IsKey()
{
return OutputType == ConsoleOutputType.Key;
}
public bool IsExitKey()
{
if (!IsKey())
return false;
var info = ((ConsoleKeyInfo)MyObject);
return (info.Modifiers & ConsoleModifiers.Control) != 0 && info.Key == ConsoleKey.B;
}
public string GetValue()
{
return (string)MyObject;
}
// returns null if user pressed Escape, or the contents of the line if they pressed Enter.
public static ConsoleOutput ReadLineOrKey()
{
string retString = "";
int curIndex = 0;
do
{
ConsoleKeyInfo readKeyResult = Console.ReadKey(true);
// handle Enter
if (readKeyResult.Key == ConsoleKey.Enter)
{
ReadInput?.Invoke(retString);
Console.WriteLine();
return new ConsoleOutput(retString);
}
// handle backspace
if (readKeyResult.Key == ConsoleKey.Backspace)
{
if (curIndex > 0)
{
retString = retString.Remove(retString.Length - 1);
Console.Write(readKeyResult.KeyChar);
Console.Write(' ');
Console.Write(readKeyResult.KeyChar);
--curIndex;
}
}
else if (readKeyResult.Key == ConsoleKey.Delete)
{
if (retString.Length - curIndex > 0)
{
// Store current position
int curLeftPos = Console.CursorLeft;
// Redraw string
for (int i = curIndex + 1; i < retString.Length; ++i)
Console.Write(retString[i]);
// Remove last repeated char
Console.Write(' ');
// Restore position
Console.SetCursorPosition(curLeftPos, Console.CursorTop);
// Remove string
retString = retString.Remove(curIndex, 1);
}
}
else if (readKeyResult.Key == ConsoleKey.RightArrow)
{
if (curIndex < retString.Length)
{
++Console.CursorLeft;
++curIndex;
}
}
else if (readKeyResult.Key == ConsoleKey.LeftArrow)
{
if (curIndex > 0)
{
--Console.CursorLeft;
--curIndex;
}
}
else if (readKeyResult.Key == ConsoleKey.Insert)
{
IsInserting = !IsInserting;
}
#if DEBUG
else if (readKeyResult.Key == ConsoleKey.UpArrow)
{
if (Console.CursorTop > 0)
--Console.CursorTop;
}
else if (readKeyResult.Key == ConsoleKey.DownArrow)
{
if (Console.CursorTop < Console.BufferHeight - 1)
++Console.CursorTop;
}
#endif
else
// handle all other keypresses
{
if (IsInserting || curIndex == retString.Length)
{
retString += readKeyResult.KeyChar;
Console.Write(readKeyResult.KeyChar);
++curIndex;
}
else
{
// Store char
char c = readKeyResult.KeyChar;
// Write char at position
Console.Write(c);
// Store cursor position
int curLeftPos = Console.CursorLeft;
// Clear console from curIndex to end
for (int i = curIndex; i < retString.Length; ++i)
Console.Write(' ');
// Go back
Console.SetCursorPosition(curLeftPos, Console.CursorTop);
// Write the chars from curIndex to end (with the new appended char)
for (int i = curIndex; i < retString.Length; ++i)
Console.Write(retString[i]);
// Restore again
Console.SetCursorPosition(curLeftPos, Console.CursorTop);
// Store in the string
retString = retString.Insert(curIndex, new string(c, 1));
// Sum one to the cur index (we appended one char)
++curIndex;
}
}
if (char.IsControl(readKeyResult.KeyChar) &&
readKeyResult.Key != ConsoleKey.Enter &&
readKeyResult.Key != ConsoleKey.Backspace &&
readKeyResult.Key != ConsoleKey.Tab &&
readKeyResult.Key != ConsoleKey.Delete &&
readKeyResult.Key != ConsoleKey.RightArrow &&
readKeyResult.Key != ConsoleKey.LeftArrow &&
readKeyResult.Key != ConsoleKey.Insert)
{
#if DEBUG
if (readKeyResult.Key == ConsoleKey.UpArrow || readKeyResult.Key == ConsoleKey.DownArrow)
continue;
#endif
ReadKey?.Invoke(readKeyResult);
Console.WriteLine();
return new ConsoleOutput(readKeyResult);
}
}
while (true);
}
}
如您所见,我实现了插入,箭头控制,删除等等...(插入是一件很重要的事情,因为如果您使用此代码编写任何文本,您将看到插入键提供的行为)。
和使用的例子:
internal class Program
{
private static void Main(string[] args)
{
Console.Write("Write test string: ");
var test = ConsoleOutput.ReadLineOrKey();
if (test.IsKey())
Console.WriteLine(test.KeyName);
else
Console.WriteLine($"Output string: {test.OutputString}");
Console.Read();
}
}
这是我创建的一种非常有效的方法。 您不必按两次按钮即可开始出现字符串。 基本上这取代了Console.ReadLine()
但它也寻找按下的Esc键。 只需查看方法的返回类型,如果它为null
那么您就知道按下了Esc 。
private string ReadLineOrEscape()
{
ConsoleKeyInfo keyInfo = new ConsoleKeyInfo();
StringBuilder sb = new StringBuilder();
int index = 0;
while (keyInfo.Key != ConsoleKey.Enter)
{
keyInfo = Console.ReadKey(true);
if (keyInfo.Key == ConsoleKey.Escape)
{
return null;
}
if(keyInfo.Key == ConsoleKey.Backspace)
{
if (index > 0)
{
Console.CursorLeft = index - 1;
sb.Remove(index - 1, 1);
Console.Write(" \b");
index--;
}
}
if(keyInfo.KeyChar > 31 && keyInfo.KeyChar < 127)
{
index++;
Console.Write(keyInfo.KeyChar);
sb.Append(keyInfo.KeyChar);
}
}
return sb.ToString(); ;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.