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