如何在c#中等待控制台输入15秒左右

时间:2008-10-17 01:24:56

标签: c# multithreading user-input sleep

我需要在控制台中询问输入并等待几秒钟,然后我需要默认为某个值。基本上如何在c#中控制台输入并继续默认设置?如果你有一个很棒的示例代码。

4 个答案:

答案 0 :(得分:3)

您可以在System.Timers.Timer中使用计时器对象并将其设置为60秒,启用它,如果有人在控制台中输入内容,只需禁用它,如果没有,则只需处理Timer.Elapsed事件中发生的事情

static void Main(string[] args)
        {
            System.Timers.Timer timer = new System.Timers.Timer(60000);
            timer.Elapsed += new System.Timers.ElapsedEventHandler(T_Elapsed);
            timer.Start();
            var i = Console.ReadLine();
            if (string.IsNullOrEmpty(i)) 
            {
                timer.Stop();
                Console.WriteLine("{0}", i);
            }
        }

        static void T_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Console.WriteLine("Defult Values Used");
            var T = (Timer)sender;
            T.Stop;

        }

不确定这是否是最好的方法。我测试了这个,但正如我所说,它可能不是最好的方式。

答案 1 :(得分:2)

参见here,它在控制台上使用了一种不错的小轮询技术,虽然有点粗糙,非常有效。

答案 2 :(得分:2)

您可能需要考虑执行类似添加命令行参数的操作,以充当使用默认值的自动模式和完整用户输入模式之间的切换。

如果您对请求使用特定解释,则变得非常简单。在此模型中,系统会提示用户输入。如果在超时期限后没有输入任何内容,则使用默认值。如果他们开始输入内容,则不使用超时。这也解决了当他们花费很长时间输入内容时放弃和使用默认值的可用性问题。

    static void Main(string[] args)
    {
        Console.WriteLine("Please enter your name ");
        string input;

        if (TryReadLine(out input, 10000, true))
        {
            Console.WriteLine(input);
        }
        else
        {
            Console.WriteLine("[DEFAULT]");
        }

        Console.ReadKey(true);
    }

    const string timerString = "[{0} seconds until default value is used]";

    public static bool TryReadLine(out string s, double timeout, bool showTimer)
    {
        DateTime timeoutDateTime = DateTime.Now.AddMilliseconds(10000);
        DateTime nextTimer = DateTime.Now;
        while (DateTime.Now < timeoutDateTime)
        {
            if (Console.KeyAvailable)
            {
                ClearTimer(timeoutDateTime);
                s = Console.ReadLine();
                return true;
            }

            if (showTimer && DateTime.Now > nextTimer)
            {
                WriteTimer(string.Format(timerString, (timeoutDateTime - DateTime.Now).Seconds));
                nextTimer = DateTime.Now.AddSeconds(1);
            }
        }

        ClearTimer(timeoutDateTime);
        s = null;
        return false;
    }

    private static void ClearTimer(DateTime timeoutDateTime)
    {
        WriteTimer(new string(' ', string.Format(timerString, (timeoutDateTime - DateTime.Now).Seconds).Length));
    }

    private static void WriteTimer(string s)
    {
        int cursorLeft = Console.CursorLeft;
        Console.CursorLeft = 0;
        Console.CursorTop += 1;
        Console.Write(s);
        Console.CursorLeft = cursorLeft;
        Console.CursorTop -= 1;
    }
}

因为在我意识到有更好的方法之前我花了这么长时间,所以这里有一些代码我只是从控制台读取一个字符串,超时。它还可以选择打印剩余的当前时间到控制台。它没有经过彻底的测试,所以很可能会有很多错误。回调功能使用.NET 3.0 Action,但如果这是针对C#2.0,则可以将其转换为委托。

    static void Main(string[] args)
    {
        string input;
        Console.Write("Please enter your name (");
        int timerPromptStart = Console.CursorLeft;
        Console.Write("    seconds left): ");
        if (TryReadLine(out input, 10000, delegate(TimeSpan timeSpan)
                                          {
                                              int inputPos = Console.CursorLeft;
                                              Console.CursorLeft = timerPromptStart;
                                              Console.Write(timeSpan.Seconds.ToString("000"));
                                              Console.CursorLeft = inputPos;
                                          },
                                          1000))
        {
            Console.WriteLine(input);
        }
        else
        {
            Console.WriteLine("DEFAULT");
        }
        while (true) { }
    }

    /// <summary>
    /// Tries to read a line of input from the Console.
    /// </summary>
    /// <param name="s">The string to put the input into.</param>
    /// <param name="timeout">The time in milliseconds before the attempt fails.</param>
    /// <returns>Whether the user inputted a line before the timeout.</returns>
    public static bool TryReadLine(out string s, double timeout)
    {
        return TryReadLine(out s, timeout, null, 0);
    }

    /// <summary>
    /// Tries to read a line of input from the Console.
    /// </summary>
    /// <param name="s">The string to put the input into.</param>
    /// <param name="timeout">The time in milliseconds before the attempt fails.</param>
    /// <param name="timerCallback">A function to call every callbackInterval.</param>
    /// <param name="callbackInterval">The length of time between calls to timerCallback.</param>
    /// <returns>Whether the user inputted a line before the timeout.</returns>
    public static bool TryReadLine(out string s, double timeout, Action<TimeSpan> timerCallback, double callbackInterval)
    {
        const int tabLength = 6;

        StringBuilder inputBuilder = new StringBuilder();
        int readStart = Console.CursorLeft;
        int lastLength = 0;
        bool isInserting = true;
        DateTime endTime = DateTime.Now.AddMilliseconds(timeout);
        DateTime nextCallback = DateTime.Now;
        while (DateTime.Now < endTime)
        {
            if (timerCallback != null && DateTime.Now > nextCallback)
            {
                nextCallback = DateTime.Now.AddMilliseconds(callbackInterval);
                timerCallback((endTime - DateTime.Now));
            }

            if (Console.KeyAvailable)
            {
                ConsoleKeyInfo key = Console.ReadKey(true);
                switch (key.Key)
                {
                    case ConsoleKey.Enter:
                        Console.WriteLine();
                        s = inputBuilder.ToString();
                        return true;

                    case ConsoleKey.Backspace:
                        if (Console.CursorLeft > readStart)
                        {
                            Console.CursorLeft -= 1;
                            inputBuilder.Remove(Console.CursorLeft - readStart, 1);
                        }
                        break;

                    case ConsoleKey.Delete:
                        if (Console.CursorLeft < readStart + inputBuilder.Length)
                        {
                            inputBuilder.Remove(Console.CursorLeft - readStart, 1);
                        }
                        break;

                    case ConsoleKey.Tab:
                        // Tabs are very difficult to handle properly, so we'll simply replace it with spaces.
                        AddOrInsert(inputBuilder, new String(' ', tabLength), isInserting, readStart);
                        Console.CursorLeft += tabLength;
                        break;

                    case ConsoleKey.Escape:
                        Console.CursorLeft = readStart;
                        inputBuilder = new StringBuilder();
                        break;

                    case ConsoleKey.Insert:
                        isInserting = !isInserting;
                        // This may be dependant on a variable somewhere.
                        if (isInserting)
                        {
                            Console.CursorSize = 25;
                        }
                        else
                        {
                            Console.CursorSize = 50;
                        }
                        break;

                    case ConsoleKey.Home:
                        Console.CursorLeft = readStart;
                        break;

                    case ConsoleKey.End:
                        Console.CursorLeft = readStart + inputBuilder.Length;
                        break;

                    case ConsoleKey.LeftArrow:
                        if (Console.CursorLeft > readStart)
                        {
                            Console.CursorLeft -= 1;
                        }
                        break;

                    case ConsoleKey.RightArrow:
                        if (Console.CursorLeft < readStart + inputBuilder.Length)
                        {
                            Console.CursorLeft += 1;
                        }
                        break;

                    case ConsoleKey.UpArrow:
                        // N.B. We can't handle Up like we normally would as we don't know the last console input.
                        //      You might want to handle this so it works appropriately within your own application.
                        break;

                    case ConsoleKey.PageUp:
                    case ConsoleKey.PageDown:
                    case ConsoleKey.PrintScreen:
                    case ConsoleKey.LeftWindows:
                    case ConsoleKey.RightWindows:
                    case ConsoleKey.Sleep:
                    case ConsoleKey.F1:
                    case ConsoleKey.F2:
                    case ConsoleKey.F3:
                    case ConsoleKey.F4:
                    case ConsoleKey.F5:
                    case ConsoleKey.F6:
                    case ConsoleKey.F7:
                    case ConsoleKey.F8:
                    case ConsoleKey.F9:
                    case ConsoleKey.F10:
                    case ConsoleKey.F11:
                    case ConsoleKey.F12:
                    case ConsoleKey.F13:
                    case ConsoleKey.F14:
                    case ConsoleKey.F15:
                    case ConsoleKey.F16:
                    case ConsoleKey.F17:
                    case ConsoleKey.F18:
                    case ConsoleKey.F19:
                    case ConsoleKey.F20:
                    case ConsoleKey.F21:
                    case ConsoleKey.F22:
                    case ConsoleKey.F23:
                    case ConsoleKey.F24:
                    case ConsoleKey.BrowserBack:
                    case ConsoleKey.BrowserForward:
                    case ConsoleKey.BrowserStop:
                    case ConsoleKey.BrowserRefresh:
                    case ConsoleKey.BrowserSearch:
                    case ConsoleKey.BrowserFavorites:
                    case ConsoleKey.BrowserHome:
                    case ConsoleKey.VolumeMute:
                    case ConsoleKey.VolumeUp:
                    case ConsoleKey.VolumeDown:
                    case ConsoleKey.MediaNext:
                    case ConsoleKey.MediaPrevious:
                    case ConsoleKey.MediaStop:
                    case ConsoleKey.MediaPlay:
                    case ConsoleKey.LaunchMail:
                    case ConsoleKey.LaunchMediaSelect:
                    case ConsoleKey.LaunchApp1:
                    case ConsoleKey.LaunchApp2:
                    case ConsoleKey.Play:
                    case ConsoleKey.Zoom:
                    case ConsoleKey.NoName:
                    case ConsoleKey.Pa1:
                        // These keys shouldn't do anything.
                        break;

                    case ConsoleKey.Clear:
                    case ConsoleKey.Pause:
                    case ConsoleKey.Select:
                    case ConsoleKey.Print:
                    case ConsoleKey.Execute:
                    case ConsoleKey.Process:
                    case ConsoleKey.Help:
                    case ConsoleKey.Applications:
                    case ConsoleKey.Packet:
                    case ConsoleKey.Attention:
                    case ConsoleKey.CrSel:
                    case ConsoleKey.ExSel:
                    case ConsoleKey.EraseEndOfFile:
                    case ConsoleKey.OemClear:
                        // I'm not sure what these do.
                        break;

                    default:
                        Console.Write(key.KeyChar);
                        AddOrInsert(inputBuilder, key.KeyChar.ToString(), isInserting, readStart);
                        break;
                }

                // Write what has current been typed in back out to the Console.
                // We write out everything after the cursor to handle cases where the current input string is shorter than before
                // (i.e. the user deleted stuff).
                // There is probably a more efficient way to do this.
                int oldCursorPos = Console.CursorLeft;
                Console.CursorLeft = readStart;
                Console.Write(inputBuilder.ToString());
                if (lastLength > inputBuilder.Length)
                {
                    Console.Write(new String(' ', lastLength - inputBuilder.Length));
                }
                lastLength = inputBuilder.Length;
                Console.CursorLeft = oldCursorPos;
            }
        }

        // The timeout period was reached.
        Console.WriteLine();
        s = null;
        return false;
    }

    // This is a rather ugly helper method to add text to the inputBuilder, either inserting or appending as appropriate.
    private static void AddOrInsert(StringBuilder inputBuilder, string s, bool insert, int readStart)
    {
        if (Console.CursorLeft < readStart + inputBuilder.Length + (insert ? -1 : 1))
        {
            if (!insert)
            {
                inputBuilder.Remove(Console.CursorLeft - 1 - readStart, 1);
            }
            inputBuilder.Insert(Console.CursorLeft - 1 - readStart, s);
        }
        else
        {
            inputBuilder.Append(s);
        }
    }
}

答案 3 :(得分:0)

一种方法是循环,调用Console.In.Peek(),等待输入或有足够的时间过去。