[CONCFG]: Diverse improvements/additions for the console configuration library. CORE...
[reactos.git] / reactos / win32ss / user / winsrv / concfg / settings.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/concfg/settings.c
5 * PURPOSE: Console settings management
6 * PROGRAMMERS: Johannes Anderwald
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "precomp.h"
13
14 // /* Undocumented user definitions */
15 // #include <undocuser.h>
16
17 #include "settings.h"
18
19 #define NDEBUG
20 #include <debug.h>
21
22 /* GLOBALS ********************************************************************/
23
24 /* Default cursor size -- see conio_winsrv.h */
25 // #define SMALL_SIZE 25
26 #define CSR_DEFAULT_CURSOR_SIZE 25
27
28 /* Default attributes -- see conio.h */
29 #define DEFAULT_SCREEN_ATTRIB (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
30 #define DEFAULT_POPUP_ATTRIB (FOREGROUND_BLUE | FOREGROUND_RED | \
31 BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY)
32
33 /*
34 * Default 16-color palette for foreground and background
35 * (corresponding flags in comments).
36 */
37 static const COLORREF s_Colors[16] =
38 {
39 RGB(0, 0, 0), // (Black)
40 RGB(0, 0, 128), // BLUE
41 RGB(0, 128, 0), // GREEN
42 RGB(0, 128, 128), // BLUE | GREEN
43 RGB(128, 0, 0), // RED
44 RGB(128, 0, 128), // BLUE | RED
45 RGB(128, 128, 0), // GREEN | RED
46 RGB(192, 192, 192), // BLUE | GREEN | RED
47
48 RGB(128, 128, 128), // (Grey) INTENSITY
49 RGB(0, 0, 255), // BLUE | INTENSITY
50 RGB(0, 255, 0), // GREEN | INTENSITY
51 RGB(0, 255, 255), // BLUE | GREEN | INTENSITY
52 RGB(255, 0, 0), // RED | INTENSITY
53 RGB(255, 0, 255), // BLUE | RED | INTENSITY
54 RGB(255, 255, 0), // GREEN | RED | INTENSITY
55 RGB(255, 255, 255) // BLUE | GREEN | RED | INTENSITY
56 };
57
58
59 /* FUNCTIONS ******************************************************************/
60
61 static VOID
62 TranslateConsoleName(
63 OUT LPWSTR DestString,
64 IN LPCWSTR ConsoleName,
65 IN UINT MaxStrLen)
66 {
67 #define PATH_SEPARATOR L'\\'
68
69 UINT wLength;
70
71 if ( DestString == NULL || ConsoleName == NULL ||
72 *ConsoleName == L'\0' || MaxStrLen == 0 )
73 {
74 return;
75 }
76
77 wLength = GetSystemWindowsDirectoryW(DestString, MaxStrLen);
78 if ((wLength > 0) && (_wcsnicmp(ConsoleName, DestString, wLength) == 0))
79 {
80 StringCchCopyW(DestString, MaxStrLen, L"%SystemRoot%");
81 StringCchCatW(DestString, MaxStrLen, ConsoleName + wLength);
82 }
83 else
84 {
85 StringCchCopyW(DestString, MaxStrLen, ConsoleName);
86 }
87
88 /* Replace path separators (backslashes) by underscores */
89 while ((DestString = wcschr(DestString, PATH_SEPARATOR))) *DestString = L'_';
90 }
91
92 BOOLEAN
93 ConCfgOpenUserSettings(
94 IN LPCWSTR ConsoleTitle,
95 OUT PHKEY phSubKey,
96 IN REGSAM samDesired,
97 IN BOOLEAN Create)
98 {
99 BOOLEAN Success = TRUE;
100 NTSTATUS Status;
101 WCHAR szBuffer[MAX_PATH] = L"Console\\";
102 WCHAR szBuffer2[MAX_PATH] = L"";
103 HKEY hKey; // CurrentUserKeyHandle
104
105 /*
106 * Console properties are stored under the HKCU\Console\* key.
107 *
108 * We use the original console title as the subkey name for storing
109 * console properties. We need to distinguish whether we were launched
110 * via the console application directly or via a shortcut.
111 *
112 * If the title of the console corresponds to a path (more precisely,
113 * if the title is of the form: C:\ReactOS\<some_path>\<some_app.exe>),
114 * then use the corresponding unexpanded path and with the backslashes
115 * replaced by underscores, to make the registry happy,
116 * i.e. %SystemRoot%_<some_path>_<some_app.exe>
117 */
118
119 /* Open the per-user registry key where the console properties are saved */
120 Status = RtlOpenCurrentUser(/*samDesired*/MAXIMUM_ALLOWED, (PHANDLE)&/*CurrentUserKeyHandle*/hKey);
121 if (!NT_SUCCESS(Status))
122 {
123 DPRINT1("RtlOpenCurrentUser failed, Status = 0x%08lx\n", Status);
124 SetLastError(RtlNtStatusToDosError(Status));
125 return FALSE;
126 }
127
128 /*
129 * Try to open properties via the console title:
130 * to make the registry happy, replace all the
131 * backslashes by underscores.
132 */
133 TranslateConsoleName(szBuffer2, ConsoleTitle, ARRAYSIZE(szBuffer2));
134
135 /* Create the registry path */
136 StringCchCatW(szBuffer, MAX_PATH - wcslen(szBuffer) - 1, szBuffer2);
137
138 /* Create or open the registry key */
139 if (Create)
140 {
141 /* Create the key */
142 Success = (RegCreateKeyExW(hKey,
143 szBuffer,
144 0, NULL,
145 REG_OPTION_NON_VOLATILE,
146 samDesired,
147 NULL,
148 phSubKey,
149 NULL) == ERROR_SUCCESS);
150 }
151 else
152 {
153 /* Open the key */
154 Success = (RegOpenKeyExW(hKey,
155 szBuffer,
156 0,
157 samDesired,
158 phSubKey) == ERROR_SUCCESS);
159 }
160
161 /* Close the parent key and return success or not */
162 NtClose(hKey);
163 return Success;
164 }
165
166 BOOLEAN
167 ConCfgReadUserSettings(
168 IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
169 IN BOOLEAN DefaultSettings)
170 {
171 BOOLEAN Success = FALSE;
172 HKEY hKey;
173 DWORD dwNumSubKeys = 0;
174 DWORD dwIndex;
175 DWORD dwColorIndex = 0;
176 DWORD dwType;
177 WCHAR szValueName[MAX_PATH];
178 DWORD dwValueName;
179 WCHAR szValue[LF_FACESIZE] = L"";
180 DWORD Value;
181 DWORD dwValue;
182
183 if (!ConCfgOpenUserSettings(DefaultSettings ? L"" : ConsoleInfo->ConsoleTitle,
184 &hKey, KEY_READ, FALSE))
185 {
186 DPRINT("ConCfgOpenUserSettings failed\n");
187 return FALSE;
188 }
189
190 if (RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, NULL, NULL,
191 &dwNumSubKeys, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
192 {
193 DPRINT("ConCfgReadUserSettings: RegQueryInfoKeyW failed\n");
194 RegCloseKey(hKey);
195 return FALSE;
196 }
197
198 DPRINT("ConCfgReadUserSettings entered dwNumSubKeys %d\n", dwNumSubKeys);
199
200 for (dwIndex = 0; dwIndex < dwNumSubKeys; dwIndex++)
201 {
202 dwValue = sizeof(Value);
203 dwValueName = ARRAYSIZE(szValueName);
204
205 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, &dwType, (BYTE*)&Value, &dwValue) != ERROR_SUCCESS)
206 {
207 if (dwType == REG_SZ)
208 {
209 /*
210 * Retry in case of string value
211 */
212 dwValue = sizeof(szValue);
213 dwValueName = ARRAYSIZE(szValueName);
214 if (RegEnumValueW(hKey, dwIndex, szValueName, &dwValueName, NULL, NULL, (BYTE*)szValue, &dwValue) != ERROR_SUCCESS)
215 break;
216 }
217 else
218 {
219 break;
220 }
221 }
222
223 if (!wcsncmp(szValueName, L"ColorTable", wcslen(L"ColorTable")))
224 {
225 dwColorIndex = 0;
226 swscanf(szValueName, L"ColorTable%2d", &dwColorIndex);
227 if (dwColorIndex < ARRAYSIZE(ConsoleInfo->ColorTable))
228 {
229 ConsoleInfo->ColorTable[dwColorIndex] = Value;
230 Success = TRUE;
231 }
232 }
233 if (!wcscmp(szValueName, L"CodePage"))
234 {
235 if (IsValidCodePage(Value))
236 ConsoleInfo->CodePage = Value;
237 Success = TRUE;
238 }
239 else if (!wcscmp(szValueName, L"FaceName"))
240 {
241 StringCchCopyNW(ConsoleInfo->FaceName, ARRAYSIZE(ConsoleInfo->FaceName),
242 szValue, ARRAYSIZE(szValue));
243 Success = TRUE;
244 }
245 else if (!wcscmp(szValueName, L"FontFamily"))
246 {
247 ConsoleInfo->FontFamily = Value;
248 Success = TRUE;
249 }
250 else if (!wcscmp(szValueName, L"FontSize"))
251 {
252 ConsoleInfo->FontSize.X = LOWORD(Value); // Width
253 ConsoleInfo->FontSize.Y = HIWORD(Value); // Height
254 Success = TRUE;
255 }
256 else if (!wcscmp(szValueName, L"FontWeight"))
257 {
258 ConsoleInfo->FontWeight = Value;
259 Success = TRUE;
260 }
261 else if (!wcscmp(szValueName, L"HistoryBufferSize"))
262 {
263 ConsoleInfo->HistoryBufferSize = Value;
264 Success = TRUE;
265 }
266 else if (!wcscmp(szValueName, L"NumberOfHistoryBuffers"))
267 {
268 ConsoleInfo->NumberOfHistoryBuffers = Value;
269 Success = TRUE;
270 }
271 else if (!wcscmp(szValueName, L"HistoryNoDup"))
272 {
273 ConsoleInfo->HistoryNoDup = !!Value;
274 Success = TRUE;
275 }
276 else if (!wcscmp(szValueName, L"QuickEdit"))
277 {
278 ConsoleInfo->QuickEdit = !!Value;
279 Success = TRUE;
280 }
281 else if (!wcscmp(szValueName, L"InsertMode"))
282 {
283 ConsoleInfo->InsertMode = !!Value;
284 Success = TRUE;
285 }
286 else if (!wcscmp(szValueName, L"ScreenBufferSize"))
287 {
288 ConsoleInfo->ScreenBufferSize.X = LOWORD(Value);
289 ConsoleInfo->ScreenBufferSize.Y = HIWORD(Value);
290 Success = TRUE;
291 }
292 else if (!wcscmp(szValueName, L"FullScreen"))
293 {
294 ConsoleInfo->FullScreen = Value;
295 Success = TRUE;
296 }
297 else if (!wcscmp(szValueName, L"WindowPosition"))
298 {
299 ConsoleInfo->AutoPosition = FALSE;
300 ConsoleInfo->WindowPosition.x = LOWORD(Value);
301 ConsoleInfo->WindowPosition.y = HIWORD(Value);
302 Success = TRUE;
303 }
304 else if (!wcscmp(szValueName, L"WindowSize"))
305 {
306 ConsoleInfo->WindowSize.X = LOWORD(Value);
307 ConsoleInfo->WindowSize.Y = HIWORD(Value);
308 Success = TRUE;
309 }
310 else if (!wcscmp(szValueName, L"CursorSize"))
311 {
312 ConsoleInfo->CursorSize = min(max(Value, 0), 100);
313 Success = TRUE;
314 }
315 else if (!wcscmp(szValueName, L"ScreenColors"))
316 {
317 ConsoleInfo->ScreenAttributes = (USHORT)Value;
318 Success = TRUE;
319 }
320 else if (!wcscmp(szValueName, L"PopupColors"))
321 {
322 ConsoleInfo->PopupAttributes = (USHORT)Value;
323 Success = TRUE;
324 }
325 }
326
327 RegCloseKey(hKey);
328 return Success;
329 }
330
331 BOOLEAN
332 ConCfgWriteUserSettings(
333 IN PCONSOLE_STATE_INFO ConsoleInfo,
334 IN BOOLEAN DefaultSettings)
335 {
336 HKEY hKey;
337 DWORD Storage = 0;
338
339 #define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue) \
340 do { \
341 if (DefaultSettings || (!DefaultSettings && (*(Setting) != (DefaultValue)))) \
342 { \
343 RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
344 } \
345 else \
346 { \
347 RegDeleteValueW(hKey, (SettingName)); \
348 } \
349 } while (0)
350
351 WCHAR szValueName[15];
352 UINT i;
353
354 if (!ConCfgOpenUserSettings(DefaultSettings ? L"" : ConsoleInfo->ConsoleTitle,
355 &hKey, KEY_WRITE, TRUE))
356 {
357 return FALSE;
358 }
359
360 for (i = 0; i < ARRAYSIZE(ConsoleInfo->ColorTable); ++i)
361 {
362 /*
363 * Write only the new value if we are saving the global settings
364 * or we are saving settings for a particular console, which differs
365 * from the default ones.
366 */
367 swprintf(szValueName, L"ColorTable%02u", i);
368 SetConsoleSetting(szValueName, REG_DWORD, sizeof(DWORD), &ConsoleInfo->ColorTable[i], s_Colors[i]);
369 }
370
371 SetConsoleSetting(L"CodePage", REG_DWORD, sizeof(DWORD), &ConsoleInfo->CodePage, CP_ACP /* CP_OEMCP */);
372 SetConsoleSetting(L"FaceName", REG_SZ, (wcslen(ConsoleInfo->FaceName) + 1) * sizeof(WCHAR), ConsoleInfo->FaceName, UNICODE_NULL); // wcsnlen
373 SetConsoleSetting(L"FontFamily", REG_DWORD, sizeof(DWORD), &ConsoleInfo->FontFamily, FF_DONTCARE);
374
375 Storage = MAKELONG(ConsoleInfo->FontSize.X, ConsoleInfo->FontSize.Y); // Width, Height
376 SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &Storage, 0);
377
378 SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &ConsoleInfo->FontWeight, FW_DONTCARE);
379
380 SetConsoleSetting(L"HistoryBufferSize", REG_DWORD, sizeof(DWORD), &ConsoleInfo->HistoryBufferSize, 50);
381 SetConsoleSetting(L"NumberOfHistoryBuffers", REG_DWORD, sizeof(DWORD), &ConsoleInfo->NumberOfHistoryBuffers, 4);
382
383 Storage = ConsoleInfo->HistoryNoDup;
384 SetConsoleSetting(L"HistoryNoDup", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
385
386 Storage = ConsoleInfo->QuickEdit;
387 SetConsoleSetting(L"QuickEdit", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
388
389 Storage = ConsoleInfo->InsertMode;
390 SetConsoleSetting(L"InsertMode", REG_DWORD, sizeof(DWORD), &Storage, TRUE);
391
392 Storage = MAKELONG(ConsoleInfo->ScreenBufferSize.X, ConsoleInfo->ScreenBufferSize.Y);
393 SetConsoleSetting(L"ScreenBufferSize", REG_DWORD, sizeof(DWORD), &Storage, MAKELONG(80, 300));
394
395 Storage = ConsoleInfo->FullScreen;
396 SetConsoleSetting(L"FullScreen", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
397
398 if (ConsoleInfo->AutoPosition == FALSE)
399 {
400 Storage = MAKELONG(ConsoleInfo->WindowPosition.x, ConsoleInfo->WindowPosition.y);
401 RegSetValueExW(hKey, L"WindowPosition", 0, REG_DWORD, (PBYTE)&Storage, sizeof(DWORD));
402 }
403 else
404 {
405 RegDeleteValueW(hKey, L"WindowPosition");
406 }
407
408 Storage = MAKELONG(ConsoleInfo->WindowSize.X, ConsoleInfo->WindowSize.Y);
409 SetConsoleSetting(L"WindowSize", REG_DWORD, sizeof(DWORD), &Storage, MAKELONG(80, 25));
410
411 SetConsoleSetting(L"CursorSize", REG_DWORD, sizeof(DWORD), &ConsoleInfo->CursorSize, CSR_DEFAULT_CURSOR_SIZE);
412
413 Storage = ConsoleInfo->ScreenAttributes;
414 SetConsoleSetting(L"ScreenColors", REG_DWORD, sizeof(DWORD), &Storage, DEFAULT_SCREEN_ATTRIB);
415
416 Storage = ConsoleInfo->PopupAttributes;
417 SetConsoleSetting(L"PopupColors", REG_DWORD, sizeof(DWORD), &Storage, DEFAULT_POPUP_ATTRIB);
418
419 RegCloseKey(hKey);
420 return TRUE;
421 }
422
423 VOID
424 ConCfgInitDefaultSettings(
425 IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
426 {
427 if (ConsoleInfo == NULL) return;
428
429 // ASSERT(ConsoleInfo->cbSize >= sizeof(CONSOLE_STATE_INFO));
430
431 /// HKCU,"Console","LoadConIme",0x00010003,1
432
433 // wcsncpy(ConsoleInfo->FaceName, L"DejaVu Sans Mono", LF_FACESIZE);
434 // ConsoleInfo->FontSize = MAKELONG(8, 12); // 0x000C0008; // font is 8x12
435
436 StringCchCopyW(ConsoleInfo->FaceName, ARRAYSIZE(ConsoleInfo->FaceName), L"VGA"); // HACK: !!
437 // ConsoleInfo->FaceName[0] = UNICODE_NULL;
438 // ConsoleInfo->FontSize.X = 8;
439 // ConsoleInfo->FontSize.Y = 12;
440 ConsoleInfo->FontSize.X = 0; // HACK: !!
441 ConsoleInfo->FontSize.Y = 16; // HACK: !!
442 ConsoleInfo->FontFamily = FF_DONTCARE;
443 ConsoleInfo->FontWeight = FW_NORMAL; // FW_DONTCARE;
444
445 /* Initialize the default properties */
446
447 // #define DEFAULT_HISTORY_COMMANDS_NUMBER 50
448 // #define DEFAULT_HISTORY_BUFFERS_NUMBER 4
449 ConsoleInfo->HistoryBufferSize = 50;
450 ConsoleInfo->NumberOfHistoryBuffers = 4;
451 ConsoleInfo->HistoryNoDup = FALSE;
452
453 ConsoleInfo->QuickEdit = FALSE;
454 ConsoleInfo->InsertMode = TRUE;
455 // ConsoleInfo->InputBufferSize = 0;
456
457 // Rule: ScreenBufferSize >= WindowSize
458 ConsoleInfo->ScreenBufferSize.X = 80;
459 ConsoleInfo->ScreenBufferSize.Y = 300;
460 ConsoleInfo->WindowSize.X = 80;
461 ConsoleInfo->WindowSize.Y = 25;
462
463 ConsoleInfo->FullScreen = FALSE;
464 ConsoleInfo->AutoPosition = TRUE;
465 ConsoleInfo->WindowPosition.x = 0;
466 ConsoleInfo->WindowPosition.y = 0;
467
468 ConsoleInfo->CursorSize = CSR_DEFAULT_CURSOR_SIZE;
469
470 ConsoleInfo->ScreenAttributes = DEFAULT_SCREEN_ATTRIB;
471 ConsoleInfo->PopupAttributes = DEFAULT_POPUP_ATTRIB;
472
473 RtlCopyMemory(ConsoleInfo->ColorTable, s_Colors, sizeof(s_Colors));
474
475 ConsoleInfo->CodePage = GetOEMCP();
476 }
477
478 VOID
479 ConCfgGetDefaultSettings(
480 IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
481 {
482 if (ConsoleInfo == NULL) return;
483
484 /*
485 * 1. Load the default values
486 */
487 ConCfgInitDefaultSettings(ConsoleInfo);
488
489 /*
490 * 2. Overwrite them with the ones stored in HKCU\Console.
491 * If the HKCU\Console key doesn't exist, create it
492 * and store the default values inside.
493 */
494 if (!ConCfgReadUserSettings(ConsoleInfo, TRUE))
495 ConCfgWriteUserSettings(ConsoleInfo, TRUE);
496 }
497
498 /* EOF */