2010-12-04 2 views
8

У меня есть простое консольное приложение, написанное на C#. Я хочу иметь возможность обнаруживать нажатия клавиш со стрелками, поэтому я могу позволить пользователю управлять. Как определить события keydown/keyup с помощью консольного приложения?C# клавиша со стрелкой для консольного приложения

Все мои поисковые запросы привели к информации о видах форм. У меня нет графического интерфейса. Это консольное приложение (для управления роботом через последовательный порт).

У меня есть функции, написанные для обработки этих событий, но я понятия не имею, как зарегистрироваться на самом деле получить событие:

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 Forms. Это раздражает, поскольку я не могу использовать его в безголовой системе. Требование графического интерфейса формы для приема ввода с клавиатуры ... глупо.

Но в любом случае, для потомков, вот мое решение. Я создал новый проект формы в моем .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 будет вызываться только один раз (при отпускании). Таким образом, вы должны обрабатывать повторяющиеся вызовы KeyDown изящно.

+0

Вы можете вызвать ReadKey в другом потоке, см. Мое предложение о вращающемся потоке. Хотя это не касается файлов keyup/keydown. – Rushyo 2010-12-05 18:51:34

ответ

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); 
} 
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 2010-12-04 01:04:05

+0

Затем вам нужно обрабатывать сообщения клавиатуры напрямую. Самый простой способ сделать это - использовать DirectInput в Windows. – Rushyo 2010-12-05 18:45:48

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?

Я должен эмулировать выход ШИМ через малина GPIO (с помощью моно C#) для проверки подсветки ЖК-дисплея. С двумя простыми клавишами я хотел изменить рабочий цикл (вверх/вниз) и дополнительный ключ, чтобы остановить программу.

Я попробовал это (переменные):

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».