xref: /reactos/dll/cpl/intl/kblayouts.c (revision 40462c92)
1 /*
2  * PROJECT:         ReactOS International Control Panel
3  * FILE:            dll/cpl/intl/kblayouts.c
4  * PURPOSE:         Functions for manipulation with keyboard layouts
5  * PROGRAMMER:      Dmitry Chapyshev (dmitry@reactos.org)
6  */
7 
8 #include "intl.h"
9 
10 /* Character Count of a layout ID like "00000409" */
11 #define CCH_LAYOUT_ID    8
12 
13 /* Maximum Character Count of a ULONG in decimal */
14 #define CCH_ULONG_DEC    10
15 
16 
17 /* szLayoutID like 00000409, szLangID like 00000409 */
18 static BOOL
19 IsLayoutExists(PWSTR szLayoutID, PWSTR szLangID)
20 {
21     HKEY hKey, hSubKey;
22     WCHAR szPreload[CCH_LAYOUT_ID + 1], szLayoutNum[3 + 1],
23           szTmp[CCH_LAYOUT_ID + 1], szOldLangID[CCH_LAYOUT_ID + 1];
24     DWORD dwIndex = 0, dwType, dwSize;
25     BOOL IsLangExists = FALSE;
26     LANGID langid;
27 
28     if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload",
29         0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
30     {
31         dwSize = sizeof(szLayoutNum);
32 
33         while (RegEnumValueW(hKey, dwIndex, szLayoutNum, &dwSize, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS)
34         {
35             dwSize = sizeof(szPreload);
36             if (RegQueryValueExW(hKey, szLayoutNum, NULL, NULL, (LPBYTE)szPreload, &dwSize) != ERROR_SUCCESS)
37             {
38                 RegCloseKey(hKey);
39                 return FALSE;
40             }
41 
42             langid = (LANGID)wcstoul(szPreload, NULL, 16);
43             GetLocaleInfoW(langid, LOCALE_ILANGUAGE, szTmp, sizeof(szTmp) / sizeof(WCHAR));
44             wsprintf(szOldLangID, L"0000%s", szTmp);
45 
46             if (wcscmp(szOldLangID, szLangID) == 0)
47                 IsLangExists = TRUE;
48             else
49                 IsLangExists = FALSE;
50 
51             if (szPreload[0] == 'd')
52             {
53                 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes",
54                                  0, KEY_QUERY_VALUE, &hSubKey) == ERROR_SUCCESS)
55                 {
56                     dwSize = sizeof(szTmp);
57                     RegQueryValueExW(hSubKey, szPreload, NULL, NULL, (LPBYTE)szTmp, &dwSize);
58 
59                     if ((wcscmp(szTmp, szLayoutID) == 0)&&(IsLangExists))
60                     {
61                         RegCloseKey(hSubKey);
62                         RegCloseKey(hKey);
63                         return TRUE;
64                     }
65                 }
66             }
67             else
68             {
69                 if ((wcscmp(szPreload, szLayoutID) == 0) && (IsLangExists))
70                 {
71                     RegCloseKey(hKey);
72                     return TRUE;
73                 }
74             }
75 
76             IsLangExists = FALSE;
77             dwSize = sizeof(szLayoutNum);
78             dwIndex++;
79         }
80 
81         RegCloseKey(hKey);
82     }
83 
84     return FALSE;
85 }
86 
87 static INT
88 GetLayoutCount(PWSTR szLang)
89 {
90     HKEY hKey;
91     WCHAR szLayoutID[3 + 1], szPreload[CCH_LAYOUT_ID + 1], szLOLang[MAX_PATH];
92     DWORD dwIndex = 0, dwType, dwSize;
93     UINT Count = 0, i, j;
94 
95     if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload",
96         0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
97     {
98         dwSize = sizeof(szLayoutID);
99 
100         while (RegEnumValue(hKey, dwIndex, szLayoutID, &dwSize, NULL, &dwType, NULL, NULL) == ERROR_SUCCESS)
101         {
102             dwSize = sizeof(szPreload);
103             RegQueryValueExW(hKey, szLayoutID, NULL, NULL, (LPBYTE)szPreload, &dwSize);
104 
105             for (i = 4, j = 0; i < wcslen(szPreload)+1; i++, j++)
106                 szLOLang[j] = szPreload[i];
107 
108             if (wcscmp(szLOLang, szLang) == 0) Count += 1;
109 
110             dwSize = sizeof(szLayoutID);
111             dwIndex++;
112         }
113 
114         RegCloseKey(hKey);
115     }
116 
117     return Count;
118 }
119 
120 /* szLayoutID like 00000409, szLangID like 00000409 */
121 static BOOL
122 AddNewLayout(PWSTR szLayoutID, PWSTR szLangID)
123 {
124     WCHAR NewLayout[CCH_ULONG_DEC + 1], Lang[MAX_PATH],
125           LangID[CCH_LAYOUT_ID + 1], SubPath[CCH_LAYOUT_ID + 1];
126     HKEY hKey, hSubKey;
127     DWORD cValues;
128     LCID lcid;
129 
130     if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
131     {
132         if (RegQueryInfoKey(hKey, NULL, NULL, NULL, NULL, NULL, NULL, &cValues, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
133         {
134             _ultow(cValues + 1, NewLayout, 10);
135 
136             lcid = wcstoul(szLangID, NULL, 16);
137 
138             GetLocaleInfoW(MAKELCID(lcid, SORT_DEFAULT), LOCALE_ILANGUAGE, Lang, sizeof(Lang) / sizeof(WCHAR));
139             wsprintf(LangID, L"0000%s", Lang);
140 
141             if (IsLayoutExists(szLayoutID, LangID))
142             {
143                 RegCloseKey(hKey);
144                 return FALSE;
145             }
146 
147             if (GetLayoutCount(Lang) >= 1)
148             {
149                 wsprintf(SubPath, L"d%03d%s", GetLayoutCount(Lang), Lang);
150             }
151             else if ((wcscmp(LangID, szLayoutID) != 0) && (GetLayoutCount(Lang) == 0))
152             {
153                 wsprintf(SubPath, L"d%03d%s", 0, Lang);
154             }
155             else SubPath[0] = L'\0';
156 
157             if (wcslen(SubPath) != 0)
158             {
159                 if (RegCreateKeyExW(HKEY_CURRENT_USER, L"Keyboard Layout\\Substitutes", 0, NULL,
160                                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
161                                     NULL, &hSubKey, NULL) == ERROR_SUCCESS)
162                 {
163                     if (RegSetValueExW(hSubKey, SubPath, 0, REG_SZ, (LPBYTE)szLayoutID,
164                                        (DWORD)((CCH_LAYOUT_ID + 1) * sizeof(WCHAR))) != ERROR_SUCCESS)
165                     {
166                         RegCloseKey(hSubKey);
167                         RegCloseKey(hKey);
168                         return FALSE;
169                     }
170                     RegCloseKey(hSubKey);
171                 }
172                 lstrcpy(szLayoutID, SubPath);
173             }
174 
175             RegSetValueExW(hKey,
176                            NewLayout,
177                            0,
178                            REG_SZ,
179                            (LPBYTE)szLayoutID,
180                            (DWORD)((CCH_LAYOUT_ID + 1) * sizeof(WCHAR)));
181         }
182         RegCloseKey(hKey);
183     }
184 
185     return TRUE;
186 }
187 
188 VOID
189 AddNewKbLayoutsByLcid(LCID Lcid)
190 {
191     HINF hIntlInf;
192     WCHAR szLang[CCH_LAYOUT_ID + 1], szLangID[CCH_LAYOUT_ID + 1];
193     WCHAR szLangStr[MAX_STR_SIZE], szLayoutStr[MAX_STR_SIZE], szStr[MAX_STR_SIZE];
194     INFCONTEXT InfContext;
195     LONG Count;
196     DWORD FieldCount, Index;
197 
198     GetLocaleInfoW(MAKELCID(Lcid, SORT_DEFAULT), LOCALE_ILANGUAGE, szLang, sizeof(szLang) / sizeof(WCHAR));
199     wsprintf(szLangID, L"0000%s", szLang);
200 
201     hIntlInf = SetupOpenInfFileW(L"intl.inf", NULL, INF_STYLE_WIN4, NULL);
202 
203     if (hIntlInf == INVALID_HANDLE_VALUE)
204         return;
205 
206     if (!SetupOpenAppendInfFile(NULL, hIntlInf, NULL))
207     {
208         SetupCloseInfFile(hIntlInf);
209         hIntlInf = NULL;
210         return;
211     }
212 
213     Count = SetupGetLineCount(hIntlInf, L"Locales");
214     if (Count <= 0) return;
215 
216     if (SetupFindFirstLine(hIntlInf, L"Locales", szLangID, &InfContext))
217     {
218         FieldCount = SetupGetFieldCount(&InfContext);
219 
220         if (FieldCount != 0)
221         {
222             for (Index = 5; Index <= FieldCount; Index++)
223             {
224                 if (SetupGetStringField(&InfContext, Index, szStr, MAX_STR_SIZE, NULL))
225                 {
226                     INT i, j;
227 
228                     if (wcslen(szStr) != 13) continue;
229 
230                     wsprintf(szLangStr, L"0000%s", szStr);
231                     szLangStr[8] = L'\0';
232 
233                     for (i = 5, j = 0; i <= wcslen(szStr); i++, j++)
234                         szLayoutStr[j] = szStr[i];
235 
236                     AddNewLayout(szLayoutStr, szLangStr);
237                 }
238             }
239         }
240     }
241     SetupCloseInfFile(hIntlInf);
242 }
243