2010-12-04 20 views
8

私はC#で書かれた簡単なコンソールアプリケーションを持っています。矢印キーの押下を検出できるようにしたいので、ユーザーが操縦できるようにすることができます。コンソールアプリでkeydown/keyupイベントを検出するにはどうすればよいですか?C#コンソールアプリケーション用のキー入力

私のすべてのグーグルがWindows Formsについての情報をもたらしました。私は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を要求するのは...愚かです。

しかし、とにかく後世のために、私の解決策です。あなたがキーを押した場合、KeyDownイベントが何度も呼び出され、(あなたがそれを解放するとき)keyUpイベントは一度だけ呼び出されること

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 
    } 

注:私は私の.slnで新しいフォームプロジェクトを作成しました。したがって、KeyDownの繰り返しの呼び出しを適切に処理する必要があります。ちょうどあなたのケースのための

+0

別のスレッドでReadKeyを呼び出すことができます。回転スレッドの提案を参照してください。それはkeyup/keydownのものには言及しませんが。 – Rushyo

答えて

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); 
} 
+0

面白い。これは自分でキーボードをポーリングする必要があります。つまり、イベントベースのアプリだけでは意味がありません。しかし、それは十分に簡単です。 – Tim

+2

はい、コンソールアプリケーションには通常、メッセージループはありませんが、自分自身をロールバックするのを止めることはできません。残りのアプリケーションをイベント駆動にすることはできません。 – Ergwun

+0

非常に便利です、+1これ! – teodron

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

+0

その後、キーボードメッセージを直接処理する必要があります。これを行う最も簡単な方法は、Windows上でDirectInputを使用することです。 – Rushyo

+0

手動で行う必要がある場合、関連するWin32関数はGetConsoleWindowとSetWindowsHookExです。コンソールの 'WH_CALLWNDPROC'イベントをフックして、未処理のWindowsメッセージをトラップします。コンソールには、Windowsフォームの抽象概念の多くはありませんが、それはあなたの次の論理的なステップであることを誰も示唆していないという事実を探している機能を持つかもしれません。 – Rushyo

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?

Iは、LCDバックライトをテストする(モノC#を使用して)ラズベリーGPIOを介してPWM出力をエミュレートしなければなりません。 2つのシンプルなキーでデューティサイクル(上下)とプログラムを停止するための余分なキーを変更したかったのです。

私はこの(変数)を試してみました:

static ConsoleKeyInfo key = new ConsoleKeyInfo(); 
static int counter = 0; 
static int duty = 5; // Starts in 50% 

主なプログラム:「W」キーが主なタスクは義務を変更することになり押すと、デューティ・サイクルをインクリメントするのに必要だ

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

、サイクル変数(duty)。 'S'キーを減らして同じことをする。プログラムは「X」キーが押されると終了します。

関連する問題