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 HRESULT FakeSHLoadRegUIStringW(HKEY hkey, LPCWSTR value, LPWSTR buf, DWORD size) 91 { 92 HRESULT hr = E_FAIL; 93 HINSTANCE hSHLWAPI = LoadLibraryW(L"shlwapi"); 94 FN_SHLoadRegUIStringW fn; 95 fn = (FN_SHLoadRegUIStringW)GetProcAddress(hSHLWAPI, (LPCSTR)(INT_PTR)439); 96 if (fn) 97 hr = fn(hkey, value, buf, size); 98 FreeLibrary(hSHLWAPI); 99 return hr; 100 } 101 102 static BOOL 103 LayoutList_ReadLayout(HKEY hLayoutKey, LPCWSTR szKLID, LPCWSTR szSystemDirectory) 104 { 105 WCHAR szFile[80], szImeFile[80], szBuffer[MAX_PATH], szFilePath[MAX_PATH]; 106 DWORD dwSize, dwKLID = DWORDfromString(szKLID); 107 WORD wSpecialId = 0; 108 LPWSTR pszImeFile = NULL; 109 110 dwSize = sizeof(szFile); 111 if (RegQueryValueExW(hLayoutKey, L"Layout File", NULL, NULL, 112 (LPBYTE)szFile, &dwSize) != ERROR_SUCCESS) 113 { 114 return FALSE; /* No "Layout File" value */ 115 } 116 117 if (IS_IME_KLID(dwKLID)) 118 { 119 WCHAR szPath[MAX_PATH]; 120 dwSize = sizeof(szImeFile); 121 if (RegQueryValueExW(hLayoutKey, L"IME File", NULL, NULL, 122 (LPBYTE)szImeFile, &dwSize) != ERROR_SUCCESS) 123 { 124 return FALSE; /* No "IME File" value */ 125 } 126 127 if (wcschr(szImeFile, L'\\') != NULL) 128 return FALSE; /* Invalid character */ 129 130 GetSystemLibraryPath(szPath, ARRAYSIZE(szPath), szImeFile); 131 if (GetFileAttributesW(szPath) == INVALID_FILE_ATTRIBUTES) 132 return FALSE; /* Does not exist */ 133 134 pszImeFile = szImeFile; 135 } 136 137 /* Build the "Layout File" full path and check existence */ 138 StringCchPrintfW(szFilePath, ARRAYSIZE(szFilePath), L"%s\\%s", szSystemDirectory, szFile); 139 if (GetFileAttributesW(szFilePath) == INVALID_FILE_ATTRIBUTES) 140 return FALSE; /* No layout file found */ 141 142 /* Get the special ID */ 143 dwSize = sizeof(szBuffer); 144 if (RegQueryValueExW(hLayoutKey, L"Layout Id", NULL, NULL, 145 (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS) 146 { 147 wSpecialId = LOWORD(DWORDfromString(szBuffer)); 148 } 149 150 /* If there is a valid "Layout Display Name", then use it as the entry name */ 151 if (FakeSHLoadRegUIStringW(hLayoutKey, L"Layout Display Name", 152 szBuffer, ARRAYSIZE(szBuffer)) == S_OK) 153 { 154 LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile); 155 return TRUE; 156 } 157 158 /* Otherwise, use "Layout Text" value as the entry name */ 159 dwSize = sizeof(szBuffer); 160 if (RegQueryValueExW(hLayoutKey, L"Layout Text", NULL, NULL, 161 (LPBYTE)szBuffer, &dwSize) == ERROR_SUCCESS) 162 { 163 LayoutList_AppendNode(dwKLID, wSpecialId, szFile, szBuffer, pszImeFile); 164 return TRUE; 165 } 166 167 return FALSE; 168 } 169 170 VOID 171 LayoutList_Create(VOID) 172 { 173 WCHAR szSystemDirectory[MAX_PATH], szKLID[KL_NAMELENGTH]; 174 DWORD dwSize, dwIndex; 175 HKEY hKey, hLayoutKey; 176 177 if (!GetSystemDirectoryW(szSystemDirectory, ARRAYSIZE(szSystemDirectory))) 178 return; 179 180 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts", 181 0, KEY_READ, &hKey) != ERROR_SUCCESS) 182 { 183 return; 184 } 185 186 for (dwIndex = 0; ; ++dwIndex) 187 { 188 dwSize = ARRAYSIZE(szKLID); 189 if (RegEnumKeyExW(hKey, dwIndex, szKLID, &dwSize, NULL, NULL, 190 NULL, NULL) != ERROR_SUCCESS) 191 { 192 break; 193 } 194 195 if (RegOpenKeyExW(hKey, szKLID, 0, KEY_QUERY_VALUE, &hLayoutKey) == ERROR_SUCCESS) 196 { 197 LayoutList_ReadLayout(hLayoutKey, szKLID, szSystemDirectory); 198 RegCloseKey(hLayoutKey); 199 } 200 } 201 202 RegCloseKey(hKey); 203 } 204 205 206 LAYOUT_LIST_NODE* 207 LayoutList_GetByHkl(HKL hkl) 208 { 209 LAYOUT_LIST_NODE *pCurrent; 210 211 if (IS_SPECIAL_HKL(hkl)) 212 { 213 WORD wSpecialId = SPECIALIDFROMHKL(hkl); 214 215 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext) 216 { 217 if (wSpecialId == pCurrent->wSpecialId) 218 { 219 return pCurrent; 220 } 221 } 222 } 223 else if (IS_IME_HKL(hkl)) 224 { 225 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext) 226 { 227 if (hkl == UlongToHandle(pCurrent->dwKLID)) 228 { 229 return pCurrent; 230 } 231 } 232 } 233 else 234 { 235 for (pCurrent = _LayoutList; pCurrent != NULL; pCurrent = pCurrent->pNext) 236 { 237 if (HIWORD(hkl) == LOWORD(pCurrent->dwKLID)) 238 { 239 return pCurrent; 240 } 241 } 242 } 243 244 return NULL; 245 } 246 247 248 LAYOUT_LIST_NODE* 249 LayoutList_GetFirst(VOID) 250 { 251 return _LayoutList; 252 } 253