web-dev-qa-db-ja.com

コンソールアプリのC#矢印キー入力

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は1回だけ呼び出されることに注意してください(キーを離したとき)。したがって、繰り返されるKeyDown呼び出しを適切に処理する必要があります。

12
Tim

今は少し遅れていますが、コンソールアプリケーションでキーボードの状態にアクセスする方法は次のとおりです。

GetKeyState を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);
}
15
Ergwun
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;
   }
}
4
The Smallest
System.Console.ReadKey(true).Key == ConsoleKey.UpArrow

次のように、それをスピンさせることができます。

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

あなたはこれを行うことができます

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
Sagiv Oulu

サンプルコード:

        ConsoleKeyInfo kb = Console.ReadKey();
        if (kb.Key == ConsoleKey.LeftArrow)
                Console.WriteLine("Left Arrow pressed");
0
BrokenGlass

私はあなたと私が見つけたのと同じ問題を抱えています。ここでは、タスクを使用した興味深い投稿があります。元の投稿はここにあります: C#コンソールアプリケーション-コンソールからの入力を常に読み取るにはどうすればよいですか?

LCDバックライトをテストするために(モノラルC#を使用して)Raspberry GPIOを介してPWM出力をエミュレートする必要があります。2つの単純なキーを使用して、デューティサイクル(アップ/ダウン)と追加のキーを変更したかったプログラムを停止するためのキー。

私はこれを試しました(変数):

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'キーを押すとプログラムは終了します。

0
Hagen