Edit

How to handle keyboard input messages in the form

Windows Forms provides the ability to handle keyboard messages at the form level, before the messages reach a control. This article shows how to accomplish this task.

Handle a keyboard message

Handle the KeyPress or KeyDown event of the active form and set the KeyPreview property of the form to true. This property causes keyboard input to reach the form before it reaches any controls on the form. The following code example handles the KeyPress event by detecting all of the number keys and consuming 1, 4, and 7.

// Detect all numeric characters at the form level and consume 1, 4, and 7.
// Form.KeyPreview must be set to true for this event handler to be called.
void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (char.IsDigit(e.KeyChar))
    {
        MessageBox.Show($"Form.KeyPress: '{e.KeyChar}' pressed.");

        switch (e.KeyChar)
        {
            case '1':
            case '4':
            case '7':
                MessageBox.Show($"Form.KeyPress: '{e.KeyChar}' consumed.");
                e.Handled = true;
                break;
        }
    }
}
' Detect all numeric characters at the form level and consume 1, 4, and 7.
' Form.KeyPreview must be set to true for this event handler to be called.
Private Sub Form1_KeyPress(sender As Object, e As KeyPressEventArgs)
    If Char.IsDigit(e.KeyChar) Then
        MessageBox.Show($"Form.KeyPress: '{e.KeyChar}' pressed.")

        Select Case e.KeyChar
            Case "1"c, "4"c, "7"c
                MessageBox.Show($"Form.KeyPress: '{e.KeyChar}' consumed.")
                e.Handled = True
        End Select
    End If

End Sub

When KeyPreview is not enough

Setting Form.KeyPreview = true doesn't guarantee that every key reaches form-level event handlers. Certain keys go through preprocessing before standard form events run. Understanding these exceptions is important for handling command keys, dialog keys, and control-specific input correctly.

Command and dialog key preprocessing

Before form-level keyboard events fire, Windows preprocesses certain keys through these methods (in order):

  1. ProcessCmdKey: Intercepts command keys such as menu shortcuts and accelerators. If this method returns true, the key is consumed and no event fires.
  2. IsInputKey: Determines whether a key should raise a KeyDown event or go to ProcessDialogKey.
  3. ProcessDialogKey: Handles navigation keys (Escape, Tab, Return, and arrow keys). If processed, no event fires.

If a focused control consumes a key during preprocessing, the form never receives it, regardless of KeyPreview.

Special cases that bypass form-level handlers

  • Enter and Escape: These keys might be handled by AcceptButton and CancelButton before reaching form events.
  • Tab: Often consumed by control focus management and won't reach form handlers.
  • Menu shortcuts: Alt key combinations are handled by menu preprocessing.

Intercept command keys at the form level

To handle command keys (including menu shortcuts and dialog keys) at the form level, override ProcessCmdKey on your form. This runs during preprocessing, before standard form events.

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    // Intercept Ctrl+A for custom handling
    if (keyData == (Keys.Control | Keys.A))
    {
        MessageBox.Show("Ctrl+A intercepted at form level");
        return true; // Mark as handled
    }

    // Pass other keys to the base handler
    return base.ProcessCmdKey(ref msg, keyData);
}
Protected Overrides Function ProcessCmdKey(ByRef msg As Message, keyData As Keys) As Boolean
    ' Intercept Ctrl+A for custom handling
    If keyData = (Keys.Control Or Keys.A) Then
        MessageBox.Show("Ctrl+A intercepted at form level")
        Return True ' Mark as handled
    End If

    ' Pass other keys to the base handler
    Return MyBase.ProcessCmdKey(msg, keyData)
End Function

For keys that should raise standard events in a specific control, use PreviewKeyDown with IsInputKey set to true on that control.

See also