Thursday, 10 April 2008

Hooking keyboard events in Windows CE/PPC

Hi,

I saw someone had asked about this on a newsgroup. Hooking keyboard events is where we can insert some code into GWES to see any keyboard presses that are happening in the system.

This is a useful process if you want to record a series of keypresses from a user which may span over a number of applications. Once recorded you can play back the keypresses by inserting them into GWES again using Keybd_event.


Note in Windows CE you can't hook mouse messages like in XP.

Heres the code:

// keyboardHook.cpp : Defines the entry point for the application.
//
#include "stdafx.h"

#define WH_KEYBOARD_LL 20

extern "C" BOOL WINAPI UnhookWindowsHookEx(HHOOK hhk);
extern "C" LRESULT WINAPI CallNextHookEx(HHOOK hhk, int nCode, WPARAM wParam,LPARAM lParam);
extern "C" BOOL RegisterHotKey(HWND hWnd, int id, UINT fsModifiers, UINT vk);
typedef LRESULT (CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM lParam);
extern "C" HHOOK WINAPI SetWindowsHookExW(int idHook,HOOKPROC lpfn,HINSTANCE hmod,DWORD dwThreadId);

#define SetWindowsHookEx SetWindowsHookExW

struct HHOOK__ * hKeyHook=NULL;

typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode; // virtual key code
DWORD scanCode; // scan code DWORD flags;
DWORD flags; // unused
DWORD time; // time stamp for this message
DWORD dwExtraInfo; // extra info from the driver or keybd_event
} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

//Low level Keyboard Hook Proc
__declspec(dllexport) LRESULT CALLBACK TabHook( int code, WPARAM wParam, LPARAM lParam )
{
KBDLLHOOKSTRUCT* v_kbdllData = (KBDLLHOOKSTRUCT*)lParam;
RETAILMSG(1, (TEXT("nCode = %d, wParam = %d\r\n"), code, wParam));
RETAILMSG(1, (TEXT("vkCode = %d, scan = %d, time = %d\r\n"),
v_kbdllData->vkCode, v_kbdllData->scanCode, v_kbdllData->time));
return CallNextHookEx(hKeyHook,code,wParam, lParam);
}

// This is a simple message loop that will be used
// to block while we are logging keys. It does not
// perform any real task ...

void MsgLoop()
{
MSG message;
while (GetMessage(&message,NULL,0,0))
{
TranslateMessage( &message );
DispatchMessage( &message );
}
}

HHOOK InstallHook()
{
HINSTANCE hExe = GetModuleHandle(NULL);
return SetWindowsHookEx (WH_KEYBOARD_LL,TabHook, hExe, NULL);
}

///////////////////////////////////////////////////////////////////////////////
//
// WinMain - Test Entry point
//
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
hKeyHook = InstallHook();
MsgLoop();
UnhookWindowsHookEx(hKeyHook);
return 1;
}

4 comments:

Alister Roberts said...

Indeed - it's a handy technique, especially for vetoing keypresses.

If you've got (and want to keep) the CE shell running quietly in the background and have a keyboard attached to your device, it's useful to be able to decide whether or not you want a given key combination to be passed on to the next hook...

That way you can prevent Windows+E (and the multitude of other combinations that CE uses) from doing their thing and disrupting your app.

max said...

Hi, is is possible to use WH_JOURNALRECORD to capture mouse events?

GraemeW said...

I didn't think you could hook mouse just keyboard on CE, but its worth a shot to try.

Anonymous said...

I always motivated by you, your views and way of thinking, again, thanks for this nice post.

- Murk