Possible to pause, cache, flush keyboard input in c# .net console?
I was wondering if it is possible to pause, then cache and flush keyboard input in a c# .net console. For example, imagine I create a thread that sets the console cursor position, writes characters to draw a board for a progress bar (ANSI chars), and as the percentage of the background tasks completion changes, again the thread changes the cursor postion to add another bar within the progress bar, and the cursor changes back to its original position. At the same time as this happens I want the original thread, to handle Console.ReadLine(); I am wondering if there is anyway that I can pause, then cache, and flush keyboard input, or if there is a way to support bidirectional input output without the side effects. Here is an example: You will notice if you hold the key down, it inter ups.
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();
EDIT: Solution =
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(Conso开发者_高级运维leColor.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;
}
}
}
note: doesnt support backspace and might be better to draw a cursor myself
Don't use Console.ReadLine()
or Console.Read()
. Rather, look to Console.ReadKey()
and Console.KeyAvailable()
Flushing the Keyboard queue is as easy as:
public void FlushKeyBoardInput()
{
while ( Console.KeyAvailable )
{
ConsoleKeyInfo key = Console.ReadKey() ;
}
}
Console.ReadKey()
even has an overload that lets you control whether the key is echoed to the screen.
As far as pausing or caching keyboard input, the command shell itself has a certain amount of keyboard buffer, but you'd want to slurp keypresses into a queue without echoing them to the screen as the cache and write your input methods to read from the cache before pulling from the actual keyboard.
精彩评论