https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7396ba84ce54f4841913289da17e3cb9a98edbb4

commit 7396ba84ce54f4841913289da17e3cb9a98edbb4
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Wed May 11 10:03:02 2022 +0900
Commit:     GitHub <[email protected]>
CommitDate: Wed May 11 10:03:02 2022 +0900

    [USER32] Implement UnloadKeyboardLayout (#4503)
    
    - Add IntSetFeKeyboardFlags, CliImmSetHotKeyWorker, 
CliSetDefaultImeHotKeys, CliGetPreloadKeyboardLayouts, 
CliGetImeHotKeysFromRegistry, CliImmInitializeHotKeys, CliSetSingleHotKey, and 
CliReadRegistryValue helper functions.
    CORE-11700
---
 win32ss/user/user32/user32.spec     |   2 +-
 win32ss/user/user32/windows/input.c | 285 ++++++++++++++++++++++++++++++++++++
 2 files changed, 286 insertions(+), 1 deletion(-)

diff --git a/win32ss/user/user32/user32.spec b/win32ss/user/user32/user32.spec
index 9e87f95c49f..c026984892a 100644
--- a/win32ss/user/user32/user32.spec
+++ b/win32ss/user/user32/user32.spec
@@ -703,7 +703,7 @@
 694 stdcall UnhookWindowsHook(long ptr)
 695 stdcall UnhookWindowsHookEx(long) NtUserUnhookWindowsHookEx
 696 stdcall UnionRect(ptr ptr ptr)
-697 stdcall UnloadKeyboardLayout(long) NtUserUnloadKeyboardLayout
+697 stdcall UnloadKeyboardLayout(ptr)
 698 stdcall UnlockWindowStation(long) NtUserUnlockWindowStation
 699 stdcall UnpackDDElParam(long long ptr ptr)
 700 stdcall UnregisterClassA(str long)
diff --git a/win32ss/user/user32/windows/input.c 
b/win32ss/user/user32/windows/input.c
index aa398d7dcc5..4cd7832d7b3 100644
--- a/win32ss/user/user32/windows/input.c
+++ b/win32ss/user/user32/windows/input.c
@@ -31,6 +31,279 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(user32);
 
+typedef struct tagIMEHOTKEYENTRY
+{
+    DWORD  dwHotKeyId;
+    UINT   uVirtualKey;
+    UINT   uModifiers;
+    HKL    hKL;
+} IMEHOTKEYENTRY, *PIMEHOTKEYENTRY;
+
+// Japanese
+IMEHOTKEYENTRY DefaultHotKeyTableJ[] =
+{
+    { IME_JHOTKEY_CLOSE_OPEN, VK_KANJI, MOD_IGNORE_ALL_MODIFIER, NULL },
+};
+
+// Chinese Traditional
+IMEHOTKEYENTRY DefaultHotKeyTableT[] =
+{
+    { IME_THOTKEY_IME_NONIME_TOGGLE, VK_SPACE, MOD_LEFT | MOD_RIGHT | 
MOD_CONTROL, NULL },
+    { IME_THOTKEY_SHAPE_TOGGLE, VK_SPACE, MOD_LEFT | MOD_RIGHT | MOD_SHIFT, 
NULL },
+};
+
+// Chinese Simplified
+IMEHOTKEYENTRY DefaultHotKeyTableC[] =
+{
+    { IME_CHOTKEY_IME_NONIME_TOGGLE, VK_SPACE, MOD_LEFT | MOD_RIGHT | 
MOD_CONTROL, NULL },
+    { IME_CHOTKEY_SHAPE_TOGGLE, VK_SPACE, MOD_LEFT | MOD_RIGHT | MOD_SHIFT, 
NULL },
+};
+
+// The far-east flags
+#define FE_JAPANESE             (1 << 0)
+#define FE_CHINESE_TRADITIONAL  (1 << 1)
+#define FE_CHINESE_SIMPLIFIED   (1 << 2)
+#define FE_KOREAN               (1 << 3)
+
+// Sets the far-east flags
+// Win: SetFeKeyboardFlags
+VOID FASTCALL IntSetFeKeyboardFlags(LANGID LangID, PBYTE pbFlags)
+{
+    switch (LangID)
+    {
+        case MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT):
+            *pbFlags |= FE_JAPANESE;
+            break;
+
+        case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL):
+        case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_HONGKONG):
+            *pbFlags |= FE_CHINESE_TRADITIONAL;
+            break;
+
+        case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED):
+        case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SINGAPORE):
+            *pbFlags |= FE_CHINESE_SIMPLIFIED;
+            break;
+
+        case MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN):
+            *pbFlags |= FE_KOREAN;
+            break;
+
+        default:
+            break;
+    }
+}
+
+DWORD FASTCALL CliReadRegistryValue(HANDLE hKey, LPCWSTR pszName)
+{
+    DWORD dwValue, cbValue;
+    LONG error;
+
+    cbValue = sizeof(dwValue);
+    error = RegQueryValueExW(hKey, pszName, NULL, NULL, (LPBYTE)&dwValue, 
&cbValue);
+    if (error != ERROR_SUCCESS || cbValue < sizeof(DWORD))
+        return 0;
+
+    return dwValue;
+}
+
+BOOL APIENTRY
+CliImmSetHotKeyWorker(DWORD dwHotKeyId, UINT uModifiers, UINT uVirtualKey, HKL 
hKL, DWORD dwAction)
+{
+    if (dwAction == SETIMEHOTKEY_ADD)
+    {
+        if (IME_HOTKEY_DSWITCH_FIRST <= dwHotKeyId && dwHotKeyId <= 
IME_HOTKEY_DSWITCH_LAST)
+        {
+            if (!hKL)
+                goto Failure;
+        }
+        else
+        {
+            if (hKL)
+                goto Failure;
+
+            if (IME_KHOTKEY_SHAPE_TOGGLE <= dwHotKeyId &&
+                dwHotKeyId < IME_THOTKEY_IME_NONIME_TOGGLE)
+            {
+                // The Korean cannot set the IME hotkeys
+                goto Failure;
+            }
+        }
+
+#define MOD_ALL_MODS (MOD_ALT | MOD_CONTROL | MOD_SHIFT | MOD_WIN)
+        if ((uModifiers & MOD_ALL_MODS) && !(uModifiers & (MOD_LEFT | 
MOD_RIGHT)))
+            goto Failure;
+#undef MOD_ALL_MODS
+    }
+
+    return NtUserSetImeHotKey(dwHotKeyId, uModifiers, uVirtualKey, hKL, 
dwAction);
+
+Failure:
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return FALSE;
+}
+
+BOOL FASTCALL CliSetSingleHotKey(LPCWSTR pszSubKey, HANDLE hKey)
+{
+    LONG error;
+    HKEY hSubKey;
+    DWORD dwHotKeyId = 0;
+    UINT uModifiers = 0, uVirtualKey = 0;
+    HKL hKL = NULL;
+    UNICODE_STRING ustrName;
+
+    error = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hSubKey);
+    if (error != ERROR_SUCCESS)
+        return FALSE;
+
+    RtlInitUnicodeString(&ustrName, pszSubKey);
+    RtlUnicodeStringToInteger(&ustrName, 16, &dwHotKeyId);
+
+    uModifiers = CliReadRegistryValue(hSubKey, L"Key Modifiers");
+    hKL = (HKL)(ULONG_PTR)CliReadRegistryValue(hSubKey, L"Target IME");
+    uVirtualKey = CliReadRegistryValue(hSubKey, L"Virtual Key");
+
+    RegCloseKey(hSubKey);
+
+    return CliImmSetHotKeyWorker(dwHotKeyId, uModifiers, uVirtualKey, hKL, 
SETIMEHOTKEY_ADD);
+}
+
+BOOL FASTCALL CliGetImeHotKeysFromRegistry(VOID)
+{
+    HKEY hKey;
+    LONG error;
+    BOOL ret = FALSE;
+    DWORD dwIndex, cchKeyName;
+    WCHAR szKeyName[16];
+
+    error = RegOpenKeyExW(HKEY_CURRENT_USER,
+                          L"Control Panel\\Input Method\\Hot Keys",
+                          0,
+                          KEY_ALL_ACCESS,
+                          &hKey);
+    if (error != ERROR_SUCCESS)
+        return ret;
+
+    for (dwIndex = 0; ; ++dwIndex)
+    {
+        cchKeyName = _countof(szKeyName);
+        error = RegEnumKeyExW(hKey, dwIndex, szKeyName, &cchKeyName, NULL, 
NULL, NULL, NULL);
+        if (error == ERROR_NO_MORE_ITEMS || error != ERROR_SUCCESS)
+            break;
+
+        szKeyName[_countof(szKeyName) - 1] = 0;
+
+        if (CliSetSingleHotKey(szKeyName, hKey))
+            ret = TRUE;
+    }
+
+    RegCloseKey(hKey);
+    return ret;
+}
+
+VOID APIENTRY CliGetPreloadKeyboardLayouts(PBYTE pbFlags)
+{
+    WCHAR szValueName[8], szValue[16];
+    UNICODE_STRING ustrValue;
+    DWORD dwKL, cbValue, dwType;
+    UINT iNumber;
+    HKEY hKey;
+    LONG error;
+
+    error = RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, 
KEY_READ, &hKey);
+    if (error != ERROR_SUCCESS)
+        return;
+
+    for (iNumber = 1; iNumber < 1000; ++iNumber)
+    {
+        StringCchPrintfW(szValueName, _countof(szValueName), L"%u", iNumber);
+
+        cbValue = sizeof(szValue);
+        error = RegQueryValueExW(hKey, szValueName, NULL, &dwType, 
(LPBYTE)szValue, &cbValue);
+        if (error != ERROR_SUCCESS || dwType != REG_SZ)
+            break;
+
+        szValue[_countof(szValue) - 1] = 0;
+
+        RtlInitUnicodeString(&ustrValue, szValue);
+        RtlUnicodeStringToInteger(&ustrValue, 16, &dwKL);
+
+        IntSetFeKeyboardFlags(LOWORD(dwKL), pbFlags);
+    }
+
+    RegCloseKey(hKey);
+}
+
+VOID APIENTRY CliSetDefaultImeHotKeys(PIMEHOTKEYENTRY pEntries, UINT nCount, 
BOOL bCheck)
+{
+    UINT uVirtualKey, uModifiers;
+    HKL hKL;
+
+    while (nCount-- > 0)
+    {
+        if (!bCheck || !NtUserGetImeHotKey(pEntries->dwHotKeyId, &uModifiers, 
&uVirtualKey, &hKL))
+        {
+            CliImmSetHotKeyWorker(pEntries->dwHotKeyId,
+                                  pEntries->uModifiers,
+                                  pEntries->uVirtualKey,
+                                  pEntries->hKL,
+                                  SETIMEHOTKEY_ADD);
+        }
+        ++pEntries;
+    }
+}
+
+VOID APIENTRY CliImmInitializeHotKeys(DWORD dwAction, HKL hKL)
+{
+    UINT nCount;
+    LPHKL pList;
+    UINT iIndex;
+    LANGID LangID;
+    BYTE bFlags = 0;
+    BOOL bCheck;
+
+    NtUserSetImeHotKey(0, 0, 0, NULL, SETIMEHOTKEY_DELETEALL);
+
+    bCheck = CliGetImeHotKeysFromRegistry();
+
+    if (dwAction == SETIMEHOTKEY_DELETEALL)
+    {
+        LangID = LANGIDFROMLCID(GetUserDefaultLCID());
+        IntSetFeKeyboardFlags(LangID, &bFlags);
+
+        CliGetPreloadKeyboardLayouts(&bFlags);
+    }
+    else
+    {
+        nCount = NtUserGetKeyboardLayoutList(0, NULL);
+        if (!nCount)
+            return;
+
+        pList = RtlAllocateHeap(RtlGetProcessHeap(), 0, nCount * sizeof(HKL));
+        if (!pList)
+            return;
+
+        NtUserGetKeyboardLayoutList(nCount, pList);
+
+        for (iIndex = 0; iIndex < nCount; ++iIndex)
+        {
+            LangID = LOWORD(pList[iIndex]);
+            IntSetFeKeyboardFlags(LangID, &bFlags);
+        }
+
+        RtlFreeHeap(RtlGetProcessHeap(), 0, pList);
+    }
+
+    if (bFlags & FE_JAPANESE)
+        CliSetDefaultImeHotKeys(DefaultHotKeyTableJ, 
_countof(DefaultHotKeyTableJ), bCheck);
+
+    if (bFlags & FE_CHINESE_TRADITIONAL)
+        CliSetDefaultImeHotKeys(DefaultHotKeyTableT, 
_countof(DefaultHotKeyTableT), bCheck);
+
+    if (bFlags & FE_CHINESE_SIMPLIFIED)
+        CliSetDefaultImeHotKeys(DefaultHotKeyTableC, 
_countof(DefaultHotKeyTableC), bCheck);
+}
+
 /*
  * @implemented
  */
@@ -330,6 +603,18 @@ LoadKeyboardLayoutW(LPCWSTR pwszKLID,
                                       dwhkl, Flags);
 }
 
+/*
+ * @implemented
+ */
+BOOL WINAPI UnloadKeyboardLayout(HKL hKL)
+{
+    if (!NtUserUnloadKeyboardLayout(hKL))
+        return FALSE;
+
+    CliImmInitializeHotKeys(SETIMEHOTKEY_DELETE, hKL);
+    return TRUE;
+}
+
 /*
  * @implemented
  */

Reply via email to