Recently I got involved in a project as PM which deals with user input in Windows. The task was not easy so I hope to share some know-hows and tricks to implement the one.
There are two categories of user input: from character devices like keyboard and mouse, from inner process. An example of inner process is network packet-capturing. Anyway, I got to quote some code related to the first type of capture below. (Actually I don’t intend to post about the second type) Those implementations are actually in object-oriented structure. It is not that difficult so I just focused on the main issue rather than abstraction matter.
int idHook = NULL;
HHOOK hHook = NULL;bool SetHook(HOOKPROC HookProc, HINSTANCE hInst) {
ClearHook();
hHook = SetWindowsHookEx(idHook, HookProc, hInst, 0);
return (hHook != 0);}
bool SetHook(HOOKPROC HookProc, HINSTANCE hInst, DWORD dwThreadId) {ClearHook();
hHook = SetWindowsHookEx(idHook, HookProc, hInst, dwThreadId);
return (hHook != 0);}
void ClearHook() {if (hHook) {
UnhookWindowsHookEx(hHook);
hHook = NULL;}
}
It’s very simple idea to register or clear hook process. To get inputs from character devices, we can use WH_JOURNALRECORD for idHook variable. It hooks all the messages from keyboard and mouse, returns the specific values in HookProc event handler. SetHook function gets 2~3 arguments which are hook procedure, Window instance handle and not necessarily, thread ID. I set the HookProc like this.
LRESULT CALLBACK JournalRecordProc(int code, WPARAM wParam, LPARAM lParam) {
if (code >= 0) UserInteractionProc(wParam, lParam);
return CallNextHookEx(hHook, code, wParam, lParam);}
JournalRecordProc seems to be simple and concise. UserInteractionProc represents an abstraction for disposal of the input message. That looks finished the implementation, however, there is a missing point. If user sends interrupt message, then the hook procedure would cease the operation. And the interruption easily occurs as Ctrl+ESC or Ctrl+Alt+Del key composition would make such an interruption. To retrieve the operation, you need to interleave a snippet of code lines.
// Here is message loop in Windows application
while (GetMessage(&msg, NULL, 0, 0)) {// Retrieve the hook procedure here!
if (msg.message == WM_CANCELJOURNAL) SetHook(JournalRecordProc, hInst);TranslateMessage(&msg);
DispatchMessage(&msg);}
I checked out that it works well in Windows XP. For Vista and 7, additional authorization process needed. For more information, see the MSDN documentation here. It refers the User Interface Privilege Isolation (UIPI) and integrity in the lowest part of the document and you can get an answer for it.

