Keyboard Input

OpenTK offers two keyboard input mechanisms:

  1. A stateless polling mechanism in OpenTK.Input.Keyboard
  2. An event-based mechanism in GameWindow

The first mechanism is independent of any GameWindow (you can use it with GLControl) and supports multiple keyboard devices.

// get the combined state of all keyboard devices:
var state = OpenTK.Input.Keyboard.GetState();
 
// get the state of the second keyboard device:
var state = OpenTK.Input.Keyboard.GetState(1);
 
if (state[Key.Up])
    ; // move up
if (state[Key.Down])
    ; // move down

The second mechanism is bound to a specific GameWindow and does not distinguish between different keyboard devices:

GameWindow win = new GameWindow();
 
// Use for game input
// Independent of keyboard layout
win.KeyDown += (sender, e) =>
{
    switch (e.Key)
    {
        case Key.Left:
            // move left
            break;
        ...
        case Key.Space:
            // start charging weapon
            break;
    }
};
win.KeyUp += (sender, e) =>
{
    switch (e.Key)
    {
        case Key.Space:
            // fire charged weapon
            break;
        ...
    }
};
 
// Use for text input
// Depends on keyboard layout
win.KeyPress += (sender, e) =>
{
    Console.WriteLine(e.KeyChar);
};

A KeyDown event is fired as soon as any keyboard key is pressed. Conversely, a KeyUp event is fired as soon as any keyboard key is released. Both are independent of the current keyboard layout!

A KeyPress event is fired whenever a completed character is formed. It is meant for text input and depends on the current keyboard layout.

The distinction between KeyDown and KeyPress is important, because not all keys generate text input. For instance, the accent key on a greek keyboard layout latches the accent character "΄" but does not generate a KeyPress event until a vowel is typed (e.g. "ά"). If a consonant is typed, then two KeyPress events are generated (e.g. "΄β").

On a typical 101-key PC keyboard, the sequence of events would be as follows:

// press ΄
KeyDown:  Key.Quote
KeyUp:    Key.Quote
// press α
KeyDown:  Key.A
KeyPress: ά
KeyUp:    Key.A
 
// press ΄
KeyDown:  Key.Quote
KeyUp:    Key.Quote
// press β
KeyDown:  Key.B
KeyPress: ΄
KeyPress: β
KeyUp:    Key.B

Control keys (i.e. keys where Char.IsControl() returns true) do not generate KeyPress events at all. Escape is one of those.

Note that you need OpenTK 1.1 beta4 or newer to use GameWindow keyboard events successfully.

In previous versions, replace with:

win.Keyboard.KeyDown += (sender, e) => ...
win.Keyboard.KeyUp += (sender, e) => ...

In this case, KeyPress events may not work correctly.