Present for GreatLord:

Implement WH_KEYBOARD_LL hook

svn path=/trunk/; revision=15281
This commit is contained in:
Gé van Geldorp 2005-05-14 18:03:31 +00:00
parent f326ceb70f
commit c1557a2be1
9 changed files with 206 additions and 43 deletions

View file

@ -281,6 +281,7 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
PHOOKPROC_CBT_CREATEWND_EXTRA_ARGUMENTS CbtCreatewndExtra;
WPARAM wParam;
LPARAM lParam;
KBDLLHOOKSTRUCT *KeyboardLlData;
Common = (PHOOKPROC_CALLBACK_ARGUMENTS) Arguments;
@ -353,6 +354,10 @@ User32CallHookProcFromKernel(PVOID Arguments, ULONG ArgumentLength)
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);
}

View file

@ -28,6 +28,7 @@ typedef struct _USER_SENT_MESSAGE
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 @@ MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue);
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

View file

@ -240,6 +240,43 @@ Win32kThreadCallback (struct _ETHREAD *Thread,
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

View file

@ -293,6 +293,9 @@ IntCallHookProc(INT HookId,
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 @@ IntCallHookProc(INT HookId,
break;
}
break;
case WH_KEYBOARD_LL:
RtlCopyMemory(Extra, (PVOID) lParam, sizeof(KBDLLHOOKSTRUCT));
Common->lParam = (LPARAM) (Extra - (PCHAR) Common);
break;
}
ResultPointer = &Result;

View file

@ -182,8 +182,10 @@ IntFreeHook(PHOOKTABLE Table, PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
RtlFreeUnicodeString(&Hook->ModuleName);
/* Dereference thread if required */
if(Hook->Flags & HOOK_THREAD_REFERENCED)
if (Hook->Flags & HOOK_THREAD_REFERENCED)
{
ObDereferenceObject(Hook->Thread);
}
/* Close handle */
ObmCloseHandle(WinStaObj->HandleTable, Hook->Self);
@ -191,7 +193,7 @@ IntFreeHook(PHOOKTABLE Table, PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
/* 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 @@ IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
return;
}
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 @@ IntRemoveHook(PHOOK Hook, PWINSTATION_OBJECT WinStaObj)
{
IntFreeHook(Table, Hook, WinStaObj);
}
if (! TableAlreadyLocked)
{
IntUnLockHookTable(Table);
}
}
/* release a hook chain, removing deleted hooks if the use count drops to 0 */
@ -249,17 +257,42 @@ IntReleaseHookChain(PHOOKTABLE Table, int HookId, PWINSTATION_OBJECT WinStaObj)
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 @@ HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
}
}
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 @@ HOOK_CallHooks(INT HookId, INT Code, WPARAM wParam, LPARAM lParam)
0,
&WinStaObj);
if(! NT_SUCCESS(Status))
if (! NT_SUCCESS(Status))
{
DPRINT1("Invalid window station????\n");
}
@ -324,7 +364,7 @@ HOOK_DestroyThreadHooks(PETHREAD Thread)
0,
&WinStaObj);
if(! NT_SUCCESS(Status))
if (! NT_SUCCESS(Status))
{
DPRINT1("Invalid window station????\n");
return;
@ -344,7 +384,7 @@ HOOK_DestroyThreadHooks(PETHREAD Thread)
Elem = Elem->Flink;
if (HookObj->Thread == Thread)
{
IntRemoveHook(HookObj, WinStaObj);
IntRemoveHook(HookObj, WinStaObj, TRUE);
}
}
break;
@ -372,7 +412,7 @@ NtUserCallNextHookEx(
0,
&WinStaObj);
if(! NT_SUCCESS(Status))
if (! NT_SUCCESS(Status))
{
SetLastNtError(Status);
return FALSE;
@ -433,7 +473,7 @@ NtUserSetWindowsHookEx(
BOOL Ansi)
{
PWINSTATION_OBJECT WinStaObj;
BOOLEAN Global, ReleaseThread;
BOOLEAN Global;
PETHREAD Thread;
PHOOK Hook;
UNICODE_STRING ModuleName;
@ -473,15 +513,23 @@ NtUserSetWindowsHookEx(
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 @@ NtUserSetWindowsHookEx(
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)
if (NULL != Thread)
{
ObDereferenceObject(Thread);
}
SetLastWin32Error(ERROR_NOT_SUPPORTED);
return NULL;
}
@ -514,10 +566,12 @@ NtUserSetWindowsHookEx(
0,
&WinStaObj);
if(! NT_SUCCESS(Status))
if (! NT_SUCCESS(Status))
{
if (NULL != Thread)
{
if(ReleaseThread && Thread)
ObDereferenceObject(Thread);
}
SetLastNtError(Status);
return (HANDLE) NULL;
}
@ -525,14 +579,18 @@ NtUserSetWindowsHookEx(
Hook = IntAddHook(Thread, HookId, Global, WinStaObj);
if (NULL == Hook)
{
if(ReleaseThread)
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 @@ NtUserSetWindowsHookEx(
if (! NT_SUCCESS(Status))
{
ObmDereferenceObject(Hook);
IntRemoveHook(Hook, WinStaObj);
if(ReleaseThread)
IntRemoveHook(Hook, WinStaObj, FALSE);
if (NULL != Thread)
{
ObDereferenceObject(Thread);
}
ObDereferenceObject(WinStaObj);
SetLastNtError(Status);
return NULL;
@ -553,9 +613,11 @@ NtUserSetWindowsHookEx(
if (NULL == Hook->ModuleName.Buffer)
{
ObmDereferenceObject(Hook);
IntRemoveHook(Hook, WinStaObj);
if(ReleaseThread)
IntRemoveHook(Hook, WinStaObj, FALSE);
if (NULL != Thread)
{
ObDereferenceObject(Thread);
}
ObDereferenceObject(WinStaObj);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
@ -567,9 +629,11 @@ NtUserSetWindowsHookEx(
if (! NT_SUCCESS(Status))
{
ObmDereferenceObject(Hook);
IntRemoveHook(Hook, WinStaObj);
if(ReleaseThread)
IntRemoveHook(Hook, WinStaObj, FALSE);
if (NULL != Thread)
{
ObDereferenceObject(Thread);
}
ObDereferenceObject(WinStaObj);
SetLastNtError(Status);
return NULL;
@ -618,7 +682,7 @@ NtUserUnhookWindowsHookEx(
0,
&WinStaObj);
if(! NT_SUCCESS(Status))
if (! NT_SUCCESS(Status))
{
SetLastNtError(Status);
return FALSE;
@ -635,7 +699,7 @@ NtUserUnhookWindowsHookEx(
}
ASSERT(Hook == HookObj->Self);
IntRemoveHook(HookObj, WinStaObj);
IntRemoveHook(HookObj, WinStaObj, FALSE);
ObmDereferenceObject(HookObj);
ObDereferenceObject(WinStaObj);

View file

@ -184,7 +184,7 @@ MouseThreadMain(PVOID StartContext)
DPRINT("Mouse Input Thread Starting...\n");
/*
* Receive and process keyboard input.
* Receive and process mouse input.
*/
while(InputThreadsRunning)
{
@ -409,6 +409,8 @@ KeyboardThreadMain(PVOID StartContext)
MSG msg;
PUSER_MESSAGE_QUEUE FocusQueue;
struct _ETHREAD *FocusThread;
extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
UINT ModifierState = 0;
@ -434,6 +436,22 @@ KeyboardThreadMain(PVOID StartContext)
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);

View file

@ -1332,7 +1332,7 @@ IntSendMessageTimeoutSingle(HWND hWnd,
}
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)
{

View file

@ -618,6 +618,7 @@ MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
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 @@ MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
/* 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 @@ MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
IntUnLockMessageQueue(MessageQueue);
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 @@ MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
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 @@ MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
Message->SenderQueue = ThreadQueue;
IntReferenceMessageQueue(ThreadQueue);
Message->CompletionCallback = NULL;
Message->HookMessage = HookMessage;
IntReferenceMessageQueue(MessageQueue);

View file

@ -2147,7 +2147,10 @@ extern "C" {
#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