实时显示键盘输入(C#控制台应用程序)
我现在正在尝试创建一个基本程序,在输入时显示实时输入。示例输出如下所示: 当前输入:CTRL-ALT S V空格 (请注意,这些将是当前保留的键。如果用户释放CTRL键,该输入将消失)。 我在这里创建了一些示例代码。这很粗糙,但这是我最好的尝试。它在一个更大的程序中(我将其用作沙箱),但唯一需要的上下文是实时显示键盘输入(C#控制台应用程序),c#,console,C#,Console,我现在正在尝试创建一个基本程序,在输入时显示实时输入。示例输出如下所示: 当前输入:CTRL-ALT S V空格 (请注意,这些将是当前保留的键。如果用户释放CTRL键,该输入将消失)。 我在这里创建了一些示例代码。这很粗糙,但这是我最好的尝试。它在一个更大的程序中(我将其用作沙箱),但唯一需要的上下文是使用系统位于程序的顶部 public static void KeypressTest() { char[] keys = new char[10];
使用系统代码>位于程序的顶部
public static void KeypressTest()
{
char[] keys = new char[10];
int x;
while (1==1)
{
for (x = 0; x < 10; x++) //All the loops attempt to fill the array if possible. I figured this was the easiest way to store multiple characters at once
{
keys[x] = Convert.ToChar(ConsoleKey.MediaStop); //I don't know how to set it to blank, so I picked a character that isn't likely to be used
}
for (x = 0; x < 10; x++)
{
if (keys[x] != Convert.ToChar(ConsoleKey.MediaStop)) { x += 1; } //This skips the key if it is not the default (MediaStop). This is temporary and will be altered once I can figure out how to register a key has been lifted
else { keys[x] = Console.ReadKey().KeyChar; }
}
Console.Write("\rCurrent inputs: \n");
for (x = 0; x < 10; x++)
{ Console.Write(Convert.ToString(keys[x])); }
Console.WriteLine();
}
}
公共静态无效按键测试()
{
字符[]键=新字符[10];
int x;
而(1==1)
{
for(x=0;x<10;x++)//如果可能,所有循环都会尝试填充数组。我认为这是一次存储多个字符的最简单方法
{
keys[x]=Convert.ToChar(ConsoleKey.MediaStop);//我不知道如何将其设置为空白,所以我选择了一个不太可能使用的字符
}
对于(x=0;x<10;x++)
{
如果(keys[x]!=Convert.ToChar(ConsoleKey.MediaStop)){x+=1;}//如果不是默认值(MediaStop),则跳过该键。这是临时的,一旦我知道如何注册一个已解除的键,就会进行更改
else{keys[x]=Console.ReadKey().KeyChar;}
}
控制台。写入(“\r当前输入:\n”);
对于(x=0;x<10;x++)
{Console.Write(Convert.ToString(键[x]);}
Console.WriteLine();
}
}
代码本身的问题是等待所有10个输入,然后显示键入的键,并忽略键的释放。它似乎更像是一个键盘记录器,而不是显示当前持有的钥匙的目标。如果用户键入“hello everyone!!!”,示例输出将如下所示:
电流输入:
你好吗
电流输入:
你
目标会在其持有的瞬间显示每个键,并且在释放后不会显示(但我不知道如何执行此操作)
问题是,我对C#还是个新手,还没有找到在输入时更新输入的方法(我知道Console.ReadKey()但是我不知道如何使它在后台运行。我知道线程是什么,但不知道如何执行,因此任何提示都将不胜感激。谢谢!我更改了我的答案,这更接近您想要的。我在该线程中发现了一个按键事件实现(NativeKeyboard内部类):
解决方案在于多线程定时器联合检查值或条件。主程序线程处于循环中,直到满足退出条件(按ESC键)。有一个提示计时器,它将表示按下键列表的值的缓存打印到同一行,然后用空格清除该行。对于每个ConsoleKey枚举,将创建一个计时器并映射计时器键duo。每当按下一个键时,该键的映射计时器将能够确定按下了特定键并更新l带有键的值/字符串的列表。每当释放键时,列表也会用该键的空字符串值更新
我不得不添加LocalModifiers enum作为ALT、CTRL、SHIFT和CAPS LOCK的键代码
我必须使用lock()来确保所有这些计时器都可以工作,而不会产生并发问题
当我执行代码时,它的输出与您描述的非常接近。有时在按下7-8个键的情况下,一些按下的键不显示
这是我的密码:
class Program
{
public static Dictionary<int, String> inputMap = new Dictionary<int, string>();
public static Dictionary<Timer, ConsoleKey> TimerKeyMap = new Dictionary<Timer, ConsoleKey>();
public static Dictionary<Timer, LocalModifiers> TimerModifierMap = new Dictionary<Timer, LocalModifiers>();
public static bool continueLoop = true;
public static object locker = new object();
static void Main(string[] args)
{
Program program = new Program();
program.run();
}
public enum LocalModifiers :int
{
SHIFT = 0x10,
CTL = 0x11,
ALT = 0x12,
CAPS_LOCK = 0x14
}
public void run()
{
Timer keyPressedPrompter = new Timer();
keyPressedPrompter.Interval = 60;
keyPressedPrompter.Elapsed += new ElapsedEventHandler(KeyPressedPrompterEvent);
keyPressedPrompter.Enabled = true;
foreach (ConsoleKey key in Enum.GetValues(typeof(ConsoleKey)))
{
Timer timer = new Timer();
TimerKeyMap[timer] = key;
timer.Interval = 60;
timer.Elapsed += new ElapsedEventHandler(KeyPressedCheckerEvent);
timer.Enabled = true;
}
foreach (LocalModifiers key in Enum.GetValues(typeof(LocalModifiers)))
{
Timer timer = new Timer();
TimerModifierMap[timer] = key;
timer.Interval = 60;
timer.Elapsed += new ElapsedEventHandler(ModifierPressedCheckerEvent);
timer.Enabled = true;
}
Console.WriteLine("Current inputs:");
while (continueLoop) { }
}
public static void ModifierPressedCheckerEvent(object source, EventArgs e)
{
lock (locker)
{
if (NativeKeyboard.IsKeyDown((int)TimerModifierMap[(Timer)source]))
{
//Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString()+ " pressed");
inputMap[(int)TimerModifierMap[(Timer)source]] = TimerModifierMap[(Timer)source].ToString() + " ";
}
else
{
// Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString() + " released");
inputMap[(int)TimerModifierMap[(Timer)source]] = "";
}
}
}
public static void KeyPressedCheckerEvent(object source, EventArgs e)
{
lock (locker)
{
if (NativeKeyboard.IsKeyDown((int)TimerKeyMap[(Timer)source]))
{
if (TimerKeyMap[(Timer)source] == ConsoleKey.Escape)
continueLoop = false;
//Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString()+ " pressed");
inputMap[(int)TimerKeyMap[(Timer)source]] = TimerKeyMap[(Timer)source].ToString() + " ";
}
else
{
// Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString() + " released");
inputMap[(int)TimerKeyMap[(Timer)source]] = "";
}
}
}
public static void KeyPressedPrompterEvent(object source, EventArgs e)
{
Console.Write(" ");//clear the line - - can be extended
Console.Write("\r");
lock (locker)
{
foreach (KeyValuePair<int, String> entry in inputMap)
{
// do something with entry.Value or entry.Key
Console.Write(entry.Value);
}
}
}
}
/// <summary>
/// Provides keyboard access.
/// </summary>
internal static class NativeKeyboard
{
/// <summary>
/// A positional bit flag indicating the part of a key state denoting
/// key pressed.
/// </summary>
private const int KeyPressed = 0x8000;
/// <summary>
/// Returns a value indicating if a given key is pressed.
/// </summary>
/// <param name="key">The key to check.</param>
/// <returns>
/// <c>true</c> if the key is pressed, otherwise <c>false</c>.
/// </returns>
public static bool IsKeyDown(int key)
{
return (GetKeyState((int)key) & KeyPressed) != 0;
}
/// <summary>
/// Gets the key state of a key.
/// </summary>
/// <param name="key">Virtuak-key code for key.</param>
/// <returns>The state of the key.</returns>
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern short GetKeyState(int key);
}
类程序
{
公共静态字典inputMap=新字典();
公共静态字典TimerKeyMap=newdictionary();
公共静态字典TimerModifierMap=新字典();
公共静态bool continueLoop=true;
公共静态对象锁定器=新对象();
静态void Main(字符串[]参数)
{
程序=新程序();
program.run();
}
公共枚举局部修饰符:int
{
SHIFT=0x10,
CTL=0x11,
ALT=0x12,
CAPS_LOCK=0x14
}
公开募捐
{
定时器键按下提示器=新定时器();
按键提示器。间隔=60;
keyPressedPrompter.Appead+=新的ElapsedEventHandler(keyPressedPrompter事件);
keyPressedPrompter.Enabled=true;
foreach(Enum.GetValues中的ConsoleKey键(typeof(ConsoleKey)))
{
定时器=新定时器();
TimerKeyMap[定时器]=键;
时间间隔=60;
timer.appead+=新的ElapsedEventHandler(按键检查事件);
timer.Enabled=true;
}
foreach(Enum.GetValues中的LocalModifiers键(typeof(LocalModifiers)))
{
定时器=新定时器();
TimerModifierMap[定时器]=键;
时间间隔=60;
timer.appead+=新的ElapsedEventHandler(ModifierPressedCheckerEvent);
timer.Enabled=true;
}
Console.WriteLine(“当前输入:”);
while(continueLoop){}
}
公共静态void ModifierPressedCheckerEvent(对象源,EventArgs e)
{
锁(储物柜)
{
if(NativeKeyboard.IsKeyDown((int)TimerModifierMap[(Timer)source]))
{
//Console.WriteLine(KeyTimerMapReverse[(计时器)源].ToString()+“按下”);
inputMap[(int)TimerModifierMap[(计时器)源]]=TimerModifierMap[(计时器)源].ToString()+“”;
}
其他的
{
//Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString()+“released”);
inputMap[(int)TimerModifierMap[(Timer)source]]=“”;
}
}
}
public static void KeyPressedCheckerEvent(对象源,事件参数e)
{
锁(储物柜)
{
如果(Nat)