繁体   English   中英

同时使用 Readline() 和 ReadKey()

[英]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();
    }
}

你可以在这个链接上保持更新(这是我目前正在工作的lib的链接)。

这是我创建的一种非常有效的方法。 您不必按两次按钮即可开始出现字符串。 基本上这取代了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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM