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)
15 #define MAX_VALUE_NAME 16383
19 * A function that locates the insertion point (index) for a given value 'Value'
20 * in a list 'List' to maintain its sorted order by increasing values.
22 * - When 'BisectRightOrLeft' == TRUE, the bisection is performed to the right,
23 * i.e. the returned insertion point comes after (to the right of) any existing
24 * entries of 'Value' in 'List'.
25 * The returned insertion point 'i' partitions the list 'List' into two halves
27 * all(val <= Value for val in List[start:i[) for the left side, and
28 * all(val > Value for val in List[i:end+1[) for the right side.
30 * - When 'BisectRightOrLeft' == FALSE, the bisection is performed to the left,
31 * i.e. the returned insertion point comes before (to the left of) any existing
32 * entries of 'Value' in 'List'.
33 * The returned insertion point 'i' partitions the list 'List' into two halves
35 * all(val < Value for val in List[start:i[) for the left side, and
36 * all(val >= Value for val in List[i:end+1[) for the right side.
38 * The exact value of List[i] may, or may not, be equal to Value, depending on
39 * whether or not 'Value' is actually present on the list.
42 BisectListSortedByValueEx(
47 OUT PUINT pValueItem OPTIONAL
,
48 IN BOOL BisectRightOrLeft
)
50 UINT iItemStart
, iItemEnd
, iItem
;
54 if (itemStart
> itemEnd
)
55 return CB_ERR
; // Fail
58 iItemStart
= itemStart
;
65 while (iItemStart
<= iItemEnd
)
68 * Bisect. Note the following:
69 * - if iItemEnd == iItemStart + 1, then iItem == iItemStart;
70 * - if iItemStart == iItemEnd, then iItemStart == iItem == iItemEnd.
71 * In all but the last case, iItemStart <= iItem < iItemEnd.
73 iItem
= (iItemStart
+ iItemEnd
) / 2;
75 itemData
= (ULONG_PTR
)SendMessageW(hWndList
, CB_GETITEMDATA
, (WPARAM
)iItem
, 0);
76 if (itemData
== CB_ERR
)
77 return CB_ERR
; // Fail
79 if (Value
== itemData
)
81 /* Found a candidate */
86 * Try to find the last element (if BisectRightOrLeft == TRUE)
87 * or the first element (if BisectRightOrLeft == FALSE).
89 if (BisectRightOrLeft
)
91 iItemStart
= iItem
+ 1; // iItemStart may be > iItemEnd
95 if (iItem
<= itemStart
) break;
96 iItemEnd
= iItem
- 1; // iItemEnd may be < iItemStart, i.e. iItemStart may be > iItemEnd
99 else if (Value
< itemData
)
101 if (iItem
<= itemStart
) break;
102 /* The value should be before iItem */
103 iItemEnd
= iItem
- 1; // iItemEnd may be < iItemStart, i.e. iItemStart may be > iItemEnd, if iItem == iItemStart.
105 else // if (itemData < Value)
107 /* The value should be after iItem */
108 iItemStart
= iItem
+ 1; // iItemStart may be > iItemEnd, if iItem == iItemEnd.
111 /* Here, iItemStart may be == iItemEnd */
118 BisectListSortedByValue(
121 OUT PUINT pValueItem OPTIONAL
,
122 IN BOOL BisectRightOrLeft
)
124 INT iItemEnd
= (INT
)SendMessageW(hWndList
, CB_GETCOUNT
, 0, 0);
125 if (iItemEnd
== CB_ERR
|| iItemEnd
<= 0)
126 return CB_ERR
; // Fail
128 return BisectListSortedByValueEx(hWndList
, Value
,
129 0, (UINT
)(iItemEnd
- 1),
140 UINT iItem
, iDupItem
;
144 * Add only valid code pages, that is:
145 * - If the CodePage is one of the reserved (alias) values:
146 * CP_ACP == 0 ; CP_OEMCP == 1 ; CP_MACCP == 2 ; CP_THREAD_ACP == 3 ;
147 * or the deprecated CP_SYMBOL == 42 (see http://archives.miloush.net/michkap/archive/2005/11/08/490495.html)
148 * it is considered invalid.
149 * - If IsValidCodePage() fails because the code page is listed but
150 * not installed on the system, it is also considered invalid.
152 if (CodePage
== CP_ACP
|| CodePage
== CP_OEMCP
|| CodePage
== CP_MACCP
||
153 CodePage
== CP_THREAD_ACP
|| CodePage
== CP_SYMBOL
|| !IsValidCodePage(CodePage
))
158 /* Retrieve the code page display name */
159 if (!GetCPInfoExW(CodePage
, 0, &CPInfo
))
161 /* We failed, just use the code page value as its name */
162 // _ultow(CodePage, CPInfo.CodePageName, 10);
163 _snwprintf(CPInfo
.CodePageName
, ARRAYSIZE(CPInfo
.CodePageName
), L
"%lu", CodePage
);
166 /* Add the code page into the list, sorted by code page value. Avoid any duplicates. */
168 iItem
= BisectListSortedByValue(hWndList
, CodePage
, &iDupItem
, TRUE
);
171 if (iDupItem
!= CB_ERR
)
173 iItem
= (UINT
)SendMessageW(hWndList
, CB_INSERTSTRING
, iItem
, (LPARAM
)CPInfo
.CodePageName
);
174 if (iItem
!= CB_ERR
&& iItem
!= CB_ERRSPACE
)
175 iItem
= SendMessageW(hWndList
, CB_SETITEMDATA
, iItem
, CodePage
);
179 BuildCodePageList(IN HWND hDlg
)
183 DWORD dwIndex
, dwSize
, dwType
;
185 WCHAR szValueName
[MAX_VALUE_NAME
];
187 // #define REGSTR_PATH_CODEPAGE TEXT("System\\CurrentControlSet\\Control\\Nls\\CodePage")
188 /* Open the Nls\CodePage key */
189 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
190 L
"System\\CurrentControlSet\\Control\\Nls\\CodePage",
192 KEY_ENUMERATE_SUB_KEYS
| KEY_QUERY_VALUE
,
193 &hKey
) != ERROR_SUCCESS
)
198 hWndList
= GetDlgItem(hDlg
, IDL_CODEPAGE
);
200 /* Enumerate all the available code pages on the system */
201 dwSize
= ARRAYSIZE(szValueName
);
203 while (RegEnumValueW(hKey
, dwIndex
, szValueName
, &dwSize
,
204 NULL
, &dwType
, NULL
, NULL
) == ERROR_SUCCESS
) // != ERROR_NO_MORE_ITEMS
206 /* Ignore these parameters, prepare for next iteration */
207 dwSize
= ARRAYSIZE(szValueName
);
210 /* Check the value type validity */
211 if (dwType
!= REG_SZ
)
215 * Add the code page into the list.
216 * If _wtol fails and returns 0, the code page is considered invalid
217 * (and indeed this value corresponds to the CP_ACP alias too).
219 CodePage
= (UINT
)_wtol(szValueName
);
220 if (CodePage
== 0) continue;
221 AddCodePage(hWndList
, CodePage
);
226 /* Add the special UTF-7 (CP_UTF7 65000) and UTF-8 (CP_UTF8 65001) code pages */
227 AddCodePage(hWndList
, CP_UTF7
);
228 AddCodePage(hWndList
, CP_UTF8
);
230 /* Find and select the current code page in the sorted list */
231 if (BisectListSortedByValue(hWndList
, ConInfo
->CodePage
, &CodePage
, FALSE
) == CB_ERR
||
234 /* Not found, select the first element */
237 SendMessageW(hWndList
, CB_SETCURSEL
, (WPARAM
)CodePage
, 0);
241 UpdateDialogElements(HWND hwndDlg
, PCONSOLE_STATE_INFO pConInfo
)
245 /* Update cursor size */
246 if (pConInfo
->CursorSize
<= 25)
249 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_SMALL_CURSOR
);
250 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_CHECKED
, 0);
252 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_MEDIUM_CURSOR
);
253 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
254 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_LARGE_CURSOR
);
255 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
257 else if (pConInfo
->CursorSize
<= 50)
259 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_MEDIUM_CURSOR
);
260 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_CHECKED
, 0);
262 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_SMALL_CURSOR
);
263 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
264 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_LARGE_CURSOR
);
265 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
267 else /* if (pConInfo->CursorSize <= 100) */
269 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_LARGE_CURSOR
);
270 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_CHECKED
, 0);
272 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_SMALL_CURSOR
);
273 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
274 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_MEDIUM_CURSOR
);
275 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
278 /* Update num buffers */
279 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_UPDOWN_NUM_BUFFER
);
280 SendMessageW(hDlgCtrl
, UDM_SETRANGE
, 0, MAKELONG(999, 1));
281 SetDlgItemInt(hwndDlg
, IDC_EDIT_NUM_BUFFER
, pConInfo
->NumberOfHistoryBuffers
, FALSE
);
283 /* Update buffer size */
284 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_UPDOWN_BUFFER_SIZE
);
285 SendMessageW(hDlgCtrl
, UDM_SETRANGE
, 0, MAKELONG(999, 1));
286 SetDlgItemInt(hwndDlg
, IDC_EDIT_BUFFER_SIZE
, pConInfo
->HistoryBufferSize
, FALSE
);
288 /* Update discard duplicates */
289 CheckDlgButton(hwndDlg
, IDC_CHECK_DISCARD_DUPLICATES
,
290 pConInfo
->HistoryNoDup
? BST_CHECKED
: BST_UNCHECKED
);
292 /* Update full/window screen */
293 if (pConInfo
->FullScreen
)
295 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_DISPLAY_FULL
);
296 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_CHECKED
, 0);
298 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_DISPLAY_WINDOW
);
299 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
303 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_DISPLAY_WINDOW
);
304 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_CHECKED
, 0);
306 hDlgCtrl
= GetDlgItem(hwndDlg
, IDC_RADIO_DISPLAY_FULL
);
307 SendMessageW(hDlgCtrl
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
310 /* Update quick edit */
311 CheckDlgButton(hwndDlg
, IDC_CHECK_QUICK_EDIT
,
312 pConInfo
->QuickEdit
? BST_CHECKED
: BST_UNCHECKED
);
314 /* Update insert mode */
315 CheckDlgButton(hwndDlg
, IDC_CHECK_INSERT_MODE
,
316 pConInfo
->InsertMode
? BST_CHECKED
: BST_UNCHECKED
);
321 OptionsProc(HWND hwndDlg
,
330 BuildCodePageList(hwndDlg
);
331 UpdateDialogElements(hwndDlg
, ConInfo
);
337 LPPSHNOTIFY lppsn
= (LPPSHNOTIFY
)lParam
;
339 if (lppsn
->hdr
.code
== UDN_DELTAPOS
)
341 LPNMUPDOWN lpnmud
= (LPNMUPDOWN
)lParam
;
343 if (lppsn
->hdr
.idFrom
== IDC_UPDOWN_BUFFER_SIZE
)
345 lpnmud
->iPos
= min(max(lpnmud
->iPos
+ lpnmud
->iDelta
, 1), 999);
346 ConInfo
->HistoryBufferSize
= lpnmud
->iPos
;
347 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
349 else if (lppsn
->hdr
.idFrom
== IDC_UPDOWN_NUM_BUFFER
)
351 lpnmud
->iPos
= min(max(lpnmud
->iPos
+ lpnmud
->iDelta
, 1), 999);
352 ConInfo
->NumberOfHistoryBuffers
= lpnmud
->iPos
;
353 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
356 else if (lppsn
->hdr
.code
== PSN_APPLY
)
358 ApplyConsoleInfo(hwndDlg
);
368 switch (LOWORD(wParam
))
370 case IDC_RADIO_SMALL_CURSOR
:
372 ConInfo
->CursorSize
= 25;
373 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
376 case IDC_RADIO_MEDIUM_CURSOR
:
378 ConInfo
->CursorSize
= 50;
379 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
382 case IDC_RADIO_LARGE_CURSOR
:
384 ConInfo
->CursorSize
= 100;
385 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
388 case IDC_RADIO_DISPLAY_WINDOW
:
390 ConInfo
->FullScreen
= FALSE
;
391 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
394 case IDC_RADIO_DISPLAY_FULL
:
396 ConInfo
->FullScreen
= TRUE
;
397 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
400 case IDC_CHECK_QUICK_EDIT
:
402 lResult
= SendMessageW((HWND
)lParam
, BM_GETCHECK
, 0, 0);
403 if (lResult
== BST_CHECKED
)
405 ConInfo
->QuickEdit
= FALSE
;
406 SendMessageW((HWND
)lParam
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
408 else if (lResult
== BST_UNCHECKED
)
410 ConInfo
->QuickEdit
= TRUE
;
411 SendMessageW((HWND
)lParam
, BM_SETCHECK
, (WPARAM
)BST_CHECKED
, 0);
413 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
416 case IDC_CHECK_INSERT_MODE
:
418 lResult
= SendMessageW((HWND
)lParam
, BM_GETCHECK
, 0, 0);
419 if (lResult
== BST_CHECKED
)
421 ConInfo
->InsertMode
= FALSE
;
422 SendMessageW((HWND
)lParam
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
424 else if (lResult
== BST_UNCHECKED
)
426 ConInfo
->InsertMode
= TRUE
;
427 SendMessageW((HWND
)lParam
, BM_SETCHECK
, (WPARAM
)BST_CHECKED
, 0);
429 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
432 case IDC_CHECK_DISCARD_DUPLICATES
:
434 lResult
= SendMessageW((HWND
)lParam
, BM_GETCHECK
, 0, 0);
435 if (lResult
== BST_CHECKED
)
437 ConInfo
->HistoryNoDup
= FALSE
;
438 SendMessageW((HWND
)lParam
, BM_SETCHECK
, (WPARAM
)BST_UNCHECKED
, 0);
440 else if (lResult
== BST_UNCHECKED
)
442 ConInfo
->HistoryNoDup
= TRUE
;
443 SendMessageW((HWND
)lParam
, BM_SETCHECK
, (WPARAM
)BST_CHECKED
, 0);
445 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
448 case IDC_EDIT_BUFFER_SIZE
:
450 if (HIWORD(wParam
) == EN_KILLFOCUS
)
454 sizeBuff
= GetDlgItemInt(hwndDlg
, IDC_EDIT_BUFFER_SIZE
, NULL
, FALSE
);
455 sizeBuff
= min(max(sizeBuff
, 1), 999);
457 ConInfo
->HistoryBufferSize
= sizeBuff
;
458 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
462 case IDC_EDIT_NUM_BUFFER
:
464 if (HIWORD(wParam
) == EN_KILLFOCUS
)
468 numBuff
= GetDlgItemInt(hwndDlg
, IDC_EDIT_NUM_BUFFER
, NULL
, FALSE
);
469 numBuff
= min(max(numBuff
, 1), 999);
471 ConInfo
->NumberOfHistoryBuffers
= numBuff
;
472 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
478 if (HIWORD(wParam
) == CBN_SELENDOK
)
483 iItem
= (INT
)SendMessageW((HWND
)lParam
, CB_GETCURSEL
, 0, 0);
486 CodePage
= (UINT
)SendMessageW((HWND
)lParam
, CB_GETITEMDATA
, iItem
, 0);
487 if (CodePage
!= CB_ERR
)
489 ConInfo
->CodePage
= CodePage
;
490 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);