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