mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 19:26:32 +00:00
[WIN32K]
- 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:
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user