1 /* 2 * PROJECT: input.dll 3 * FILE: dll/cpl/input/layout_list.c 4 * PURPOSE: input.dll 5 * PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org) 6 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 7 */ 8 9 #include "layout_list.h" 10 11 static LAYOUT_LIST_NODE *_LayoutList = NULL; 12 13 static LAYOUT_LIST_NODE* 14 LayoutList_AppendNode(DWORD dwKLID, WORD wSpecialId, LPCWSTR pszFile, LPCWSTR pszName, 15 LPCWSTR pszImeFile) 16 { 17 LAYOUT_LIST_NODE *pCurrent; 18 LAYOUT_LIST_NODE *pNew; 19 20 if (pszName == NULL) 21 return NULL; 22 23 pCurrent = _LayoutList; 24 25 pNew = (LAYOUT_LIST_NODE*)malloc(sizeof(LAYOUT_LIST_NODE)); 26 if (pNew == NULL) 27 return NULL; 28 29 ZeroMemory(pNew, sizeof(LAYOUT_LIST_NODE)); 30 31 pNew->dwKLID = dwKLID; 32 pNew->wSpecialId = wSpecialId; 33 34 pNew->pszName = _wcsdup(pszName); 35 pNew->pszFile = _wcsdup(pszFile); 36 pNew->pszImeFile = _wcsdup(pszImeFile); 37 if (pNew->pszName == NULL || pNew->pszFile == NULL || 38 (pszImeFile && pNew->pszImeFile == NULL)) 39 { 40 free(pNew->pszName); 41 free(pNew->pszFile); 42 free(pNew->pszImeFile); 43 free(pNew); 44 return NULL; 45 } 46 47 if (pCurrent == NULL) 48 { 49 _LayoutList = pNew; 50 } 51 else 52 { 53 while (pCurrent->pNext != NULL) 54 { 55 pCurrent = pCurrent->pNext; 56 } 57 58 pNew->pPrev = pCurrent; 59 pCurrent->pNext = pNew; 60 } 61 62 return pNew; 63 } 64 65 66 VOID 67 LayoutList_Destroy(VOID) 68 { 69 LAYOUT_LIST_NODE *pCurrent; 70 LAYOUT_LIST_NODE *pNext; 71 72 if (_LayoutList == NULL) 73 return; 74 75 for (pCurrent = _LayoutList; pCurrent; pCurrent = pNext) 76 { 77 pNext = pCurrent->pNext; 78 79 free(pCurrent->pszName); 80 free(pCurrent->pszFile); 81 free(pCurrent->pszImeFile); 82 free(pCurrent); 83 } 84 85 _LayoutList = NULL; 86 } 87 88 typedef HRESULT (WINAPI *FN_SHLoadRegUIStringW)(HKEY, LPCWSTR, LPWSTR, DWORD); 89 90 /* FIXME: Use shlwapi!SHLoadRegUIStringW instead when it is fully implemented */ 91 HRESULT FakeSHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size) 92 { 93 #if 1 94 PWCHAR pBuffer, pIndex; 95 WCHAR szDllPath[MAX_PATH]; 96 DWORD dwSize; 97 HINSTANCE hDllInst; 98 INT iIndex, iLength; 99 100 dwSize = size * sizeof(WCHAR); 101 if (RegQueryValueExW(hkey, value, NULL, NULL, (LPBYTE)buf, &dwSize) != ERROR_SUCCESS) 102 return E_FAIL; 103 104 if (buf[0] != L'@') 105 return S_OK; 106 107 /* Move to the position after the character "@" */ 108 pBuffer = buf + 1; 109 110 /* Get a pointer to the beginning ",-" */ 111 pIndex = wcsstr(pBuffer, L",-"); 112 if (!pIndex) 113 return E_FAIL; 114 115 /* Convert the number in the string after the ",-" */ 116 iIndex = _wtoi(pIndex + 2); 117 118 *pIndex = 0; /* Cut the string */ 119 120 if (ExpandEnvironmentStringsW(pBuffer, szDllPath, ARRAYSIZE(szDllPath)) == 0) 121 return E_FAIL; 122 123 hDllInst = LoadLibraryW(szDllPath); 124 if (!hDllInst) 125 return E_FAIL; 126 127 iLength = LoadStringW(hDllInst, iIndex, buf, size); 128 FreeLibrary(hDllInst); 129 130 if (iLength <= 0) 131 return E_FAIL; 132 133 return S_OK; 134 #else 135 HRESULT hr = E_FAIL; 136 HINSTANCE hSHLWAPI = LoadLibraryW(L"shlwapi"); 137 FN_SHLoadRegUIStringW fn; 138 fn = (FN_SHLoadRegUIStringW)GetProcAddress(hSHLWAPI, (LPCSTR)(INT_PTR)439); 139 if (fn) 140 hr = fn(hkey, value, buf, size); 141 FreeLibrary(hSHLWAPI); 142 return hr; 143 #endif 144 } 145 146 static BOOL 147 LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szKLID, LPCWSTR szSystemDirectory) 148 { 149 WCHAR szFile[80], szImeFile[80], szBuffer[MAX_PATH], szFilePath[MAX_PATH]; 150 DWORD dwSize, dwKLID = DWORDfromString(szKLID); 151 WORD wSpecialId = 0; 152 LPWSTR pszImeFile = NULL; 153 154 dwSize = sizeof(szFile); 155 if (RegQueryValueExW(hLayoutKey, L"Layout File", NULL, NULL, 156 (LPBYTE)szFile, &dwSize) != ERROR_SUCCESS) 157 { 158 return FALSE; /* No "Layout File" value */ 159 } 160 161 if (IS_IME_KLID(dwKLID)) 162 { 163 WCHAR szPath[MAX_PATH]; 164 dwSize = sizeof(szImeFile); 165 if (RegQueryValueExW(hLayoutKey, L"IME File", NULL, NULL, 166 (LPBYTE)szImeFile, &dwSize) != ERROR_SUCCESS) 167 { 168 return FALSE; /* No "IME File" value */ 169 } 170 171 if (wcschr(szImeFile, L'\\') != NULL) 172 return FALSE; /* Invalid character */ 173 174 GetSystemLibraryPath(szPath, ARRAYSIZE(szPath), szImeFile); 175 if (GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) 176 return FALSE; /* Does not exist */ 177 178 pszImeFile = szImeFile; 179 } 180 181 /* Build the "Layout File" full path and check existence */ 182 StringCchPrintfW(szFilePath, ARRAYSIZE(szFilePath), L"%s\\%s", szSystemDirectory, szFile); 183 if (GetFileAttributesW(szFilePath) == INVALID_FILE_ATTRIBUTES) 184 return FALSE; /* No layout file found */ 185 186 /* Get the special ID */ 187 dwSize = sizeof(szBuffer); 188 if (RegQueryValueExW(hLayoutKey, L"Layout Id", NULL, NULL, 189 (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS) 190 { 191 wSpecialId = LOWORD(DWORDfromString(szBuffer)); 192 } 193 194 /* If there is a valid "Layout Display Name", then use it as the entry name */ 195 if (FakeSHLoadRegUIStringW(hLayoutKey, L"Layout Display Name", 196 szBuffer, ARRAYSIZE(szBuffer)) == S_OK) 197 { 198 LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile); 199 return TRUE; 200 } 201 202 /* Otherwise, use "Layout Text" value as the entry name */ 203 dwSize = sizeof(szBuffer); 204 if (RegQueryValueExW(hLayoutKey, L"Layout Text", NULL, NULL, 205 (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS) 206 { 207 LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile); 208 return TRUE; 209 } 210 211 return FALSE; 212 } 213 214 VOID 215 LayoutList_Create(VOID) 216 { 217 WCHAR szSystemDirectory[MAX_PATH], szKLID[KL_NAMELENGTH]; 218 DWORD dwSize, dwIndex; 219 HKEY hKey, hLayoutKey; 220 221 if (!GetSystemDirectoryW(szSystemDirectory, ARRAYSIZE(szSystemDirectory))) 222 return; 223 224 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", 225 0, KEY_READ, &hKey) != ERROR_SUCCESS) 226 { 227 return; 228 } 229 230 for (dwIndex = 0; ; ++dwIndex) 231 { 232 dwSize = ARRAYSIZE(szKLID); 233 if (RegEnumKeyExW(hKey, dwIndex, szKLID, &dwSize, NULL, NULL, 234 NULL, NULL) != ERROR_SUCCESS) 235 { 236 break; 237 } 238 239 if (RegOpenKeyExW(hKey, szKLID, 0, KEY_QUERY_VALUE, &hLayoutKey) == ERROR_SUCCESS) 240 { 241 LayoutList_ReadLayout(hLayoutKey, szKLID, szSystemDirectory); 242 RegCloseKey(hLayoutKey); 243 } 244 } 245 246 RegCloseKey(hKey); 247 } 248 249 250 LAYOUT_LIST_NODE* 251 LayoutList_GetByHkl(HKL hkl) 252 { 253 LAYOUT_LIST_NODE *pCurrent; 254 255 if (IS_SPECIAL_HKL(hkl)) 256 { 257 WORD wSpecialId = SPECIALIDFROMHKL(hkl); 258 259 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext) 260 { 261 if (wSpecialId == pCurrent->wSpecialId) 262 { 263 return pCurrent; 264 } 265 } 266 } 267 else if (IS_IME_HKL(hkl)) 268 { 269 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext) 270 { 271 if (hkl == UlongToHandle(pCurrent->dwKLID)) 272 { 273 return pCurrent; 274 } 275 } 276 } 277 else 278 { 279 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext) 280 { 281 if (HIWORD(hkl) == LOWORD(pCurrent->dwKLID)) 282 { 283 return pCurrent; 284 } 285 } 286 } 287 288 return NULL; 289 } 290 291 292 LAYOUT_LIST_NODE* 293 LayoutList_GetFirst(VOID) 294 { 295 return _LayoutList; 296 } 297