[NTUSER] Implement NtUserSetImeHotKey (#4350)

- Modify NtUserGetImeHotKey and NtUserSetImeHotKey prototypes.
- Define enum SETIMEHOTKEY_ACTION in <undocuser.h>.
- Define IMEHOTKEY structure in ime.c.
- Add IntGetImeHotKeyLangId, IntAddImeHotKey, IntGetImeHotKeyById, IntGetImeHotKeyByKeyAndLang, IntDeleteImeHotKey, IntFreeImeHotKeys, and IntSetImeHotKey helper functions.
- Implement NtUserGetImeHotKey and NtUserSetImeHotKey functions.
- Cleanup the IME hotkeys at process exit.
CORE-11700
This commit is contained in:
Katayama Hirofumi MZ 2022-02-09 11:27:44 +09:00 committed by GitHub
parent e0fc48d6e2
commit 5d5cc57869
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 280 additions and 36 deletions

View file

@ -394,6 +394,14 @@ typedef enum _QUERY_INPUT_CONTEXT
QIC_DEFAULTIMC
} QUERY_INPUT_CONTEXT;
/* NtUserSetImeHotKey actions */
typedef enum tagSETIMEHOTKEY_ACTION
{
SETIMEHOTKEY_DELETE = 1,
SETIMEHOTKEY_ADD,
SETIMEHOTKEY_DELETEALL
} SETIMEHOTKEY_ACTION;
#ifdef __cplusplus
} /* extern "C" */
#endif /* defined(__cplusplus) */

View file

@ -2388,11 +2388,12 @@ NtUserGetIconSize(
LONG *plcx,
LONG *plcy);
BOOL NTAPI
NtUserGetImeHotKey(IN DWORD dwHotKey,
OUT LPUINT lpuModifiers,
OUT LPUINT lpuVKey,
OUT LPHKL lphKL);
BOOL
NTAPI
NtUserGetImeHotKey(DWORD dwHotKeyId,
LPUINT lpuModifiers,
LPUINT lpuVirtualKey,
LPHKL lphKL);
BOOL
NTAPI
@ -3184,14 +3185,14 @@ NTAPI
NtUserSetFocus(
HWND hWnd);
DWORD
BOOL
NTAPI
NtUserSetImeHotKey(
DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3,
DWORD Unknown4);
DWORD dwHotKeyId,
UINT uModifiers,
UINT uVirtualKey,
HKL hKL,
DWORD dwAction);
BOOL
NTAPI

View file

@ -11,6 +11,14 @@
DBG_DEFAULT_CHANNEL(UserMisc);
#define INVALID_THREAD_ID ((ULONG)-1)
#define MOD_KEYS (MOD_CONTROL | MOD_SHIFT | MOD_ALT | MOD_WIN)
#define MOD_LEFT_RIGHT (MOD_LEFT | MOD_RIGHT)
#define LANGID_CHINESE_SIMPLIFIED MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)
#define LANGID_JAPANESE MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)
#define LANGID_KOREAN MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN)
#define LANGID_CHINESE_TRADITIONAL MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL)
#define LANGID_NEUTRAL MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
#define IS_WND_IMELIKE(pwnd) \
(((pwnd)->pcls->style & CS_IME) || \
@ -37,6 +45,255 @@ HIMC ghIMC = NULL;
BOOL gfImeOpen = (BOOL)-1;
DWORD gdwImeConversion = (DWORD)-1;
typedef struct tagIMEHOTKEY
{
struct tagIMEHOTKEY *pNext;
DWORD dwHotKeyId;
UINT uVirtualKey;
UINT uModifiers;
HKL hKL;
} IMEHOTKEY, *PIMEHOTKEY;
PIMEHOTKEY gpImeHotKeyList = NULL;
static LANGID FASTCALL IntGetImeHotKeyLangId(DWORD dwHotKeyId)
{
#define IME_CHOTKEY 0x10
#define IME_JHOTKEY 0x30
#define IME_KHOTKEY 0x50
#define IME_THOTKEY 0x70
#define IME_XHOTKEY 0x90
static const LANGID s_array[] =
{
/* 0x00 */ (WORD)-1,
/* 0x10 */ LANGID_CHINESE_SIMPLIFIED,
/* 0x20 */ LANGID_CHINESE_SIMPLIFIED,
/* 0x30 */ LANGID_JAPANESE,
/* 0x40 */ LANGID_JAPANESE,
/* 0x50 */ LANGID_KOREAN,
/* 0x60 */ LANGID_KOREAN,
/* 0x70 */ LANGID_CHINESE_TRADITIONAL,
/* 0x80 */ LANGID_CHINESE_TRADITIONAL
};
if (IME_CHOTKEY <= dwHotKeyId && dwHotKeyId < IME_XHOTKEY)
return s_array[(dwHotKeyId & 0xF0) >> 4];
return LANGID_NEUTRAL;
}
static VOID FASTCALL IntAddImeHotKey(PIMEHOTKEY *ppList, PIMEHOTKEY pHotKey)
{
PIMEHOTKEY pNode;
if (!*ppList)
{
*ppList = pHotKey;
return;
}
for (pNode = *ppList; pNode; pNode = pNode->pNext)
{
if (!pNode->pNext)
{
pNode->pNext = pHotKey;
return;
}
}
}
static PIMEHOTKEY FASTCALL IntGetImeHotKeyById(PIMEHOTKEY pList, DWORD dwHotKeyId)
{
PIMEHOTKEY pNode;
for (pNode = pList; pNode; pNode = pNode->pNext)
{
if (pNode->dwHotKeyId == dwHotKeyId)
return pNode;
}
return NULL;
}
static PIMEHOTKEY APIENTRY
IntGetImeHotKeyByKeyAndLang(PIMEHOTKEY pList, UINT uModKeys, UINT uLeftRight,
UINT uVirtualKey, LANGID TargetLangId)
{
PIMEHOTKEY pNode;
LANGID LangID;
UINT uModifiers;
for (pNode = pList; pNode; pNode = pNode->pNext)
{
if (pNode->uVirtualKey != uVirtualKey)
continue;
LangID = IntGetImeHotKeyLangId(pNode->dwHotKeyId);
if (LangID != TargetLangId)
continue;
uModifiers = pNode->uModifiers;
if (uModifiers & MOD_IGNORE_ALL_MODIFIER)
return pNode;
if ((uModifiers & MOD_KEYS) != uModKeys)
continue;
if ((uModifiers & uLeftRight) || (uModifiers & MOD_LEFT_RIGHT) == uLeftRight)
return pNode;
}
return NULL;
}
static VOID FASTCALL IntDeleteImeHotKey(PIMEHOTKEY *ppList, PIMEHOTKEY pHotKey)
{
PIMEHOTKEY pNode;
if (*ppList == pHotKey)
{
*ppList = pHotKey->pNext;
ExFreePoolWithTag(pHotKey, USERTAG_IMEHOTKEY);
return;
}
for (pNode = *ppList; pNode; pNode = pNode->pNext)
{
if (pNode->pNext == pHotKey)
{
pNode->pNext = pHotKey->pNext;
ExFreePoolWithTag(pHotKey, USERTAG_IMEHOTKEY);
return;
}
}
}
VOID FASTCALL IntFreeImeHotKeys(VOID)
{
PIMEHOTKEY pNode, pNext;
for (pNode = gpImeHotKeyList; pNode; pNode = pNext)
{
pNext = pNode->pNext;
ExFreePoolWithTag(pNode, USERTAG_IMEHOTKEY);
}
gpImeHotKeyList = NULL;
}
static BOOL APIENTRY
IntSetImeHotKey(DWORD dwHotKeyId, UINT uModifiers, UINT uVirtualKey, HKL hKL, DWORD dwAction)
{
PIMEHOTKEY pNode;
LANGID LangId;
switch (dwAction)
{
case SETIMEHOTKEY_DELETE:
pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId);
if (!pNode)
return FALSE;
IntDeleteImeHotKey(&gpImeHotKeyList, pNode);
return TRUE;
case SETIMEHOTKEY_ADD:
if (uVirtualKey == VK_PACKET)
return FALSE;
LangId = IntGetImeHotKeyLangId(dwHotKeyId);
if (LangId == LANGID_KOREAN)
return FALSE;
pNode = IntGetImeHotKeyByKeyAndLang(gpImeHotKeyList,
(uModifiers & MOD_KEYS),
(uModifiers & MOD_LEFT_RIGHT),
uVirtualKey, LangId);
if (!pNode)
pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId);
if (pNode)
{
pNode->uModifiers = uModifiers;
pNode->uVirtualKey = uVirtualKey;
pNode->hKL = hKL;
return TRUE;
}
pNode = ExAllocatePoolWithTag(PagedPool, sizeof(IMEHOTKEY), USERTAG_IMEHOTKEY);
if (!pNode)
return FALSE;
pNode->pNext = NULL;
pNode->dwHotKeyId = dwHotKeyId;
pNode->uModifiers = uModifiers;
pNode->uVirtualKey = uVirtualKey;
pNode->hKL = hKL;
IntAddImeHotKey(&gpImeHotKeyList, pNode);
return TRUE;
case SETIMEHOTKEY_DELETEALL:
IntFreeImeHotKeys();
return TRUE;
default:
return FALSE;
}
}
BOOL NTAPI
NtUserGetImeHotKey(DWORD dwHotKeyId, LPUINT lpuModifiers, LPUINT lpuVirtualKey, LPHKL lphKL)
{
PIMEHOTKEY pNode = NULL;
UserEnterExclusive();
_SEH2_TRY
{
ProbeForWrite(lpuModifiers, sizeof(UINT), 1);
ProbeForWrite(lpuVirtualKey, sizeof(UINT), 1);
if (lphKL)
ProbeForWrite(lphKL, sizeof(HKL), 1);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
goto Quit;
}
_SEH2_END;
pNode = IntGetImeHotKeyById(gpImeHotKeyList, dwHotKeyId);
if (!pNode)
goto Quit;
_SEH2_TRY
{
*lpuModifiers = pNode->uModifiers;
*lpuVirtualKey = pNode->uVirtualKey;
if (lphKL)
*lphKL = pNode->hKL;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
pNode = NULL;
}
_SEH2_END;
Quit:
UserLeave();
return !!pNode;
}
BOOL
NTAPI
NtUserSetImeHotKey(
DWORD dwHotKeyId,
UINT uModifiers,
UINT uVirtualKey,
HKL hKL,
DWORD dwAction)
{
BOOL ret;
UserEnterExclusive();
ret = IntSetImeHotKey(dwHotKeyId, uModifiers, uVirtualKey, hKL, dwAction);
UserLeave();
return ret;
}
PWND FASTCALL IntGetTopLevelWindow(PWND pwnd)
{
if (!pwnd)
@ -194,17 +451,6 @@ Quit:
return ret;
}
BOOL WINAPI
NtUserGetImeHotKey(IN DWORD dwHotKey,
OUT LPUINT lpuModifiers,
OUT LPUINT lpuVKey,
OUT LPHKL lphKL)
{
STUB
return FALSE;
}
static VOID FASTCALL UserSetImeConversionKeyState(PTHREADINFO pti, DWORD dwConversion)
{
HKL hKL;
@ -305,20 +551,6 @@ Quit:
return 0;
}
DWORD
APIENTRY
NtUserSetImeHotKey(
DWORD Unknown0,
DWORD Unknown1,
DWORD Unknown2,
DWORD Unknown3,
DWORD Unknown4)
{
STUB
return 0;
}
DWORD
APIENTRY
NtUserCheckImeHotKey(

View file

@ -85,6 +85,7 @@ BOOL NTAPI UserSendMouseInput(MOUSEINPUT *pMouseInput, BOOL bInjected);
/* IMM */
UINT FASTCALL IntImmProcessKey(PUSER_MESSAGE_QUEUE, PWND, UINT, WPARAM, LPARAM);
VOID FASTCALL IntFreeImeHotKeys(VOID);
extern DWORD gSystemFS;
extern UINT gSystemCPCharSet;

View file

@ -180,6 +180,8 @@ UserProcessDestroy(PEPROCESS Process)
if (ppiScrnSaver == ppiCurrent)
ppiScrnSaver = NULL;
IntFreeImeHotKeys();
if (gpwlCache)
{
ExFreePoolWithTag(gpwlCache, USERTAG_WINDOWLIST);