WinForms FAQ - Keyboard Handling

How can I catch keyboard messages on a application-wide basis

You can implement the IMessageFilter interface in your main form. This amounts to adding an override for PreFilterMessage, and looking for the particular message you need to catch. Here are code snippets that catch an escape key on a keydown. You can download a sample project(C#, VB). In the sample, there are two forms, with several controls. You’ll notice that no matter what form or control has input focus, the escape key is caught in the PreFilterMessage override.

[C#]
public class MyMainForm : System.Windows.Forms.Form, IMessageFilter
{
  const int WM_KEYDOWN = 0x100;
  const int WM_KEYUP = 0x101;

  public bool PreFilterMessage(ref Message m) 
  {
    Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode;
    if(m.Msg == WM_KEYDOWN  && keyCode == Keys.Escape)
    {
      Console.WriteLine(''Ignoring Escape...'');
      return true;
    }
    return false;
  }
  ....
  ....
  ....
  private void MyMainForm_Load(object sender, System.EventArgs e)
  {
    Application.AddMessageFilter(this);
  }
}

[VB.NET]
Public Class MyMainForm
  Inherits System.Windows.Forms.Form
  Implements IMessageFilter 

  Private WM_KEYDOWN As Integer = &H100
  Private WM_KEYUP As Integer = &H101

  Public Function PreFilterMessage(ByRef m As Message) As Boolean
    Dim keyCode As Keys = CType(CInt(m.WParam), Keys) And Keys.KeyCode
    If m.Msg = WM_KEYDOWN And keyCode = Keys.Escape Then
      Console.WriteLine(''Ignoring Escape...'')
      Return True
    End If
    Return False
  End Function ’PreFilterMessage
   ....
   ....
   ....
  Private Sub MyMainForm_Load(sender As Object, e As System.EventArgs)
    Application.AddMessageFilter(Me)
  End Sub ’MyMainForm_Load
End Class ’MyMainForm
Permalink
How can I simulate keyboard input in my application

This can be done through the SendKeys class in the System.Windows.Forms namespace. Check it out in the MS help documentation.

Permalink
How can I listen for certain keys at the Form level irrespective of which Control has the focus?

When the Form.KeyPreview property is set to true, the Form’s KeyPress, KeyDown and KeyUp events will be fired even before the Control with the focus’ corresponding events. You may choose to forward these message to the Control after processing them in the Form’s event handlers (this happens by default) or set the e.Handled property to true (in the event argument) to prevent the message from being sent to the Control with focus.

Permalink
How do I check the state of the virtual keys, Caps lock for example?

If the Control.ModifierKeys doesn’t address your issue, then use Platform Invoke and call GetKeyState directly.

Declare this class first:

[
ComVisibleAttribute(false),
SuppressUnmanagedCodeSecurityAttribute()
]
internal class NativeMethods
{
	[DllImport('user32.dll', CharSet=CharSet.Auto, ExactSpelling=true, CallingConvention=CallingConvention.Winapi)] 
	public static extern short GetKeyState(int keyCode); 

	public static int HIWORD(int n)
	{
		return ((n >> 16) & 0xffff/*=~0x0000*/);
	} 

	public static int LOWORD(int n)
	{
		return (n & 0xffff/*=~0x0000*/);
	} 
}

Then when you want to check if Caps is down or ON, call:

short state = NativeMethods.GetKeyState(0x14 /*VK_CAPTIAL*/);

bool capsKeyDown = NativeMethods.HIWORD(state);
bool capsKeyON = NativeMethods.LOWORD(state);
Permalink
How can I tell if an ALT, Shift or CTL key is pressed without catching an event

Use the static property Control.ModifierKeys.

	Console.WriteLine(Control.ModifierKeys);
	if( (Control.ModifierKeys & Keys.Shift) != 0)
		Console.WriteLine('the shift key is down');
	if( (Control.ModifierKeys & Keys.Alt) != 0)
		Console.WriteLine('the alt key is down');
	if( (Control.ModifierKeys & Keys.Control) != 0)
		Console.WriteLine('the control key is down');
Permalink
How can I prevent a control from getting a particular keystroke

You can handle the control’s KeyPress event and indicate the key has been handled. Below is code that prevents a TextBox from getting an ’A’ and the return key.

private void textBox1_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
	if(e.KeyChar == (char)13 || e.KeyChar == ’A’)
		e.Handled = true;
}
Permalink