控制台应用程序的C#箭头键输入

控制台应用程序的C#箭头键输入,c#,console-application,user-input,C#,Console Application,User Input,我有一个用C#编写的简单控制台应用程序。我希望能够检测到箭头键的按下,以便允许用户转向。如何使用控制台应用程序检测按键下降/按键上升事件 我所有的谷歌搜索都得到了有关windows窗体的信息。我没有GUI。这是一个控制台应用程序(通过串口控制机器人) 我编写了处理这些事件的函数,但不知道如何注册以实际接收事件: private void myKeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) {

我有一个用C#编写的简单控制台应用程序。我希望能够检测到箭头键的按下,以便允许用户转向。如何使用控制台应用程序检测按键下降/按键上升事件

我所有的谷歌搜索都得到了有关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中创建了一个新表单项目:

    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只会调用一次(当您释放它时)。因此,您需要优雅地处理重复的按键通话

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;
   }
}
你可以把它旋转一下,比如:

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

现在有点晚了,但下面介绍如何在控制台应用程序中访问键盘状态

请注意,并非所有托管代码都需要从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);
}
//
///代表键盘键的代码。
/// 
/// 
///关键代码文档:
/// http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx
/// 
内部枚举键代码:int
{
/// 
///左箭头键。
/// 
左=0x25,
/// 
///按向上箭头键。
/// 
向上的
/// 
///右箭头键。
/// 
正确的,
/// 
///按下向下箭头键。
/// 
向下
}
/// 
///提供键盘访问。
/// 
内部静态类本机键盘
{
/// 
///一种位置位标志,指示键状态的一部分,表示
///按键。
/// 
私有常量int键按下=0x8000;
/// 
///返回一个值,该值指示是否按了给定的键。
/// 
///要检查的钥匙。
/// 
///如果按下该键,则为true,否则为false。
/// 
公共静态bool IsKeyDown(KeyCode键)
{
返回(GetKeyState((int)键)和按键)!=0;
}
/// 
///获取密钥的密钥状态。
/// 
///密钥的Virtuak密钥代码。
///密钥的状态。
[System.Runtime.InteropServices.DllImport(“user32.dll”)]
私有静态外部短GetKeyState(int-key);
}
您可以这样做

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
}

我有同样的问题,你和我发现,在这里,一个有趣的帖子使用任务。 原始帖子可在此处找到:

我必须通过Raspberry GPIO(使用mono C#)模拟PWM输出来测试LCD背光。用两个简单的键,我想改变占空比(向上/向下)和一个额外的键来停止程序

我试过这个(变量):

主程序:

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;
        }
    }
}
static void Main(字符串[]args)
{
//通过键盘字符串取消
CancellationTokenSource cts=新的CancellationTokenSource();
//侦听键盘输入的线程
var kbTask=Task.Run(()=>
{
while(true)
{
key=Console.ReadKey(true);
if(key.KeyChar=='x'| | key.KeyChar=='x')
{
cts.Cancel();
打破
}
else if(key.KeyChar=='W'| | key.KeyChar=='W')
{
如果(占空比<10)
职责++;
//Console.WriteLine(“\tIncrementa Ciclo”);
//mainAppState=StateMachineMainApp.State.TIMER;
//中断;
}
else if(key.KeyChar==“S”| key.KeyChar==“S”)
{
如果(占空比>0)
责任--;
//Console.WriteLine(“\tDecrementa Ciclo”);
//mainAppState=StateMachineMainApp.State.TIMER;
//中断;
}
}
});
//执行主要工作的线程
Task.Run(()=>DoWork(),cts.Token);
字符串OsVersion=Environment.OsVersion.ToString();
WriteLine(“操作系统:{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();
//保持控制台运行,直到调用取消令牌
kbTask.Wait();
}
静态空心榫钉()
{
while(true)
{
睡眠(50);
如果(计数器<10)
{
if(柜台<关税)
控制台。写入(“─");
//控制台。写线(计数器+“-ON”);
其他的
控制台。写(“”);
//控制台写入线(计数器+“-关闭”);
计数器++;
}
其他的
{
计数器=0;
}
}
}

当需要增加占空比时,按“W”键使主任务更改占空比变量(占空比);按“S”键减量也是一样。按下“X”键时程序结束。

按住一个键或多个键怎么样?我不想只按下最新的键-我想处理多个被按下的键(或根本不按下任何键)。然后您需要直接处理键盘消息。最简单的方法是在Windows上使用DirectInput。如果必须手动处理,则相关的Win32函数是GetConsoleWind
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;
        }
    }
}