- Right ALT on some keyboard sends LCONTROL and RALT key events
- Shift has never extended bit in key messages
- Fixes about 32 user32:input winetest
- Don't allow to register hotkeys with special keys combinations (eg. WIN key)
- Set last error in RegisterHotKey if hotkey is already registered

svn path=/trunk/; revision=54107
This commit is contained in:
Rafal Harabien
2011-10-13 13:23:57 +00:00
parent f886d23efc
commit bb162a6c86
6 changed files with 517 additions and 388 deletions
@@ -1,22 +1,25 @@
#pragma once
typedef struct _HOT_KEY_ITEM
typedef struct _HOT_KEY
{
LIST_ENTRY ListEntry;
struct _ETHREAD *Thread;
HWND hWnd;
int id;
UINT fsModifiers;
UINT vk;
} HOT_KEY_ITEM, *PHOT_KEY_ITEM;
struct _ETHREAD *pThread;
HWND hWnd;
UINT fsModifiers;
UINT vk;
INT id;
struct _HOT_KEY *pNext;
} HOT_KEY, *PHOT_KEY;
#define IDHOT_REACTOS (-9)
/* Special Hot Keys */
#define IDHK_F12 -5
#define IDHK_SHIFTF12 -6
#define IDHK_WINKEY -7
#define IDHK_REACTOS -8
INIT_FUNCTION NTSTATUS NTAPI InitHotkeyImpl(VOID);
PHOT_KEY_ITEM FASTCALL IsHotKey(UINT fsModifiers, WORD wVk);
VOID FASTCALL UnregisterWindowHotKeys(PWND Window);
VOID FASTCALL UnregisterThreadHotKeys(struct _ETHREAD *Thread);
VOID FASTCALL UnregisterThreadHotKeys(struct _ETHREAD *pThread);
BOOL NTAPI co_UserProcessHotKeys(WORD wVk, BOOL bIsDown);
UINT FASTCALL DefWndGetHotKey(HWND hwnd);
INT FASTCALL DefWndSetHotKey(PWND pWnd, WPARAM wParam);
@@ -33,17 +33,12 @@ extern PATTACHINFO gpai;
/* Scan Codes */
#define SC_KEY_UP 0x8000
/* lParam bits */
#define LP_EXT_BIT (KF_EXTENDED<<16)
#define LP_DO_NOT_CARE_BIT (1<<25) // for GetKeyNameText
#define LP_DLGMODE (KF_DLGMODE<<16)
#define LP_MENUMODE (KF_MENUMODE<<16)
#define LP_CONTEXT_BIT (KF_ALTDOWN<<16)
#define LP_PREV_STATE_BIT (KF_REPEAT<<16)
#define LP_TRANSITION_BIT (KF_UP<<16)
INIT_FUNCTION NTSTATUS NTAPI InitInputImpl(VOID);
INIT_FUNCTION NTSTATUS NTAPI InitKeyboardImpl(VOID);
VOID NTAPI UserInitKeyboard(HANDLE hKeyboardDevice);
PKBL W32kGetDefaultKeyLayout(VOID);
VOID NTAPI UserProcessKeyboardInput(PKEYBOARD_INPUT_DATA pKeyInput);
BOOL NTAPI UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected);
+259 -146
View File
@@ -19,7 +19,13 @@ DBG_DEFAULT_CHANNEL(UserHotkey);
/* GLOBALS *******************************************************************/
LIST_ENTRY gHotkeyList;
/* Hardcoded hotkeys. See http://ivanlef0u.fr/repo/windoz/VI20051005.html */
/* thread hwnd modifiers vk id next */
HOT_KEY hkF12 = {NULL, NULL, 0, VK_F12, IDHK_F12, NULL};
HOT_KEY hkShiftF12 = {NULL, NULL, MOD_SHIFT, VK_F12, IDHK_SHIFTF12, &hkF12};
HOT_KEY hkWinKey = {NULL, NULL, MOD_WIN, 0, IDHK_WINKEY, &hkShiftF12};
PHOT_KEY gphkFirst = &hkWinKey;
/* FUNCTIONS *****************************************************************/
@@ -28,19 +34,14 @@ NTSTATUS
NTAPI
InitHotkeyImpl(VOID)
{
InitializeListHead(&gHotkeyList);
return STATUS_SUCCESS;
}
#if 0 //not used
NTSTATUS FASTCALL
/*NTSTATUS FASTCALL
CleanupHotKeys(VOID)
{
return STATUS_SUCCESS;
}
#endif
}*/
/*
* IntGetModifiers
@@ -69,151 +70,235 @@ IntGetModifiers(PBYTE pKeyState)
return fModifiers;
}
/*
* UnregisterWindowHotKeys
*
* Removes hotkeys registered by specified window on its cleanup
*/
VOID FASTCALL
UnregisterWindowHotKeys(PWND Window)
UnregisterWindowHotKeys(PWND pWnd)
{
PHOT_KEY_ITEM HotKeyItem, tmp;
PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
HWND hWnd = pWnd->head.h;
LIST_FOR_EACH_SAFE(HotKeyItem, tmp, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
while (pHotKey)
{
if (HotKeyItem->hWnd == Window->head.h)
/* Save next ptr for later use */
phkNext = pHotKey->pNext;
/* Should we delete this hotkey? */
if (pHotKey->hWnd == hWnd)
{
RemoveEntryList(&HotKeyItem->ListEntry);
ExFreePool(HotKeyItem);
/* Update next ptr for previous hotkey and free memory */
*pLink = phkNext;
ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
}
else /* This hotkey will stay, use its next ptr */
pLink = &pHotKey->pNext;
/* Move to the next entry */
pHotKey = phkNext;
}
}
/*
* UnregisterThreadHotKeys
*
* Removes hotkeys registered by specified thread on its cleanup
*/
VOID FASTCALL
UnregisterThreadHotKeys(struct _ETHREAD *Thread)
UnregisterThreadHotKeys(struct _ETHREAD *pThread)
{
PHOT_KEY_ITEM HotKeyItem, tmp;
PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
LIST_FOR_EACH_SAFE(HotKeyItem, tmp, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
while (pHotKey)
{
if (HotKeyItem->Thread == Thread)
{
RemoveEntryList(&HotKeyItem->ListEntry);
ExFreePool(HotKeyItem);
}
}
/* Save next ptr for later use */
phkNext = pHotKey->pNext;
/* Should we delete this hotkey? */
if (pHotKey->pThread == pThread)
{
/* Update next ptr for previous hotkey and free memory */
*pLink = phkNext;
ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
}
else /* This hotkey will stay, use its next ptr */
pLink = &pHotKey->pNext;
/* Move to the next entry */
pHotKey = phkNext;
}
}
PHOT_KEY_ITEM FASTCALL
/*
* IsHotKey
*
* Checks if given key and modificators have corresponding hotkey
*/
static PHOT_KEY FASTCALL
IsHotKey(UINT fsModifiers, WORD wVk)
{
PHOT_KEY_ITEM pHotKeyItem;
PHOT_KEY pHotKey = gphkFirst;
LIST_FOR_EACH(pHotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
while (pHotKey)
{
if (pHotKeyItem->fsModifiers == fsModifiers && pHotKeyItem->vk == wVk)
if (pHotKey->fsModifiers == fsModifiers &&
pHotKey->vk == wVk)
{
return pHotKeyItem;
/* We have found it */
return pHotKey;
}
/* Move to the next entry */
pHotKey = pHotKey->pNext;
}
return NULL;
}
/*
* IntKeyboardSendWinKeyMsg
* SendSysCmdMsg
*
* Sends syscommand to shell, when WIN key is pressed
* Sends syscommand to specified window
*/
static
VOID NTAPI
IntKeyboardSendWinKeyMsg()
SendSysCmdMsg(HWND hWnd, WPARAM Cmd, LPARAM lParam)
{
PWND pWnd;
MSG Msg;
LARGE_INTEGER LargeTickCount;
if (!(pWnd = UserGetWindowObject(InputWindowStation->ShellWindow)))
/* Get ptr to given window */
pWnd = UserGetWindowObject(hWnd);
if (!pWnd)
{
ERR("Couldn't find window to send Windows key message!\n");
WARN("Invalid window!\n");
return;
}
Msg.hwnd = InputWindowStation->ShellWindow;
/* Prepare WM_SYSCOMMAND message */
Msg.hwnd = hWnd;
Msg.message = WM_SYSCOMMAND;
Msg.wParam = SC_TASKLIST;
Msg.lParam = 0;
Msg.wParam = Cmd;
Msg.lParam = lParam;
KeQueryTickCount(&LargeTickCount);
Msg.time = MsqCalculateMessageTime(&LargeTickCount);
Msg.pt = gpsi->ptCursor;
/* The QS_HOTKEY is just a guess */
MsqPostMessage(pWnd->head.pti->MessageQueue, &Msg, FALSE, QS_HOTKEY);
/* Post message to window */
MsqPostMessage(pWnd->head.pti->MessageQueue, &Msg, FALSE, QS_POSTMESSAGE);
}
/*
* co_UserProcessHotKeys
*
* Sends WM_HOTKEY message if given keys are hotkey
*/
BOOL NTAPI
co_UserProcessHotKeys(WORD wVk, BOOL bIsDown)
{
UINT fModifiers;
PHOT_KEY_ITEM pHotKey;
PHOT_KEY pHotKey;
if (wVk == VK_SHIFT || wVk == VK_CONTROL || wVk == VK_MENU ||
wVk == VK_LWIN || wVk == VK_RWIN)
{
/* Those keys are specified by modifiers */
wVk = 0;
}
/* Check if it is a hotkey */
fModifiers = IntGetModifiers(gafAsyncKeyState);
pHotKey = IsHotKey(fModifiers, wVk);
if (pHotKey)
{
if (bIsDown)
/* Process hotkey if it is key up event */
if (!bIsDown)
{
TRACE("Hot key pressed (hWnd %lx, id %d)\n", pHotKey->hWnd, pHotKey->id);
MsqPostHotKeyMessage(pHotKey->Thread,
pHotKey->hWnd,
(WPARAM)pHotKey->id,
MAKELPARAM((WORD)fModifiers, wVk));
TRACE("Hot key pressed (hWnd %p, id %d)\n", pHotKey->hWnd, pHotKey->id);
/* WIN and F12 keys are hardcoded here. See: http://ivanlef0u.fr/repo/windoz/VI20051005.html */
if (pHotKey == &hkWinKey)
SendSysCmdMsg(InputWindowStation->ShellWindow, SC_TASKLIST, 0);
else if (pHotKey == &hkF12 || pHotKey == &hkShiftF12)
{
//co_ActivateDebugger(); // FIXME
}
else if (pHotKey->id == IDHK_REACTOS && !pHotKey->pThread) // FIXME: those hotkeys doesn't depend on RegisterHotKey
{
SendSysCmdMsg(pHotKey->hWnd, SC_HOTKEY, (LPARAM)pHotKey->hWnd);
}
else
{
MsqPostHotKeyMessage(pHotKey->pThread,
pHotKey->hWnd,
(WPARAM)pHotKey->id,
MAKELPARAM((WORD)fModifiers, wVk));
}
}
return TRUE; /* Don't send any message */
}
if ((wVk == VK_LWIN || wVk == VK_RWIN) && fModifiers == 0)
IntKeyboardSendWinKeyMsg();
return FALSE;
}
//
// Get/SetHotKey message support.
//
/*
* DefWndGetHotKey
*
* GetHotKey message support
*/
UINT FASTCALL
DefWndGetHotKey(HWND hwnd)
DefWndGetHotKey(HWND hWnd)
{
PHOT_KEY_ITEM HotKeyItem;
PHOT_KEY pHotKey = gphkFirst;
ERR("DefWndGetHotKey\n");
WARN("DefWndGetHotKey\n");
if (IsListEmpty(&gHotkeyList)) return 0;
LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
while (pHotKey)
{
if (HotKeyItem->hWnd == hwnd &&
HotKeyItem->id == IDHOT_REACTOS)
if (pHotKey->hWnd == hWnd && pHotKey->id == IDHK_REACTOS)
{
return MAKELONG(HotKeyItem->vk, HotKeyItem->fsModifiers);
/* We have found it */
return MAKELONG(pHotKey->vk, pHotKey->fsModifiers);
}
/* Move to the next entry */
pHotKey = pHotKey->pNext;
}
return 0;
}
/*
* DefWndSetHotKey
*
* SetHotKey message support
*/
INT FASTCALL
DefWndSetHotKey(PWND pWnd, WPARAM wParam)
{
UINT fsModifiers, vk;
PHOT_KEY_ITEM HotKeyItem;
PHOT_KEY pHotKey, *pLink;
HWND hWnd;
BOOL HaveSameWnd = FALSE;
INT Ret = 1;
INT iRet = 1;
ERR("DefWndSetHotKey wParam 0x%x\n", wParam);
WARN("DefWndSetHotKey wParam 0x%x\n", wParam);
// A hot key cannot be associated with a child window.
if (pWnd->style & WS_CHILD) return 0;
if (pWnd->style & WS_CHILD)
return 0;
// VK_ESCAPE, VK_SPACE, and VK_TAB are invalid hot keys.
if (LOWORD(wParam) == VK_ESCAPE ||
LOWORD(wParam) == VK_SPACE ||
LOWORD(wParam) == VK_TAB) return -1;
LOWORD(wParam) == VK_TAB)
{
return -1;
}
vk = LOWORD(wParam);
fsModifiers = HIWORD(wParam);
@@ -221,62 +306,68 @@ DefWndSetHotKey(PWND pWnd, WPARAM wParam)
if (wParam)
{
LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
pHotKey = gphkFirst;
while (pHotKey)
{
if (HotKeyItem->fsModifiers == fsModifiers &&
HotKeyItem->vk == vk &&
HotKeyItem->id == IDHOT_REACTOS)
if (pHotKey->fsModifiers == fsModifiers &&
pHotKey->vk == vk &&
pHotKey->id == IDHK_REACTOS)
{
if (HotKeyItem->hWnd != hWnd)
Ret = 2; // Another window already has the same hot key.
if (pHotKey->hWnd != hWnd)
iRet = 2; // Another window already has the same hot key.
break;
}
/* Move to the next entry */
pHotKey = pHotKey->pNext;
}
}
LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
pHotKey = gphkFirst;
pLink = &gphkFirst;
while (pHotKey)
{
if (HotKeyItem->hWnd == hWnd &&
HotKeyItem->id == IDHOT_REACTOS)
if (pHotKey->hWnd == hWnd &&
pHotKey->id == IDHK_REACTOS)
{
HaveSameWnd = TRUE;
/* This window has already hotkey registered */
break;
}
/* Move to the next entry */
pLink = &pHotKey->pNext;
pHotKey = pHotKey->pNext;
}
if (HaveSameWnd)
if (wParam)
{
if (wParam == 0)
{ // Setting wParam to NULL removes the hot key associated with a window.
UnregisterWindowHotKeys(pWnd);
}
else
{ /* A window can only have one hot key. If the window already has a hot key
associated with it, the new hot key replaces the old one. */
HotKeyItem->fsModifiers = fsModifiers;
HotKeyItem->vk = vk;
}
}
else //
{
if (wParam == 0)
return 1; // Do nothing, exit.
HotKeyItem = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY_ITEM), USERTAG_HOTKEY);
if (HotKeyItem == NULL)
if (!pHotKey)
{
return 0;
/* Create new hotkey */
pHotKey = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY), USERTAG_HOTKEY);
if (pHotKey == NULL)
return 0;
pHotKey->hWnd = hWnd;
pHotKey->id = IDHK_REACTOS; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey
pHotKey->pNext = gphkFirst;
gphkFirst = pHotKey;
}
HotKeyItem->Thread = pWnd->head.pti->pEThread;
HotKeyItem->hWnd = hWnd;
HotKeyItem->id = IDHOT_REACTOS; // Don't care, these hot keys are unrelated to the hot keys set by RegisterHotKey.
HotKeyItem->fsModifiers = fsModifiers;
HotKeyItem->vk = vk;
InsertHeadList(&gHotkeyList, &HotKeyItem->ListEntry);
/* A window can only have one hot key. If the window already has a
hot key associated with it, the new hot key replaces the old one. */
pHotKey->pThread = NULL;
pHotKey->fsModifiers = fsModifiers;
pHotKey->vk = vk;
}
return Ret;
else if (pHotKey)
{
/* Remove hotkey */
*pLink = pHotKey->pNext;
ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
}
return iRet;
}
/* SYSCALLS *****************************************************************/
@@ -288,88 +379,110 @@ NtUserRegisterHotKey(HWND hWnd,
UINT fsModifiers,
UINT vk)
{
PHOT_KEY_ITEM HotKeyItem;
PWND Window;
PETHREAD HotKeyThread;
DECLARE_RETURN(BOOL);
PHOT_KEY pHotKey;
PWND pWnd;
PETHREAD pHotKeyThread;
BOOL bRet = FALSE;
TRACE("Enter NtUserRegisterHotKey\n");
if (fsModifiers & ~(MOD_ALT|MOD_CONTROL|MOD_SHIFT|MOD_WIN)) //FIXME: does win2k3 supports MOD_NOREPEAT?
{
WARN("Invalid modifiers: %x\n", fsModifiers);
EngSetLastError(ERROR_INVALID_FLAGS);
return 0;
}
UserEnterExclusive();
/* Find hotkey thread */
if (hWnd == NULL)
{
HotKeyThread = PsGetCurrentThread();
pHotKeyThread = PsGetCurrentThread();
}
else
{
if(!(Window = UserGetWindowObject(hWnd)))
{
RETURN( FALSE);
}
HotKeyThread = Window->head.pti->pEThread;
pWnd = UserGetWindowObject(hWnd);
if (!pWnd)
goto cleanup;
pHotKeyThread = pWnd->head.pti->pEThread;
}
/* Check for existing hotkey */
if (IsHotKey(fsModifiers, vk))
{
RETURN( FALSE);
EngSetLastError(ERROR_HOTKEY_ALREADY_REGISTERED);
WARN("Hotkey already exists\n");
goto cleanup;
}
HotKeyItem = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY_ITEM), USERTAG_HOTKEY);
if (HotKeyItem == NULL)
/* Create new hotkey */
pHotKey = ExAllocatePoolWithTag(PagedPool, sizeof(HOT_KEY), USERTAG_HOTKEY);
if (pHotKey == NULL)
{
RETURN( FALSE);
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
HotKeyItem->Thread = HotKeyThread;
HotKeyItem->hWnd = hWnd;
HotKeyItem->id = id;
HotKeyItem->fsModifiers = fsModifiers;
HotKeyItem->vk = vk;
pHotKey->pThread = pHotKeyThread;
pHotKey->hWnd = hWnd;
pHotKey->fsModifiers = fsModifiers;
pHotKey->vk = vk;
pHotKey->id = id;
InsertHeadList(&gHotkeyList, &HotKeyItem->ListEntry);
/* Insert hotkey to the global list */
pHotKey->pNext = gphkFirst;
gphkFirst = pHotKey;
RETURN( TRUE);
bRet = TRUE;
CLEANUP:
TRACE("Leave NtUserRegisterHotKey, ret=%i\n", _ret_);
cleanup:
TRACE("Leave NtUserRegisterHotKey, ret=%i\n", bRet);
UserLeave();
END_CLEANUP;
return bRet;
}
BOOL APIENTRY
NtUserUnregisterHotKey(HWND hWnd, int id)
{
PHOT_KEY_ITEM HotKeyItem;
PWND Window;
DECLARE_RETURN(BOOL);
PHOT_KEY pHotKey = gphkFirst, phkNext, *pLink = &gphkFirst;
PWND pWnd;
BOOL bRet = FALSE;
TRACE("Enter NtUserUnregisterHotKey\n");
UserEnterExclusive();
if(!(Window = UserGetWindowObject(hWnd)))
{
RETURN( FALSE);
}
pWnd = UserGetWindowObject(hWnd);
if (!pWnd)
goto cleanup;
LIST_FOR_EACH(HotKeyItem, &gHotkeyList, HOT_KEY_ITEM, ListEntry)
while (pHotKey)
{
if (HotKeyItem->hWnd == hWnd && HotKeyItem->id == id)
/* Save next ptr for later use */
phkNext = pHotKey->pNext;
/* Should we delete this hotkey? */
if (pHotKey->hWnd == hWnd && pHotKey->id == id)
{
RemoveEntryList(&HotKeyItem->ListEntry);
ExFreePoolWithTag(HotKeyItem, USERTAG_HOTKEY);
/* Update next ptr for previous hotkey and free memory */
*pLink = phkNext;
ExFreePoolWithTag(pHotKey, USERTAG_HOTKEY);
RETURN( TRUE);
bRet = TRUE;
}
else /* This hotkey will stay, use its next ptr */
pLink = &pHotKey->pNext;
/* Move to the next entry */
pHotKey = phkNext;
}
RETURN( FALSE);
CLEANUP:
TRACE("Leave NtUserUnregisterHotKey, ret=%i\n", _ret_);
cleanup:
TRACE("Leave NtUserUnregisterHotKey, ret=%i\n", bRet);
UserLeave();
END_CLEANUP;
return bRet;
}
/* EOF */
@@ -332,6 +332,8 @@ KeyboardThreadMain(PVOID StartContext)
FILE_SYNCHRONOUS_IO_ALERT);
} while (!NT_SUCCESS(Status));
UserInitKeyboard(ghKeyboardDevice);
/* 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
@@ -355,22 +357,19 @@ KeyboardThreadMain(PVOID StartContext)
KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
LOW_REALTIME_PRIORITY + 3);
//IntKeyboardGetIndicatorTrans(ghKeyboardDevice,
// &IndicatorTrans);
for (;;)
{
/*
* Wait to start input.
*/
TRACE( "Keyboard Input Thread Waiting for start event\n" );
TRACE("Keyboard Input Thread Waiting for start event\n");
Status = KeWaitForSingleObject(&InputThreadsStart,
0,
KernelMode,
TRUE,
NULL);
TRACE( "Keyboard Input Thread Starting...\n" );
TRACE("Keyboard Input Thread Starting...\n");
/*
* Receive and process keyboard input.
*/
@@ -390,16 +389,16 @@ KeyboardThreadMain(PVOID StartContext)
NULL,
NULL);
if(Status == STATUS_ALERTED && !InputThreadsRunning)
if (Status == STATUS_ALERTED && !InputThreadsRunning)
{
break;
}
if(Status == STATUS_PENDING)
if (Status == STATUS_PENDING)
{
NtWaitForSingleObject(ghKeyboardDevice, FALSE, NULL);
Status = Iosb.Status;
}
if(!NT_SUCCESS(Status))
if (!NT_SUCCESS(Status))
{
ERR("Win32K: Failed to read from keyboard.\n");
return; //(Status);
@@ -427,7 +426,7 @@ KeyboardThreadMain(PVOID StartContext)
UserLeave();
}
TRACE( "KeyboardInput Thread Stopped...\n" );
TRACE("KeyboardInput Thread Stopped...\n");
}
}
+231 -212
View File
@@ -11,8 +11,9 @@
DBG_DEFAULT_CHANNEL(UserKbd);
BYTE gafAsyncKeyState[256 * 2 / 8]; // 2 bits per key
BYTE gafAsyncKeyStateRecentDown[256 / 8]; // 1 bit per key
static BYTE gafAsyncKeyStateRecentDown[256 / 8]; // 1 bit per key
static PKEYBOARD_INDICATOR_TRANSLATION gpKeyboardIndicatorTrans = NULL;
static KEYBOARD_INDICATOR_PARAMETERS gIndicators = {0, 0};
/* FUNCTIONS *****************************************************************/
@@ -97,44 +98,87 @@ IntKeyboardGetIndicatorTrans(HANDLE hKeyboardDevice,
static
NTSTATUS APIENTRY
IntKeyboardUpdateLeds(HANDLE hKeyboardDevice,
WORD wVk,
WORD wScanCode,
BOOL bEnabled,
PKEYBOARD_INDICATOR_TRANSLATION pIndicatorTrans)
BOOL bEnabled)
{
NTSTATUS Status;
UINT i;
static KEYBOARD_INDICATOR_PARAMETERS Indicators;
USHORT LedFlag = 0;
IO_STATUS_BLOCK Block;
if (!pIndicatorTrans)
if (!gpKeyboardIndicatorTrans)
return STATUS_NOT_SUPPORTED;
for (i = 0; i < pIndicatorTrans->NumberOfIndicatorKeys; i++)
switch (wVk)
{
if (pIndicatorTrans->IndicatorList[i].MakeCode == wScanCode)
{
if (bEnabled)
Indicators.LedFlags |= pIndicatorTrans->IndicatorList[i].IndicatorFlags;
else
Indicators.LedFlags = ~pIndicatorTrans->IndicatorList[i].IndicatorFlags;
case VK_CAPITAL: LedFlag = KEYBOARD_CAPS_LOCK_ON; break;
case VK_NUMLOCK: LedFlag = KEYBOARD_NUM_LOCK_ON; break;
case VK_SCROLL: LedFlag = KEYBOARD_SCROLL_LOCK_ON; break;
default:
for (i = 0; i < gpKeyboardIndicatorTrans->NumberOfIndicatorKeys; i++)
{
if (gpKeyboardIndicatorTrans->IndicatorList[i].MakeCode == wScanCode)
{
LedFlag = gpKeyboardIndicatorTrans->IndicatorList[i].IndicatorFlags;
break;
}
}
}
/* Update the lights on the hardware */
Status = NtDeviceIoControlFile(hKeyboardDevice,
NULL,
NULL,
NULL,
&Block,
IOCTL_KEYBOARD_SET_INDICATORS,
&Indicators, sizeof(Indicators),
NULL, 0);
if (LedFlag)
{
if (bEnabled)
gIndicators.LedFlags |= LedFlag;
else
gIndicators.LedFlags = ~LedFlag;
return Status;
}
/* Update the lights on the hardware */
Status = NtDeviceIoControlFile(hKeyboardDevice,
NULL,
NULL,
NULL,
&Block,
IOCTL_KEYBOARD_SET_INDICATORS,
&gIndicators, sizeof(gIndicators),
NULL, 0);
return Status;
}
return STATUS_SUCCESS;
}
/*
* UserInitKeyboard
*
* Initializes keyboard indicators translation and their state
*/
VOID NTAPI
UserInitKeyboard(HANDLE hKeyboardDevice)
{
NTSTATUS Status;
IO_STATUS_BLOCK Block;
IntKeyboardGetIndicatorTrans(hKeyboardDevice, &gpKeyboardIndicatorTrans);
Status = NtDeviceIoControlFile(hKeyboardDevice,
NULL,
NULL,
NULL,
&Block,
IOCTL_KEYBOARD_QUERY_INDICATORS,
NULL, 0,
&gIndicators, sizeof(gIndicators));
SET_KEY_LOCKED(gafAsyncKeyState, VK_CAPITAL,
gIndicators.LedFlags & KEYBOARD_CAPS_LOCK_ON);
SET_KEY_LOCKED(gafAsyncKeyState, VK_NUMLOCK,
gIndicators.LedFlags & KEYBOARD_NUM_LOCK_ON);
SET_KEY_LOCKED(gafAsyncKeyState, VK_SCROLL,
gIndicators.LedFlags & KEYBOARD_SCROLL_LOCK_ON);
}
/*
* IntSimplifyVk
*
@@ -188,30 +232,6 @@ IntFixVk(WORD wVk, BOOL bExt)
}
}
/*
* IntGetVkOtherSide
*
* Gets other side of vk: right -> left, left -> right
*/
static
WORD
IntGetVkOtherSide(WORD wVk)
{
switch (wVk)
{
case VK_LSHIFT: return VK_RSHIFT;
case VK_RSHIFT: return VK_LSHIFT;
case VK_LCONTROL: return VK_RCONTROL;
case VK_RCONTROL: return VK_LCONTROL;
case VK_LMENU: return VK_RMENU;
case VK_RMENU: return VK_LMENU;
default: return wVk;
}
}
/*
* IntTranslateNumpadKey
*
@@ -238,24 +258,6 @@ IntTranslateNumpadKey(WORD wVk)
}
}
/*
* IntGetShiftBit
*
* Search the keyboard layout modifiers table for the shift bit
*/
static
DWORD FASTCALL
IntGetShiftBit(PKBDTABLES pKbdTbl, WORD wVk)
{
unsigned i;
for (i = 0; pKbdTbl->pCharModifiers->pVkToBit[i].Vk; i++)
if (pKbdTbl->pCharModifiers->pVkToBit[i].Vk == wVk)
return pKbdTbl->pCharModifiers->pVkToBit[i].ModBits;
return 0;
}
/*
* IntGetModBits
*
@@ -273,10 +275,6 @@ IntGetModBits(PKBDTABLES pKbdTbl, PBYTE pKeyState)
if (IS_KEY_DOWN(pKeyState, pKbdTbl->pCharModifiers->pVkToBit[i].Vk))
dwModBits |= pKbdTbl->pCharModifiers->pVkToBit[i].ModBits;
/* Handle Alt+Gr */
if ((pKbdTbl->fLocaleFlags & KLLF_ALTGR) && IS_KEY_DOWN(pKeyState, VK_RMENU))
dwModBits |= IntGetShiftBit(pKbdTbl, VK_CONTROL); /* Don't use KBDCTRL here */
TRACE("Current Mod Bits: %lx\n", dwModBits);
return dwModBits;
@@ -615,20 +613,6 @@ NtUserGetAsyncKeyState(INT Key)
return wRet;
}
/*
* co_IntKeyboardSendAltKeyMsg
*
* Sends syscommand enabling window menu
*/
static
VOID NTAPI
co_IntKeyboardSendAltKeyMsg()
{
FIXME("co_IntKeyboardSendAltKeyMsg\n");
//co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0); // This sends everything into a msg loop!
}
/*
* UpdateAsyncKeyState
*
@@ -651,26 +635,40 @@ UpdateAsyncKeyState(WORD wVk, BOOL bIsDown)
SET_KEY_DOWN(gafAsyncKeyState, wVk, FALSE);
}
LRESULT
co_CallLowLevelKeyboardHook(CONST MSG *pMsg, BOOL bInjected, DWORD dwExtraInfo)
/*
* co_CallLowLevelKeyboardHook
*
* Calls WH_KEYBOARD_LL hook
*/
static LRESULT
co_CallLowLevelKeyboardHook(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD dwTime, DWORD dwExtraInfo)
{
KBDLLHOOKSTRUCT KbdHookData;
UINT uMsg;
KbdHookData.vkCode = pMsg->wParam;
KbdHookData.scanCode = HIWORD(pMsg->lParam) & 0xFF;
KbdHookData.vkCode = wVk;
KbdHookData.scanCode = wScanCode;
KbdHookData.flags = 0;
if (pMsg->lParam & LP_EXT_BIT)
if (dwFlags & KEYEVENTF_EXTENDEDKEY)
KbdHookData.flags |= LLKHF_EXTENDED;
if (IS_KEY_DOWN(gafAsyncKeyState, VK_MENU))
KbdHookData.flags |= LLKHF_ALTDOWN;
if (pMsg->message == WM_KEYUP || pMsg->message == WM_SYSKEYUP)
if (dwFlags & KEYEVENTF_KEYUP)
KbdHookData.flags |= LLKHF_UP;
if (bInjected)
KbdHookData.flags |= LLKHF_INJECTED;
KbdHookData.time = pMsg->time;
KbdHookData.time = dwTime;
KbdHookData.dwExtraInfo = dwExtraInfo;
return co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, pMsg->message, (LPARAM) &KbdHookData);
/* Note: it doesnt support WM_SYSKEYUP */
if (dwFlags & KEYEVENTF_KEYUP)
uMsg = WM_KEYUP;
else if (IS_KEY_DOWN(gafAsyncKeyState, VK_MENU) && !IS_KEY_DOWN(gafAsyncKeyState, VK_CONTROL))
uMsg = WM_SYSKEYDOWN;
else
uMsg = WM_KEYDOWN;
return co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, uMsg, (LPARAM)&KbdHookData);
}
/*
@@ -678,19 +676,141 @@ co_CallLowLevelKeyboardHook(CONST MSG *pMsg, BOOL bInjected, DWORD dwExtraInfo)
*
* Process keyboard input from input devices and SendInput API
*/
BOOL NTAPI
ProcessKeyEvent(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD dwTime, DWORD dwExtraInfo)
{
WORD wSimpleVk = 0, wFixedVk, wVk2;
PUSER_MESSAGE_QUEUE pFocusQueue;
BOOL bExt = (dwFlags & KEYEVENTF_EXTENDEDKEY) ? TRUE : FALSE;
BOOL bIsDown = (dwFlags & KEYEVENTF_KEYUP) ? FALSE : TRUE;
BOOL bPacket = (dwFlags & KEYEVENTF_UNICODE) ? TRUE : FALSE;
BOOL bWasSimpleDown = FALSE, bPostMsg = TRUE, bIsSimpleDown;
MSG Msg;
static BOOL bMenuDownRecently = FALSE;
/* Get virtual key without shifts (VK_(L|R)* -> VK_*) */
wSimpleVk = IntSimplifyVk(wVk);
bWasSimpleDown = IS_KEY_DOWN(gafAsyncKeyState, wSimpleVk);
/* Update key without shifts */
wVk2 = IntFixVk(wSimpleVk, !bExt);
bIsSimpleDown = bIsDown || IS_KEY_DOWN(gafAsyncKeyState, wVk2);
UpdateAsyncKeyState(wSimpleVk, bIsSimpleDown);
if (bIsDown)
{
/* Update keyboard LEDs */
IntKeyboardUpdateLeds(ghKeyboardDevice,
wSimpleVk,
wScanCode,
IS_KEY_LOCKED(gafAsyncKeyState, wSimpleVk));
}
/* Call WH_KEYBOARD_LL hook */
if (co_CallLowLevelKeyboardHook(wVk, wScanCode, dwFlags, bInjected, dwTime, dwExtraInfo))
{
ERR("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
Msg.message, Msg.wParam, Msg.lParam);
bPostMsg = FALSE;
}
/* Check if this is a hotkey */
if (co_UserProcessHotKeys(wSimpleVk, bIsDown))
bPostMsg = FALSE;
wFixedVk = IntFixVk(wSimpleVk, bExt); /* LSHIFT + EXT = RSHIFT */
if (wSimpleVk == VK_SHIFT) /* shift can't be extended */
bExt = FALSE;
/* If it is F10 or ALT is down and CTRL is up, it's a system key */
if (wVk == VK_F10 ||
(wSimpleVk == VK_MENU && bMenuDownRecently) ||
(IS_KEY_DOWN(gafAsyncKeyState, VK_MENU) &&
!IS_KEY_DOWN(gafAsyncKeyState, VK_CONTROL)))
{
bMenuDownRecently = FALSE; // reset
if (bIsDown)
{
Msg.message = WM_SYSKEYDOWN;
if (wSimpleVk == VK_MENU)
{
// Note: If only LALT is pressed WM_SYSKEYUP is generated instead of WM_KEYUP
bMenuDownRecently = TRUE;
}
}
else
Msg.message = WM_SYSKEYUP;
}
else
{
bMenuDownRecently = FALSE;
if (bIsDown)
Msg.message = WM_KEYDOWN;
else
Msg.message = WM_KEYUP;
}
/* Update async state of not simplified vk here.
See user32_apitest:GetKeyState */
UpdateAsyncKeyState(wFixedVk, bIsDown);
/* Alt-Tab/Esc Check. Use FocusQueue or RIT Queue */
if (bIsSimpleDown && !bWasSimpleDown &&
IS_KEY_DOWN(gafAsyncKeyState, VK_MENU) &&
!IS_KEY_DOWN(gafAsyncKeyState, VK_CONTROL) &&
(wVk == VK_ESCAPE || wVk == VK_TAB))
{
TRACE("Alt-Tab/Esc Pressed wParam %x\n",Msg.wParam);
}
/* If we have a focus queue, post a keyboard message */
pFocusQueue = IntGetFocusMessageQueue();
if (pFocusQueue && bPostMsg)
{
/* Init message */
Msg.hwnd = pFocusQueue->FocusWindow;
Msg.wParam = wFixedVk & 0xFF; /* Note: it's simplified by msg queue */
Msg.lParam = MAKELPARAM(1, wScanCode);
Msg.time = dwTime;
Msg.pt = gpsi->ptCursor;
/* If it is VK_PACKET, high word of wParam is used for wchar */
if (!bPacket)
{
if (bExt)
Msg.lParam |= KF_EXTENDED << 16;
if (IS_KEY_DOWN(gafAsyncKeyState, VK_MENU))
Msg.lParam |= KF_ALTDOWN << 16;
if (bWasSimpleDown)
Msg.lParam |= KF_REPEAT << 16;
if (!bIsDown)
Msg.lParam |= KF_UP << 16;
/* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
if (pFocusQueue->QF_flags & QF_DIALOGACTIVE)
Msg.lParam |= KF_DLGMODE << 16;
if (pFocusQueue->MenuOwner)//pFocusQueue->MenuState) // MenuState needs a start flag...
Msg.lParam |= KF_MENUMODE << 16;
}
/* Post a keyboard message */
TRACE("Posting keyboard msg %u wParam 0x%x lParam 0x%x\n", Msg.message, Msg.wParam, Msg.lParam);
MsqPostMessage(pFocusQueue, &Msg, TRUE, QS_KEY);
}
return TRUE;
}
BOOL NTAPI
UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
{
WORD wScanCode, wVk, wSimpleVk = 0, wVkOtherSide, wSysKey;
WORD wScanCode, wVk;
PKBL pKbl = NULL;
PKBDTABLES pKbdTbl;
PUSER_MESSAGE_QUEUE pFocusQueue;
struct _ETHREAD *pFocusThread;
LARGE_INTEGER LargeTickCount;
DWORD dwTime;
BOOL bExt = (pKbdInput->dwFlags & KEYEVENTF_EXTENDEDKEY) ? TRUE : FALSE;
BOOL bIsDown = (pKbdInput->dwFlags & KEYEVENTF_KEYUP) ? FALSE : TRUE;
BOOL bWasDown = FALSE, bPostMsg = TRUE;
MSG Msg;
/* Find the target thread whose locale is in effect */
pFocusQueue = IntGetFocusMessageQueue();
@@ -713,7 +833,7 @@ UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
pKbdTbl = pKbl->KBTables;
/* Note: wScan field is always used */
wScanCode = pKbdInput->wScan & 0x7F;
wScanCode = pKbdInput->wScan;
if (pKbdInput->dwFlags & KEYEVENTF_UNICODE)
{
@@ -723,6 +843,7 @@ UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
}
else
{
wScanCode &= 0x7F;
if (pKbdInput->dwFlags & KEYEVENTF_SCANCODE)
{
/* Don't ignore invalid scan codes */
@@ -733,129 +854,26 @@ UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected)
else
{
wVk = pKbdInput->wVk & 0xFF;
/* LSHIFT + EXT = RSHIFT */
wVk = IntSimplifyVk(wVk);
wVk = IntFixVk(wVk, bExt);
}
/* Get virtual key without shifts (VK_(L|R)* -> VK_*) */
wSimpleVk = IntSimplifyVk(wVk);
wVkOtherSide = IntGetVkOtherSide(wVk);
bWasDown = IS_KEY_DOWN(gafAsyncKeyState, wSimpleVk);
if (co_UserProcessHotKeys(wSimpleVk, bIsDown))
bPostMsg = FALSE;
/* Update key without shifts */
UpdateAsyncKeyState(wSimpleVk, bIsDown || IS_KEY_DOWN(gafAsyncKeyState, wVkOtherSide));
}
/* If it is F10 or ALT is down and CTRL is up, it's a system key */
wSysKey = (pKbdTbl->fLocaleFlags & KLLF_ALTGR) ? VK_LMENU : VK_MENU;
if (wVk == VK_F10 ||
//uVkNoShift == VK_MENU || // FIXME: If only LALT is pressed WM_SYSKEYUP is generated instead of WM_KEYUP
(IS_KEY_DOWN(gafAsyncKeyState, wSysKey) && // FIXME
!IS_KEY_DOWN(gafAsyncKeyState, VK_CONTROL)))
{
if (bIsDown)
Msg.message = WM_SYSKEYDOWN;
else
Msg.message = WM_SYSKEYUP;
}
else
{
if (bIsDown)
Msg.message = WM_KEYDOWN;
else
Msg.message = WM_KEYUP;
}
/* Init hwnd and lParam */
Msg.hwnd = pFocusQueue->FocusWindow;
Msg.lParam = MAKELPARAM(1, wScanCode);
/* If it is VK_PACKET, high word of wParam is used for wchar */
if (!(pKbdInput->dwFlags & KEYEVENTF_UNICODE))
{
if (bExt)
Msg.lParam |= LP_EXT_BIT;
if (IS_KEY_DOWN(gafAsyncKeyState, VK_MENU))
Msg.lParam |= LP_CONTEXT_BIT;
if (bWasDown)
Msg.lParam |= LP_PREV_STATE_BIT;
if (!bIsDown)
Msg.lParam |= LP_TRANSITION_BIT;
}
/* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
if ( pFocusQueue && pFocusQueue->QF_flags & QF_DIALOGACTIVE )
Msg.lParam |= LP_DLGMODE;
if ( pFocusQueue && pFocusQueue->MenuOwner )//pFocusQueue->MenuState ) // MenuState needs a start flag...
Msg.lParam |= LP_MENUMODE;
/* Init wParam and cursor position */
Msg.wParam = wVk; // Note: it's simplified by msg queue
Msg.pt = gpsi->ptCursor;
/* If time is given, use it */
if (pKbdInput->time)
Msg.time = pKbdInput->time;
dwTime = pKbdInput->time;
else
{
KeQueryTickCount(&LargeTickCount);
Msg.time = MsqCalculateMessageTime(&LargeTickCount);
dwTime = MsqCalculateMessageTime(&LargeTickCount);
}
if (!(pKbdInput->dwFlags & KEYEVENTF_UNICODE))
if (wVk == VK_RMENU && (pKbdTbl->fLocaleFlags & KLLF_ALTGR))
{
if (bIsDown)
{
/* Update keyboard LEDs */
if (!gpKeyboardIndicatorTrans)
IntKeyboardGetIndicatorTrans(ghKeyboardDevice, &gpKeyboardIndicatorTrans);
if (gpKeyboardIndicatorTrans)
IntKeyboardUpdateLeds(ghKeyboardDevice,
wScanCode,
IS_KEY_LOCKED(gafAsyncKeyState, wVk),
gpKeyboardIndicatorTrans);
}
/* Call hook */
if (co_CallLowLevelKeyboardHook(&Msg, bInjected, pKbdInput->dwExtraInfo))
{
ERR("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
Msg.message, Msg.wParam, Msg.lParam);
bPostMsg = FALSE;
}
/* Update async state of not simplified vk here.
See user32_apitest:GetKeyState */
UpdateAsyncKeyState(wVk, bIsDown);
/* Support VK_*MENU keys */
if (!bIsDown && wSimpleVk == VK_MENU && !IS_KEY_DOWN(gafAsyncKeyState, VK_CONTROL))
co_IntKeyboardSendAltKeyMsg();
/* For AltGr keyboards RALT generates CTRL events */
ProcessKeyEvent(VK_LCONTROL, 0, pKbdInput->dwFlags & KEYEVENTF_KEYUP, bInjected, dwTime, 0);
}
/* Alt-Tab/Esc Check. Use FocusQueue or RIT Queue */
if (!(pKbdInput->dwFlags & KEYEVENTF_KEYUP) &&
HIWORD(Msg.lParam) & KF_ALTDOWN &&
( Msg.wParam == VK_ESCAPE || Msg.wParam == VK_TAB ) )
{
TRACE("Alt-Tab/Esc Pressed wParam %x\n",Msg.wParam);
}
/* If we have a focus queue, post a keyboard message */
if (pFocusQueue && bPostMsg)
{
/* Post a keyboard message */
TRACE("Posting keyboard msg %u wParam 0x%x lParam 0x%x\n", Msg.message, Msg.wParam, Msg.lParam);
//co_MsqPostKeyboardMessage(Msg.message, Msg.wParam, Msg.lParam, bInjected);
MsqPostMessage(pFocusQueue, &Msg, TRUE, QS_KEY);
}
return TRUE;
/* Finally process this key */
return ProcessKeyEvent(wVk, wScanCode, pKbdInput->dwFlags, bInjected, dwTime, pKbdInput->dwExtraInfo);
}
/*
@@ -1102,7 +1120,7 @@ NtUserMapVirtualKeyEx(UINT uCode, UINT uType, DWORD keyboardId, HKL dwhkl)
UINT ret = 0;
TRACE("Enter NtUserMapVirtualKeyEx\n");
UserEnterExclusive();
UserEnterShared();
if (!dwhkl)
{
@@ -1188,7 +1206,7 @@ NtUserToUnicodeEx(
}
RtlZeroMemory(pwszBuff, sizeof(WCHAR) * cchBuff);
UserEnterShared();
UserEnterExclusive(); // Note: we modify wchDead static variable
if (dwhkl)
pKbl = UserHklToKbl(dwhkl);
@@ -1227,7 +1245,7 @@ NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
PTHREADINFO pti;
DWORD i, cchKeyName, dwRet = 0;
WORD wScanCode = (lParam >> 16) & 0xFF;
BOOL bExtKey = (lParam & LP_EXT_BIT) ? TRUE : FALSE;
BOOL bExtKey = (HIWORD(lParam) & KF_EXTENDED) ? TRUE : FALSE;
PKBDTABLES pKbdTbl;
VSC_LPWSTR *pKeyNames = NULL;
CONST WCHAR *pKeyName = NULL;
@@ -1235,6 +1253,8 @@ NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
TRACE("Enter NtUserGetKeyNameText\n");
UserEnterShared();
/* Get current keyboard layout */
pti = PsGetCurrentThreadWin32Thread();
pKbdTbl = pti ? pti->KeyboardLayout->KBTables : 0;
@@ -1242,11 +1262,9 @@ NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
if (!pKbdTbl || cchSize < 1)
{
ERR("Invalid parameter\n");
return 0;
goto cleanup;
}
UserEnterShared();
/* "Do not care" flag */
if(lParam & LP_DO_NOT_CARE_BIT)
{
@@ -1309,6 +1327,7 @@ NtUserGetKeyNameText(LONG lParam, LPWSTR lpString, int cchSize)
EngSetLastError(ERROR_INVALID_PARAMETER);
}
cleanup:
UserLeave();
TRACE("Leave NtUserGetKeyNameText, ret=%i\n", dwRet);
return dwRet;
@@ -663,10 +663,10 @@ MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
id = wParam; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
Mesg.hwnd = hWnd;
Mesg.message = id != IDHOT_REACTOS ? WM_HOTKEY : WM_SYSCOMMAND;
Mesg.wParam = id != IDHOT_REACTOS ? wParam : SC_HOTKEY;
Mesg.lParam = id != IDHOT_REACTOS ? lParam : (LPARAM)hWnd;
Type = id != IDHOT_REACTOS ? QS_HOTKEY : QS_POSTMESSAGE;
Mesg.message = id != IDHK_REACTOS ? WM_HOTKEY : WM_SYSCOMMAND;
Mesg.wParam = id != IDHK_REACTOS ? wParam : SC_HOTKEY;
Mesg.lParam = id != IDHK_REACTOS ? lParam : (LPARAM)hWnd;
Type = id != IDHK_REACTOS ? QS_HOTKEY : QS_POSTMESSAGE;
KeQueryTickCount(&LargeTickCount);
Mesg.time = MsqCalculateMessageTime(&LargeTickCount);
Mesg.pt = gpsi->ptCursor;