Programming Examples

Are you a Programmer or Application Developer or a DBA? Take a cup of coffee, sit back and spend few minutes here :)

MFC – Keyboard Hook Filter Functions

1. Introduction to Keyboard Hooks and Filter Functions

Windows Hook (Keyboard Hook is a Subtype) intercepts specific type of windows hardware Event before it hits its last target say an SDI window. MFC messaging will pass this intercepted hardware events to a special function, which can change the event and even can discard it. We call such a function as a Filter function. There are unique types of windows hook available.

1.1 Hook Messages & Filters

Below are the most used Hook Messages, which are taken from the MSDN (Microsoft Developer Network):

WH_KEYBOARD:

The WH_KEYBOARD is the Keyboard Hook Message. Windows will deliver this intercepted message to the keyboard filter function.

WH_MOUSE:

The WH_MOUSE is the Hook Message for the Mouse Events. Windows will deliver this message to the mouse filter function.

WH_GETMESSAGE

This Hook Message is to intercept all the messages posted to the windows message queue. By defining the filter function, we can intercept any windows message and discard them.

We should attach a hook to a Filter Function. For Example, when we attach the WH_MOUSE hook to a filter function, all the mouse hardware messages first go to the filter function before it reaches the target window. In this article, we are going to use the Keyboard hook. Note, we can also call the filter function as hook procedure as we attach it to a hook.

1.2 Hook Chain

We can attach more than one filter functions to a windows hook. This forms a Hook Chain. For example, let us say you have two filter functions for a WH_KEYBOARD, then this forms a hook chain. When a keyboard event triggers, it reaches to all the filter functions in the keyboard hook chain. Have a look at the below picture:

Keyboard Hook and Filter Functions
Keyboard Hook and Filter Functions

Hope you went through the above picture. Let us say user pressed a numeric key ‘7’ to show that in the notepad. The keyboard hook watches the hardware event of pressing the keyboard key. So, before this hardware event ends into the notepad, the keyboard hook ( WH_KEYBOARD) will direct that to the tied filter functions. The filter function(s) after dealing with the message sends it to the actual target window or application.

From the above picture, you can see four filter functions attached to the keyboard hook. Let us say we added the filter function D at last. Now, the lastly added filter function receives the tapped keyboard event first and after processing, it sends that to Filter function ‘C’. This way the event reaches the notepad application at last once all the filter function in the chain processed the message. Ok, let us go ahead & create the example application.

2. About Keyboard Hook Example

The example is an MFC SDI application. Refer the picture below:

About the KeyBoard Hook C++ MFC Example
About the Keyboard Hook C++ MFC Example

The SDI sample, under the file menu, has two menu items called Hook CAPS Lock, Unhook CAPS Lock. When the user clicks the Hook Caps Lock menu item, the Keyboard hook is attached to the application and hooks the keyboard event. The UnHook CAPS Lock event removes installed hook from the application.

Our example SDI contains two menu items called First Dialog and Second Dialog under view menu. These menu items will bring up two dialogs with text boxes in it. When a hook is installed, you can type only the capital letters in the dialogs. After opting for the Un-Hook action, you will not have upper case constraint on the dialogs. Let us jump into the explanation-based walk-through.

3. Create Menus & Dialogs of Example

3.1 Creating the Example

First, we create a MFC Single document Interface Project called WinHooks. While creating the project, we remove the support for Document/View architecture and Unicode libraries. For this example, we can accept the defaults for all other settings. This is shown in the below video:

Video 1:  Creating the Example

3.2 Adding MFC Dialog Resources To Test Keyboard Hooks

Once the project is ready, we add two dialog templates to it as shown below:

Dialog Resource IDs for this Example
Dialog Resource IDs for this Example

In each dialog, we add some text boxes. After the dialog design, we also add the dialog class using the class wizard, which can be accessed through the context menu of the dialog template. Adding the dialog through resource and attaching a class to it is shown in the below video:

Video 2: Adding Dialog Templates

3.3 Adding Menus

After adding the dialog templates to the project via the dialog editor, we need to add two menu items and handler functions. From these handler functions, we will launch our dialogs. Below video shows adding two menu items:

Video 3: Adding Menu Items

Like how we added the menu items for launching the dialogs, the same way we add two menu items under the file menu to engage and disengage the hook for spying the keyboard events. The picture in section 2 shows the display names of these menu items.

4. Display Dialogs

In the MainFrm.cpp file, we provide the #include pre-processor directive to include the dialog classes. Below are the two statements:

Next, in the menu items handler (Created in video 3), we make call to the DoModal API which brings the dialog in front of the user. Note, we are launching the dialogs as Modal dialogs. Below is the code that displays the dialogs:

5. Add Hook Filter Functions

Hope by this time you are aware of what is a filter function. In this section, we will create a filter function and it will be attached to the Keyboard Hook which we will create in the next section.

5.1 Declare Hook Handle

First, we add the Win32 handle of type HHOOK as a global variable. Note, we are going to add a global filter function sooner and for convenience we are adding the win32 handle at a global level. This is to hold the Windows Hook in a Windows Handle. Below is the Declaration:

5.2 Keyboard Hook Procedure Signature

The signature of the keyboard hook procedure is given below. In the keyboard hook procedure, the code shows how should a procedure respond. That is; when we receive the negative code in the first param; the keyboard procedure will call the next hook filter function in the hook chain. In our example, we are going to test the WPARAM to know what key is pressed. The LAPARAM is useful to know repeat count of a button; say, for Example, a keyboard button Up Arrow pressed down for 4 or 5 seconds.

5.3 Traversing the Filter Chain

As already told, we examine the first parameter to see if the filter function can process the message. When the code is lesser than zero, we should do nothing but make a call to the  CallNextHookEx. The API will take care of calling the next filter function in the hook chain. Below is code:

5.4 CAPS LOCK Status Filter

Next using the W PARAM w, we test to see the CAPS Lock key is pressed. Have a look at the below depiction:

Testing the Binary Bit for CAPS Lock
Testing the Binary Bit for CAPS Lock

Note that each slot in the above picture denotes the unsigned char and hence each slot consumes 8 bits. The constant VK_CAPITAL denotes 20 and using the GetKeyBoardState function call we get all the key status in an array of 256 unsigned char slot. At the char location 20, we get the CAPS lock key status. When lower order bit is 1 then the CAPS Lock status is ON. So, our filter function gets the keyboard status and always keeps the lower order bit of VK_CAPITAL as one as shown above. The net effect is, when the message reaches the application message queue, the CAPS is always ON. Below is the code which is taken from the filter function:

5.5 Don’t Break Filter Chain

Once we are done dealing with the CAPS LOCK Toggle state, make a call to the next filter function as shown below:

The complete Filter Function For Keyboard Hook is below:

6. Link Keyboard Hook & Filter Function

Recall, the filter function is ready in the past section and now it is time to link the hook and with its filter function.

6.1 Set Initial CAPS Lock State

Before that we will set the Initial CAPS Lock state as ON. Below is the code called from the application’s InitInstance that an MFC programmer is aware of:

6.2 Using SetWindowsHookEx API

The SetWindowsHookEx Win32 function installs the windows hook and attaches that to the specific filter function routine. Have a look at the below picture:

Setting Keyboard Hook via SetWindowsHookEx API
Setting Keyboard Hook via SetWindowsHookEx API

The first argument passed to this function is to mention the hook category. In our example, we are will hook the keyboard events and hence the first param passed to this function is WH_KEYBOARD. The second param passed to this function is a callback to the filter function, which will get all the intercepted keyboard messages. The third param denoted the module handle. Say, for example, if the hook filter function is in the DLL module, this parameter shows that DLL module name. In our case, this argument is null, as same EXE module is defining the filter function. The final param species the thread handle linked to the hook procedure. So we make a call to the GetCurrentThreadId to state the Filter Function is also running in the same thread.

6.3 Uninstalling the Hook

While SetWindowsHookEx installs the Keyboard Hook the API UnhookWindowsHookEx uninstalls the Hook. Note how we use the handle which we retrieved via SetWindowsHookEx API call. Below is the message map handler functions for the menu items in those handlers we will hook and unhook keyboard messages:

7. Running Keyboard Hook Example

After setting the hook, launch the dialog. Once the dialogs are launched, you can see the dialog accepts only the Capital letters. You can see this in the below video:

Video 4: Running the Application

Source Code: Download

Categories: MFC

Tags: , , , ,

Do you like this Example? Please comment about it for others!!

This site uses Akismet to reduce spam. Learn how your comment data is processed.