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 } 200