How to: Handle Keyboard Input at the Form Level

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

To handle a keyboard message at the form level

  • Handle the KeyPress or KeyDown event of the startup form, and set the KeyPreview property of the form to true so that keyboard messages are received by the form before they reach 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. Note that Form.KeyPreview must be set to true for this
        // event handler to be called.
    private:
        void Form1_KeyPress(Object^ sender, KeyPressEventArgs^ e)
        {
            if ((e->KeyChar >= '0') && (e->KeyChar <= '9'))
            {
                MessageBox::Show("Form.KeyPress: '" +
                    e->KeyChar.ToString() + "' pressed.");
    
                switch (e->KeyChar)
                {
                case '1':
                case '4':
                case '7':
                    MessageBox::Show("Form.KeyPress: '" +
                        e->KeyChar.ToString() + "' consumed.");
                    e->Handled = true;
                    break;
                }
            }
        }
    
    // Detect all numeric characters at the form level and consume 1,
    // 4, and 7. Note that Form.KeyPreview must be set to true for this
    // event handler to be called.
    void Form1_KeyPress(object sender, KeyPressEventArgs e)
    {
        if (e.KeyChar >= 48 && e.KeyChar <= 57)
        {
            MessageBox.Show("Form.KeyPress: '" +
                e.KeyChar.ToString() + "' pressed.");
    
            switch (e.KeyChar)
            {
                case (char)49:
                case (char)52:
                case (char)55:
                    MessageBox.Show("Form.KeyPress: '" +
                        e.KeyChar.ToString() + "' consumed.");
                    e.Handled = true;
                    break;
            }
        }
    }
    
    ' Detect all numeric characters at the form level and consume 1, 
    ' 4, and 7. Note that Form.KeyPreview must be set to true for this
    ' event handler to be called.
    Sub Form1_KeyPress(ByVal sender As Object, _
        ByVal e As KeyPressEventArgs) Handles Me.KeyPress
    
        If e.KeyChar >= ChrW(48) And e.KeyChar <= ChrW(57) Then
            MessageBox.Show(("Form.KeyPress: '" + _
                e.KeyChar.ToString() + "' pressed."))
    
            Select Case e.KeyChar
                Case ChrW(49), ChrW(52), ChrW(55)
                    MessageBox.Show(("Form.KeyPress: '" + _
                        e.KeyChar.ToString() + "' consumed."))
                    e.Handled = True
            End Select
        End If
    End Sub
    

Example

The following code example is the entire application for the above example. The application includes a TextBox along with several other controls that allow you to move focus from the TextBox. The KeyPress event of the main Form consumes '1', '4', and '7', and the KeyPress event of the TextBox consumes '2', '5', and '8' while displaying the remaining keys. Compare the MessageBox output when you press a number key while the TextBox has focus with the MessageBox output when you press a number key while focus is on one of the other controls.

#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
#using <System.dll>

using namespace System;
using namespace System::Drawing;
using namespace System::Windows::Forms;
using namespace System::Security::Permissions;

namespace KeyboardInputForm
{
    public ref class Form1 sealed: public Form, public IMessageFilter
    {
        // The following Windows message value is defined in Winuser.h.
    private:
        static const int WM_KEYDOWN = 0x100;
    private:
        TextBox^ inputTextBox;
    public:
        Form1()
        {
            inputTextBox = gcnew TextBox();
            this->AutoSize = true;
            Application::AddMessageFilter(this);
            FlowLayoutPanel^ panel = gcnew FlowLayoutPanel();
            panel->AutoSize = true;
            panel->FlowDirection = FlowDirection::TopDown;
            panel->Controls->Add(gcnew Button());
            panel->Controls->Add(gcnew RadioButton());
            panel->Controls->Add(inputTextBox);
            this->Controls->Add(panel);
            this->KeyPreview = true;
            this->KeyPress +=
                gcnew KeyPressEventHandler(this, &Form1::Form1_KeyPress);
            inputTextBox->KeyPress +=
                gcnew KeyPressEventHandler(this,
                &Form1::inputTextBox_KeyPress);
        }

        // Detect all numeric characters at the
        // application level and consume 0.
        virtual bool PreFilterMessage(Message% m)
        {
            // Detect key down messages.
            if (m.Msg == WM_KEYDOWN)
            {
                Keys keyCode =  (Keys)((int)m.WParam) & Keys::KeyCode;
                // Determine whether the keystroke is a number from the top of
                // the keyboard, or a number from the keypad.
                if (((keyCode >= Keys::D0) && (keyCode <= Keys::D9))
                    ||((keyCode >= Keys::NumPad0)
                    && (keyCode <= Keys::NumPad9)))
                {
                    MessageBox::Show(
                        "IMessageFilter.PreFilterMessage: '" +
                        keyCode.ToString() + "' pressed.");

                    if ((keyCode == Keys::D0) || (keyCode == Keys::NumPad0))
                    {
                        MessageBox::Show(
                            "IMessageFilter.PreFilterMessage: '" +
                            keyCode.ToString() + "' consumed.");
                        return true;
                    }
                }
            }

            // Forward all other messages.
            return false;
        }

        // Detect all numeric characters at the form level and consume 1,
        // 4, and 7. Note that Form.KeyPreview must be set to true for this
        // event handler to be called.
    private:
        void Form1_KeyPress(Object^ sender, KeyPressEventArgs^ e)
        {
            if ((e->KeyChar >= '0') && (e->KeyChar <= '9'))
            {
                MessageBox::Show("Form.KeyPress: '" +
                    e->KeyChar.ToString() + "' pressed.");

                switch (e->KeyChar)
                {
                case '1':
                case '4':
                case '7':
                    MessageBox::Show("Form.KeyPress: '" +
                        e->KeyChar.ToString() + "' consumed.");
                    e->Handled = true;
                    break;
                }
            }
        }

        // Detect all numeric characters at the TextBox level and consume
        // 2, 5, and 8.
    private:
        void inputTextBox_KeyPress(Object^ sender, KeyPressEventArgs^ e)
        {
            if ((e->KeyChar >= '0') && (e->KeyChar <= '9'))
            {
                MessageBox::Show("Control.KeyPress: '" +
                    e->KeyChar.ToString() + "' pressed.");

                switch (e->KeyChar)
                {
                case '2':
                case '5':
                case '8':
                    MessageBox::Show("Control.KeyPress: '" +
                        e->KeyChar.ToString() + "' consumed.");
                    e->Handled = true;
                    break;
                }
            }
        }
    };
}

[STAThread]
int main()
{
    Application::EnableVisualStyles();
    Application::Run(gcnew KeyboardInputForm::Form1());
}
using System;
using System.Drawing;
using System.Windows.Forms;

namespace KeyboardInputForm
{
    class Form1 : Form
    {
        TextBox TextBox1 = new TextBox();

        [STAThread]
        public static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new Form1());
        }

        public Form1()
        {
            this.AutoSize = true;

            FlowLayoutPanel panel = new FlowLayoutPanel();
            panel.AutoSize = true;
            panel.FlowDirection = FlowDirection.TopDown;
            panel.Controls.Add(TextBox1);
            this.Controls.Add(panel);

            this.KeyPreview = true;
            this.KeyPress +=
                new KeyPressEventHandler(Form1_KeyPress);
            TextBox1.KeyPress +=
                new KeyPressEventHandler(TextBox1_KeyPress);
        }

        // Detect all numeric characters at the form level and consume 1,
        // 4, and 7. Note that Form.KeyPreview must be set to true for this
        // event handler to be called.
        void Form1_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar >= 48 && e.KeyChar <= 57)
            {
                MessageBox.Show("Form.KeyPress: '" +
                    e.KeyChar.ToString() + "' pressed.");

                switch (e.KeyChar)
                {
                    case (char)49:
                    case (char)52:
                    case (char)55:
                        MessageBox.Show("Form.KeyPress: '" +
                            e.KeyChar.ToString() + "' consumed.");
                        e.Handled = true;
                        break;
                }
            }
        }

        // Detect all numeric characters at the TextBox level and consume
        // 2, 5, and 8.
        void TextBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar >= 48 && e.KeyChar <= 57)
            {
                MessageBox.Show("Control.KeyPress: '" +
                    e.KeyChar.ToString() + "' pressed.");

                switch (e.KeyChar)
                {
                    case (char)50:
                    case (char)53:
                    case (char)56:
                        MessageBox.Show("Control.KeyPress: '" +
                            e.KeyChar.ToString() + "' consumed.");
                        e.Handled = true;
                        break;
                }
            }
        }
    }
}
Imports System.Drawing
Imports System.Windows.Forms

Namespace KeyboardInputForm

     Class Form1
      Inherits Form

        Private WithEvents TextBox1 As New TextBox()

      <STAThread()> _
      Public Shared Sub Main()
         Application.EnableVisualStyles()
         Application.Run(New Form1())
      End Sub

      Public Sub New()
         Me.AutoSize = True

         Dim panel As New FlowLayoutPanel()
         panel.AutoSize = True
         panel.FlowDirection = FlowDirection.TopDown
         panel.Controls.Add(TextBox1)
         Me.Controls.Add(panel)

         Me.KeyPreview = True
        End Sub

        ' Detect all numeric characters at the form level and consume 1, 
        ' 4, and 7. Note that Form.KeyPreview must be set to true for this
        ' event handler to be called.
        Sub Form1_KeyPress(ByVal sender As Object, _
            ByVal e As KeyPressEventArgs) Handles Me.KeyPress

            If e.KeyChar >= ChrW(48) And e.KeyChar <= ChrW(57) Then
                MessageBox.Show(("Form.KeyPress: '" + _
                    e.KeyChar.ToString() + "' pressed."))

                Select Case e.KeyChar
                    Case ChrW(49), ChrW(52), ChrW(55)
                        MessageBox.Show(("Form.KeyPress: '" + _
                            e.KeyChar.ToString() + "' consumed."))
                        e.Handled = True
                End Select
            End If
        End Sub

      ' Detect all numeric characters at the TextBox level and consume  
      ' 2, 5, and 8.
      Sub TextBox1_KeyPress(ByVal sender As Object, _
          ByVal e As KeyPressEventArgs) Handles TextBox1.KeyPress

         If e.KeyChar >= ChrW(48) And e.KeyChar <= ChrW(57) Then
            MessageBox.Show(("Control.KeyPress: '" + _
                e.KeyChar.ToString() + "' pressed."))

            Select Case e.KeyChar
               Case ChrW(50), ChrW(53), ChrW(56)
                  MessageBox.Show(("Control.KeyPress: '" + _
                      e.KeyChar.ToString() + "' consumed."))
                  e.Handled = True
            End Select
         End If
      End Sub

   End Class
End Namespace

Compiling the Code

This example requires:

  • References to the System, System.Drawing and System.Windows.Forms assemblies.

See also