控制台应用程序的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”键时程序结束。