Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# arrow key input for a console app

I have a simple console app written in C#. I want to be able to detect arrow key presses, so I can allow the user to steer. How do I detect keydown/keyup events with a console app?

All my googling has led to info about windows Forms. I don't have a GUI. This is a console app (to control a robot over a serial port).

I have functions written to handle these events, but I have no idea how to register to actually receive the events:

  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
  }

This is probably a really basic question, but I'm fairly new to C#, and I've never needed to get this kind of input before.

Update: Many are suggesting I use System.Console.ReadKey(true).Key. This will not help. I need to know the moment a key is held down, when it is released, with support for multiple keys to be held down simultaneously. Also, ReadKey is a blocking call -- which means that the program will stop and wait for a key to be pressed.

Update: It seems that the only viable way to do this is to use Windows Forms. This is annoying, as I cannot use it on a headless system. Requiring a Form GUI to receive keyboard input is ... stupid.

But anyway, for posterity, here's my solution. I created a new Form project in my .sln:

    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
    }

Note that if you hold down a key, KeyDown will be called numerous times, and KeyUp will only be called once (when you release it). So you need to handle repeated KeyDown calls gracefully.

like image 298
Tim Avatar asked Dec 04 '10 00:12

Tim


2 Answers

var isUp = Console.ReadKey().Key == ConsoleKey.UpArrow;

or another example, just for your case:

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;
   }
}
like image 174
The Smallest Avatar answered Sep 18 '22 15:09

The Smallest


A bit late now, but here's how to access keyboard state in a console application.

Note that it's not all managed code as it requires GetKeyState to be imported from User32.dll.

/// <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);
}
like image 33
Ergwun Avatar answered Sep 20 '22 15:09

Ergwun