【问题标题】:Possible to pause, cache, flush keyboard input in c# .net console?可以在 c# .net 控制台中暂停、缓存、刷新键盘输入吗?
【发布时间】:2011-06-30 21:26:15
【问题描述】:

我想知道是否可以暂停,然后在 c# .net 控制台中缓存和刷新键盘输入。例如,假设我创建了一个线程来设置控制台光标位置,写入字符以绘制进度条的板(ANSI 字符),并且随着后台任务完成百分比的变化,线程再次更改光标位置以添加进度条中的另一个条,并且光标变回其原始位置。在发生这种情况的同时,我想要原始线程来处理 Console.ReadLine();我想知道是否有任何方法可以暂停、缓存和刷新键盘输入,或者是否有一种方法可以支持双向输入输出而不会产生副作用。下面是一个例子:你会注意到如果你按住键,它就会交互起来。

public void DrawScreenBackground()
{
    List<ConsoleColor> ColourArray = new List<ConsoleColor>();
    //ColourArray.Add(ConsoleColor.Black);
    ColourArray.Add(ConsoleColor.DarkGray);
    ColourArray.Add(ConsoleColor.DarkGreen);
    ColourArray.Add(ConsoleColor.Green);
    ColourArray.Add(ConsoleColor.Green);
    ColourArray.Add(ConsoleColor.DarkGreen);
    ColourArray.Add(ConsoleColor.DarkGray);

    int minProgress = 0;
    int maxProgress = 20;
    int currentProgress = minProgress;
    bool reverse = false;
    while (1 == 1)
    {
        if (!reverse)
        {
            if (currentProgress == maxProgress)
                reverse = !reverse;
            else
                currentProgress += 1;
        }
        else
        {
            if (currentProgress == minProgress)
                reverse = !reverse;
            else
                currentProgress -= 1;
        }
        //draw/////
        int curLeft = Console.CursorLeft;
        int curTop = Console.CursorTop;
        ConsoleColor defaultColor = Console.ForegroundColor;
        ConsoleColor item = ColourArray[0];
        ColourArray.RemoveAt(0);
        ColourArray.Insert(ColourArray.Count-1, item);
        DrawDoubleBorder(9, 9, 21, 2);
        Console.ForegroundColor = item;
        Console.SetCursorPosition(10, 10);
        for (int i = 0; i < maxProgress - minProgress; i += 1)
            Console.Write(" ");
        Console.SetCursorPosition(10, 10);
        for (int i = 0; i < currentProgress - minProgress; i += 1)
            Console.Write("#");
        Console.ForegroundColor = defaultColor;
        Console.SetCursorPosition(curLeft, curTop);
        ///////////
        Thread.Sleep(125);
    }
}
private void DrawDoubleBorder(int x, int y, int width, int height)
{
    Console.SetCursorPosition(x, y);
    int currentX = x;
    int currentY = y;
    for (int h = 0; h <= height; h += 1)
    {
        for (int w = 0; w <= width; w += 1)
        {
            if (w == 0 && h == 0)
                Console.Write(ConsoleChars.DoubleBorderTopLeft);
            else if (w == width && h == height)
                Console.Write(ConsoleChars.DoubleBorderBottomRight);
            else if (w == width && h == 0)
                Console.Write(ConsoleChars.DoubleBorderTopRight);
            else if (w == 0 && h == height)
                Console.Write(ConsoleChars.DoubleBorderBottomLeft);
            else if (w == 0 || w == width)
                Console.Write(ConsoleChars.DoubleBorderVerticle);
            else if (h == 0 || h == height)
                Console.Write(ConsoleChars.DoubleBorderHorizontal);
            else
                Console.Write(" ");
        }
        currentY += 1;
        Console.SetCursorPosition(currentX, currentY);
    }
}
public struct ConsoleChars
{
    public static char DoubleBorderHorizontal = (char)205;
    public static char DoubleBorderVerticle = (char)186;
    public static char DoubleBorderBottomLeft = (char)200;
    public static char DoubleBorderTopRight = (char)187;
    public static char DoubleBorderBottomRight = (char)188;
    public static char DoubleBorderFourWaySplit = (char)206;
    public static char DoubleBorderTopLeft = (char)201;
    public static char DoubleBorderLeftThreeWaySplit = (char)204;
    public static char DoubleBorderRightThreeWaySplit = (char)185;
}

 

        Thread thread = new Thread(new ThreadStart(DrawScreenBackground));
        thread.Start();
        Console.ReadLine();

编辑:解决方案 =

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = System.Text.Encoding.GetEncoding(1252);
            Thread thread = new Thread(new ParameterizedThreadStart(DrawScreenBackground));
            object locker = new object();
            thread.Start(locker);
            string input = string.Empty;
            while(!input.Contains("\r\n"))
            {
                string temp = FlushKeyBoardInput();
                if(temp!=string.Empty)
                {
                    lock(locker)
                    {
                        Console.Write(temp);
                        input+=temp;
                    }
                }
            }
        }

        public static string FlushKeyBoardInput()
        {
            string output = string.Empty;
            while (Console.KeyAvailable)
            {
                ConsoleKeyInfo key = Console.ReadKey(true);
                output += key.KeyChar;
            }
            return output;
        }

        public static void DrawScreenBackground(object locker)
        {
            List<ConsoleColor> ColourArray = new List<ConsoleColor>();
            //ColourArray.Add(ConsoleColor.Black);
            ColourArray.Add(ConsoleColor.DarkGray);
            ColourArray.Add(ConsoleColor.DarkGreen);
            ColourArray.Add(ConsoleColor.Green);
            ColourArray.Add(ConsoleColor.Green);
            ColourArray.Add(ConsoleColor.DarkGreen);
            ColourArray.Add(ConsoleColor.DarkGray);

            int minProgress = 0;
            int maxProgress = 20;
            int currentProgress = minProgress;
            bool reverse = false;
            while (1 == 1)
            {
                if (!reverse)
                {
                    if (currentProgress == maxProgress)
                        reverse = !reverse;
                    else
                        currentProgress += 1;
                }
                else
                {
                    if (currentProgress == minProgress)
                        reverse = !reverse;
                    else
                        currentProgress -= 1;
                }
                //draw/////
                lock (locker)
                {
                    int curLeft = Console.CursorLeft;
                    int curTop = Console.CursorTop;
                    ConsoleColor defaultColor = Console.ForegroundColor;
                    ConsoleColor item = ColourArray[0];
                    ColourArray.RemoveAt(0);
                    ColourArray.Insert(ColourArray.Count - 1, item);
                    DrawDoubleBorder(9, 9, 21, 2);
                    Console.ForegroundColor = item;
                    Console.SetCursorPosition(10, 10);
                    for (int i = 0; i < maxProgress - minProgress; i += 1)
                        Console.Write(" ");
                    Console.SetCursorPosition(10, 10);
                    for (int i = 0; i < currentProgress - minProgress; i += 1)
                        Console.Write("#");
                    Console.ForegroundColor = defaultColor;
                    Console.SetCursorPosition(curLeft, curTop);
                    ///////////
                }
                Thread.Sleep(50);
            }
        }
        public static void DrawDoubleBorder(int x, int y, int width, int height)
        {
            Console.SetCursorPosition(x, y);
            int currentX = x;
            int currentY = y;
            for (int h = 0; h <= height; h += 1)
            {
                for (int w = 0; w <= width; w += 1)
                {
                    if (w == 0 && h == 0)
                        Console.Write(ConsoleChars.DoubleBorderTopLeft);
                    else if (w == width && h == height)
                        Console.Write(ConsoleChars.DoubleBorderBottomRight);
                    else if (w == width && h == 0)
                        Console.Write(ConsoleChars.DoubleBorderTopRight);
                    else if (w == 0 && h == height)
                        Console.Write(ConsoleChars.DoubleBorderBottomLeft);
                    else if (w == 0 || w == width)
                        Console.Write(ConsoleChars.DoubleBorderVerticle);
                    else if (h == 0 || h == height)
                        Console.Write(ConsoleChars.DoubleBorderHorizontal);
                    else
                        Console.Write(" ");
                }
                currentY += 1;
                Console.SetCursorPosition(currentX, currentY);
            }
        }
        public struct ConsoleChars
        {
            public static char DoubleBorderHorizontal = (char)205;
            public static char DoubleBorderVerticle = (char)186;
            public static char DoubleBorderBottomLeft = (char)200;
            public static char DoubleBorderTopRight = (char)187;
            public static char DoubleBorderBottomRight = (char)188;
            public static char DoubleBorderFourWaySplit = (char)206;
            public static char DoubleBorderTopLeft = (char)201;
            public static char DoubleBorderLeftThreeWaySplit = (char)204;
            public static char DoubleBorderRightThreeWaySplit = (char)185;
        }
    }
}

注意:不支持退格,自己画光标可能会更好

【问题讨论】:

  • Console.OutputEncoding = System.Text.Encoding.GetEncoding(1252);

标签: c# .net multithreading interop console


【解决方案1】:

不要使用Console.ReadLine()Console.Read()。相反,请查看Console.ReadKey()Console.KeyAvailable()

刷新键盘队列很简单:

public void FlushKeyBoardInput()
{
  while ( Console.KeyAvailable )
  {
    ConsoleKeyInfo key = Console.ReadKey() ;
  }
}

Console.ReadKey() 甚至还有一个重载功能,可以让您控制按键是否回显到屏幕上。

就暂停或缓存键盘输入而言,命令外壳本身具有一定数量的键盘缓冲区,但您希望将按键放入队列中,而不是将它们作为缓存回显到屏幕并将您的输入方法写入在从实际键盘拉出之前从缓存中读取。

【讨论】:

    猜你喜欢
    • 2010-11-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多