Click here to Skip to main content
12,817,428 members (39,213 online)
Click here to Skip to main content
Add your own
alternative version

Tagged as


35 bookmarked
Posted 3 Mar 2011

Filtering Special Keys Using C#

, 3 Mar 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
Filter out unwanted keys and key combinations: Alt+F4, Ctrl+F4, Alt+Tab, Ctrl+Esc, Windows keys, Windows key shortcuts, and Windows hotkeys in C# by capturing Win32 low-level keyboard events.


This article demonstrates capturing and filtering any key or key combination (except CTRL+ALT+DEL) in a C# application. This is useful if you'd like to prohibit a user from using: ALT+F4 to close the application, Windows key or CTRL+Esc to access the Start Menu, CTRL+F4 to close a tab, ALT+Tab to switch applications, and Windows hotkeys like Windows+E, Windows+D, and Windows+R.

This article demonstrates using Win32 system hooks in C# to capture all keystrokes and key combinations and then hide any keys that aren't specifically permitted for this application.


The KeyCapture class presented in this article uses Win32 calls to register a low-level keyboard event hook with Windows that gives us more control over what keyboard events are processed than can be done through the keyboard events available in the .NET Framework. We'll register (and unregister) a callback that allows us to receive all low-level keyboard events and then permit keys that are on our 'permitted' list and quietly discard keys that are not on the list.

This article and code was based on the excellent blog article written by Agha Usman Ahmed that can be found here:

Many thanks to Agha for posting his article and allowing me to use his code in this article.

Using the code

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace WindowsKeyCapture
    /// <span class="code-SummaryComment"><summary>

The KeyCapture class allows filtering of keys using Win32 hooks to capture low-level keyboard events. To use the KeyCapture class, place the 'permitted' keys into the PermittedKeys list using System.Windows.Forms.Keys and set KeyCapture.FilterKeys to true.

KeyCapture.PermittedKeys = new List<Keys>(new Keys[] 
    { Keys.A, Keys.B, Keys.C, ... });
KeyCapture.FilterKeys = true;

By default, KeyCapture is initialized with a list of only the basic 'typing keys': A-Z, 0-9, space, punctuation, navigation (up, down, left, right, home, end, page up, page down), and editing (backspace, delete) keys. This disables any special key combinations: ALT+F4, CTL+F4, Windows keys, and so on. It also disables any hot keys built-into the keyboard, such as volume up/down, quick launch buttons, and so on.

If you're using KeyCapture in a Windows Forms application, you can enable FilterKeys when the main form loads and disable it when the main form is destroyed. The Dispose method can be found in the Form1.designer.cs file.

/// <span class="code-SummaryComment"><summary>

Points of interest

KDBLLHOOKSTRUCT contains details passed to our callback method in the form of a struct. Here, we're mainly interested in the Keys field.

/// <span class="code-SummaryComment"><summary>

This constant identifies the type of event that we are adding a 'hook' (or callback) to process. This is the constant that identifies the low-level keyboard event.

private const int WH_KEYBOARD_LL = 13;

This delegate is the callback signature required to receive low-level keyboard events:

// System level function used to hook and unhook keyboard input
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

These are the Win32 function signatures that we are importing from user32.dll for the purpose of receiving low-level keyboard events:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int id, 
        LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hook, 
                      int nCode, IntPtr wp, IntPtr lp);

[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern short GetAsyncKeyState(Keys key);

When the FilterKeys property is set to true, this code registers our callback method CaptureKey as a hook:

// When enabled, register our key capture method.
if (value)
    // Get Current Module
    ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule;

    // Assign callback function each time keyboard process
    objKeyboardProcess = new LowLevelKeyboardProc(CaptureKey);

    // Setting Hook of Keyboard Process for current module
    ptrHook = SetWindowsHookEx(WH_KEYBOARD_LL, objKeyboardProcess, 
                  GetModuleHandle(objCurrentModule.ModuleName), 0);

When the FilterKeys property is set to false, this code removes our callback and enables keyboard events to be processed normally:

if (ptrHook != IntPtr.Zero)
    ptrHook = IntPtr.Zero;

CaptureKey is the callback method that receives low-level keyboard events. We convert the lp parameter into a KBDLLHOOKSTRUCT struct that allows us to extract the type of key that's been pressed. If we decide to reject the key, we return (IntPtr)1 to indicate that we've 'handled' the key already. If not (or if nCode is a negative number), we pass the keyboard event along to the next hook in the chain by calling CallNextHookEx.

/// <span class="code-SummaryComment"><summary>


This is the first iteration of KeyCapture and of this article; created on February 27, 2010.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

AC Everspaugh
United States United States
No Biography provided

You may also be interested in...


Comments and Discussions

Generalthis is useful Pin
BenDerPan8-Oct-13 22:29
memberBenDerPan8-Oct-13 22:29 
GeneralMy vote of 3 Pin
KA123451-Apr-11 11:21
memberKA123451-Apr-11 11:21 
GeneralNice Article Pin
icetea948-Mar-11 0:33
membericetea948-Mar-11 0:33 
GeneralMy vote of 5 Pin
NeoPunk6-Mar-11 7:26
memberNeoPunk6-Mar-11 7:26 
GeneralNo ! Pin
herves4-Mar-11 3:59
memberherves4-Mar-11 3:59 
GeneralRe: No ! Pin
NeoPunk6-Mar-11 7:26
memberNeoPunk6-Mar-11 7:26 
GeneralRe: No ! [modified] Pin
herves6-Mar-11 23:16
memberherves6-Mar-11 23:16 
GeneralRe: No ! Pin
NeoPunk7-Mar-11 1:51
memberNeoPunk7-Mar-11 1:51 
PInvokeStackImbalance it's not exception, and it appeared only in Visual Studio 2010, you can easy disable it and ignore. I fixed this error by changes CallingConvesion in DllImport attribute.
GeneralRe: No ! Pin
herves8-Mar-11 0:09
memberherves8-Mar-11 0:09 
GeneralMy vote of 3 Pin
EdMan1964-Mar-11 3:11
memberEdMan1964-Mar-11 3:11 
QuestionWhy write something thats already in the framework??? Pin
Paw Jershauge3-Mar-11 23:15
memberPaw Jershauge3-Mar-11 23:15 
AnswerRe: Why write something thats already in the framework??? Pin
Paw Jershauge3-Mar-11 23:48
memberPaw Jershauge3-Mar-11 23:48 
GeneralRe: Why write something thats already in the framework??? Pin
NeoPunk6-Mar-11 12:35
memberNeoPunk6-Mar-11 12:35 
GeneralRe: Why write something thats already in the framework??? Pin
Paw Jershauge8-Mar-11 22:03
memberPaw Jershauge8-Mar-11 22:03 
GeneralRe: Why write something thats already in the framework??? Pin
BenDerPan8-Oct-13 22:37
memberBenDerPan8-Oct-13 22:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170308.1 | Last Updated 3 Mar 2011
Article Copyright 2011 by AC Everspaugh
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid