2010-12-04 123 views
8

我有一个用C#编写的简单控制台应用程序。我希望能够检测箭头按键,这样我就可以让用户转向。如何使用控制台应用程序检测keydown/keyup事件?控制台应用程序的C#箭头键输入

我的所有Google搜索都导致了关于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窗体。这很烦人,因为我无法在无头系统上使用它。要求Form 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调用。

+0

你可以在不同的线程中调用ReadKey,看看我的纺线建议。尽管这不能解决keyup/keydown的问题。 – Rushyo 2010-12-05 18:51:34

回答

14

现在有点晚了,但这里是如何访问控制台应用程序中的键盘状态。

请注意,它不是全部托管代码,因为它需要从User32.dll中导入GetKeyState

/// <summary> 
/// Codes representing keyboard keys. 
/// </summary> 
/// <remarks> 
/// Key code documentation: 
/// http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx 
/// </remarks> 
internal enum KeyCode : int 
{ 
    /// <summary> 
    /// The left arrow key. 
    /// </summary> 
    Left = 0x25, 

    /// <summary> 
    /// The up arrow key. 
    /// </summary> 
    Up, 

    /// <summary> 
    /// The right arrow key. 
    /// </summary> 
    Right, 

    /// <summary> 
    /// The down arrow key. 
    /// </summary> 
    Down 
} 

/// <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(KeyCode 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); 
} 
4
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; 
    } 
} 
0

示例代码:

 ConsoleKeyInfo kb = Console.ReadKey(); 
     if (kb.Key == ConsoleKey.LeftArrow) 
       Console.WriteLine("Left Arrow pressed"); 
2
System.Console.ReadKey(true).Key == ConsoleKey.UpArrow 

你可以将它放入旋转,像这样:

while(Running) 
{ 
    DoStuff(); 
    System.Console.ReadKey(true).Key == ConsoleKey.UpArrow 
    Thread.Sleep(1) 
} 
+0

按住一个键或按住多个键怎么办?我不只是想得到最新的按键 - 我想处理多个按键(或者根本没有任何按键)。 – Tim 2010-12-04 01:04:05

+0

然后你需要直接处理键盘消息。最简单的方法是在Windows上使用DirectInput。 – Rushyo 2010-12-05 18:45:48

0

你可以做到这一点

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 
} 
0

我有你,我才发现,在这里,使用任务的有趣的帖子同样的问题。 原始讯息可以在这里找到: C# Console Application - How do I always read input from the console?

我有通过覆盆子GPIO以模拟PWM输出(使用单C#)来测试一个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”键,使主任务改变占空比循环变量(duty);与'S'键相同的东西减少。当按下“X”键时程序结束。