Present for GreatLord: Implement WH_KEYBOARD_LL hook Modified: trunk/reactos/lib/user32/windows/hook.c Modified: trunk/reactos/subsys/win32k/include/msgqueue.h Modified: trunk/reactos/subsys/win32k/main/dllmain.c Modified: trunk/reactos/subsys/win32k/ntuser/callback.c Modified: trunk/reactos/subsys/win32k/ntuser/hook.c Modified: trunk/reactos/subsys/win32k/ntuser/input.c Modified: trunk/reactos/subsys/win32k/ntuser/message.c Modified: trunk/reactos/subsys/win32k/ntuser/msgqueue.c Modified: trunk/reactos/w32api/include/winuser.h _____
Modified: trunk/reactos/lib/user32/windows/hook.c --- trunk/reactos/lib/user32/windows/hook.c 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/lib/user32/windows/hook.c 2005-05-14 18:03:31 UTC (rev 15281) @@ -281,6 +281,7 @@
PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra; WPARAM wParam; LPARAM lParam; + KBDLLHOOKSTRUCT *KeyboardLlData;
Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Arguments;
@@ -353,6 +354,10 @@ break; } break; + case WH_KEYBOARD_LL: + KeyboardLlData = (KBDLLHOOKSTRUCT *)((PCHAR) Common + Common->lParam); + Result = Common->Proc(Common->Code, Common->wParam, (LPARAM) KeyboardLlData); + break; default: return ZwCallbackReturn(NULL, 0, STATUS_NOT_SUPPORTED); } _____
Modified: trunk/reactos/subsys/win32k/include/msgqueue.h --- trunk/reactos/subsys/win32k/include/msgqueue.h 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/subsys/win32k/include/msgqueue.h 2005-05-14 18:03:31 UTC (rev 15281) @@ -28,6 +28,7 @@
ULONG_PTR CompletionCallbackContext; /* entry in the dispatching list of the sender's message queue */ LIST_ENTRY DispatchingListEntry; + BOOL HookMessage; } USER_SENT_MESSAGE, *PUSER_SENT_MESSAGE;
typedef struct _USER_SENT_MESSAGE_NOTIFY @@ -127,7 +128,8 @@ NTSTATUS FASTCALL MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, - UINT uTimeout, BOOL Block, ULONG_PTR *uResult); + UINT uTimeout, BOOL Block, BOOL HookMessage, + ULONG_PTR *uResult); PUSER_MESSAGE FASTCALL MsqCreateMessage(LPMSG Msg, BOOLEAN FreeLParam); VOID FASTCALL _____
Modified: trunk/reactos/subsys/win32k/main/dllmain.c --- trunk/reactos/subsys/win32k/main/dllmain.c 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/subsys/win32k/main/dllmain.c 2005-05-14 18:03:31 UTC (rev 15281) @@ -240,7 +240,44 @@
return STATUS_SUCCESS; }
+/* Only used in ntuser/input.c KeyboardThreadMain(). If it's + not called there anymore, please delete */ +NTSTATUS +Win32kInitWin32Thread(PETHREAD Thread) +{ + PEPROCESS Process;
+ Process = Thread->ThreadsProcess; + + if (Process->Win32Process == NULL) + { + /* FIXME - lock the process */ + Process->Win32Process = ExAllocatePool(NonPagedPool, sizeof(W32PROCESS)); + + if (Process->Win32Process == NULL) + return STATUS_NO_MEMORY; + + RtlZeroMemory(Process->Win32Process, sizeof(W32PROCESS)); + /* FIXME - unlock the process */ + + Win32kProcessCallback(Process, TRUE); + } + + if (Thread->Tcb.Win32Thread == NULL) + { + Thread->Tcb.Win32Thread = ExAllocatePool (NonPagedPool, sizeof(W32THREAD)); + if (Thread->Tcb.Win32Thread == NULL) + return STATUS_NO_MEMORY; + + RtlZeroMemory(Thread->Tcb.Win32Thread, sizeof(W32THREAD)); + + Win32kThreadCallback(Thread, TRUE); + } + + return(STATUS_SUCCESS); +} + + /* * This definition doesn't work */ _____
Modified: trunk/reactos/subsys/win32k/ntuser/callback.c --- trunk/reactos/subsys/win32k/ntuser/callback.c 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/subsys/win32k/ntuser/callback.c 2005-05-14 18:03:31 UTC (rev 15281) @@ -293,6 +293,9 @@
return 0; } break; + case WH_KEYBOARD_LL: + ArgumentLength += sizeof(KBDLLHOOKSTRUCT); + break; default: DPRINT1("Trying to call unsupported window hook %d\n", HookId); return 0; @@ -343,6 +346,10 @@ break; } break; + case WH_KEYBOARD_LL: + RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT)); + Common->lParam = (LPARAM) (Extra - (PCHAR) Common); + break; }
ResultPointer = &Result; _____
Modified: trunk/reactos/subsys/win32k/ntuser/hook.c --- trunk/reactos/subsys/win32k/ntuser/hook.c 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/subsys/win32k/ntuser/hook.c 2005-05-14 18:03:31 UTC (rev 15281) @@ -182,8 +182,10 @@
RtlFreeUnicodeString(&Hook->ModuleName);
/* Dereference thread if required */ - if(Hook->Flags & HOOK_THREAD_REFERENCED) - ObDereferenceObject(Hook->Thread); + if (Hook->Flags & HOOK_THREAD_REFERENCED) + { + ObDereferenceObject(Hook->Thread); + }
/* Close handle */ ObmCloseHandle(WinStaObj->HandleTable, Hook->Self); @@ -191,7 +193,7 @@
/* remove a hook, freeing it if the chain is not in use */ STATIC FASTCALL VOID -IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj) +IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj, BOOL TableAlreadyLocked) { PHOOKTABLE Table = IntGetTable(Hook);
@@ -201,7 +203,10 @@ return; }
- IntLockHookTable(Table); + if (! TableAlreadyLocked) + { + IntLockHookTable(Table); + } if (0 != Table->Counts[HOOKID_TO_INDEX(Hook->HookId)]) { Hook->Proc = NULL; /* chain is in use, just mark it and return */ @@ -210,7 +215,10 @@ { IntFreeHook(Table, Hook, WinStaObj); } - IntUnLockHookTable(Table); + if (! TableAlreadyLocked) + { + IntUnLockHookTable(Table); + } }
/* release a hook chain, removing deleted hooks if the use count drops to 0 */ @@ -249,17 +257,42 @@ IntUnLockHookTable(Table); }
+static LRESULT FASTCALL +IntCallLowLevelHook(INT HookId, INT Code, WPARAM wParam, LPARAM lParam, PHOOK Hook) +{ + NTSTATUS Status; + ULONG_PTR uResult; + + /* FIXME should get timeout from + * HKEY_CURRENT_USER\Control Panel\Desktop\LowLevelHooksTimeout */ + Status = MsqSendMessage(Hook->Thread->Tcb.Win32Thread->MessageQueue, (HWND) Code, HookId, + wParam, lParam, /*500*/0, TRUE, TRUE, &uResult); + + return NT_SUCCESS(Status) ? uResult : 0; +} + LRESULT FASTCALL HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam) { PHOOK Hook; - PHOOKTABLE Table = MsqGetHooks(PsGetWin32Thread()->MessageQueue); + PW32THREAD Win32Thread; + PHOOKTABLE Table; LRESULT Result; PWINSTATION_OBJECT WinStaObj; NTSTATUS Status;
ASSERT(WH_MINHOOK <= HookId && HookId <= WH_MAXHOOK);
+ Win32Thread = PsGetWin32Thread(); + if (NULL == Win32Thread) + { + Table = NULL; + } + else + { + Table = MsqGetHooks(Win32Thread->MessageQueue); + } + if (NULL == Table || ! (Hook = IntGetFirstValidHook(Table, HookId))) { /* try global table */ @@ -270,6 +303,13 @@ } }
+ if (Hook->Thread != PsGetCurrentThread() + && (WH_KEYBOARD_LL == HookId || WH_MOUSE_LL == HookId)) + { + DPRINT("Calling hook in owning thread\n"); + return IntCallLowLevelHook(HookId, Code, wParam, lParam, Hook); + } + if (Hook->Thread != PsGetCurrentThread()) { DPRINT1("Calling hooks in other threads not implemented yet"); @@ -294,7 +334,7 @@ 0, &WinStaObj);
- if(! NT_SUCCESS(Status)) + if (! NT_SUCCESS(Status)) { DPRINT1("Invalid window station????\n"); } @@ -324,7 +364,7 @@ 0, &WinStaObj);
- if(! NT_SUCCESS(Status)) + if (! NT_SUCCESS(Status)) { DPRINT1("Invalid window station????\n"); return; @@ -344,7 +384,7 @@ Elem = Elem->Flink; if (HookObj->Thread == Thread) { - IntRemoveHook(HookObj, WinStaObj); + IntRemoveHook(HookObj, WinStaObj, TRUE); } } break; @@ -372,7 +412,7 @@ 0, &WinStaObj);
- if(! NT_SUCCESS(Status)) + if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return FALSE; @@ -433,7 +473,7 @@ BOOL Ansi) { PWINSTATION_OBJECT WinStaObj; - BOOLEAN Global, ReleaseThread; + BOOLEAN Global; PETHREAD Thread; PHOOK Hook; UNICODE_STRING ModuleName; @@ -473,15 +513,23 @@ SetLastWin32Error(ERROR_INVALID_PARAMETER); return NULL; } - ReleaseThread = TRUE; } else /* system-global hook */ { - ReleaseThread = FALSE; if (HookId == WH_KEYBOARD_LL || HookId == WH_MOUSE_LL) { Mod = NULL; Thread = PsGetCurrentThread(); + Status = ObReferenceObjectByPointer(Thread, + THREAD_ALL_ACCESS, + PsThreadType, + KernelMode); + + if (! NT_SUCCESS(Status)) + { + SetLastNtError(Status); + return (HANDLE) NULL; + } } else if (NULL == Mod) { @@ -495,16 +543,20 @@ Global = TRUE; }
- /* We only (partially) support local WH_CBT hooks for now */ - if (WH_CBT != HookId || Global) + /* We only (partially) support local WH_CBT hooks and + * WH_KEYBOARD_LL/WH_MOUSE_LL hooks for now */ + if ((WH_CBT != HookId || Global) + && WH_KEYBOARD_LL != HookId && WH_MOUSE_LL != HookId) { #if 0 /* Removed to get winEmbed working again */ UNIMPLEMENTED #else DPRINT1("Not implemented: HookId %d Global %s\n", HookId, Global ? "TRUE" : "FALSE"); #endif - if(ReleaseThread) - ObDereferenceObject(Thread); + if (NULL != Thread) + { + ObDereferenceObject(Thread); + } SetLastWin32Error(ERROR_NOT_SUPPORTED); return NULL; } @@ -514,10 +566,12 @@ 0, &WinStaObj);
- if(! NT_SUCCESS(Status)) + if (! NT_SUCCESS(Status)) { - if(ReleaseThread && Thread) - ObDereferenceObject(Thread); + if (NULL != Thread) + { + ObDereferenceObject(Thread); + } SetLastNtError(Status); return (HANDLE) NULL; } @@ -525,14 +579,18 @@ Hook = IntAddHook(Thread, HookId, Global, WinStaObj); if (NULL == Hook) { - if(ReleaseThread) - ObDereferenceObject(Thread); + if (NULL != Thread) + { + ObDereferenceObject(Thread); + } ObDereferenceObject(WinStaObj); return NULL; }
- if(ReleaseThread) + if (NULL != Thread) + { Hook->Flags |= HOOK_THREAD_REFERENCED; + }
if (NULL != Mod) { @@ -540,9 +598,11 @@ if (! NT_SUCCESS(Status)) { ObmDereferenceObject(Hook); - IntRemoveHook(Hook, WinStaObj); - if(ReleaseThread) - ObDereferenceObject(Thread); + IntRemoveHook(Hook, WinStaObj, FALSE); + if (NULL != Thread) + { + ObDereferenceObject(Thread); + } ObDereferenceObject(WinStaObj); SetLastNtError(Status); return NULL; @@ -553,9 +613,11 @@ if (NULL == Hook->ModuleName.Buffer) { ObmDereferenceObject(Hook); - IntRemoveHook(Hook, WinStaObj); - if(ReleaseThread) - ObDereferenceObject(Thread); + IntRemoveHook(Hook, WinStaObj, FALSE); + if (NULL != Thread) + { + ObDereferenceObject(Thread); + } ObDereferenceObject(WinStaObj); SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY); return NULL; @@ -567,9 +629,11 @@ if (! NT_SUCCESS(Status)) { ObmDereferenceObject(Hook); - IntRemoveHook(Hook, WinStaObj); - if(ReleaseThread) - ObDereferenceObject(Thread); + IntRemoveHook(Hook, WinStaObj, FALSE); + if (NULL != Thread) + { + ObDereferenceObject(Thread); + } ObDereferenceObject(WinStaObj); SetLastNtError(Status); return NULL; @@ -618,7 +682,7 @@ 0, &WinStaObj);
- if(! NT_SUCCESS(Status)) + if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return FALSE; @@ -635,7 +699,7 @@ } ASSERT(Hook == HookObj->Self);
- IntRemoveHook(HookObj, WinStaObj); + IntRemoveHook(HookObj, WinStaObj, FALSE);
ObmDereferenceObject(HookObj); ObDereferenceObject(WinStaObj); _____
Modified: trunk/reactos/subsys/win32k/ntuser/input.c --- trunk/reactos/subsys/win32k/ntuser/input.c 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/subsys/win32k/ntuser/input.c 2005-05-14 18:03:31 UTC (rev 15281) @@ -184,7 +184,7 @@
DPRINT("Mouse Input Thread Starting...\n");
/* - * Receive and process keyboard input. + * Receive and process mouse input. */ while(InputThreadsRunning) { @@ -409,7 +409,9 @@ MSG msg; PUSER_MESSAGE_QUEUE FocusQueue; struct _ETHREAD *FocusThread; + extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
+ PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL; UINT ModifierState = 0; USHORT LastMakeCode = 0; @@ -434,6 +436,22 @@ return; //(Status); }
+ /* Not sure if converting this thread to a win32 thread is such + a great idea. Since we're posting keyboard messages to the focus + window message queue, we'll be (indirectly) doing sendmessage + stuff from this thread (for WH_KEYBOARD_LL processing), which + means we need our own message queue. If keyboard messages were + instead queued to the system message queue, the thread removing + the message from the system message queue would be responsible + for WH_KEYBOARD_LL processing and we wouldn't need this thread + to be a win32 thread. */ + Status = Win32kInitWin32Thread(PsGetCurrentThread()); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n"); + return; //(Status); + } + IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle, &IndicatorTrans);
_____
Modified: trunk/reactos/subsys/win32k/ntuser/message.c --- trunk/reactos/subsys/win32k/ntuser/message.c 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/subsys/win32k/ntuser/message.c 2005-05-14 18:03:31 UTC (rev 15281) @@ -1332,7 +1332,7 @@
}
Status = MsqSendMessage(Window->MessageQueue, hWnd, Msg, wParam, lParam, - uTimeout, (uFlags & SMTO_BLOCK), uResult); + uTimeout, (uFlags & SMTO_BLOCK), FALSE, uResult); IntReleaseWindowObject(Window); if (STATUS_TIMEOUT == Status) { _____
Modified: trunk/reactos/subsys/win32k/ntuser/msgqueue.c --- trunk/reactos/subsys/win32k/ntuser/msgqueue.c 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/subsys/win32k/ntuser/msgqueue.c 2005-05-14 18:03:31 UTC (rev 15281) @@ -618,6 +618,7 @@
PUSER_MESSAGE_QUEUE FocusMessageQueue; MSG Msg; LARGE_INTEGER LargeTickCount; + KBDLLHOOKSTRUCT KbdHookData;
DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n", uMsg, wParam, lParam); @@ -632,6 +633,20 @@ /* We can't get the Msg.pt point here since we don't know thread (and thus the window station) the message will end up in yet. */
+ KbdHookData.vkCode = Msg.wParam; + KbdHookData.scanCode = (Msg.lParam >> 16) & 0xff; + KbdHookData.flags = (0 == (Msg.lParam & 0x01000000) ? 0 : LLKHF_EXTENDED) | + (0 == (Msg.lParam & 0x20000000) ? 0 : LLKHF_ALTDOWN) | + (0 == (Msg.lParam & 0x80000000) ? 0 : LLKHF_UP); + KbdHookData.time = Msg.time; + KbdHookData.dwExtraInfo = 0; + if (HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData)) + { + DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n", + Msg.message, Msg.wParam, Msg.lParam); + return; + } + FocusMessageQueue = IntGetFocusMessageQueue(); if( !IntGetScreenDC() ) { /* FIXME: What to do about Msg.pt here? */ @@ -793,11 +808,21 @@
IntUnLockMessageQueue(MessageQueue);
- /* Call the window procedure. */ - Result = IntSendMessage(Message->Msg.hwnd, - Message->Msg.message, - Message->Msg.wParam, - Message->Msg.lParam); + if (Message->HookMessage) + { + Result = HOOK_CallHooks(Message->Msg.message, + (INT) Message->Msg.hwnd, + Message->Msg.wParam, + Message->Msg.lParam); + } + else + { + /* Call the window procedure. */ + Result = IntSendMessage(Message->Msg.hwnd, + Message->Msg.message, + Message->Msg.wParam, + Message->Msg.lParam); + }
/* remove the message from the local dispatching list, because it doesn't need to be cleaned up on thread termination anymore */ @@ -957,7 +982,8 @@ NTSTATUS FASTCALL MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, - UINT uTimeout, BOOL Block, ULONG_PTR *uResult) + UINT uTimeout, BOOL Block, BOOL HookMessage, + ULONG_PTR *uResult) { PUSER_SENT_MESSAGE Message; KEVENT CompletionEvent; @@ -992,6 +1018,7 @@ Message->SenderQueue = ThreadQueue; IntReferenceMessageQueue(ThreadQueue); Message->CompletionCallback = NULL; + Message->HookMessage = HookMessage;
IntReferenceMessageQueue(MessageQueue);
_____
Modified: trunk/reactos/w32api/include/winuser.h --- trunk/reactos/w32api/include/winuser.h 2005-05-14 17:57:31 UTC (rev 15280) +++ trunk/reactos/w32api/include/winuser.h 2005-05-14 18:03:31 UTC (rev 15281) @@ -2147,7 +2147,10 @@
#define MOD_ON_KEYUP 2048 #define MOD_RIGHT 16384 #define MOD_LEFT 32768 +#define LLKHF_EXTENDED 0x00000001 +#define LLKHF_INJECTED 0x00000010 #define LLKHF_ALTDOWN 0x00000020 +#define LLKHF_UP 0x00000080 #if (WINVER >= 0x0500) #define FLASHW_STOP 0 #define FLASHW_CAPTION 1