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