1 /* 2 * PROJECT: ReactOS Console Configuration DLL 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/cpl/console/options.c 5 * PURPOSE: Options dialog 6 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org) 7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 8 */ 9 10 #include "console.h" 11 12 #define NDEBUG 13 #include <debug.h> 14 15 #define MAX_VALUE_NAME 16383 16 17 18 static INT 19 List_GetCount(IN PLIST_CTL ListCtl) 20 { 21 return (INT)SendMessageW(ListCtl->hWndList, CB_GETCOUNT, 0, 0); 22 } 23 24 static ULONG_PTR 25 List_GetData(IN PLIST_CTL ListCtl, IN INT Index) 26 { 27 return (ULONG_PTR)SendMessageW(ListCtl->hWndList, CB_GETITEMDATA, (WPARAM)Index, 0); 28 } 29 30 static VOID 31 AddCodePage( 32 IN PLIST_CTL ListCtl, 33 IN UINT CodePage) 34 { 35 UINT iItem, iDupItem; 36 CPINFOEXW CPInfo; 37 38 /* 39 * Add only valid code pages, that is: 40 * - If the CodePage is one of the reserved (alias) values: 41 * CP_ACP == 0 ; CP_OEMCP == 1 ; CP_MACCP == 2 ; CP_THREAD_ACP == 3 ; 42 * or the deprecated CP_SYMBOL == 42 (see http://archives.miloush.net/michkap/archive/2005/11/08/490495.html) 43 * it is considered invalid. 44 * - If IsValidCodePage() fails because the code page is listed but 45 * not installed on the system, it is also considered invalid. 46 */ 47 if (CodePage == CP_ACP || CodePage == CP_OEMCP || CodePage == CP_MACCP || 48 CodePage == CP_THREAD_ACP || CodePage == CP_SYMBOL || !IsValidCodePage(CodePage)) 49 { 50 return; 51 } 52 53 /* Retrieve the code page display name */ 54 if (!GetCPInfoExW(CodePage, 0, &CPInfo)) 55 { 56 /* We failed, just use the code page value as its name */ 57 // _ultow(CodePage, CPInfo.CodePageName, 10); 58 StringCchPrintfW(CPInfo.CodePageName, ARRAYSIZE(CPInfo.CodePageName), L"%lu", CodePage); 59 } 60 61 /* Add the code page into the list, sorted by code page value. Avoid any duplicates. */ 62 iDupItem = CB_ERR; 63 iItem = BisectListSortedByValue(ListCtl, CodePage, &iDupItem, TRUE); 64 if (iItem == CB_ERR) 65 iItem = 0; 66 if (iDupItem != CB_ERR) 67 return; 68 iItem = (UINT)SendMessageW(ListCtl->hWndList, CB_INSERTSTRING, iItem, (LPARAM)CPInfo.CodePageName); 69 if (iItem != CB_ERR && iItem != CB_ERRSPACE) 70 iItem = SendMessageW(ListCtl->hWndList, CB_SETITEMDATA, iItem, CodePage); 71 } 72 73 static VOID 74 BuildCodePageList( 75 IN HWND hDlg, 76 IN UINT CurrentCodePage) 77 { 78 LIST_CTL ListCtl; 79 LRESULT lResult; 80 HKEY hKey; 81 DWORD dwIndex, dwType; 82 DWORD cchValueName; 83 UINT CodePage; 84 85 /* Valid code page value names are string representations 86 * of their corresponding decimal values, that are not larger 87 * than MAXUSHORT == 65535. */ 88 WCHAR szValueName[sizeof("65535")]; 89 90 /* Open the Nls\CodePage key */ 91 // #define REGSTR_PATH_CODEPAGE TEXT("System\\CurrentControlSet\\Control\\Nls\\CodePage") 92 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, 93 L"System\\CurrentControlSet\\Control\\Nls\\CodePage", 94 0, 95 KEY_QUERY_VALUE, 96 &hKey) != ERROR_SUCCESS) 97 { 98 return; 99 } 100 101 ListCtl.hWndList = GetDlgItem(hDlg, IDL_CODEPAGE); 102 ListCtl.GetCount = List_GetCount; 103 ListCtl.GetData = List_GetData; 104 105 /* Enumerate all the available code pages on the system */ 106 for (dwIndex = 0, cchValueName = ARRAYSIZE(szValueName); 107 (lResult = RegEnumValueW(hKey, dwIndex, 108 szValueName, &cchValueName, 109 NULL, &dwType, 110 NULL, NULL)) != ERROR_NO_MORE_ITEMS; 111 ++dwIndex, cchValueName = ARRAYSIZE(szValueName)) 112 { 113 /* Ignore if we failed for another reason, e.g. because 114 * the value name is too long (and thus, invalid). */ 115 if (lResult != ERROR_SUCCESS) 116 continue; 117 118 /* Validate the value name (exclude the unnamed value) */ 119 if (!cchValueName || (*szValueName == UNICODE_NULL)) 120 continue; 121 /* Too large value names have already been handled with ERROR_MORE_DATA */ 122 ASSERT((cchValueName < ARRAYSIZE(szValueName)) && 123 (szValueName[cchValueName] == UNICODE_NULL)); 124 125 /* Validate the value type */ 126 if (dwType != REG_SZ) 127 continue; 128 129 /* 130 * Add the code page into the list. 131 * If _wtol fails and returns 0, the code page is considered invalid 132 * (and indeed this value corresponds to the CP_ACP alias too). 133 */ 134 CodePage = (UINT)_wtol(szValueName); 135 if (CodePage == 0) continue; 136 AddCodePage(&ListCtl, CodePage); 137 } 138 139 RegCloseKey(hKey); 140 141 /* Add the special UTF-7 (CP_UTF7 65000) and UTF-8 (CP_UTF8 65001) code pages */ 142 AddCodePage(&ListCtl, CP_UTF7); 143 AddCodePage(&ListCtl, CP_UTF8); 144 145 /* Find and select the current code page in the sorted list */ 146 if (BisectListSortedByValue(&ListCtl, CurrentCodePage, &CodePage, FALSE) == CB_ERR || 147 CodePage == CB_ERR) 148 { 149 /* Not found, select the first element */ 150 CodePage = 0; 151 } 152 SendMessageW(ListCtl.hWndList, CB_SETCURSEL, (WPARAM)CodePage, 0); 153 } 154 155 static VOID 156 UpdateDialogElements( 157 IN HWND hDlg, 158 IN PCONSOLE_STATE_INFO pConInfo) 159 { 160 /* Update the cursor size */ 161 if (pConInfo->CursorSize <= 25) 162 { 163 /* Small cursor */ 164 CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_SMALL_CURSOR); 165 // CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_CHECKED); 166 // CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_UNCHECKED); 167 // CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_UNCHECKED); 168 } 169 else if (pConInfo->CursorSize <= 50) 170 { 171 /* Medium cursor */ 172 CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_MEDIUM_CURSOR); 173 // CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_UNCHECKED); 174 // CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_CHECKED); 175 // CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_UNCHECKED); 176 } 177 else /* if (pConInfo->CursorSize <= 100) */ 178 { 179 /* Large cursor */ 180 CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_LARGE_CURSOR); 181 // CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_UNCHECKED); 182 // CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_UNCHECKED); 183 // CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_CHECKED); 184 } 185 186 /* Update the number of history buffers */ 187 SendDlgItemMessageW(hDlg, IDC_UPDOWN_NUM_BUFFER, UDM_SETRANGE, 0, MAKELONG(999, 1)); 188 SetDlgItemInt(hDlg, IDC_EDIT_NUM_BUFFER, pConInfo->NumberOfHistoryBuffers, FALSE); 189 190 /* Update the history buffer size */ 191 SendDlgItemMessageW(hDlg, IDC_UPDOWN_BUFFER_SIZE, UDM_SETRANGE, 0, MAKELONG(999, 1)); 192 SetDlgItemInt(hDlg, IDC_EDIT_BUFFER_SIZE, pConInfo->HistoryBufferSize, FALSE); 193 194 /* Update discard duplicates */ 195 CheckDlgButton(hDlg, IDC_CHECK_DISCARD_DUPLICATES, 196 pConInfo->HistoryNoDup ? BST_CHECKED : BST_UNCHECKED); 197 198 /* Update full/window screen state */ 199 if (pConInfo->FullScreen) 200 { 201 CheckRadioButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, IDC_RADIO_DISPLAY_FULL, IDC_RADIO_DISPLAY_FULL); 202 // CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, BST_UNCHECKED); 203 // CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_FULL , BST_CHECKED); 204 } 205 else 206 { 207 CheckRadioButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, IDC_RADIO_DISPLAY_FULL, IDC_RADIO_DISPLAY_WINDOW); 208 // CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, BST_CHECKED); 209 // CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_FULL , BST_UNCHECKED); 210 } 211 212 /* Update "Quick-edit" state */ 213 CheckDlgButton(hDlg, IDC_CHECK_QUICK_EDIT, 214 pConInfo->QuickEdit ? BST_CHECKED : BST_UNCHECKED); 215 216 /* Update "Insert mode" state */ 217 CheckDlgButton(hDlg, IDC_CHECK_INSERT_MODE, 218 pConInfo->InsertMode ? BST_CHECKED : BST_UNCHECKED); 219 } 220 221 INT_PTR 222 CALLBACK 223 OptionsProc(HWND hDlg, 224 UINT uMsg, 225 WPARAM wParam, 226 LPARAM lParam) 227 { 228 switch (uMsg) 229 { 230 case WM_INITDIALOG: 231 { 232 BuildCodePageList(hDlg, ConInfo->CodePage); 233 UpdateDialogElements(hDlg, ConInfo); 234 return TRUE; 235 } 236 237 case WM_NOTIFY: 238 { 239 LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam; 240 241 if (lppsn->hdr.code == UDN_DELTAPOS) 242 { 243 LPNMUPDOWN lpnmud = (LPNMUPDOWN)lParam; 244 245 if (lppsn->hdr.idFrom == IDC_UPDOWN_BUFFER_SIZE) 246 { 247 lpnmud->iPos = min(max(lpnmud->iPos + lpnmud->iDelta, 1), 999); 248 ConInfo->HistoryBufferSize = lpnmud->iPos; 249 PropSheet_Changed(GetParent(hDlg), hDlg); 250 } 251 else if (lppsn->hdr.idFrom == IDC_UPDOWN_NUM_BUFFER) 252 { 253 lpnmud->iPos = min(max(lpnmud->iPos + lpnmud->iDelta, 1), 999); 254 ConInfo->NumberOfHistoryBuffers = lpnmud->iPos; 255 PropSheet_Changed(GetParent(hDlg), hDlg); 256 } 257 } 258 else if (lppsn->hdr.code == PSN_APPLY) 259 { 260 ApplyConsoleInfo(hDlg); 261 return TRUE; 262 } 263 break; 264 } 265 266 case WM_COMMAND: 267 { 268 if (HIWORD(wParam) == BN_CLICKED) 269 { 270 switch (LOWORD(wParam)) 271 { 272 case IDC_RADIO_SMALL_CURSOR: 273 { 274 ConInfo->CursorSize = 25; 275 PropSheet_Changed(GetParent(hDlg), hDlg); 276 break; 277 } 278 case IDC_RADIO_MEDIUM_CURSOR: 279 { 280 ConInfo->CursorSize = 50; 281 PropSheet_Changed(GetParent(hDlg), hDlg); 282 break; 283 } 284 case IDC_RADIO_LARGE_CURSOR: 285 { 286 ConInfo->CursorSize = 100; 287 PropSheet_Changed(GetParent(hDlg), hDlg); 288 break; 289 } 290 case IDC_RADIO_DISPLAY_WINDOW: 291 { 292 ConInfo->FullScreen = FALSE; 293 PropSheet_Changed(GetParent(hDlg), hDlg); 294 break; 295 } 296 case IDC_RADIO_DISPLAY_FULL: 297 { 298 ConInfo->FullScreen = TRUE; 299 PropSheet_Changed(GetParent(hDlg), hDlg); 300 break; 301 } 302 case IDC_CHECK_QUICK_EDIT: 303 { 304 ConInfo->QuickEdit = (IsDlgButtonChecked(hDlg, IDC_CHECK_QUICK_EDIT) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE 305 PropSheet_Changed(GetParent(hDlg), hDlg); 306 break; 307 } 308 case IDC_CHECK_INSERT_MODE: 309 { 310 ConInfo->InsertMode = (IsDlgButtonChecked(hDlg, IDC_CHECK_INSERT_MODE) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE 311 PropSheet_Changed(GetParent(hDlg), hDlg); 312 break; 313 } 314 case IDC_CHECK_DISCARD_DUPLICATES: 315 { 316 ConInfo->HistoryNoDup = (IsDlgButtonChecked(hDlg, IDC_CHECK_DISCARD_DUPLICATES) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE 317 PropSheet_Changed(GetParent(hDlg), hDlg); 318 break; 319 } 320 } 321 } 322 else 323 if (HIWORD(wParam) == EN_KILLFOCUS) 324 { 325 switch (LOWORD(wParam)) 326 { 327 case IDC_EDIT_BUFFER_SIZE: 328 { 329 DWORD sizeBuff; 330 331 sizeBuff = GetDlgItemInt(hDlg, IDC_EDIT_BUFFER_SIZE, NULL, FALSE); 332 sizeBuff = min(max(sizeBuff, 1), 999); 333 334 ConInfo->HistoryBufferSize = sizeBuff; 335 PropSheet_Changed(GetParent(hDlg), hDlg); 336 break; 337 } 338 case IDC_EDIT_NUM_BUFFER: 339 { 340 DWORD numBuff; 341 342 numBuff = GetDlgItemInt(hDlg, IDC_EDIT_NUM_BUFFER, NULL, FALSE); 343 numBuff = min(max(numBuff, 1), 999); 344 345 ConInfo->NumberOfHistoryBuffers = numBuff; 346 PropSheet_Changed(GetParent(hDlg), hDlg); 347 break; 348 } 349 } 350 } 351 else 352 // (HIWORD(wParam) == CBN_KILLFOCUS) 353 if ((HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_SELENDOK) && 354 (LOWORD(wParam) == IDL_CODEPAGE)) 355 { 356 HWND hWndList = GetDlgItem(hDlg, IDL_CODEPAGE); 357 INT iItem; 358 UINT CodePage; 359 360 iItem = (INT)SendMessageW(hWndList, CB_GETCURSEL, 0, 0); 361 if (iItem == CB_ERR) 362 break; 363 364 CodePage = (UINT)SendMessageW(hWndList, CB_GETITEMDATA, iItem, 0); 365 if (CodePage == CB_ERR) 366 break; 367 368 /* If the user has selected a different code page... */ 369 if ((HIWORD(wParam) == CBN_SELENDOK) && (CodePage != ConInfo->CodePage)) 370 { 371 /* ... update the code page and change the property sheet state */ 372 ConInfo->CodePage = CodePage; 373 ResetFontPreview(&FontPreview); 374 PropSheet_Changed(GetParent(hDlg), hDlg); 375 } 376 } 377 378 break; 379 } 380 381 default: 382 break; 383 } 384 385 return FALSE; 386 } 387