reactos/dll/cpl/console/options.c
Hermès Bélusca-Maïto c4e2826c73
[CONSOLE][CONCFG][CONSRV] Provide support for specified additional TrueType fonts + bugfixes.
CORE-12451 CORE-13182 CORE-13196

- CONSOLE: Initialize the additional TrueType fonts cache.
  * Fix the font preview when a TrueType font has been selected.
  * Refresh the available fonts and the font preview when the selected
    code page is changed (Work In Progress), or when the OS pool of
    font resources has changed (WM_FONTCHANGE message).

- CONCFG: Implement support for the additional TrueType fonts cache:
  the contents of the cache is enumerated under the registry key
    HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont

  * Add helper functions and macros.
  * In CreateConsoleFontEx(), set the mandatory font pitch&family flags
    and remove those that we do not support.
  * In IsValidConsoleFont2(), update the validity checks and the
    documentation links.

- CONSRV: Load/refresh the additional TrueType fonts cache when needed.
2019-05-19 23:10:41 +02:00

372 lines
13 KiB
C

/*
* PROJECT: ReactOS Console Configuration DLL
* LICENSE: GPL - See COPYING in the top level directory
* FILE: dll/cpl/console/options.c
* PURPOSE: Options dialog
* PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
#include "console.h"
#define NDEBUG
#include <debug.h>
#define MAX_VALUE_NAME 16383
static INT
List_GetCount(IN PLIST_CTL ListCtl)
{
return (INT)SendMessageW(ListCtl->hWndList, CB_GETCOUNT, 0, 0);
}
static ULONG_PTR
List_GetData(IN PLIST_CTL ListCtl, IN INT Index)
{
return (ULONG_PTR)SendMessageW(ListCtl->hWndList, CB_GETITEMDATA, (WPARAM)Index, 0);
}
static VOID
AddCodePage(
IN PLIST_CTL ListCtl,
IN UINT CodePage)
{
UINT iItem, iDupItem;
CPINFOEXW CPInfo;
/*
* Add only valid code pages, that is:
* - If the CodePage is one of the reserved (alias) values:
* CP_ACP == 0 ; CP_OEMCP == 1 ; CP_MACCP == 2 ; CP_THREAD_ACP == 3 ;
* or the deprecated CP_SYMBOL == 42 (see http://archives.miloush.net/michkap/archive/2005/11/08/490495.html)
* it is considered invalid.
* - If IsValidCodePage() fails because the code page is listed but
* not installed on the system, it is also considered invalid.
*/
if (CodePage == CP_ACP || CodePage == CP_OEMCP || CodePage == CP_MACCP ||
CodePage == CP_THREAD_ACP || CodePage == CP_SYMBOL || !IsValidCodePage(CodePage))
{
return;
}
/* Retrieve the code page display name */
if (!GetCPInfoExW(CodePage, 0, &CPInfo))
{
/* We failed, just use the code page value as its name */
// _ultow(CodePage, CPInfo.CodePageName, 10);
StringCchPrintfW(CPInfo.CodePageName, ARRAYSIZE(CPInfo.CodePageName), L"%lu", CodePage);
}
/* Add the code page into the list, sorted by code page value. Avoid any duplicates. */
iDupItem = CB_ERR;
iItem = BisectListSortedByValue(ListCtl, CodePage, &iDupItem, TRUE);
if (iItem == CB_ERR)
iItem = 0;
if (iDupItem != CB_ERR)
return;
iItem = (UINT)SendMessageW(ListCtl->hWndList, CB_INSERTSTRING, iItem, (LPARAM)CPInfo.CodePageName);
if (iItem != CB_ERR && iItem != CB_ERRSPACE)
iItem = SendMessageW(ListCtl->hWndList, CB_SETITEMDATA, iItem, CodePage);
}
static VOID
BuildCodePageList(
IN HWND hDlg,
IN UINT CurrentCodePage)
{
LIST_CTL ListCtl;
HKEY hKey;
DWORD dwIndex, dwSize, dwType;
UINT CodePage;
WCHAR szValueName[MAX_VALUE_NAME];
// #define REGSTR_PATH_CODEPAGE TEXT("System\\CurrentControlSet\\Control\\Nls\\CodePage")
/* Open the Nls\CodePage key */
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Control\\Nls\\CodePage",
0,
KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
&hKey) != ERROR_SUCCESS)
{
return;
}
ListCtl.hWndList = GetDlgItem(hDlg, IDL_CODEPAGE);
ListCtl.GetCount = List_GetCount;
ListCtl.GetData = List_GetData;
/* Enumerate all the available code pages on the system */
dwSize = ARRAYSIZE(szValueName);
dwIndex = 0;
while (RegEnumValueW(hKey, dwIndex, szValueName, &dwSize,
NULL, &dwType, NULL, NULL) == ERROR_SUCCESS) // != ERROR_NO_MORE_ITEMS
{
/* Ignore these parameters, prepare for next iteration */
dwSize = ARRAYSIZE(szValueName);
++dwIndex;
/* Check the value type validity */
if (dwType != REG_SZ)
continue;
/*
* Add the code page into the list.
* If _wtol fails and returns 0, the code page is considered invalid
* (and indeed this value corresponds to the CP_ACP alias too).
*/
CodePage = (UINT)_wtol(szValueName);
if (CodePage == 0) continue;
AddCodePage(&ListCtl, CodePage);
}
RegCloseKey(hKey);
/* Add the special UTF-7 (CP_UTF7 65000) and UTF-8 (CP_UTF8 65001) code pages */
AddCodePage(&ListCtl, CP_UTF7);
AddCodePage(&ListCtl, CP_UTF8);
/* Find and select the current code page in the sorted list */
if (BisectListSortedByValue(&ListCtl, CurrentCodePage, &CodePage, FALSE) == CB_ERR ||
CodePage == CB_ERR)
{
/* Not found, select the first element */
CodePage = 0;
}
SendMessageW(ListCtl.hWndList, CB_SETCURSEL, (WPARAM)CodePage, 0);
}
static VOID
UpdateDialogElements(
IN HWND hDlg,
IN PCONSOLE_STATE_INFO pConInfo)
{
/* Update the cursor size */
if (pConInfo->CursorSize <= 25)
{
/* Small cursor */
CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_SMALL_CURSOR);
// CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_CHECKED);
// CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_UNCHECKED);
// CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_UNCHECKED);
}
else if (pConInfo->CursorSize <= 50)
{
/* Medium cursor */
CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_MEDIUM_CURSOR);
// CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_UNCHECKED);
// CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_CHECKED);
// CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_UNCHECKED);
}
else /* if (pConInfo->CursorSize <= 100) */
{
/* Large cursor */
CheckRadioButton(hDlg, IDC_RADIO_SMALL_CURSOR, IDC_RADIO_LARGE_CURSOR, IDC_RADIO_LARGE_CURSOR);
// CheckDlgButton(hDlg, IDC_RADIO_SMALL_CURSOR , BST_UNCHECKED);
// CheckDlgButton(hDlg, IDC_RADIO_MEDIUM_CURSOR, BST_UNCHECKED);
// CheckDlgButton(hDlg, IDC_RADIO_LARGE_CURSOR , BST_CHECKED);
}
/* Update the number of history buffers */
SendDlgItemMessageW(hDlg, IDC_UPDOWN_NUM_BUFFER, UDM_SETRANGE, 0, MAKELONG(999, 1));
SetDlgItemInt(hDlg, IDC_EDIT_NUM_BUFFER, pConInfo->NumberOfHistoryBuffers, FALSE);
/* Update the history buffer size */
SendDlgItemMessageW(hDlg, IDC_UPDOWN_BUFFER_SIZE, UDM_SETRANGE, 0, MAKELONG(999, 1));
SetDlgItemInt(hDlg, IDC_EDIT_BUFFER_SIZE, pConInfo->HistoryBufferSize, FALSE);
/* Update discard duplicates */
CheckDlgButton(hDlg, IDC_CHECK_DISCARD_DUPLICATES,
pConInfo->HistoryNoDup ? BST_CHECKED : BST_UNCHECKED);
/* Update full/window screen state */
if (pConInfo->FullScreen)
{
CheckRadioButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, IDC_RADIO_DISPLAY_FULL, IDC_RADIO_DISPLAY_FULL);
// CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, BST_UNCHECKED);
// CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_FULL , BST_CHECKED);
}
else
{
CheckRadioButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, IDC_RADIO_DISPLAY_FULL, IDC_RADIO_DISPLAY_WINDOW);
// CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_WINDOW, BST_CHECKED);
// CheckDlgButton(hDlg, IDC_RADIO_DISPLAY_FULL , BST_UNCHECKED);
}
/* Update "Quick-edit" state */
CheckDlgButton(hDlg, IDC_CHECK_QUICK_EDIT,
pConInfo->QuickEdit ? BST_CHECKED : BST_UNCHECKED);
/* Update "Insert mode" state */
CheckDlgButton(hDlg, IDC_CHECK_INSERT_MODE,
pConInfo->InsertMode ? BST_CHECKED : BST_UNCHECKED);
}
INT_PTR
CALLBACK
OptionsProc(HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
BuildCodePageList(hDlg, ConInfo->CodePage);
UpdateDialogElements(hDlg, ConInfo);
return TRUE;
}
case WM_NOTIFY:
{
LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
if (lppsn->hdr.code == UDN_DELTAPOS)
{
LPNMUPDOWN lpnmud = (LPNMUPDOWN)lParam;
if (lppsn->hdr.idFrom == IDC_UPDOWN_BUFFER_SIZE)
{
lpnmud->iPos = min(max(lpnmud->iPos + lpnmud->iDelta, 1), 999);
ConInfo->HistoryBufferSize = lpnmud->iPos;
PropSheet_Changed(GetParent(hDlg), hDlg);
}
else if (lppsn->hdr.idFrom == IDC_UPDOWN_NUM_BUFFER)
{
lpnmud->iPos = min(max(lpnmud->iPos + lpnmud->iDelta, 1), 999);
ConInfo->NumberOfHistoryBuffers = lpnmud->iPos;
PropSheet_Changed(GetParent(hDlg), hDlg);
}
}
else if (lppsn->hdr.code == PSN_APPLY)
{
ApplyConsoleInfo(hDlg);
return TRUE;
}
break;
}
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED)
{
switch (LOWORD(wParam))
{
case IDC_RADIO_SMALL_CURSOR:
{
ConInfo->CursorSize = 25;
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case IDC_RADIO_MEDIUM_CURSOR:
{
ConInfo->CursorSize = 50;
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case IDC_RADIO_LARGE_CURSOR:
{
ConInfo->CursorSize = 100;
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case IDC_RADIO_DISPLAY_WINDOW:
{
ConInfo->FullScreen = FALSE;
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case IDC_RADIO_DISPLAY_FULL:
{
ConInfo->FullScreen = TRUE;
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case IDC_CHECK_QUICK_EDIT:
{
ConInfo->QuickEdit = (IsDlgButtonChecked(hDlg, IDC_CHECK_QUICK_EDIT) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case IDC_CHECK_INSERT_MODE:
{
ConInfo->InsertMode = (IsDlgButtonChecked(hDlg, IDC_CHECK_INSERT_MODE) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case IDC_CHECK_DISCARD_DUPLICATES:
{
ConInfo->HistoryNoDup = (IsDlgButtonChecked(hDlg, IDC_CHECK_DISCARD_DUPLICATES) == BST_CHECKED); // BST_UNCHECKED or BST_INDETERMINATE => FALSE
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
}
}
else
if (HIWORD(wParam) == EN_KILLFOCUS)
{
switch (LOWORD(wParam))
{
case IDC_EDIT_BUFFER_SIZE:
{
DWORD sizeBuff;
sizeBuff = GetDlgItemInt(hDlg, IDC_EDIT_BUFFER_SIZE, NULL, FALSE);
sizeBuff = min(max(sizeBuff, 1), 999);
ConInfo->HistoryBufferSize = sizeBuff;
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
case IDC_EDIT_NUM_BUFFER:
{
DWORD numBuff;
numBuff = GetDlgItemInt(hDlg, IDC_EDIT_NUM_BUFFER, NULL, FALSE);
numBuff = min(max(numBuff, 1), 999);
ConInfo->NumberOfHistoryBuffers = numBuff;
PropSheet_Changed(GetParent(hDlg), hDlg);
break;
}
}
}
else
// (HIWORD(wParam) == CBN_KILLFOCUS)
if ((HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_SELENDOK) &&
(LOWORD(wParam) == IDL_CODEPAGE))
{
HWND hWndList = GetDlgItem(hDlg, IDL_CODEPAGE);
INT iItem;
UINT CodePage;
iItem = (INT)SendMessageW(hWndList, CB_GETCURSEL, 0, 0);
if (iItem == CB_ERR)
break;
CodePage = (UINT)SendMessageW(hWndList, CB_GETITEMDATA, iItem, 0);
if (CodePage == CB_ERR)
break;
/* If the user validated a different code page... */
if ((HIWORD(wParam) == CBN_SELENDOK) && (CodePage != ConInfo->CodePage))
{
/* ... update the code page, notify the siblings and change the property sheet state */
ConInfo->CodePage = CodePage;
// PropSheet_QuerySiblings(GetParent(hDlg), IDL_CODEPAGE, 0);
ResetFontPreview(&FontPreview);
PropSheet_Changed(GetParent(hDlg), hDlg);
}
}
break;
}
default:
break;
}
return FALSE;
}