Reactos

[IMM32_APITEST] Add KLID testcase (#6590)

Confirming keyboard layout
implementation by checking
HKL, KLID, and registry.
JIRA issue: CORE-19268
- Add KLID testcase.
- Check HKLs, KLIDs (Keyboard
Layout IDs), and related
registry, with using
user32!GetKeyboardLayoutList
function.

authored by

Katayama Hirofumi MZ and committed by
GitHub
e6c0081c 0c65ceca

+203 -1
+2 -1
modules/rostests/apitests/imm32/CMakeLists.txt
··· 10 10 ImmIsUIMessage.c 11 11 JapanImeConvTestA.c 12 12 JapanImeConvTestW.c 13 + KLID.c 13 14 testlist.c 14 15 resource.rc) 15 16 16 17 add_executable(imm32_apitest ${SOURCE}) 17 18 target_link_libraries(imm32_apitest wine ${PSEH_LIB}) 18 19 set_module_type(imm32_apitest win32cui) 19 - add_importlibs(imm32_apitest imm32 msvcrt user32 kernel32 ntdll) 20 + add_importlibs(imm32_apitest advapi32 imm32 msvcrt user32 kernel32 ntdll) 20 21 add_rostests_file(TARGET imm32_apitest)
+199
modules/rostests/apitests/imm32/KLID.c
··· 1 + /* 2 + * PROJECT: ReactOS api tests 3 + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 + * PURPOSE: Test for Keyboard Layout ID (KLID), HKL, and registry 5 + * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 6 + */ 7 + 8 + #include "precomp.h" 9 + 10 + #include <stdlib.h> 11 + #include <imm32_undoc.h> 12 + #include <strsafe.h> 13 + 14 + typedef enum tagHKL_TYPE 15 + { 16 + HKL_TYPE_PURE = 0, 17 + HKL_TYPE_SPECIAL = 1, 18 + HKL_TYPE_IME = 2, 19 + HKL_TYPE_CHIMERA = 3, 20 + } HKL_TYPE; 21 + 22 + static HKL_TYPE GetHKLType(HKL hKL) 23 + { 24 + /* 0xEXXXYYYY: An IME HKL. EXXX is an IME keyboard. YYYY is a language */ 25 + if (IS_IME_HKL(hKL)) 26 + return HKL_TYPE_IME; 27 + 28 + /* 0xFXXXYYYY: A special HKL. XXX is a special ID. YYYY is a language */ 29 + if (IS_SPECIAL_HKL(hKL)) 30 + return HKL_TYPE_SPECIAL; 31 + 32 + /* 0xXXXXXXXX: The keyboard layout and language is the same value */ 33 + if (LOWORD(hKL) == HIWORD(hKL)) 34 + return HKL_TYPE_PURE; 35 + 36 + /* 0xXXXXYYYY: XXXX is a keyboard. YYYY is a language */ 37 + return HKL_TYPE_CHIMERA; 38 + } 39 + 40 + static HKEY OpenKeyboardLayouts(void) 41 + { 42 + HKEY hKey = NULL; 43 + RegOpenKeyExW(HKEY_LOCAL_MACHINE, 44 + L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", 45 + 0, KEY_READ, &hKey); 46 + return hKey; 47 + } 48 + 49 + static DWORD KLIDFromSpecialHKL(HKL hKL) 50 + { 51 + WCHAR szName[16], szLayoutId[16]; 52 + HKEY hkeyLayouts, hkeyKLID; 53 + LSTATUS error; 54 + DWORD dwSpecialId, dwLayoutId, cbValue, dwKLID = 0; 55 + 56 + hkeyLayouts = OpenKeyboardLayouts(); 57 + ok(hkeyLayouts != NULL, "hkeyLayouts was NULL\n"); 58 + 59 + dwSpecialId = SPECIALIDFROMHKL(hKL); 60 + 61 + /* Search from "Keyboard Layouts" registry key */ 62 + for (DWORD dwIndex = 0; dwIndex < 1000; ++dwIndex) 63 + { 64 + error = RegEnumKeyW(hkeyLayouts, dwIndex, szName, _countof(szName)); 65 + szName[_countof(szName) - 1] = UNICODE_NULL; /* Avoid buffer overrun */ 66 + if (error != ERROR_SUCCESS) 67 + break; 68 + 69 + error = RegOpenKeyExW(hkeyLayouts, szName, 0, KEY_READ, &hkeyKLID); 70 + if (error != ERROR_SUCCESS) 71 + break; 72 + 73 + cbValue = sizeof(szLayoutId); 74 + error = RegQueryValueExW(hkeyKLID, L"Layout Id", NULL, NULL, (LPBYTE)szLayoutId, &cbValue); 75 + szLayoutId[_countof(szLayoutId) - 1] = UNICODE_NULL; /* Avoid buffer overrun */ 76 + if (error != ERROR_SUCCESS) 77 + { 78 + RegCloseKey(hkeyKLID); 79 + continue; 80 + } 81 + 82 + dwLayoutId = wcstoul(szLayoutId, NULL, 16); 83 + RegCloseKey(hkeyKLID); 84 + if (dwLayoutId == dwSpecialId) /* Found */ 85 + { 86 + dwKLID = wcstoul(szName, NULL, 16); 87 + break; 88 + } 89 + } 90 + 91 + RegCloseKey(hkeyLayouts); 92 + return dwKLID; 93 + } 94 + 95 + static DWORD KLIDFromHKL(HKL hKL) 96 + { 97 + HKL_TYPE type = GetHKLType(hKL); 98 + 99 + trace("type: %d\n", type); 100 + switch (type) 101 + { 102 + case HKL_TYPE_PURE: 103 + case HKL_TYPE_CHIMERA: 104 + return HIWORD(hKL); 105 + 106 + case HKL_TYPE_SPECIAL: 107 + return KLIDFromSpecialHKL(hKL); 108 + 109 + case HKL_TYPE_IME: 110 + return HandleToUlong(hKL); 111 + } 112 + 113 + return 0; 114 + } 115 + 116 + static void Test_KLID(DWORD dwKLID, HKL hKL) 117 + { 118 + WCHAR szKLID[16], szValue[MAX_PATH]; 119 + LSTATUS error; 120 + DWORD dwValue, cbValue; 121 + HKEY hkeyKLID, hkeyLayouts; 122 + HKL_TYPE type; 123 + 124 + hkeyLayouts = OpenKeyboardLayouts(); 125 + ok(hkeyLayouts != NULL, "hkeyLayouts was NULL\n"); 126 + 127 + StringCchPrintfW(szKLID, _countof(szKLID), L"%08lX", dwKLID); 128 + RegOpenKeyExW(hkeyLayouts, szKLID, 0, KEY_READ, &hkeyKLID); 129 + ok(hkeyKLID != NULL, "hkeyKLID was NULL\n"); 130 + 131 + error = RegQueryValueExW(hkeyKLID, L"Layout File", NULL, NULL, NULL, NULL); 132 + ok_long(error, ERROR_SUCCESS); 133 + 134 + type = GetHKLType(hKL); 135 + 136 + if (type == HKL_TYPE_IME) 137 + { 138 + ok_long(dwKLID, HandleToUlong(hKL)); 139 + error = RegQueryValueExW(hkeyKLID, L"IME File", NULL, NULL, NULL, NULL); 140 + ok_long(error, ERROR_SUCCESS); 141 + } 142 + 143 + if (type == HKL_TYPE_SPECIAL) 144 + { 145 + cbValue = sizeof(szValue); 146 + error = RegQueryValueExW(hkeyKLID, L"Layout Id", NULL, NULL, (LPBYTE)&szValue, &cbValue); 147 + ok_long(error, ERROR_SUCCESS); 148 + 149 + dwValue = wcstoul(szValue, NULL, 16); 150 + ok_long(dwValue, SPECIALIDFROMHKL(hKL)); 151 + } 152 + 153 + RegCloseKey(hkeyKLID); 154 + RegCloseKey(hkeyLayouts); 155 + } 156 + 157 + static void Test_HKL(HKL hKL) 158 + { 159 + DWORD dwKLID; 160 + 161 + ok(hKL != NULL, "hKL was NULL\n"); 162 + 163 + dwKLID = KLIDFromHKL(hKL); 164 + trace("dwKLID 0x%08lX, hKL %p\n", dwKLID, hKL); 165 + 166 + Test_KLID(dwKLID, hKL); 167 + } 168 + 169 + START_TEST(KLID) 170 + { 171 + HKL *phKLs; 172 + INT iKL, cKLs; 173 + 174 + cKLs = GetKeyboardLayoutList(0, NULL); 175 + trace("cKLs: %d\n", cKLs); 176 + if (!cKLs) 177 + { 178 + skip("cKLs was zero\n"); 179 + return; 180 + } 181 + 182 + phKLs = calloc(cKLs, sizeof(HKL)); 183 + if (!phKLs) 184 + { 185 + skip("!phKLs\n"); 186 + return; 187 + } 188 + 189 + ok_int(GetKeyboardLayoutList(cKLs, phKLs), cKLs); 190 + 191 + for (iKL = 0; iKL < cKLs; ++iKL) 192 + { 193 + trace("---\n"); 194 + trace("phKLs[%d]: %p\n", iKL, phKLs[iKL]); 195 + Test_HKL(phKLs[iKL]); 196 + } 197 + 198 + free(phKLs); 199 + }
+2
modules/rostests/apitests/imm32/testlist.c
··· 8 8 extern void func_ImmEnumInputContext(void); 9 9 extern void func_ImmGetImeInfoEx(void); 10 10 extern void func_ImmIsUIMessage(void); 11 + extern void func_KLID(void); 11 12 extern void func_JapanImeConvTestA(void); 12 13 extern void func_JapanImeConvTestW(void); 13 14 ··· 19 20 { "ImmEnumInputContext", func_ImmEnumInputContext }, 20 21 { "ImmGetImeInfoEx", func_ImmGetImeInfoEx }, 21 22 { "ImmIsUIMessage", func_ImmIsUIMessage }, 23 + { "KLID", func_KLID }, 22 24 { "JapanImeConvTestA", func_JapanImeConvTestA }, 23 25 { "JapanImeConvTestW", func_JapanImeConvTestW }, 24 26 { 0, 0 }