控制台应用程序的C#箭头键输入
我有一个用C#编写的简单控制台应用程序。 我希望能够检测箭头按键,这样我就可以让用户转向。 如何使用控制台应用程序检测keydown / keyup事件?
我所有的谷歌搜索都导致了关于Windows窗体的信息。 我没有GUI。 这是一个控制台应用程序(通过串口控制机器人)。
我有编写函数来处理这些事件,但我不知道如何注册以实际接收事件:
private void myKeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) { case Keys.Left: ... case Keys.Right: ... case Keys.Up: ... } } private void myKeyUp(object sender, KeyEventArgs e) { ... pretty much the same as myKeyDown }
这可能是一个非常基本的问题,但我对C#还不熟悉,而且我以前从未需要这样的输入。
更新:许多人建议我使用System.Console.ReadKey(true).Key
。 这没有用。 我需要知道按下按键的时刻,当它被释放时,支持同时按下多个按键。 此外,ReadKey是一个阻塞调用 – 这意味着程序将停止并等待按下一个键。
更新:似乎唯一可行的方法是使用Windows窗体。 这很烦人,因为我无法在无头系统上使用它。 要求表单GUI接收键盘输入是……愚蠢的。
但无论如何,对后代来说,这是我的解决方案。 我在.sln中创建了一个新的Form项目:
private void Form1_Load(object sender, EventArgs e) { try { this.KeyDown += new KeyEventHandler(Form1_KeyDown); this.KeyUp += new KeyEventHandler(Form1_KeyUp); } catch (Exception exc) { ... } } void Form1_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) { // handle up/down/left/right case Keys.Up: case Keys.Left: case Keys.Right: case Keys.Down: default: return; // ignore other keys } } private void Form1_KeyUp(object sender, KeyEventArgs e) { // undo what was done by KeyDown }
请注意,如果您按住某个键,KeyDown将被多次调用,而KeyUp只会被调用一次(当您释放它时)。 所以你需要优雅地处理重复的KeyDown调用。
现在有点晚了,但这里是如何在控制台应用程序中访问键盘状态。
请注意,它不是所有托管代码,因为它需要从User32.dll导入GetKeyState 。
/// /// Codes representing keyboard keys. /// /// /// Key code documentation: /// http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx /// internal enum KeyCode : int { /// /// The left arrow key. /// Left = 0x25, /// /// The up arrow key. /// Up, /// /// The right arrow key. /// Right, /// /// The down arrow key. /// Down } /// /// Provides keyboard access. /// internal static class NativeKeyboard { /// /// A positional bit flag indicating the part of a key state denoting /// key pressed. /// private const int KeyPressed = 0x8000; /// /// Returns a value indicating if a given key is pressed. /// /// The key to check. /// /// true if the key is pressed, otherwise false . /// public static bool IsKeyDown(KeyCode key) { return (GetKeyState((int)key) & KeyPressed) != 0; } /// /// Gets the key state of a key. /// /// Virtuak-key code for key. /// The state of the key. [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern short GetKeyState(int key); }
var isUp = Console.ReadKey().Key == ConsoleKey.UpArrow;
或者另一个例子,仅适用于您的情况:
while (true) { var ch = Console.ReadKey(false).Key; switch(ch) { case ConsoleKey.Escape: ShutdownRobot(); return; case ConsoleKey.UpArrow: MoveRobotUp(); break; case ConsoleKey.DownArrow: MoveRobotDown(); break; } }
System.Console.ReadKey(true).Key == ConsoleKey.UpArrow
你可以把它变成旋转,例如:
while(Running) { DoStuff(); System.Console.ReadKey(true).Key == ConsoleKey.UpArrow Thread.Sleep(1) }
示例代码:
ConsoleKeyInfo kb = Console.ReadKey(); if (kb.Key == ConsoleKey.LeftArrow) Console.WriteLine("Left Arrow pressed");
你可以这样做
bool keyWasPressed = false; if (consolekey.avalable) { keyvar = console.readkey(true); keyWasPressed = true; } if(keyWasPressed) { //enter you code here using keyvar } else { //the commands that happen if you don't press anything }
我有同样的问题,你和我在这里发现了一个使用任务的有趣post。 可以在此处找到原始post: C#控制台应用程序 – 如何始终从控制台读取输入?
我必须通过Raspberry GPIO(使用单声道C#)模拟PWM输出来测试LCD背光。 使用两个简单的键我想改变占空比(上/下)和一个额外的键来停止程序。
我试过这个(变量):
static ConsoleKeyInfo key = new ConsoleKeyInfo(); static int counter = 0; static int duty = 5; // Starts in 50%
主程序:
static void Main(string[] args) { // cancellation by keyboard string CancellationTokenSource cts = new CancellationTokenSource(); // thread that listens for keyboard input var kbTask = Task.Run(() => { while (true) { key = Console.ReadKey(true); if (key.KeyChar == 'x' || key.KeyChar == 'X') { cts.Cancel(); break; } else if (key.KeyChar == 'W' || key.KeyChar == 'w') { if (duty < 10) duty++; //Console.WriteLine("\tIncrementa Ciclo"); //mainAppState = StateMachineMainApp.State.TIMER; //break; } else if (key.KeyChar == 'S' || key.KeyChar == 's') { if (duty > 0) duty--; //Console.WriteLine("\tDecrementa Ciclo"); //mainAppState = StateMachineMainApp.State.TIMER; // break; } } }); // thread that performs main work Task.Run(() => DoWork(), cts.Token); string OsVersion = Environment.OSVersion.ToString(); Console.WriteLine("Sistema operativo: {0}", OsVersion); Console.WriteLine("Menú de Progama:"); Console.WriteLine(" W. Aumentar ciclo útil"); Console.WriteLine(" S. Disminuir ciclo útil"); Console.WriteLine(" X. Salir del programa"); Console.WriteLine(); // keep Console running until cancellation token is invoked kbTask.Wait(); } static void DoWork() { while (true) { Thread.Sleep(50); if (counter < 10) { if (counter < duty) Console.Write("─"); //Console.WriteLine(counter + " - ON"); else Console.Write("_"); //Console.WriteLine(counter + " - OFF"); counter++; } else { counter = 0; } } }
当需要增加占空比时,按“W”键使主任务改变占空比变量(占空比); 同样的事情用'S'键减少。 按下“X”键时程序结束。