How to modify keyboard key events (Windows Forms .NET)

Windows Forms provides the ability to consume and modify keyboard input. Consuming a key refers to handling a key within a method or event handler so that other methods and events further down the message queue don't receive the key value. And, modifying a key refers to modifying the value of a key so that methods and event handlers further down the message queue receive a different key value. This article shows how to accomplish these tasks.

Important

The Desktop Guide documentation for .NET 6 and .NET 5 (including .NET Core 3.1) is under construction.

Consume a key

In a KeyPress event handler, set the Handled property of the KeyPressEventArgs class to true.

-or-

In a KeyDown event handler, set the Handled property of the KeyEventArgs class to true.

Note

Setting the Handled property in the KeyDown event handler does not prevent the KeyPress and KeyUp events from being raised for the current keystroke. Use the SuppressKeyPress property for this purpose.

The following example handles the KeyPress event to consume the A and a character keys. Those keys can't be typed into the text box:

private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (e.KeyChar == 'a' || e.KeyChar == 'A')
        e.Handled = true;
}
Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs)
    If e.KeyChar = "a"c Or e.KeyChar = "A"c Then
        e.Handled = True
    End If
End Sub

Modify a standard character key

In a KeyPress event handler, set the KeyChar property of the KeyPressEventArgs class to the value of the new character key.

The following example handles the KeyPress event to change any A and a character keys to !:

private void textBox2_KeyPress(object sender, KeyPressEventArgs e)
{
    if (e.KeyChar == 'a' || e.KeyChar == 'A')
    {
        e.KeyChar = '!';
        e.Handled = false;
    }
}
Private Sub TextBox2_KeyPress(sender As Object, e As KeyPressEventArgs)
    If e.KeyChar = "a"c Or e.KeyChar = "A"c Then
        e.KeyChar = "!"c
        e.Handled = False
    End If
End Sub

Modify a non-character key

You can only modify non-character key presses by inheriting from the control and overriding the PreProcessMessage method. As the input Message is sent to the control, it's processed before the control raising events. You can intercept these messages to modify or block them.

The following code example demonstrates how to use the WParam property of the Message parameter to change the key pressed. This code detects a key from F1 through F10 and translates the key into a numeric key ranging from 0 through 9 (where F10 maps to 0).

public override bool PreProcessMessage(ref Message m)
{
    const int WM_KEYDOWN = 0x100;

    if (m.Msg == WM_KEYDOWN)
    {
        Keys keyCode = (Keys)m.WParam & Keys.KeyCode;

        // Detect F1 through F9.
        m.WParam = keyCode switch
        {
            Keys.F1 => (IntPtr)Keys.D1,
            Keys.F2 => (IntPtr)Keys.D2,
            Keys.F3 => (IntPtr)Keys.D3,
            Keys.F4 => (IntPtr)Keys.D4,
            Keys.F5 => (IntPtr)Keys.D5,
            Keys.F6 => (IntPtr)Keys.D6,
            Keys.F7 => (IntPtr)Keys.D7,
            Keys.F8 => (IntPtr)Keys.D8,
            Keys.F9 => (IntPtr)Keys.D9,
            Keys.F10 => (IntPtr)Keys.D0,
            _ => m.WParam
        };
    }

    // Send all other messages to the base method.
    return base.PreProcessMessage(ref m);
}
Public Overrides Function PreProcessMessage(ByRef m As Message) As Boolean

    Const WM_KEYDOWN = &H100

    If m.Msg = WM_KEYDOWN Then
        Dim keyCode As Keys = CType(m.WParam, Keys) And Keys.KeyCode

        Select Case keyCode
            Case Keys.F1 : m.WParam = CType(Keys.D1, IntPtr)
            Case Keys.F2 : m.WParam = CType(Keys.D2, IntPtr)
            Case Keys.F3 : m.WParam = CType(Keys.D3, IntPtr)
            Case Keys.F4 : m.WParam = CType(Keys.D4, IntPtr)
            Case Keys.F5 : m.WParam = CType(Keys.D5, IntPtr)
            Case Keys.F6 : m.WParam = CType(Keys.D6, IntPtr)
            Case Keys.F7 : m.WParam = CType(Keys.D7, IntPtr)
            Case Keys.F8 : m.WParam = CType(Keys.D8, IntPtr)
            Case Keys.F9 : m.WParam = CType(Keys.D9, IntPtr)
            Case Keys.F10 : m.WParam = CType(Keys.D0, IntPtr)
        End Select
    End If

    Return MyBase.PreProcessMessage(m)
End Function

See also