Here's my code to actually trap/untrap all keys. This code goes in the C
DLL:
static
HHOOK localHook = NULL;
static
HWND messageWindow = NULL;
static
UINT message = 0;
FOCUSHELPER_API int HookTabs( HWND msgWindow )
{
OutputDebugString( _T( "HookTabs: enter\r\n" ) );
// Save the messagewindow for use in the hook routine.
messageWindow = msgWindow;
// Set up a hook and send all of the keys to the indicated
// MessageWindow subclass.
// This works, but isn't really what we want. Ideally, we'd like
// to associate the key with the target window. Maybe we can figure
// out how to decide if we should notify the message window, though.
localHook = SetWindowsHookEx( WH_KEYBOARD_LL,
&TabHook,
(HINSTANCE)hMod,
0 /* Associate with current thread */ );
if ( localHook == NULL )
{
TCHAR syserrs[ 512 ];
DWORD err = GetLastError();
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, err,
0, syserrs, sizeof( syserrs ) / sizeof( syserrs[ 0 ] ), 0 );
OutputDebugString( syserrs );
return err;
}
// Register the window message sent to the target message window when
// a tab is detected.
message = RegisterWindowMessage( _T( "KeyMessage" ) );
return 0;
}
FOCUSHELPER_API int UnhookTabs( HWND msgWindow )
{
OutputDebugString( _T( "UnhookTabs: enter\r\n" ) );
// Stop capturing the Tab keys (maybe the application is no longer
// in front or something).
UnhookWindowsHookEx( localHook );
localHook = NULL;
return 0;
}
Note that, in your case, you might want to unhook when your application is
no longer in front, etc. Or, you can set up your message window to do that
right thing in that case and just keep the hook installed for the life of
the application. You might also note that I'm registering my own message to
send.
Here's the actual hook routine:
LRESULT CALLBACK TabHook( int code, WPARAM wParam, LPARAM lParam )
{
if ( code < 0 )
{
DEBUGMSG( 1, (TEXT( "TabHook (%x): got a code less than zero\r\n" ),
GetCurrentThreadId() ) );
// Send the message to the next hook and return its return value.
return CallNextHookEx( localHook, code, wParam, lParam );
}
if ( code != HC_ACTION )
{
DEBUGMSG( 1, (TEXT( "TabHook (%x): got a code other than HC_ACTION\r\n" ),
GetCurrentThreadId() ) );
}
// Process the message ourselves.
KBDLLHOOKSTRUCT *msg = (KBDLLHOOKSTRUCT*)lParam;
// Check for tab and shift-tab.
if ( ( wParam == WM_KEYDOWN ) && ( msg->vkCode == VK_TAB ) )
{
LPARAM lp = 0;
if ( GetKeyState( VK_SHIFT ) )
lp |= SHIFT_DOWN;
if ( GetKeyState( VK_CONTROL ) )
lp |= CONTROL_DOWN;
if ( GetKeyState( VK_MENU ) )
lp |= ALT_DOWN;
// Trying to do this as fast as possible so that the hook doesn't
// violate any timing specifications. SendMessage might take too
// long, for example.
PostMessage( messageWindow, message, msg->vkCode, lp );
}
else if ( ( wParam == WM_KEYDOWN ) &&
( ( msg->vkCode == VK_UP ) || ( msg->vkCode == VK_DOWN ) || ( msg->vkCode
== VK_LEFT ) || ( msg->vkCode == VK_RIGHT ) ) )
{
LPARAM lp = 0;
if ( GetKeyState( VK_SHIFT ) )
lp |= SHIFT_DOWN;
if ( GetKeyState( VK_CONTROL ) )
lp |= CONTROL_DOWN;
if ( GetKeyState( VK_MENU ) )
lp |= ALT_DOWN;
// Trying to do this as fast as possible so that the hook doesn't
// violate any timing specifications. SendMessage might take too
// long, for example.
PostMessage( messageWindow, message, msg->vkCode, lp );
}
else if ( ( wParam == WM_SYSKEYDOWN ) &&
( msg->vkCode >= 'A' ) && ( msg->vkCode <= 'Z' ) )
{
// This might be an accelerator. Send it on.
LPARAM lp = 0;
if ( GetKeyState( VK_SHIFT ) )
lp |= SHIFT_DOWN;
if ( GetKeyState( VK_CONTROL ) )
lp |= CONTROL_DOWN;
if ( GetKeyState( VK_MENU ) )
lp |= ALT_DOWN;
// Trying to do this as fast as possible so that the hook doesn't
// violate any timing specifications. SendMessage might take too
// long, for example.
PostMessage( messageWindow, message, msg->vkCode, lp );
}
return CallNextHookEx( localHook, code, wParam, lParam );
}
Note that I'm only forwarding some keys and you may want to do that, also,
since the C code can handle those messages pretty quickly and the managed
code might be slower; you can decide.
Here's the message window code in C#:
public class KeysMessageWindow :
Microsoft.WindowsCE.Forms.MessageWindow
{
protected int message;
public KeysMessageWindow( )
{
// Register the window message which will be sent
// when the key is pressed. Note
// that this string must match the string used in
// the helper DLL.
message = RegisterWindowMessage( "KeyMessage" );
}
protected override void WndProc ( ref Microsoft.WindowsCE.Forms.Message
m )
// override
{
// Handle arrival of registered message.
if ( m.Msg == message )
{
// ???? do whatever you want to do with the message here.
}
}
/// <summary>
/// This external function found in coredll is used to
/// register a named message used to communicate between
/// the helper DLL and this MessageWindow.
/// </summary>
[DllImport("coredll.dll")]
protected static extern int RegisterWindowMessage( string lpString );
}
#endif
That's about it...
Paul T.
Jared Miniman said:
Can you possibly point me to an example that does something vaguely similar
to this?
--
_________________________________
Jared Miniman, MS-MVP Mobile Devices
Mobile Computer Consultant
ActiveSync problems?
http://www.microsoft.com/mobile/pocketpc/support/help/activesync.asp
Connection Mngr Q's?
http://www.microsoft.com/mobile/pocketpc/tutorials/connectionmanager
pass you not
seem
want