xref: /reactos/win32ss/user/winsrv/concfg/settings.c (revision 58588b76)
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 dwNumValues = 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                          &dwNumValues, 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, dwNumValues %d\n", dwNumValues);
199 
200     for (dwIndex = 0; dwIndex < dwNumValues; 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             /* A NULL value means that the defaults should be used instead */
242             if (*szValue)
243             {
244                 StringCchCopyNW(ConsoleInfo->FaceName, ARRAYSIZE(ConsoleInfo->FaceName),
245                                 szValue, ARRAYSIZE(szValue));
246             }
247             Success = TRUE;
248         }
249         else if (!wcscmp(szValueName, L"FontFamily"))
250         {
251             /* A zero value means that the defaults should be used instead */
252             if (Value)
253                 ConsoleInfo->FontFamily = Value;
254             Success = TRUE;
255         }
256         else if (!wcscmp(szValueName, L"FontSize"))
257         {
258             /* A zero value means that the defaults should be used instead */
259             if (Value)
260             {
261                 ConsoleInfo->FontSize.X = LOWORD(Value); // Width
262                 ConsoleInfo->FontSize.Y = HIWORD(Value); // Height
263             }
264             Success = TRUE;
265         }
266         else if (!wcscmp(szValueName, L"FontWeight"))
267         {
268             /* A zero value means that the defaults should be used instead */
269             if (Value)
270                 ConsoleInfo->FontWeight = Value;
271             Success = TRUE;
272         }
273         else if (!wcscmp(szValueName, L"HistoryBufferSize"))
274         {
275             ConsoleInfo->HistoryBufferSize = Value;
276             Success = TRUE;
277         }
278         else if (!wcscmp(szValueName, L"NumberOfHistoryBuffers"))
279         {
280             ConsoleInfo->NumberOfHistoryBuffers = Value;
281             Success = TRUE;
282         }
283         else if (!wcscmp(szValueName, L"HistoryNoDup"))
284         {
285             ConsoleInfo->HistoryNoDup = !!Value;
286             Success = TRUE;
287         }
288         else if (!wcscmp(szValueName, L"QuickEdit"))
289         {
290             ConsoleInfo->QuickEdit = !!Value;
291             Success = TRUE;
292         }
293         else if (!wcscmp(szValueName, L"InsertMode"))
294         {
295             ConsoleInfo->InsertMode = !!Value;
296             Success = TRUE;
297         }
298         else if (!wcscmp(szValueName, L"ScreenBufferSize"))
299         {
300             ConsoleInfo->ScreenBufferSize.X = LOWORD(Value);
301             ConsoleInfo->ScreenBufferSize.Y = HIWORD(Value);
302             Success = TRUE;
303         }
304         else if (!wcscmp(szValueName, L"FullScreen"))
305         {
306             ConsoleInfo->FullScreen = Value;
307             Success = TRUE;
308         }
309         else if (!wcscmp(szValueName, L"WindowPosition"))
310         {
311             ConsoleInfo->AutoPosition     = FALSE;
312             ConsoleInfo->WindowPosition.x = LOWORD(Value);
313             ConsoleInfo->WindowPosition.y = HIWORD(Value);
314             Success = TRUE;
315         }
316         else if (!wcscmp(szValueName, L"WindowSize"))
317         {
318             ConsoleInfo->WindowSize.X = LOWORD(Value);
319             ConsoleInfo->WindowSize.Y = HIWORD(Value);
320             Success = TRUE;
321         }
322         else if (!wcscmp(szValueName, L"CursorSize"))
323         {
324             ConsoleInfo->CursorSize = min(max(Value, 0), 100);
325             Success = TRUE;
326         }
327         else if (!wcscmp(szValueName, L"ScreenColors"))
328         {
329             ConsoleInfo->ScreenAttributes = (USHORT)Value;
330             Success = TRUE;
331         }
332         else if (!wcscmp(szValueName, L"PopupColors"))
333         {
334             ConsoleInfo->PopupAttributes = (USHORT)Value;
335             Success = TRUE;
336         }
337     }
338 
339     RegCloseKey(hKey);
340     return Success;
341 }
342 
343 BOOLEAN
344 ConCfgWriteUserSettings(
345     IN PCONSOLE_STATE_INFO ConsoleInfo,
346     IN BOOLEAN DefaultSettings)
347 {
348     HKEY hKey;
349     DWORD Storage = 0;
350 
351 #define SetConsoleSetting(SettingName, SettingType, SettingSize, Setting, DefaultValue)         \
352 do {                                                                                            \
353     if (DefaultSettings || (!DefaultSettings && (*(Setting) != (DefaultValue))))                \
354     {                                                                                           \
355         RegSetValueExW(hKey, (SettingName), 0, (SettingType), (PBYTE)(Setting), (SettingSize)); \
356     }                                                                                           \
357     else                                                                                        \
358     {                                                                                           \
359         RegDeleteValueW(hKey, (SettingName));                                                   \
360     }                                                                                           \
361 } while (0)
362 
363     WCHAR szValueName[15];
364     UINT i;
365 
366     if (!ConCfgOpenUserSettings(DefaultSettings ? L"" : ConsoleInfo->ConsoleTitle,
367                                 &hKey, KEY_WRITE, TRUE))
368     {
369         return FALSE;
370     }
371 
372     for (i = 0; i < ARRAYSIZE(ConsoleInfo->ColorTable); ++i)
373     {
374         /*
375          * Write only the new value if we are saving the global settings
376          * or we are saving settings for a particular console, which differs
377          * from the default ones.
378          */
379         swprintf(szValueName, L"ColorTable%02u", i);
380         SetConsoleSetting(szValueName, REG_DWORD, sizeof(DWORD), &ConsoleInfo->ColorTable[i], s_Colors[i]);
381     }
382 
383     SetConsoleSetting(L"CodePage", REG_DWORD, sizeof(DWORD), &ConsoleInfo->CodePage, CP_ACP /* CP_OEMCP */);
384     SetConsoleSetting(L"FaceName", REG_SZ, (wcslen(ConsoleInfo->FaceName) + 1) * sizeof(WCHAR), ConsoleInfo->FaceName, UNICODE_NULL); // wcsnlen
385     SetConsoleSetting(L"FontFamily", REG_DWORD, sizeof(DWORD), &ConsoleInfo->FontFamily, FF_DONTCARE);
386 
387     Storage = MAKELONG(ConsoleInfo->FontSize.X, ConsoleInfo->FontSize.Y); // Width, Height
388     SetConsoleSetting(L"FontSize", REG_DWORD, sizeof(DWORD), &Storage, 0);
389 
390     SetConsoleSetting(L"FontWeight", REG_DWORD, sizeof(DWORD), &ConsoleInfo->FontWeight, FW_DONTCARE);
391 
392     SetConsoleSetting(L"HistoryBufferSize", REG_DWORD, sizeof(DWORD), &ConsoleInfo->HistoryBufferSize, 50);
393     SetConsoleSetting(L"NumberOfHistoryBuffers", REG_DWORD, sizeof(DWORD), &ConsoleInfo->NumberOfHistoryBuffers, 4);
394 
395     Storage = ConsoleInfo->HistoryNoDup;
396     SetConsoleSetting(L"HistoryNoDup", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
397 
398     Storage = ConsoleInfo->QuickEdit;
399     SetConsoleSetting(L"QuickEdit", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
400 
401     Storage = ConsoleInfo->InsertMode;
402     SetConsoleSetting(L"InsertMode", REG_DWORD, sizeof(DWORD), &Storage, TRUE);
403 
404     Storage = MAKELONG(ConsoleInfo->ScreenBufferSize.X, ConsoleInfo->ScreenBufferSize.Y);
405     SetConsoleSetting(L"ScreenBufferSize", REG_DWORD, sizeof(DWORD), &Storage, MAKELONG(80, 300));
406 
407     Storage = ConsoleInfo->FullScreen;
408     SetConsoleSetting(L"FullScreen", REG_DWORD, sizeof(DWORD), &Storage, FALSE);
409 
410     if (ConsoleInfo->AutoPosition == FALSE)
411     {
412         Storage = MAKELONG(ConsoleInfo->WindowPosition.x, ConsoleInfo->WindowPosition.y);
413         RegSetValueExW(hKey, L"WindowPosition", 0, REG_DWORD, (PBYTE)&Storage, sizeof(DWORD));
414     }
415     else
416     {
417         RegDeleteValueW(hKey, L"WindowPosition");
418     }
419 
420     Storage = MAKELONG(ConsoleInfo->WindowSize.X, ConsoleInfo->WindowSize.Y);
421     SetConsoleSetting(L"WindowSize", REG_DWORD, sizeof(DWORD), &Storage, MAKELONG(80, 25));
422 
423     SetConsoleSetting(L"CursorSize", REG_DWORD, sizeof(DWORD), &ConsoleInfo->CursorSize, CSR_DEFAULT_CURSOR_SIZE);
424 
425     Storage = ConsoleInfo->ScreenAttributes;
426     SetConsoleSetting(L"ScreenColors", REG_DWORD, sizeof(DWORD), &Storage, DEFAULT_SCREEN_ATTRIB);
427 
428     Storage = ConsoleInfo->PopupAttributes;
429     SetConsoleSetting(L"PopupColors", REG_DWORD, sizeof(DWORD), &Storage, DEFAULT_POPUP_ATTRIB);
430 
431     RegCloseKey(hKey);
432     return TRUE;
433 }
434 
435 VOID
436 ConCfgInitDefaultSettings(
437     IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
438 {
439     if (ConsoleInfo == NULL) return;
440 
441     // ASSERT(ConsoleInfo->cbSize >= sizeof(CONSOLE_STATE_INFO));
442 
443 /// HKCU,"Console","LoadConIme",0x00010003,1
444 
445     // wcsncpy(ConsoleInfo->FaceName, L"DejaVu Sans Mono", LF_FACESIZE);
446     // ConsoleInfo->FontSize = MAKELONG(8, 12); // 0x000C0008; // font is 8x12
447 
448     StringCchCopyW(ConsoleInfo->FaceName, ARRAYSIZE(ConsoleInfo->FaceName), L"VGA"); // HACK: !!
449     // ConsoleInfo->FaceName[0] = UNICODE_NULL;
450     // ConsoleInfo->FontSize.X = 8;
451     // ConsoleInfo->FontSize.Y = 12;
452     ConsoleInfo->FontSize.X = 0;  // HACK: !!
453     ConsoleInfo->FontSize.Y = 16; // HACK: !!
454     ConsoleInfo->FontFamily = FF_DONTCARE;
455     ConsoleInfo->FontWeight = FW_NORMAL; // FW_DONTCARE;
456 
457     /* Initialize the default properties */
458 
459 // #define DEFAULT_HISTORY_COMMANDS_NUMBER 50
460 // #define DEFAULT_HISTORY_BUFFERS_NUMBER 4
461     ConsoleInfo->HistoryBufferSize = 50;
462     ConsoleInfo->NumberOfHistoryBuffers = 4;
463     ConsoleInfo->HistoryNoDup = FALSE;
464 
465     ConsoleInfo->QuickEdit  = FALSE;
466     ConsoleInfo->InsertMode = TRUE;
467     // ConsoleInfo->InputBufferSize = 0;
468 
469     // Rule: ScreenBufferSize >= WindowSize
470     ConsoleInfo->ScreenBufferSize.X = 80;
471     ConsoleInfo->ScreenBufferSize.Y = 300;
472     ConsoleInfo->WindowSize.X = 80;
473     ConsoleInfo->WindowSize.Y = 25;
474 
475     ConsoleInfo->FullScreen   = FALSE;
476     ConsoleInfo->AutoPosition = TRUE;
477     ConsoleInfo->WindowPosition.x = 0;
478     ConsoleInfo->WindowPosition.y = 0;
479 
480     ConsoleInfo->CursorSize = CSR_DEFAULT_CURSOR_SIZE;
481 
482     ConsoleInfo->ScreenAttributes = DEFAULT_SCREEN_ATTRIB;
483     ConsoleInfo->PopupAttributes  = DEFAULT_POPUP_ATTRIB;
484 
485     RtlCopyMemory(ConsoleInfo->ColorTable, s_Colors, sizeof(s_Colors));
486 
487     ConsoleInfo->CodePage = GetOEMCP();
488 }
489 
490 VOID
491 ConCfgGetDefaultSettings(
492     IN OUT PCONSOLE_STATE_INFO ConsoleInfo)
493 {
494     if (ConsoleInfo == NULL) return;
495 
496     /*
497      * 1. Load the default values
498      */
499     ConCfgInitDefaultSettings(ConsoleInfo);
500 
501     /*
502      * 2. Overwrite them with the ones stored in HKCU\Console.
503      *    If the HKCU\Console key doesn't exist, create it
504      *    and store the default values inside.
505      */
506     if (!ConCfgReadUserSettings(ConsoleInfo, TRUE))
507         ConCfgWriteUserSettings(ConsoleInfo, TRUE);
508 }
509 
510 /* EOF */
511