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