https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5d5cc578697966c5171fb…
commit 5d5cc578697966c5171fb81ad2b59fef3744fb22
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Wed Feb 9 11:27:44 2022 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Wed Feb 9 11:27:44 2022 +0900
[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
---
sdk/include/reactos/undocuser.h | 8 ++
win32ss/include/ntuser.h | 23 ++--
win32ss/user/ntuser/ime.c | 282 ++++++++++++++++++++++++++++++++++++----
win32ss/user/ntuser/input.h | 1 +
win32ss/user/ntuser/main.c | 2 +
5 files changed, 280 insertions(+), 36 deletions(-)
diff --git a/sdk/include/reactos/undocuser.h b/sdk/include/reactos/undocuser.h
index 3c0ebb3c149..f396c58a7ba 100644
--- a/sdk/include/reactos/undocuser.h
+++ b/sdk/include/reactos/undocuser.h
@@ -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) */
diff --git a/win32ss/include/ntuser.h b/win32ss/include/ntuser.h
index 6f897a24736..f792c08a2c0 100644
--- a/win32ss/include/ntuser.h
+++ b/win32ss/include/ntuser.h
@@ -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
diff --git a/win32ss/user/ntuser/ime.c b/win32ss/user/ntuser/ime.c
index 5c67c673afe..25adc48265d 100644
--- a/win32ss/user/ntuser/ime.c
+++ b/win32ss/user/ntuser/ime.c
@@ -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(
diff --git a/win32ss/user/ntuser/input.h b/win32ss/user/ntuser/input.h
index bd185a12c04..3cae36048f1 100644
--- a/win32ss/user/ntuser/input.h
+++ b/win32ss/user/ntuser/input.h
@@ -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;
diff --git a/win32ss/user/ntuser/main.c b/win32ss/user/ntuser/main.c
index 62e1f157271..dfdf2d64c0b 100644
--- a/win32ss/user/ntuser/main.c
+++ b/win32ss/user/ntuser/main.c
@@ -180,6 +180,8 @@ UserProcessDestroy(PEPROCESS Process)
if (ppiScrnSaver == ppiCurrent)
ppiScrnSaver = NULL;
+ IntFreeImeHotKeys();
+
if (gpwlCache)
{
ExFreePoolWithTag(gpwlCache, USERTAG_WINDOWLIST);