Keyboard Hooking?

B

Ben Urbanski

Hello Everyone,

I'm writing a .Net Compact Framework application using C#. I'd like to be
able to capture keyboard messages at the application level (tab key messages
specifically, so I can implement tab navigation). I've done some research,
and I've made some progress, but I'm still having problems.

First, I'd like to summarize my findings for those trying to solve a similar
problem, then I'd like to present problems I'm still having for those of you
who might be able to help. Lastly, I'll insert my unmanaged DLL code for
your use/inspection.

1. Findings:

a. First, I looked for a way to accomplish my goal using only
managed code. Then, I looked for a way to do it using the WinAPI from
managed code. Ultimately, I settled on what seems to be the most discussed,
if not only, approach. I inherited the MessageWindow class in managed code,
overrode its WinProc method (see
http://msdn.microsoft.com/library/en-us/dnnetcomp/html/messagewindow.asp?fra
me=true), created an instance of my new MessageWindow class, and passed the
value of the instance's Hwnd property to an unmanaged DLL written using
eMbedded Visual C++ that handles hooking low level keyboard events and
sending appropriate message back to my MessageWindow class instance (see
unmanaged DLL code below).

b. Though hooking in general, and SetWindowsHookExW specifically are
not documented functionality of the Windows CE API, they do work in a
limited fashion (see item 10.9 "SetWindowsHookEx really does work, sort of."
at http://www.cegadgets.com/wincedevfaq.htm).

c. Note that with respect to keyboard hooks, only low level keyboard
hooks are accepted.

d. Note that WH_KEYBOARD_LL is defined with a value of 20, not 13 as
defined in the WinUser.h file of the Windows platform SDK.

e. I first tried to download and use eMbedded Visual C++ 4.0 to no
avail. I later found an article (paragraph 6,
http://msdn.microsoft.com/vstudio/device/embedded/evcandcenet.aspx) which
suggested I needed eMbedded Visual Tools 3.0
(http://www.microsoft.com/downloads/details.aspx?familyid=f663bf48-31ee-4cbe
-aac5-0affd5fb27dd&languageid=f49e8428-7071-4979-8a67-3cffcb0c2524&displayla
ng=en) instead.

2. Problems:

a. Using my ultimate approach as detailed in 1.a above, and the
unmanaged DLL code attached in item 3 below, I've been able to successfully
capture low level keyboard messages in the emulator. However, I haven't been
able to capture tab key messages in the emulator. I've seen one person
recommend the age old, ALT approach to indicating special characters (e.g.
if in MS Word you press and hold the ALT key, then type 090, the result is
Z). In other words, if the emulator window has focus and you type ALT+009,
the emulator should simulate pressing the tab key. However, this doesn't
work for me. Does anybody else have some suggestions?

b. While my approach mostly works in the emulator, it hardly works
with my actual Pocket PC and keyboard (I have a Dell Axim with the Dell
foldable keyboard). The only key down messages my DLL sees when running on
my Dell with a real keyboard are some of the non-standard keys like Caps
Lock, Shift, etc. Does anyone have any ideas why this is? Are keyboard hooks
tightly tied to specific makes and models of Pocket PC's and attachable
keyboards?

c. While I've seen some good technical articles about marshaling
between managed and unmanaged code, either they did not explain or I
overlooked how to dereference a pointer to a struct passed by unmanaged code
to managed code (most of the discussion seemed to center around passing
structs from managed code to unmanaged code). Specifically, I'd like to know
how to get at the KBDLLHOOKSTRUCT struct behind the LowLevelKeyboardProc's
lParam pointer that I pass on to the managed MessageWindow class from
managed code using C#.

3. Unmanaged DLL code:

// ******************* Header *******************

#ifdef TESTLIBRARY_EXPORTS
#define TESTLIBRARY_API __declspec(dllexport) WINAPI
#else
#define TESTLIBRARY_API __declspec(dllimport) WINAPI
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef LRESULT (CALLBACK* HOOKPROC)(int code, WPARAM wParam, LPARAM
lParam);

typedef struct KBDLLHOOKSTRUCT {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;

HHOOK SetWindowsHookExW(int code, HOOKPROC, HINSTANCE hInstance, DWORD
threadId);
int UnhookWindowsHookEx(HHOOK hhook);
int CallNextHookEx(HHOOK hhook, int code, WPARAM wParam, LPARAM lParam);

int TESTLIBRARY_API SetKeyboardHook(HWND messageWindow);
int TESTLIBRARY_API UnhookKeyboardHook();

#ifdef __cplusplus
}
#endif

// ******************* Source *******************

#include "stdafx.h"
#include "TestLibrary.h"

#define WH_KEYBOARD_LL 20

#define MSG (WM_USER+1)

HHOOK mKeyboardHook = NULL;
HWND mMessageWindow = NULL;
HINSTANCE mThisInstance = NULL;

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID
lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
mThisInstance = (HINSTANCE)hModule;
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}

return TRUE;
}

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM
lParam)
{
if (nCode < 0)
return CallNextHookEx(mKeyboardHook, nCode, wParam, lParam);

SendMessage(mMessageWindow, MSG, wParam, lParam);

return CallNextHookEx(mKeyboardHook, nCode, wParam, lParam);
}

int TESTLIBRARY_API UnhookKeyboardHook()
{
if (mKeyboardHook == NULL)
{
return FALSE;
}

BOOL status = UnhookWindowsHookEx(mKeyboardHook);

mKeyboardHook = NULL;

if (status)
{
return FALSE;
}

return GetLastError();
}

int TESTLIBRARY_API SetKeyboardHook(HWND messageWindow)
{
UnhookKeyboardHook();

mMessageWindow = messageWindow;

mKeyboardHook = SetWindowsHookExW(WH_KEYBOARD_LL,
(HOOKPROC)LowLevelKeyboardProc, mThisInstance, 0);

if (mKeyboardHook) return FALSE;

return GetLastError();
}

Thanks,

Ben Urbanski
 
T

Tibor Meinczinger

Hi,

a:
The tab doesn't work for me either, nor the Alt009
approach. So I have to choose another key, e.g. some
function key (F10). I have also implemented shortcuts, so
the tabbing is not so important for me. Maybe it could
help you as well.
b:
I have a Symbol device with Pocket PC running on it and
the hook works for almost all the keys, except the Tab and
the Enter keys.
c:
For marshaling use:
KBDLLHOOKSTRUCT _struct = (KBDLLHOOKSTRUCT)
System.Runtime.InteropServices.Marshal.PrtToStructure(
message.LParam, typeof(KBDLLHOOKSTRUCT))

Hope it helps,

Tibor
-----Original Message-----
Hello Everyone,

I'm writing a .Net Compact Framework application using C#. I'd like to be
able to capture keyboard messages at the application level (tab key messages
specifically, so I can implement tab navigation). I've done some research,
and I've made some progress, but I'm still having problems.

First, I'd like to summarize my findings for those trying to solve a similar
problem, then I'd like to present problems I'm still having for those of you
who might be able to help. Lastly, I'll insert my unmanaged DLL code for
your use/inspection.

1. Findings:

a. First, I looked for a way to accomplish my goal using only
managed code. Then, I looked for a way to do it using the WinAPI from
managed code. Ultimately, I settled on what seems to be the most discussed,
if not only, approach. I inherited the MessageWindow class in managed code,
overrode its WinProc method (see
http://msdn.microsoft.com/library/en- us/dnnetcomp/html/messagewindow.asp?fra
me=true), created an instance of my new MessageWindow class, and passed the
value of the instance's Hwnd property to an unmanaged DLL written using
eMbedded Visual C++ that handles hooking low level keyboard events and
sending appropriate message back to my MessageWindow class instance (see
unmanaged DLL code below).

b. Though hooking in general, and
SetWindowsHookExW specifically are
 
B

Ben Urbanski

Thanks, Tibor.

Tibor Meinczinger said:
Hi,

a:
The tab doesn't work for me either, nor the Alt009
approach. So I have to choose another key, e.g. some
function key (F10). I have also implemented shortcuts, so
the tabbing is not so important for me. Maybe it could
help you as well.
b:
I have a Symbol device with Pocket PC running on it and
the hook works for almost all the keys, except the Tab and
the Enter keys.
c:
For marshaling use:
KBDLLHOOKSTRUCT _struct = (KBDLLHOOKSTRUCT)
System.Runtime.InteropServices.Marshal.PrtToStructure(
message.LParam, typeof(KBDLLHOOKSTRUCT))

Hope it helps,

Tibor

SetWindowsHookExW specifically are
 
P

PeterB

Hi, I am just looking into this area because I, as many besides me, want the
tab-navigation functionality on my PPC-app. I realize that there are a lot
of things I need to read through but I was wondering if anyone has some
test-code to put in a PPC and see what events are firing while different
keys are pressed on the keyboard?

Could your code be useful for this Ben?

thanks in advance,

Peter
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top