C# arrow key input for a console app
Solution 1
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);
}
Solution 2
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;
}
}
Solution 3
System.Console.ReadKey(true).Key == ConsoleKey.UpArrow
You could put that into a spin, something like:
while(Running)
{
DoStuff();
System.Console.ReadKey(true).Key == ConsoleKey.UpArrow
Thread.Sleep(1)
}
Tim
Updated on July 12, 2022Comments
-
Tim almost 2 years
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.
-
Rushyo over 13 yearsYou can call ReadKey in a different thread, see my spinning thread suggestion. Though that doesn't address keyup/keydown stuff.
-
-
Tim over 13 yearswhat about holding down a key, or holding down multiple keys? I don't just want to get the latest key pressed - I want to handle multiple keys being held down (or no keys pressed at all).
-
Rushyo over 13 yearsThen you need to handle keyboard messages directly. Easiest way to do that is using DirectInput on Windows.
-
Rushyo over 13 yearsIf you must do it manually, the relevant Win32 functions are GetConsoleWindow and SetWindowsHookEx. Hook the Console's 'WH_CALLWNDPROC' event to trap the raw Windows messages. A console doesn't get much of the abstraction that a Windows Form does, though it may have the functionality you're looking for the fact no one has suggested it implies to me this is your next logical step.
-
Rushyo over 13 yearsIf you are intending to create a highly interactive application you might be better off creating a faux-console in a Windows Form. This is a popular technique for creating rudimentary video games UIs.
-
Rushyo over 13 yearsBear in mind that between every key on a keyboard and the shift, ctrl, alt, etc modifiers you have hundreds of key combinations at your disposal. Hence why it's not exactly standard functionality to want more than that.
-
Rushyo over 13 yearsDuh. Handling multiple arrow keys. Ignore that ;)
-
Tim almost 13 yearsInteresting. This would require polling the keyboard on my own, which means I can't just have an event-based app. But it's simple enough to do.
-
Ergwun almost 13 yearsYes, console applications don't typically have a message loop, but there's nothing to stop you rolling your own, and then having the rest of your application be event driven.
-
Gerardo Grignoli about 2 yearsWT actually supports this, but you need to enable win32-input-mode