https://git.reactos.org/?p=reactos.git;a=commitdiff;h=5d5cc578697966c5171fb8...
commit 5d5cc578697966c5171fb81ad2b59fef3744fb22 Author: Katayama Hirofumi MZ katayama.hirofumi.mz@gmail.com AuthorDate: Wed Feb 9 11:27:44 2022 +0900 Commit: GitHub noreply@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);