https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5d5cc578697966c5171fb81ad2b59fef3744fb22

commit 5d5cc578697966c5171fb81ad2b59fef3744fb22
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Wed Feb 9 11:27:44 2022 +0900
Commit:     GitHub <[email protected]>
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);

Reply via email to