You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2006 lines
58 KiB
2006 lines
58 KiB
/*++
|
|
|
|
Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
misc.c
|
|
|
|
Abstract:
|
|
|
|
This file implements the NT console server font routines.
|
|
|
|
Author:
|
|
|
|
Therese Stowell (thereses) 22-Jan-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#if DBG && defined(DEBUG_PRINT)
|
|
#error yo!
|
|
ULONG gDebugFlag;
|
|
#endif
|
|
|
|
ULONG NumberOfMouseButtons;
|
|
|
|
PFONT_INFO FontInfo;
|
|
ULONG FontInfoLength;
|
|
ULONG NumberOfFonts;
|
|
|
|
WCHAR DefaultFaceName[LF_FACESIZE];
|
|
COORD DefaultFontSize;
|
|
BYTE DefaultFontFamily;
|
|
ULONG DefaultFontIndex = 0;
|
|
|
|
typedef struct _FONTENUMDC {
|
|
HDC hDC;
|
|
BOOL bFindFaces;
|
|
BOOL bFarEastOK;
|
|
SHORT TTPointSize;
|
|
} FONTENUMDC, *PFONTENUMDC;
|
|
|
|
/*
|
|
* Custom CP for glyph translations
|
|
*/
|
|
CPTABLEINFO GlyphCP;
|
|
USHORT GlyphTable[256];
|
|
|
|
|
|
#define FONT_BUFFER_SIZE 12
|
|
|
|
#define CHAR_NULL ((char)0)
|
|
/*
|
|
* Initial default fonts and face names
|
|
*/
|
|
PFACENODE gpFaceNames;
|
|
|
|
|
|
NTSTATUS
|
|
GetMouseButtons(
|
|
PULONG NumButtons
|
|
)
|
|
{
|
|
*NumButtons = NumberOfMouseButtons;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
InitializeMouseButtons( VOID )
|
|
{
|
|
NumberOfMouseButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
|
|
}
|
|
|
|
PFACENODE AddFaceNode(PFACENODE *ppStart, LPWSTR pwsz) {
|
|
PFACENODE pNew;
|
|
PFACENODE *ppTmp;
|
|
int cb;
|
|
|
|
/*
|
|
* Is it already here?
|
|
*/
|
|
for (ppTmp = ppStart; *ppTmp; ppTmp = &((*ppTmp)->pNext)) {
|
|
if (wcscmp(((*ppTmp)->awch), pwsz) == 0) {
|
|
// already there !
|
|
return *ppTmp;
|
|
}
|
|
}
|
|
|
|
cb = (wcslen(pwsz) + 1) * sizeof(WCHAR);
|
|
pNew = ConsoleHeapAlloc(FONT_TAG, sizeof(FACENODE) + cb);
|
|
if (pNew == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
pNew->pNext = NULL;
|
|
pNew->dwFlag = 0;
|
|
wcscpy(pNew->awch, pwsz);
|
|
*ppTmp = pNew;
|
|
return pNew;
|
|
}
|
|
|
|
VOID
|
|
InitializeFonts( VOID )
|
|
{
|
|
WCHAR FontName[CONSOLE_MAX_FONT_NAME_LENGTH];
|
|
int i;
|
|
static CONST LPWSTR FontList[] = {L"woafont",
|
|
L"ega80woa.fon",
|
|
L"ega40woa.fon",
|
|
L"cga80woa.fon",
|
|
L"cga40woa.fon"};
|
|
|
|
//
|
|
// Read software.ini to get the values for "woafont",
|
|
// "ega80woa.fon", "ega40woa.fon", "cga80woa.fon", and
|
|
// "cga40woa.fon", respectively, to pass to AddFontResource.
|
|
//
|
|
// If any of the entries are empty or non-existent,
|
|
// GetPrivateProfileString will return a NULL (empty) string.
|
|
// If such is the case, the call to AddPermanentFontResource will
|
|
// simply fail.
|
|
//
|
|
|
|
OpenProfileUserMapping();
|
|
|
|
for (i = 0; i < NELEM(FontList); i++) {
|
|
GetPrivateProfileString(L"386enh", FontList[i], L"",
|
|
FontName, NELEM(FontName), L"system.ini");
|
|
GdiAddFontResourceW(FontName, AFRW_ADD_LOCAL_FONT,NULL);
|
|
}
|
|
|
|
CloseProfileUserMapping();
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FontEnum
|
|
*
|
|
* This routine is called exactly once by GDI for each font in the system,
|
|
* and is used to store the FONT_INFO structure.
|
|
\***************************************************************************/
|
|
int CALLBACK
|
|
FontEnum(
|
|
LPENUMLOGFONTW lpLogFont,
|
|
LPNEWTEXTMETRICW lpTextMetric,
|
|
int nFontType,
|
|
LPARAM lParam
|
|
)
|
|
{
|
|
PFONTENUMDC pfed = (PFONTENUMDC)lParam;
|
|
HDC hDC = pfed->hDC;
|
|
BOOL bFindFaces = pfed->bFindFaces;
|
|
HFONT hFont;
|
|
TEXTMETRICW tmi;
|
|
LONG nFont;
|
|
LONG nFontNew;
|
|
COORD SizeToShow;
|
|
COORD SizeActual;
|
|
COORD SizeWant;
|
|
BYTE tmFamily;
|
|
SIZE Size;
|
|
LPWSTR pwszFace = lpLogFont->elfLogFont.lfFaceName;
|
|
PFACENODE pFN;
|
|
|
|
DBGFONTS((" FontEnum \"%ls\" (%d,%d) weight 0x%lx(%d) -- %s\n",
|
|
pwszFace,
|
|
lpLogFont->elfLogFont.lfWidth, lpLogFont->elfLogFont.lfHeight,
|
|
lpLogFont->elfLogFont.lfWeight, lpLogFont->elfLogFont.lfWeight,
|
|
bFindFaces ? "Finding Faces" : "Creating Fonts"));
|
|
|
|
//
|
|
// reject variable width and italic fonts, also tt fonts with neg ac
|
|
//
|
|
|
|
if
|
|
(
|
|
!(lpLogFont->elfLogFont.lfPitchAndFamily & FIXED_PITCH) ||
|
|
(lpLogFont->elfLogFont.lfItalic) ||
|
|
!(lpTextMetric->ntmFlags & NTM_NONNEGATIVE_AC)
|
|
)
|
|
{
|
|
if (!IsAvailableTTFont(pwszFace))
|
|
{
|
|
DBGFONTS((" REJECT face (variable pitch, italic, or neg a&c)\n"));
|
|
return bFindFaces ? TRUE : FALSE; // unsuitable font
|
|
}
|
|
}
|
|
|
|
if (nFontType == TRUETYPE_FONTTYPE) {
|
|
lpLogFont->elfLogFont.lfHeight = pfed->TTPointSize;
|
|
lpLogFont->elfLogFont.lfWidth = 0;
|
|
lpLogFont->elfLogFont.lfWeight = FW_NORMAL;
|
|
}
|
|
|
|
/*
|
|
* reject TT fonts for whoom family is not modern, that is do not use
|
|
* FF_DONTCARE // may be surprised unpleasantly
|
|
* FF_DECORATIVE // likely to be symbol fonts
|
|
* FF_SCRIPT // cursive, inappropriate for console
|
|
* FF_SWISS OR FF_ROMAN // variable pitch
|
|
*/
|
|
|
|
if ((nFontType == TRUETYPE_FONTTYPE) &&
|
|
((lpLogFont->elfLogFont.lfPitchAndFamily & 0xf0) != FF_MODERN)) {
|
|
DBGFONTS((" REJECT face (TT but not FF_MODERN)\n"));
|
|
return bFindFaces ? TRUE : FALSE; // unsuitable font
|
|
}
|
|
|
|
/*
|
|
* reject non-TT fonts that aren't OEM
|
|
*/
|
|
if ((nFontType != TRUETYPE_FONTTYPE) &&
|
|
#if defined(FE_SB)
|
|
(!CONSOLE_IS_DBCS_ENABLED() ||
|
|
!IS_ANY_DBCS_CHARSET(lpLogFont->elfLogFont.lfCharSet)) &&
|
|
#endif
|
|
(lpLogFont->elfLogFont.lfCharSet != OEM_CHARSET)) {
|
|
DBGFONTS((" REJECT face (not TT nor OEM)\n"));
|
|
return bFindFaces ? TRUE : FALSE; // unsuitable font
|
|
}
|
|
|
|
/*
|
|
* reject non-TT fonts that are virtical font
|
|
*/
|
|
if ((nFontType != TRUETYPE_FONTTYPE) &&
|
|
(pwszFace[0] == L'@')) {
|
|
DBGFONTS((" REJECT face (not TT and TATEGAKI)\n"));
|
|
return bFindFaces ? TRUE : FALSE; // unsuitable font
|
|
}
|
|
|
|
/*
|
|
* reject non-TT fonts that aren't Terminal
|
|
*/
|
|
if (CONSOLE_IS_DBCS_ENABLED() &&
|
|
(nFontType != TRUETYPE_FONTTYPE) &&
|
|
(wcscmp(pwszFace, L"Terminal") != 0)) {
|
|
DBGFONTS((" REJECT face (not TT nor Terminal)\n"));
|
|
return bFindFaces ? TRUE : FALSE; // unsuitable font
|
|
}
|
|
|
|
/*
|
|
* reject Far East TT fonts that aren't Far East charset.
|
|
*/
|
|
if (IsAvailableTTFont(pwszFace) &&
|
|
!IS_ANY_DBCS_CHARSET(lpLogFont->elfLogFont.lfCharSet) &&
|
|
!IsAvailableTTFontCP(pwszFace,0)
|
|
) {
|
|
DBGFONTS((" REJECT face (Far East TT and not Far East charset)\n"));
|
|
return TRUE; // should be enumerate next charset.
|
|
}
|
|
|
|
/*
|
|
* Add or find the facename
|
|
*/
|
|
pFN = AddFaceNode(&gpFaceNames, pwszFace);
|
|
if (pFN == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (bFindFaces) {
|
|
if (nFontType == TRUETYPE_FONTTYPE) {
|
|
DBGFONTS(("NEW TT FACE %ls\n", pwszFace));
|
|
pFN->dwFlag |= EF_TTFONT;
|
|
} else if (nFontType == RASTER_FONTTYPE) {
|
|
DBGFONTS(("NEW OEM FACE %ls\n",pwszFace));
|
|
pFN->dwFlag |= EF_OEMFONT;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (IS_BOLD(lpLogFont->elfLogFont.lfWeight)) {
|
|
DBGFONTS2((" A bold font (weight %d)\n", lpLogFont->elfLogFont.lfWeight));
|
|
// return 0;
|
|
}
|
|
|
|
/* get font info */
|
|
SizeWant.Y = (SHORT)lpLogFont->elfLogFont.lfHeight;
|
|
SizeWant.X = (SHORT)lpLogFont->elfLogFont.lfWidth;
|
|
CreateBoldFont:
|
|
lpLogFont->elfLogFont.lfQuality = DEFAULT_QUALITY;
|
|
hFont = CreateFontIndirectW(&lpLogFont->elfLogFont);
|
|
if (!hFont) {
|
|
DBGFONTS((" REJECT font (can't create)\n"));
|
|
RIPMSG0(RIP_WARNING, "FontEnum: CreateFontIndirectW returned NULL hFont.");
|
|
return 0; // same font in other sizes may still be suitable
|
|
}
|
|
|
|
DBGFONTS2((" hFont = %lx\n", hFont));
|
|
|
|
//
|
|
// for reasons unbeknownst to me, removing this code causes GDI
|
|
// to yack, claiming that the font is owned by another process.
|
|
//
|
|
|
|
SelectObject(hDC,hFont);
|
|
if (!GetTextMetricsW(hDC, &tmi)) {
|
|
tmi = *((LPTEXTMETRICW)lpTextMetric);
|
|
}
|
|
|
|
if (GetTextExtentPoint32W(hDC, L"0", 1, &Size)) {
|
|
SizeActual.X = (SHORT)Size.cx;
|
|
} else {
|
|
SizeActual.X = (SHORT)(tmi.tmMaxCharWidth);
|
|
}
|
|
SizeActual.Y = (SHORT)(tmi.tmHeight + tmi.tmExternalLeading);
|
|
DBGFONTS2((" actual size %d,%d\n", SizeActual.X, SizeActual.Y));
|
|
tmFamily = tmi.tmPitchAndFamily;
|
|
if (TM_IS_TT_FONT(tmFamily) && (SizeWant.Y >= 0)) {
|
|
SizeToShow = SizeWant;
|
|
if (SizeWant.X == 0) {
|
|
// Asking for zero width height gets a default aspect-ratio width
|
|
// It's better to show that width rather than 0.
|
|
SizeToShow.X = SizeActual.X;
|
|
}
|
|
} else {
|
|
SizeToShow = SizeActual;
|
|
}
|
|
DBGFONTS2((" SizeToShow = (%d,%d), SizeActual = (%d,%d)\n",
|
|
SizeToShow.X, SizeToShow.Y, SizeActual.X, SizeActual.Y));
|
|
|
|
// there's a GDI bug - this assert fails occasionally
|
|
//ASSERT (tmi.tmw.tmMaxCharWidth == lpTextMetric->tmMaxCharWidth);
|
|
|
|
/*
|
|
* NOW, determine whether this font entry has already been cached
|
|
* LATER : it may be possible to do this before creating the font, if
|
|
* we can trust the dimensions & other info from lpTextMetric.
|
|
* Sort by size:
|
|
* 1) By pixelheight (negative Y values)
|
|
* 2) By height (as shown)
|
|
* 3) By width (as shown)
|
|
*/
|
|
for (nFont = 0; nFont < (LONG)NumberOfFonts; ++nFont) {
|
|
COORD SizeShown;
|
|
|
|
if (FontInfo[nFont].hFont == NULL) {
|
|
DBGFONTS(("! Font %x has a NULL hFont\n", nFont));
|
|
continue;
|
|
}
|
|
|
|
|
|
if (FontInfo[nFont].SizeWant.X > 0) {
|
|
SizeShown.X = FontInfo[nFont].SizeWant.X;
|
|
} else {
|
|
SizeShown.X = FontInfo[nFont].Size.X;
|
|
}
|
|
|
|
if (FontInfo[nFont].SizeWant.Y > 0) {
|
|
// This is a font specified by cell height.
|
|
SizeShown.Y = FontInfo[nFont].SizeWant.Y;
|
|
} else {
|
|
SizeShown.Y = FontInfo[nFont].Size.Y;
|
|
if (FontInfo[nFont].SizeWant.Y < 0) {
|
|
// This is a TT font specified by character height.
|
|
if (SizeWant.Y < 0 && SizeWant.Y > FontInfo[nFont].SizeWant.Y) {
|
|
// Requested pixelheight is smaller than this one.
|
|
DBGFONTS(("INSERT %d pt at %x, before %d pt\n",
|
|
-SizeWant.Y, nFont, -FontInfo[nFont].SizeWant.Y));
|
|
nFontNew = nFont;
|
|
goto InsertNewFont;
|
|
}
|
|
}
|
|
}
|
|
|
|
// DBGFONTS((" SizeShown(%x) = (%d,%d)\n",nFont,SizeShown.X,SizeShown.Y));
|
|
|
|
if (SIZE_EQUAL(SizeShown, SizeToShow) &&
|
|
FontInfo[nFont].Family == tmFamily &&
|
|
FontInfo[nFont].Weight == tmi.tmWeight &&
|
|
wcscmp(FontInfo[nFont].FaceName, pwszFace) == 0) {
|
|
/*
|
|
* Already have this font
|
|
*/
|
|
DBGFONTS2((" Already have the font\n"));
|
|
DeleteObject(hFont);
|
|
pfed->bFarEastOK = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
if ((SizeToShow.Y < SizeShown.Y) ||
|
|
(SizeToShow.Y == SizeShown.Y && SizeToShow.X < SizeShown.X)) {
|
|
/*
|
|
* This new font is smaller than nFont
|
|
*/
|
|
DBGFONTS(("INSERT at %x, SizeToShow = (%d,%d)\n", nFont,
|
|
SizeToShow.X,SizeToShow.Y));
|
|
nFontNew = nFont;
|
|
goto InsertNewFont;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The font we are adding should be appended to the list,
|
|
* since it is bigger (or equal) to the last one.
|
|
*/
|
|
nFontNew = (LONG)NumberOfFonts;
|
|
|
|
InsertNewFont: // at nFontNew
|
|
|
|
// ASSERT ((lpTextMetric->tmPitchAndFamily & 1) == 0);
|
|
/* If we have to grow our font table, do it */
|
|
|
|
if (NumberOfFonts == FontInfoLength) {
|
|
PFONT_INFO Temp;
|
|
|
|
FontInfoLength += FONT_INCREMENT;
|
|
Temp = ConsoleHeapReAlloc(FONT_TAG, FontInfo, sizeof(FONT_INFO) * FontInfoLength);
|
|
if (Temp == NULL) {
|
|
RIPMSG0(RIP_WARNING, "FontEnum: failed to allocate PFONT_INFO");
|
|
FontInfoLength -= FONT_INCREMENT;
|
|
return FALSE;
|
|
}
|
|
FontInfo = Temp;
|
|
}
|
|
|
|
if (nFontNew < (LONG)NumberOfFonts) {
|
|
RtlMoveMemory(&FontInfo[nFontNew+1],
|
|
&FontInfo[nFontNew],
|
|
sizeof(FONT_INFO)*(NumberOfFonts - nFontNew));
|
|
//
|
|
// Fix up DefaultFontIndex if nFontNew less than DefaultFontIndex.
|
|
//
|
|
if (nFontNew < (LONG)DefaultFontIndex &&
|
|
DefaultFontIndex+1 < NumberOfFonts) {
|
|
DefaultFontIndex++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Store the font info
|
|
*/
|
|
FontInfo[nFontNew].hFont = hFont;
|
|
FontInfo[nFontNew].Family = tmFamily;
|
|
FontInfo[nFontNew].Size = SizeActual;
|
|
if (TM_IS_TT_FONT(tmFamily)) {
|
|
FontInfo[nFontNew].SizeWant = SizeWant;
|
|
} else {
|
|
FontInfo[nFontNew].SizeWant.X = 0;
|
|
FontInfo[nFontNew].SizeWant.Y = 0;
|
|
}
|
|
FontInfo[nFontNew].Weight = tmi.tmWeight;
|
|
FontInfo[nFont].FaceName = pFN->awch;
|
|
#if defined(FE_SB)
|
|
FontInfo[nFontNew].tmCharSet = tmi.tmCharSet;
|
|
#endif
|
|
|
|
++NumberOfFonts;
|
|
|
|
if (nFontType == TRUETYPE_FONTTYPE && !IS_BOLD(FontInfo[nFontNew].Weight)) {
|
|
lpLogFont->elfLogFont.lfWeight = FW_BOLD;
|
|
goto CreateBoldFont;
|
|
}
|
|
|
|
pfed->bFarEastOK = TRUE; // and continue enumeration
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
DoFontEnum(
|
|
HDC hDC,
|
|
LPWSTR pwszFace,
|
|
SHORT TTPointSize)
|
|
{
|
|
BOOL bDeleteDC = FALSE;
|
|
BOOL bFindFaces = (pwszFace == NULL);
|
|
FONTENUMDC fed;
|
|
LOGFONTW LogFont;
|
|
|
|
DBGFONTS(("DoFontEnum \"%ls\"\n", pwszFace));
|
|
|
|
if (hDC == NULL) {
|
|
hDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
|
|
bDeleteDC = TRUE;
|
|
}
|
|
|
|
fed.hDC = hDC;
|
|
fed.bFindFaces = bFindFaces;
|
|
fed.bFarEastOK = FALSE;
|
|
fed.TTPointSize = TTPointSize;
|
|
RtlZeroMemory(&LogFont, sizeof(LOGFONT));
|
|
LogFont.lfCharSet = DEFAULT_CHARSET;
|
|
if (pwszFace) {
|
|
wcscpy(LogFont.lfFaceName, pwszFace);
|
|
}
|
|
|
|
/*
|
|
* EnumFontFamiliesEx function enumerates one font in every face in
|
|
* every character set.
|
|
*/
|
|
EnumFontFamiliesExW(hDC, &LogFont, (FONTENUMPROC)FontEnum, (LPARAM)&fed, 0);
|
|
if (bDeleteDC) {
|
|
DeleteDC(hDC);
|
|
}
|
|
|
|
return fed.bFarEastOK;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
EnumerateFonts(
|
|
DWORD Flags)
|
|
{
|
|
TEXTMETRIC tmi;
|
|
HDC hDC;
|
|
PFACENODE pFN;
|
|
ULONG ulOldEnumFilter;
|
|
DWORD FontIndex;
|
|
DWORD dwFontType = 0;
|
|
|
|
DBGFONTS(("EnumerateFonts %lx\n", Flags));
|
|
|
|
dwFontType = (EF_TTFONT|EF_OEMFONT|EF_DEFFACE) & Flags;
|
|
|
|
if (FontInfo == NULL) {
|
|
//
|
|
// Allocate memory for the font array.
|
|
//
|
|
NumberOfFonts = 0;
|
|
|
|
FontInfo = ConsoleHeapAlloc(FONT_TAG, sizeof(FONT_INFO) * INITIAL_FONTS);
|
|
if (FontInfo == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
FontInfoLength = INITIAL_FONTS;
|
|
}
|
|
|
|
hDC = CreateDCW(L"DISPLAY",NULL,NULL,NULL);
|
|
|
|
// Before enumeration, turn off font enumeration filters.
|
|
ulOldEnumFilter = SetFontEnumeration(0);
|
|
// restore all the other flags
|
|
SetFontEnumeration(ulOldEnumFilter & ~FE_FILTER_TRUETYPE);
|
|
|
|
if (Flags & EF_DEFFACE) {
|
|
SelectObject(hDC,GetStockObject(OEM_FIXED_FONT));
|
|
|
|
if (GetTextMetricsW(hDC, &tmi)) {
|
|
DefaultFontSize.X = (SHORT)(tmi.tmMaxCharWidth);
|
|
DefaultFontSize.Y = (SHORT)(tmi.tmHeight+tmi.tmExternalLeading);
|
|
DefaultFontFamily = tmi.tmPitchAndFamily;
|
|
#if defined(FE_SB)
|
|
if (IS_ANY_DBCS_CHARSET(tmi.tmCharSet))
|
|
DefaultFontSize.X /= 2;
|
|
#endif
|
|
}
|
|
GetTextFaceW(hDC, LF_FACESIZE, DefaultFaceName);
|
|
#if defined(FE_SB)
|
|
DBGFONTS(("Default (OEM) Font %ls (%d,%d) CharSet 0x%02X\n", DefaultFaceName,
|
|
DefaultFontSize.X, DefaultFontSize.Y,
|
|
tmi.tmCharSet));
|
|
#else
|
|
DBGFONTS(("Default (OEM) Font %ls (%d,%d)\n", DefaultFaceName,
|
|
DefaultFontSize.X, DefaultFontSize.Y));
|
|
#endif
|
|
|
|
// Make sure we are going to enumerate the OEM face.
|
|
pFN = AddFaceNode(&gpFaceNames, DefaultFaceName);
|
|
if (pFN) {
|
|
pFN->dwFlag |= EF_DEFFACE | EF_OEMFONT;
|
|
}
|
|
}
|
|
|
|
// Use DoFontEnum to get all fonts from the system. Our FontEnum
|
|
// proc puts just the ones we want into an array
|
|
//
|
|
for (pFN = gpFaceNames; pFN; pFN = pFN->pNext) {
|
|
DBGFONTS(("\"%ls\" is %s%s%s%s%s%s\n", pFN->awch,
|
|
pFN->dwFlag & EF_NEW ? "NEW " : " ",
|
|
pFN->dwFlag & EF_OLD ? "OLD " : " ",
|
|
pFN->dwFlag & EF_ENUMERATED ? "ENUMERATED " : " ",
|
|
pFN->dwFlag & EF_OEMFONT ? "OEMFONT " : " ",
|
|
pFN->dwFlag & EF_TTFONT ? "TTFONT " : " ",
|
|
pFN->dwFlag & EF_DEFFACE ? "DEFFACE " : " "));
|
|
|
|
if ((pFN->dwFlag & dwFontType) == 0) {
|
|
// not the kind of face we want
|
|
continue;
|
|
}
|
|
if (pFN->dwFlag & EF_ENUMERATED) {
|
|
// we already enumerated this face
|
|
continue;
|
|
}
|
|
|
|
DoFontEnum(hDC, pFN->awch, DefaultFontSize.Y);
|
|
pFN->dwFlag |= EF_ENUMERATED;
|
|
}
|
|
|
|
|
|
// After enumerating fonts, restore the font enumeration filter.
|
|
SetFontEnumeration(ulOldEnumFilter);
|
|
|
|
DeleteDC(hDC);
|
|
|
|
// Make sure the default font is set correctly
|
|
if (NumberOfFonts > 0 && DefaultFontSize.X == 0 && DefaultFontSize.Y == 0) {
|
|
DefaultFontSize.X = FontInfo[0].Size.X;
|
|
DefaultFontSize.Y = FontInfo[0].Size.Y;
|
|
DefaultFontFamily = FontInfo[0].Family;
|
|
}
|
|
|
|
for (FontIndex = 0; FontIndex < NumberOfFonts; FontIndex++) {
|
|
if (FontInfo[FontIndex].Size.X == DefaultFontSize.X &&
|
|
FontInfo[FontIndex].Size.Y == DefaultFontSize.Y &&
|
|
FontInfo[FontIndex].Family == DefaultFontFamily) {
|
|
#if defined(FE_SB)
|
|
if (CONSOLE_IS_DBCS_ENABLED() &&
|
|
!IS_ANY_DBCS_CHARSET(FontInfo[FontIndex].tmCharSet))
|
|
{
|
|
continue ;
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(FontIndex < NumberOfFonts);
|
|
if (FontIndex < NumberOfFonts) {
|
|
DefaultFontIndex = FontIndex;
|
|
} else {
|
|
DefaultFontIndex = 0;
|
|
}
|
|
DBGFONTS(("EnumerateFonts : DefaultFontIndex = %ld\n", DefaultFontIndex));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* Get the font index for a new font
|
|
* If necessary, attempt to create the font.
|
|
* Always return a valid FontIndex (even if not correct)
|
|
* Family: Find/Create a font with of this Family
|
|
* 0 - don't care
|
|
* pwszFace: Find/Create a font with this face name.
|
|
* NULL or L"" - use DefaultFaceName
|
|
* Size: Must match SizeWant or actual Size.
|
|
*/
|
|
int
|
|
FindCreateFont(
|
|
DWORD Family,
|
|
LPWSTR pwszFace,
|
|
COORD Size,
|
|
LONG Weight,
|
|
UINT CodePage)
|
|
{
|
|
#define NOT_CREATED_NOR_FOUND -1
|
|
#define CREATED_BUT_NOT_FOUND -2
|
|
|
|
int i;
|
|
int FontIndex = NOT_CREATED_NOR_FOUND;
|
|
int BestMatch = NOT_CREATED_NOR_FOUND;
|
|
BOOL bFontOK;
|
|
WCHAR AltFaceName[LF_FACESIZE];
|
|
COORD AltFontSize;
|
|
BYTE AltFontFamily;
|
|
ULONG AltFontIndex = 0;
|
|
LPWSTR pwszAltFace = NULL;
|
|
|
|
BYTE CharSet = CodePageToCharSet(CodePage);
|
|
|
|
DBGFONTS(("FindCreateFont Family=%x %ls (%d,%d) %d %d %x\n",
|
|
Family, pwszFace, Size.X, Size.Y, Weight, CodePage, CharSet));
|
|
|
|
if (CONSOLE_IS_DBCS_ENABLED() &&
|
|
!IS_ANY_DBCS_CHARSET(CharSet))
|
|
{
|
|
MakeAltRasterFont(CodePage, FontInfo[DefaultFontIndex].Size,
|
|
&AltFontSize, &AltFontFamily, &AltFontIndex, AltFaceName);
|
|
|
|
if (pwszFace == NULL || *pwszFace == L'\0') {
|
|
pwszFace = AltFaceName;
|
|
}
|
|
if (Size.Y == 0) {
|
|
Size.X = AltFontSize.X;
|
|
Size.Y = AltFontSize.Y;
|
|
}
|
|
}
|
|
else {
|
|
if (pwszFace == NULL || *pwszFace == L'\0') {
|
|
pwszFace = DefaultFaceName;
|
|
}
|
|
if (Size.Y == 0) {
|
|
Size.X = DefaultFontSize.X;
|
|
Size.Y = DefaultFontSize.Y;
|
|
}
|
|
}
|
|
|
|
if (IsAvailableTTFont(pwszFace)) {
|
|
pwszAltFace = GetAltFaceName(pwszFace);
|
|
}
|
|
else {
|
|
pwszAltFace = pwszFace;
|
|
}
|
|
|
|
/*
|
|
* Try to find the exact font
|
|
*/
|
|
TryFindExactFont:
|
|
for (i=0; i < (int)NumberOfFonts; i++) {
|
|
/*
|
|
* If looking for a particular Family, skip non-matches
|
|
*/
|
|
if ((Family != 0) &&
|
|
((BYTE)Family != FontInfo[i].Family)) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Skip non-matching sizes
|
|
*/
|
|
if ((FontInfo[i].SizeWant.Y != Size.Y) &&
|
|
!SIZE_EQUAL(FontInfo[i].Size, Size)) {
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* Skip non-matching weights
|
|
*/
|
|
if ((Weight != 0) && (Weight != FontInfo[i].Weight)) {
|
|
continue;
|
|
}
|
|
#if defined(FE_SB)
|
|
if (!TM_IS_TT_FONT(FontInfo[i].Family) &&
|
|
FontInfo[i].tmCharSet != CharSet) {
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Size (and maybe Family) match.
|
|
* If we don't care about the name, or if it matches, use this font.
|
|
* Else if name doesn't match and it is a raster font, consider it.
|
|
*/
|
|
if ((pwszFace == NULL) || (pwszFace[0] == L'\0') ||
|
|
wcscmp(FontInfo[i].FaceName, pwszFace) == 0 ||
|
|
wcscmp(FontInfo[i].FaceName, pwszAltFace) == 0
|
|
) {
|
|
FontIndex = i;
|
|
goto FoundFont;
|
|
} else if (!TM_IS_TT_FONT(FontInfo[i].Family)) {
|
|
BestMatch = i;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Didn't find the exact font, so try to create it
|
|
*/
|
|
if (FontIndex == NOT_CREATED_NOR_FOUND) {
|
|
ULONG ulOldEnumFilter;
|
|
ulOldEnumFilter = SetFontEnumeration(0);
|
|
// restore all the other flags
|
|
SetFontEnumeration(ulOldEnumFilter & ~FE_FILTER_TRUETYPE);
|
|
if (Size.Y < 0) {
|
|
Size.Y = -Size.Y;
|
|
}
|
|
bFontOK = DoFontEnum(NULL, pwszFace, Size.Y);
|
|
SetFontEnumeration(ulOldEnumFilter);
|
|
if (bFontOK) {
|
|
DBGFONTS(("FindCreateFont created font!\n"));
|
|
FontIndex = CREATED_BUT_NOT_FOUND;
|
|
goto TryFindExactFont;
|
|
} else {
|
|
DBGFONTS(("FindCreateFont failed to create font!\n"));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Failed to find exact match, but we have a close Raster Font
|
|
* fit - only the name doesn't match.
|
|
*/
|
|
if (BestMatch >= 0) {
|
|
FontIndex = BestMatch;
|
|
goto FoundFont;
|
|
}
|
|
|
|
/*
|
|
* Failed to find exact match, even after enumeration, so now try
|
|
* to find a font of same family and same size or bigger
|
|
*/
|
|
for (i=0; i < (int)NumberOfFonts; i++) {
|
|
#if defined(FE_SB)
|
|
if (CONSOLE_IS_DBCS_ENABLED()) {
|
|
if ((Family != 0) &&
|
|
((BYTE)Family != FontInfo[i].Family)) {
|
|
continue;
|
|
}
|
|
|
|
if (!TM_IS_TT_FONT(FontInfo[i].Family) &&
|
|
FontInfo[i].tmCharSet != CharSet) {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
if ((BYTE)Family != FontInfo[i].Family) {
|
|
continue;
|
|
}
|
|
#if defined(FE_SB)
|
|
}
|
|
#endif
|
|
|
|
if (FontInfo[i].Size.Y >= Size.Y &&
|
|
FontInfo[i].Size.X >= Size.X) {
|
|
// Same family, size >= desired.
|
|
FontIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (FontIndex < 0) {
|
|
DBGFONTS(("FindCreateFont defaults!\n"));
|
|
#if defined(FE_SB)
|
|
if (CONSOLE_IS_DBCS_ENABLED() &&
|
|
!IsAvailableFarEastCodePage(CodePage))
|
|
{
|
|
FontIndex = AltFontIndex;
|
|
}
|
|
else
|
|
#endif
|
|
FontIndex = DefaultFontIndex;
|
|
}
|
|
|
|
FoundFont:
|
|
DBGFONTS(("FindCreateFont returns %x : %ls (%d,%d)\n", FontIndex,
|
|
FontInfo[FontIndex].FaceName,
|
|
FontInfo[FontIndex].Size.X, FontInfo[FontIndex].Size.Y));
|
|
return FontIndex;
|
|
|
|
#undef NOT_CREATED_NOR_FOUND
|
|
#undef CREATED_BUT_NOT_FOUND
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
FindTextBufferFontInfo(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN UINT CodePage,
|
|
OUT PTEXT_BUFFER_FONT_INFO TextFontInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine find a font information which correspond to code page value.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PTEXT_BUFFER_FONT_INFO CurrentFont;
|
|
|
|
CurrentFont = ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont;
|
|
|
|
while (CurrentFont != NULL) {
|
|
if (CurrentFont->FontCodePage == CodePage) {
|
|
*TextFontInfo = *CurrentFont;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
CurrentFont = CurrentFont->NextTextBufferFont;
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
NTSTATUS
|
|
StoreTextBufferFontInfo(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN ULONG FontIndex,
|
|
IN COORD FontSize,
|
|
IN BYTE FontFamily,
|
|
IN LONG FontWeight,
|
|
IN LPWSTR FaceName,
|
|
IN UINT CodePage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine store a font information in CurrentTextBufferFont and ListOfTextBufferFont.
|
|
If specified code page does not exist in ListOfTextBufferFont, then create new list.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PTEXT_BUFFER_FONT_INFO CurrentFont, PrevFont;
|
|
|
|
CurrentFont = ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont;
|
|
|
|
while (CurrentFont != NULL) {
|
|
if (CurrentFont->FontCodePage == CodePage) {
|
|
CurrentFont->FontNumber = FontIndex;
|
|
CurrentFont->FontSize = FontSize;
|
|
CurrentFont->Family = FontFamily;
|
|
CurrentFont->Weight = FontWeight;
|
|
// CurrentFont->FontCodePage = CodePage; // Redundant
|
|
wcscpy(CurrentFont->FaceName, FaceName);
|
|
break;
|
|
}
|
|
PrevFont = CurrentFont;
|
|
CurrentFont = CurrentFont->NextTextBufferFont;
|
|
}
|
|
|
|
if (CurrentFont == NULL) {
|
|
CurrentFont = ConsoleHeapAlloc(FONT_TAG, sizeof(TEXT_BUFFER_FONT_INFO));
|
|
if (CurrentFont == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
CurrentFont->NextTextBufferFont = NULL;
|
|
CurrentFont->FontNumber = FontIndex;
|
|
CurrentFont->FontSize = FontSize;
|
|
CurrentFont->Family = FontFamily;
|
|
CurrentFont->Weight = FontWeight;
|
|
CurrentFont->FontCodePage = CodePage;
|
|
wcscpy(CurrentFont->FaceName, FaceName);
|
|
|
|
if (ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont == NULL) {
|
|
ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont = CurrentFont;
|
|
}
|
|
else {
|
|
PrevFont->NextTextBufferFont = CurrentFont;
|
|
}
|
|
}
|
|
|
|
ScreenInfo->BufferInfo.TextInfo.CurrentTextBufferFont = *CurrentFont;
|
|
ScreenInfo->BufferInfo.TextInfo.CurrentTextBufferFont.NextTextBufferFont = NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
RemoveTextBufferFontInfo(
|
|
IN PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine all remove a font information in ListOfTextBufferFont.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PTEXT_BUFFER_FONT_INFO CurrentFont;
|
|
|
|
CurrentFont = ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont;
|
|
|
|
while (CurrentFont != NULL) {
|
|
PTEXT_BUFFER_FONT_INFO NextFont;
|
|
|
|
NextFont = CurrentFont->NextTextBufferFont;
|
|
ConsoleHeapFree(CurrentFont);
|
|
|
|
CurrentFont = NextFont;
|
|
}
|
|
|
|
ScreenInfo->BufferInfo.TextInfo.ListOfTextBufferFont = NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetNumFonts(
|
|
OUT PULONG NumFonts
|
|
)
|
|
{
|
|
*NumFonts = NumberOfFonts;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetAvailableFonts(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN BOOLEAN MaximumWindow,
|
|
OUT PVOID Buffer,
|
|
IN OUT PULONG NumFonts
|
|
)
|
|
{
|
|
PCONSOLE_FONT_INFO BufPtr;
|
|
ULONG i;
|
|
COORD WindowSize;
|
|
WINDOW_LIMITS WindowLimits;
|
|
|
|
//
|
|
// if the buffer is too small to return all the fonts, return
|
|
// the number that will fit.
|
|
//
|
|
|
|
*NumFonts = (*NumFonts > NumberOfFonts) ? NumberOfFonts : *NumFonts;
|
|
|
|
//
|
|
// convert font size in pixels to font size in rows/columns
|
|
//
|
|
|
|
BufPtr = (PCONSOLE_FONT_INFO)Buffer;
|
|
|
|
if (MaximumWindow) {
|
|
GetWindowLimits(ScreenInfo, &WindowLimits);
|
|
WindowSize = WindowLimits.MaximumWindowSize;
|
|
}
|
|
else {
|
|
WindowSize.X = (SHORT)CONSOLE_WINDOW_SIZE_X(ScreenInfo);
|
|
WindowSize.Y = (SHORT)CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
|
|
}
|
|
for (i=0;i<*NumFonts;i++,BufPtr++) {
|
|
BufPtr->nFont = i;
|
|
BufPtr->dwFontSize.X = WindowSize.X * SCR_FONTSIZE(ScreenInfo).X / FontInfo[i].Size.X;
|
|
BufPtr->dwFontSize.Y = WindowSize.Y * SCR_FONTSIZE(ScreenInfo).Y / FontInfo[i].Size.Y;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetFontSize(
|
|
IN DWORD FontIndex,
|
|
OUT PCOORD FontSize
|
|
)
|
|
{
|
|
if (FontIndex >= NumberOfFonts)
|
|
return STATUS_INVALID_PARAMETER;
|
|
*FontSize = FontInfo[FontIndex].Size;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
GetCurrentFont(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN BOOLEAN MaximumWindow,
|
|
OUT PULONG FontIndex,
|
|
OUT PCOORD FontSize
|
|
)
|
|
{
|
|
COORD WindowSize;
|
|
WINDOW_LIMITS WindowLimits;
|
|
|
|
if (MaximumWindow) {
|
|
GetWindowLimits(ScreenInfo, &WindowLimits);
|
|
WindowSize = WindowLimits.MaximumWindowSize;
|
|
}
|
|
else {
|
|
WindowSize.X = (SHORT)CONSOLE_WINDOW_SIZE_X(ScreenInfo);
|
|
WindowSize.Y = (SHORT)CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
|
|
}
|
|
*FontIndex = SCR_FONTNUMBER(ScreenInfo);
|
|
*FontSize = WindowSize;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SetScreenBufferFont(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN ULONG FontIndex,
|
|
IN UINT CodePage
|
|
)
|
|
{
|
|
COORD FontSize;
|
|
WINDOW_LIMITS WindowLimits;
|
|
NTSTATUS Status;
|
|
ULONG ulFlagPrev;
|
|
DBGFONTS(("SetScreenBufferFont %lx %x\n", ScreenInfo, FontIndex));
|
|
|
|
if (ScreenInfo == NULL) {
|
|
/* If shutdown occurs with font dlg up */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Don't try to set the font if we're not in text mode
|
|
*/
|
|
if (!(ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER)) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
Status = GetFontSize(FontIndex, &FontSize);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return((ULONG) Status);
|
|
}
|
|
|
|
ulFlagPrev = ScreenInfo->Flags;
|
|
if (TM_IS_TT_FONT(FontInfo[FontIndex].Family)) {
|
|
ScreenInfo->Flags &= ~CONSOLE_OEMFONT_DISPLAY;
|
|
} else {
|
|
ScreenInfo->Flags |= CONSOLE_OEMFONT_DISPLAY;
|
|
}
|
|
|
|
/*
|
|
* Convert from UnicodeOem to Unicode or vice-versa if necessary
|
|
*/
|
|
if ((ulFlagPrev & CONSOLE_OEMFONT_DISPLAY) != (ScreenInfo->Flags & CONSOLE_OEMFONT_DISPLAY)) {
|
|
if (ulFlagPrev & CONSOLE_OEMFONT_DISPLAY) {
|
|
/*
|
|
* Must convert from UnicodeOem to real Unicode
|
|
*/
|
|
DBGCHARS(("SetScreenBufferFont converts UnicodeOem to Unicode\n"));
|
|
FalseUnicodeToRealUnicode(
|
|
ScreenInfo->BufferInfo.TextInfo.TextRows,
|
|
ScreenInfo->ScreenBufferSize.X * ScreenInfo->ScreenBufferSize.Y,
|
|
ScreenInfo->Console->OutputCP);
|
|
} else {
|
|
/*
|
|
* Must convert from real Unicode to UnicodeOem
|
|
*/
|
|
DBGCHARS(("SetScreenBufferFont converts Unicode to UnicodeOem\n"));
|
|
RealUnicodeToFalseUnicode(
|
|
ScreenInfo->BufferInfo.TextInfo.TextRows,
|
|
ScreenInfo->ScreenBufferSize.X * ScreenInfo->ScreenBufferSize.Y,
|
|
ScreenInfo->Console->OutputCP);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Store font properties
|
|
*/
|
|
Status = StoreTextBufferFontInfo(ScreenInfo,
|
|
FontIndex,
|
|
FontSize,
|
|
FontInfo[FontIndex].Family,
|
|
FontInfo[FontIndex].Weight,
|
|
FontInfo[FontIndex].FaceName,
|
|
CodePage);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return((ULONG) Status);
|
|
}
|
|
|
|
//
|
|
// set font
|
|
//
|
|
Status = SetFont(ScreenInfo);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return((ULONG) Status);
|
|
}
|
|
|
|
//
|
|
// if window is growing, make sure it's not bigger than the screen.
|
|
//
|
|
|
|
GetWindowLimits(ScreenInfo, &WindowLimits);
|
|
if (WindowLimits.MaximumWindowSize.X < CONSOLE_WINDOW_SIZE_X(ScreenInfo)) {
|
|
ScreenInfo->Window.Right -= CONSOLE_WINDOW_SIZE_X(ScreenInfo) - WindowLimits.MaximumWindowSize.X;
|
|
ScreenInfo->WindowMaximizedX = (ScreenInfo->Window.Left == 0 &&
|
|
(SHORT)(ScreenInfo->Window.Right+1) == ScreenInfo->ScreenBufferSize.X);
|
|
}
|
|
if (WindowLimits.MaximumWindowSize.Y < CONSOLE_WINDOW_SIZE_Y(ScreenInfo)) {
|
|
ScreenInfo->Window.Bottom -= CONSOLE_WINDOW_SIZE_Y(ScreenInfo) - WindowLimits.MaximumWindowSize.Y;
|
|
if (ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y > ScreenInfo->Window.Bottom) {
|
|
ScreenInfo->Window.Top += ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y - ScreenInfo->Window.Bottom;
|
|
ScreenInfo->Window.Bottom += ScreenInfo->BufferInfo.TextInfo.CursorPosition.Y - ScreenInfo->Window.Bottom;
|
|
}
|
|
ScreenInfo->WindowMaximizedY = (ScreenInfo->Window.Top == 0 &&
|
|
(SHORT)(ScreenInfo->Window.Bottom+1) == ScreenInfo->ScreenBufferSize.Y);
|
|
}
|
|
if (WindowLimits.MinimumWindowSize.X > CONSOLE_WINDOW_SIZE_X(ScreenInfo)) {
|
|
if (WindowLimits.MinimumWindowSize.X > ScreenInfo->ScreenBufferSize.X) {
|
|
COORD NewBufferSize;
|
|
|
|
NewBufferSize.X = WindowLimits.MinimumWindowSize.X;
|
|
NewBufferSize.Y = ScreenInfo->ScreenBufferSize.Y;
|
|
ResizeScreenBuffer(ScreenInfo,
|
|
NewBufferSize,
|
|
FALSE
|
|
);
|
|
}
|
|
if ((ScreenInfo->Window.Left+WindowLimits.MinimumWindowSize.X) > ScreenInfo->ScreenBufferSize.X) {
|
|
ScreenInfo->Window.Left = 0;
|
|
ScreenInfo->Window.Right = WindowLimits.MinimumWindowSize.X-1;
|
|
} else {
|
|
ScreenInfo->Window.Right = ScreenInfo->Window.Left+WindowLimits.MinimumWindowSize.X-1;
|
|
}
|
|
ScreenInfo->WindowMaximizedX = (ScreenInfo->Window.Left == 0 &&
|
|
(SHORT)(ScreenInfo->Window.Right+1) == ScreenInfo->ScreenBufferSize.X);
|
|
}
|
|
|
|
SetLineChar(ScreenInfo);
|
|
{
|
|
COORD WindowedWindowSize;
|
|
|
|
WindowedWindowSize.X = CONSOLE_WINDOW_SIZE_X(ScreenInfo);
|
|
WindowedWindowSize.Y = CONSOLE_WINDOW_SIZE_Y(ScreenInfo);
|
|
|
|
|
|
#if defined(FE_IME)
|
|
if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console))
|
|
{
|
|
PCONVERSIONAREA_INFORMATION ConvAreaInfo;
|
|
|
|
ConvAreaInfo = ScreenInfo->Console->ConsoleIme.ConvAreaRoot;
|
|
while (ConvAreaInfo) {
|
|
|
|
Status = StoreTextBufferFontInfo(ConvAreaInfo->ScreenBuffer,
|
|
SCR_FONTNUMBER(ScreenInfo),
|
|
SCR_FONTSIZE(ScreenInfo),
|
|
SCR_FAMILY(ScreenInfo),
|
|
SCR_FONTWEIGHT(ScreenInfo),
|
|
SCR_FACENAME(ScreenInfo),
|
|
SCR_FONTCODEPAGE(ScreenInfo));
|
|
if (!NT_SUCCESS(Status)) {
|
|
return((ULONG) Status);
|
|
}
|
|
|
|
ConvAreaInfo->ScreenBuffer->Window = ScreenInfo->Window;
|
|
ConvAreaInfo->ScreenBuffer->BufferInfo.TextInfo.ModeIndex = ScreenInfo->BufferInfo.TextInfo.ModeIndex;
|
|
|
|
ConvAreaInfo = ConvAreaInfo->ConvAreaNext;
|
|
}
|
|
}
|
|
#endif // FE_IME
|
|
}
|
|
|
|
//
|
|
// resize window. this will take care of the scroll bars too.
|
|
//
|
|
|
|
if (ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
|
|
SetWindowSize(ScreenInfo);
|
|
}
|
|
|
|
//
|
|
// adjust cursor size.
|
|
//
|
|
|
|
SetCursorInformation(ScreenInfo,
|
|
ScreenInfo->BufferInfo.TextInfo.CursorSize,
|
|
(BOOLEAN)ScreenInfo->BufferInfo.TextInfo.CursorVisible
|
|
);
|
|
|
|
WriteToScreen(ScreenInfo,
|
|
&ScreenInfo->Window);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SetFont(
|
|
IN OUT PSCREEN_INFORMATION ScreenInfo
|
|
)
|
|
{
|
|
if (ACTIVE_SCREEN_BUFFER(ScreenInfo)) {
|
|
int FontIndex = FindCreateFont(SCR_FAMILY(ScreenInfo),
|
|
SCR_FACENAME(ScreenInfo),
|
|
SCR_FONTSIZE(ScreenInfo),
|
|
SCR_FONTWEIGHT(ScreenInfo),
|
|
SCR_FONTCODEPAGE(ScreenInfo));
|
|
if (SelectObject(ScreenInfo->Console->hDC,FontInfo[FontIndex].hFont)==0)
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
if ((DWORD)FontIndex != SCR_FONTNUMBER(ScreenInfo)) {
|
|
NTSTATUS Status;
|
|
Status = StoreTextBufferFontInfo(ScreenInfo,
|
|
FontIndex,
|
|
FontInfo[FontIndex].Size,
|
|
FontInfo[FontIndex].Family,
|
|
FontInfo[FontIndex].Weight,
|
|
FontInfo[FontIndex].FaceName,
|
|
ScreenInfo->Console->OutputCP);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return((ULONG) Status);
|
|
}
|
|
}
|
|
|
|
// hack to get text realized into DC. this is to force the
|
|
// attribute cache to get flushed to the server side, since
|
|
// we select the font with a client side DC and call ExtTextOut
|
|
// with a server side DC.
|
|
// we then need to reset the text color, since the incorrect
|
|
// client side color has been flushed to the server.
|
|
{
|
|
TEXTMETRIC tmi;
|
|
|
|
GetTextMetricsW( ScreenInfo->Console->hDC, &tmi);
|
|
ASSERT ((tmi.tmPitchAndFamily & 1) == 0);
|
|
ScreenInfo->Console->LastAttributes = ScreenInfo->Attributes;
|
|
SetTextColor(ScreenInfo->Console->hDC,ConvertAttrToRGB(ScreenInfo->Console, LOBYTE(ScreenInfo->Attributes)));
|
|
SetBkColor(ScreenInfo->Console->hDC,ConvertAttrToRGB(ScreenInfo->Console, LOBYTE(ScreenInfo->Attributes >> 4)));
|
|
}
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int
|
|
ConvertToOem(
|
|
IN UINT Codepage,
|
|
IN LPWSTR Source,
|
|
IN int SourceLength, // in chars
|
|
OUT LPSTR Target,
|
|
IN int TargetLength // in chars
|
|
)
|
|
{
|
|
DBGCHARS(("ConvertToOem U->%d %.*ls\n", Codepage,
|
|
SourceLength > 10 ? 10 : SourceLength, Source));
|
|
if (Codepage == OEMCP) {
|
|
ULONG Length;
|
|
NTSTATUS Status;
|
|
|
|
Status = RtlUnicodeToOemN(Target,
|
|
TargetLength,
|
|
&Length,
|
|
Source,
|
|
SourceLength * sizeof(WCHAR)
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return 0;
|
|
} else {
|
|
return Length;
|
|
}
|
|
} else {
|
|
return WideCharToMultiByte(Codepage,
|
|
0,
|
|
Source,
|
|
SourceLength,
|
|
Target,
|
|
TargetLength,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
int
|
|
ConvertInputToUnicode(
|
|
IN UINT Codepage,
|
|
IN LPSTR Source,
|
|
IN int SourceLength, // in chars
|
|
OUT LPWSTR Target,
|
|
IN int TargetLength // in chars
|
|
)
|
|
/*
|
|
data in the output buffer is the true unicode value
|
|
*/
|
|
{
|
|
DBGCHARS(("ConvertInputToUnicode %d->U %.*s\n", Codepage,
|
|
SourceLength > 10 ? 10 : SourceLength, Source));
|
|
if (Codepage == OEMCP) {
|
|
ULONG Length;
|
|
NTSTATUS Status;
|
|
|
|
Status = RtlOemToUnicodeN(Target,
|
|
TargetLength * sizeof(WCHAR),
|
|
&Length,
|
|
Source,
|
|
SourceLength
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return 0;
|
|
} else {
|
|
return Length / sizeof(WCHAR);
|
|
}
|
|
} else {
|
|
return MultiByteToWideChar(Codepage,
|
|
0,
|
|
Source,
|
|
SourceLength,
|
|
Target,
|
|
TargetLength);
|
|
}
|
|
}
|
|
|
|
int
|
|
ConvertOutputToUnicode(
|
|
IN UINT Codepage,
|
|
IN LPSTR Source,
|
|
IN int SourceLength, // in chars
|
|
OUT LPWSTR Target,
|
|
IN int TargetLength // in chars
|
|
)
|
|
/*
|
|
output data is always translated via the ansi codepage
|
|
so glyph translation works.
|
|
*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG Length;
|
|
CHAR StackBuffer[STACK_BUFFER_SIZE];
|
|
LPSTR pszT;
|
|
|
|
DBGCHARS(("ConvertOutputToUnicode %d->U %.*s\n", Codepage,
|
|
SourceLength > 10 ? 10 : SourceLength, Source));
|
|
if (Codepage == OEMCP) {
|
|
Status = RtlCustomCPToUnicodeN(&GlyphCP,
|
|
Target,
|
|
TargetLength * sizeof(WCHAR),
|
|
&Length,
|
|
Source,
|
|
SourceLength
|
|
);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return 0;
|
|
} else {
|
|
return Length / sizeof(WCHAR);
|
|
}
|
|
}
|
|
|
|
if (TargetLength > STACK_BUFFER_SIZE) {
|
|
pszT = ConsoleHeapAlloc(TMP_TAG, SourceLength);
|
|
if (pszT == NULL) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
pszT = StackBuffer;
|
|
}
|
|
RtlCopyMemory(pszT, Source, SourceLength);
|
|
Length = MultiByteToWideChar(Codepage, MB_USEGLYPHCHARS,
|
|
pszT, SourceLength, Target, TargetLength);
|
|
if (pszT != StackBuffer) {
|
|
ConsoleHeapFree(pszT);
|
|
}
|
|
return Length;
|
|
}
|
|
|
|
#if defined(FE_SB)
|
|
WCHAR
|
|
SB_CharToWcharGlyph(
|
|
IN UINT Codepage,
|
|
IN char Ch)
|
|
#else
|
|
WCHAR
|
|
CharToWcharGlyph(
|
|
IN UINT Codepage,
|
|
IN char Ch)
|
|
#endif
|
|
{
|
|
WCHAR wch = UNICODE_NULL;
|
|
if (Codepage == OEMCP) {
|
|
RtlCustomCPToUnicodeN(&GlyphCP, &wch, sizeof(wch), NULL, &Ch, sizeof(Ch));
|
|
} else {
|
|
MultiByteToWideChar(Codepage, MB_USEGLYPHCHARS, &Ch, 1, &wch, 1);
|
|
}
|
|
#ifdef DEBUG_PRINT
|
|
if (Ch > 0x7F) {
|
|
DBGCHARS(("CharToWcharGlyph %d 0x%02x -> 0x%04x\n",Codepage,(UCHAR)Ch,wch));
|
|
}
|
|
#endif
|
|
return wch;
|
|
}
|
|
|
|
#if defined(FE_SB)
|
|
WCHAR
|
|
SB_CharToWchar(
|
|
IN UINT Codepage,
|
|
IN char Ch)
|
|
#else
|
|
WCHAR
|
|
CharToWchar(
|
|
IN UINT Codepage,
|
|
IN char Ch)
|
|
#endif
|
|
{
|
|
WCHAR wch = UNICODE_NULL;
|
|
if (Codepage == OEMCP) {
|
|
RtlOemToUnicodeN(&wch, sizeof(wch), NULL, &Ch, sizeof(Ch));
|
|
} else {
|
|
MultiByteToWideChar(Codepage, 0, &Ch, 1, &wch, 1);
|
|
}
|
|
#ifdef DEBUG_PRINT
|
|
if (Ch > 0x7F) {
|
|
DBGCHARS(("CharToWchar %d 0x%02x -> 0x%04x\n",Codepage,(UCHAR)Ch,wch));
|
|
}
|
|
#endif
|
|
return wch;
|
|
}
|
|
|
|
char
|
|
WcharToChar(
|
|
IN UINT Codepage,
|
|
IN WCHAR Wchar)
|
|
{
|
|
char ch = CHAR_NULL;
|
|
if (Codepage == OEMCP) {
|
|
RtlUnicodeToOemN(&ch, sizeof(ch), NULL, &Wchar, sizeof(Wchar));
|
|
} else {
|
|
WideCharToMultiByte(Codepage, 0, &Wchar, 1, &ch, 1, NULL, NULL);
|
|
}
|
|
#ifdef DEBUG_PRINT
|
|
if (Wchar > 0x007F) {
|
|
DBGCHARS(("WcharToChar %d 0x%04x -> 0x%02x\n",Codepage,Wchar,(UCHAR)ch));
|
|
}
|
|
#endif
|
|
return ch;
|
|
}
|
|
|
|
int
|
|
ConvertOutputToOem(
|
|
IN UINT Codepage,
|
|
IN LPWSTR Source,
|
|
IN int SourceLength, // in chars
|
|
OUT LPSTR Target,
|
|
IN int TargetLength // in chars
|
|
)
|
|
/*
|
|
Converts SourceLength Unicode characters from Source into
|
|
not more than TargetLength Codepage characters at Target.
|
|
Returns the number characters put in Target. (0 if failure)
|
|
*/
|
|
|
|
{
|
|
if (Codepage == OEMCP) {
|
|
NTSTATUS Status;
|
|
ULONG Length;
|
|
// Can do this in place
|
|
Status = RtlUnicodeToOemN(Target,
|
|
TargetLength,
|
|
&Length,
|
|
Source,
|
|
SourceLength * sizeof(WCHAR)
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
return Length;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
ASSERT (Source != (LPWSTR)Target);
|
|
#ifdef SOURCE_EQ_TARGET
|
|
LPSTR pszDestTmp;
|
|
CHAR StackBuffer[STACK_BUFFER_SIZE];
|
|
|
|
DBGCHARS(("ConvertOutputToOem U->%d %.*ls\n", Codepage,
|
|
SourceLength > 10 ? 10 : SourceLength, Source));
|
|
|
|
if (TargetLength > STACK_BUFFER_SIZE) {
|
|
pszDestTmp = ConsoleHeapAlloc(TMP_TAG, TargetLength);
|
|
if (pszDestTmp == NULL) {
|
|
return 0;
|
|
}
|
|
} else {
|
|
pszDestTmp = StackBuffer;
|
|
}
|
|
TargetLength = WideCharToMultiByte(Codepage, 0,
|
|
Source, SourceLength,
|
|
pszDestTmp, TargetLength, NULL, NULL);
|
|
|
|
RtlCopyMemory(Target, pszDestTmp, TargetLength);
|
|
if (pszDestTmp != StackBuffer) {
|
|
ConsoleHeapFree(pszDestTmp);
|
|
}
|
|
return TargetLength;
|
|
#else
|
|
DBGCHARS(("ConvertOutputToOem U->%d %.*ls\n", Codepage,
|
|
SourceLength > 10 ? 10 : SourceLength, Source));
|
|
return WideCharToMultiByte(Codepage, 0,
|
|
Source, SourceLength, Target, TargetLength, NULL, NULL);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
RealUnicodeToFalseUnicode(
|
|
IN OUT LPWSTR Source,
|
|
IN int SourceLength, // in chars
|
|
IN UINT Codepage
|
|
)
|
|
|
|
/*
|
|
|
|
this routine converts a unicode string into the correct characters
|
|
for an OEM (cp 437) font. this code is needed because the gdi glyph
|
|
mapper converts unicode to ansi using codepage 1252 to index
|
|
font. this is how the data is stored internally.
|
|
|
|
*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
LPSTR Temp;
|
|
ULONG TempLength;
|
|
ULONG Length;
|
|
CHAR StackBuffer[STACK_BUFFER_SIZE];
|
|
BOOL NormalChars;
|
|
int i;
|
|
|
|
DBGCHARS(("RealUnicodeToFalseUnicode U->%d:ACP->U %.*ls\n", Codepage,
|
|
SourceLength > 10 ? 10 : SourceLength, Source));
|
|
#if defined(FE_SB)
|
|
if (OEMCP == WINDOWSCP && Codepage == WINDOWSCP)
|
|
return STATUS_SUCCESS;
|
|
if (SourceLength == 0 )
|
|
return STATUS_SUCCESS;
|
|
#endif
|
|
NormalChars = TRUE;
|
|
for (i=0;i<SourceLength;i++) {
|
|
if (Source[i] > 0x7f) {
|
|
NormalChars = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (NormalChars) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
TempLength = SourceLength;
|
|
if (TempLength > STACK_BUFFER_SIZE) {
|
|
Temp = ConsoleHeapAlloc(TMP_TAG, TempLength);
|
|
if (Temp == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
} else {
|
|
Temp = StackBuffer;
|
|
}
|
|
if (Codepage == OEMCP) {
|
|
Status = RtlUnicodeToOemN(Temp,
|
|
TempLength,
|
|
&Length,
|
|
Source,
|
|
SourceLength * sizeof(WCHAR)
|
|
);
|
|
} else {
|
|
Status = WideCharToMultiByte(Codepage,
|
|
0,
|
|
Source,
|
|
SourceLength,
|
|
Temp,
|
|
TempLength,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (TempLength > STACK_BUFFER_SIZE) {
|
|
ConsoleHeapFree(Temp);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
if (CONSOLE_IS_DBCS_ENABLED()) {
|
|
MultiByteToWideChar(USACP,
|
|
0,
|
|
Temp,
|
|
TempLength,
|
|
Source,
|
|
SourceLength
|
|
);
|
|
} else {
|
|
Status = RtlMultiByteToUnicodeN(Source,
|
|
SourceLength * sizeof(WCHAR),
|
|
&Length,
|
|
Temp,
|
|
TempLength
|
|
);
|
|
}
|
|
|
|
if (TempLength > STACK_BUFFER_SIZE) {
|
|
ConsoleHeapFree(Temp);
|
|
}
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
} else {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
FalseUnicodeToRealUnicode(
|
|
IN OUT LPWSTR Source,
|
|
IN int SourceLength, // in chars
|
|
IN UINT Codepage
|
|
)
|
|
|
|
/*
|
|
|
|
this routine converts a unicode string from the internally stored
|
|
unicode characters into the real unicode characters.
|
|
|
|
*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
LPSTR Temp;
|
|
ULONG TempLength;
|
|
ULONG Length;
|
|
CHAR StackBuffer[STACK_BUFFER_SIZE];
|
|
BOOL NormalChars;
|
|
int i;
|
|
|
|
DBGCHARS(("UnicodeAnsiToUnicodeAnsi U->ACP:%d->U %.*ls\n", Codepage,
|
|
SourceLength > 10 ? 10 : SourceLength, Source));
|
|
#if defined(FE_SB)
|
|
if (OEMCP == WINDOWSCP && Codepage == WINDOWSCP)
|
|
return STATUS_SUCCESS;
|
|
if (SourceLength == 0 )
|
|
return STATUS_SUCCESS;
|
|
#endif
|
|
NormalChars = TRUE;
|
|
/*
|
|
* Test for characters < 0x20 or >= 0x7F. If none are found, we don't have
|
|
* any conversion to do!
|
|
*/
|
|
for (i=0;i<SourceLength;i++) {
|
|
if ((USHORT)(Source[i] - 0x20) > 0x5e) {
|
|
NormalChars = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (NormalChars) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
TempLength = SourceLength;
|
|
if (TempLength > STACK_BUFFER_SIZE) {
|
|
Temp = ConsoleHeapAlloc(TMP_TAG, TempLength);
|
|
if (Temp == NULL) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
} else {
|
|
Temp = StackBuffer;
|
|
}
|
|
if (CONSOLE_IS_DBCS_ENABLED()) {
|
|
Status = WideCharToMultiByte(USACP,
|
|
0,
|
|
Source,
|
|
SourceLength,
|
|
Temp,
|
|
TempLength,
|
|
NULL,
|
|
NULL);
|
|
} else {
|
|
Status = RtlUnicodeToMultiByteN(Temp,
|
|
TempLength,
|
|
&Length,
|
|
Source,
|
|
SourceLength * sizeof(WCHAR)
|
|
);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (TempLength > STACK_BUFFER_SIZE) {
|
|
ConsoleHeapFree(Temp);
|
|
}
|
|
return Status;
|
|
}
|
|
if (Codepage == OEMCP) {
|
|
Status = RtlCustomCPToUnicodeN(&GlyphCP,
|
|
Source,
|
|
SourceLength * sizeof(WCHAR),
|
|
&Length,
|
|
Temp,
|
|
TempLength
|
|
);
|
|
} else {
|
|
Status = MultiByteToWideChar(Codepage,
|
|
MB_USEGLYPHCHARS,
|
|
Temp,
|
|
TempLength*sizeof(WCHAR),
|
|
Source,
|
|
SourceLength);
|
|
}
|
|
#if defined(FE_SB)
|
|
if (SourceLength > STACK_BUFFER_SIZE) {
|
|
ConsoleHeapFree(Temp);
|
|
}
|
|
#else
|
|
if (TempLength > STACK_BUFFER_SIZE) {
|
|
ConsoleHeapFree(Temp);
|
|
}
|
|
#endif
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
} else {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
BOOL InitializeCustomCP() {
|
|
PPEB pPeb;
|
|
|
|
pPeb = NtCurrentPeb();
|
|
if ((pPeb == NULL) || (pPeb->OemCodePageData == NULL)) {
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Fill in the CPTABLEINFO struct
|
|
*/
|
|
RtlInitCodePageTable(pPeb->OemCodePageData, &GlyphCP);
|
|
|
|
/*
|
|
* Make a copy of the MultiByteToWideChar table
|
|
*/
|
|
RtlCopyMemory(GlyphTable, GlyphCP.MultiByteTable, 256 * sizeof(USHORT));
|
|
|
|
/*
|
|
* Modify the first 0x20 bytes so that they are glyphs.
|
|
*/
|
|
MultiByteToWideChar(CP_OEMCP, MB_USEGLYPHCHARS,
|
|
"\x20\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
|
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
|
|
0x20, GlyphTable, 0x20);
|
|
MultiByteToWideChar(CP_OEMCP, MB_USEGLYPHCHARS,
|
|
"\x7f", 1, &GlyphTable[0x7f], 1);
|
|
|
|
|
|
/*
|
|
* Point the Custom CP at the glyph table
|
|
*/
|
|
GlyphCP.MultiByteTable = GlyphTable;
|
|
|
|
#if defined(FE_SB) && defined(i386)
|
|
if (ISNECPC98(gdwMachineId)) {
|
|
InitializeNEC_OS2_CP();
|
|
}
|
|
#endif
|
|
return TRUE;
|
|
}
|
|
|
|
#if defined(FE_SB)
|
|
VOID
|
|
SetConsoleCPInfo(
|
|
IN PCONSOLE_INFORMATION Console,
|
|
IN BOOL Output
|
|
)
|
|
{
|
|
if (Output) {
|
|
if (! GetCPInfo(Console->OutputCP,
|
|
&Console->OutputCPInfo)) {
|
|
Console->OutputCPInfo.LeadByte[0] = 0;
|
|
}
|
|
}
|
|
else {
|
|
if (! GetCPInfo(Console->CP,
|
|
&Console->CPInfo)) {
|
|
Console->CPInfo.LeadByte[0] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
CheckBisectStringW(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN DWORD CodePage,
|
|
IN PWCHAR Buffer,
|
|
IN DWORD NumWords,
|
|
IN DWORD NumBytes
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine check bisected on Unicode string end.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - Pointer to screen information structure.
|
|
|
|
CodePage - Value of code page.
|
|
|
|
Buffer - Pointer to Unicode string buffer.
|
|
|
|
NumWords - Number of Unicode string.
|
|
|
|
NumBytes - Number of bisect position by byte counts.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Bisected character.
|
|
|
|
FALSE - Correctly.
|
|
|
|
--*/
|
|
|
|
{
|
|
while(NumWords && NumBytes) {
|
|
if (IsConsoleFullWidth(ScreenInfo->Console->hDC,CodePage,*Buffer)) {
|
|
if (NumBytes < 2)
|
|
return TRUE;
|
|
else {
|
|
NumWords--;
|
|
NumBytes -= 2;
|
|
Buffer++;
|
|
}
|
|
}
|
|
else {
|
|
NumWords--;
|
|
NumBytes--;
|
|
Buffer++;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
CheckBisectProcessW(
|
|
IN PSCREEN_INFORMATION ScreenInfo,
|
|
IN DWORD CodePage,
|
|
IN PWCHAR Buffer,
|
|
IN DWORD NumWords,
|
|
IN DWORD NumBytes,
|
|
IN SHORT OriginalXPosition,
|
|
IN BOOL Echo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine check bisected on Unicode string end.
|
|
|
|
Arguments:
|
|
|
|
ScreenInfo - Pointer to screen information structure.
|
|
|
|
CodePage - Value of code page.
|
|
|
|
Buffer - Pointer to Unicode string buffer.
|
|
|
|
NumWords - Number of Unicode string.
|
|
|
|
NumBytes - Number of bisect position by byte counts.
|
|
|
|
Echo - TRUE if called by Read (echoing characters)
|
|
|
|
Return Value:
|
|
|
|
TRUE - Bisected character.
|
|
|
|
FALSE - Correctly.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR Char;
|
|
ULONG TabSize;
|
|
|
|
if (ScreenInfo->OutputMode & ENABLE_PROCESSED_OUTPUT) {
|
|
while(NumWords && NumBytes) {
|
|
Char = *Buffer;
|
|
if (Char >= (WCHAR)' ') {
|
|
if (IsConsoleFullWidth(ScreenInfo->Console->hDC,CodePage,Char)) {
|
|
if (NumBytes < 2)
|
|
return TRUE;
|
|
else {
|
|
NumWords--;
|
|
NumBytes -= 2;
|
|
Buffer++;
|
|
OriginalXPosition += 2;
|
|
}
|
|
}
|
|
else {
|
|
NumWords--;
|
|
NumBytes--;
|
|
Buffer++;
|
|
OriginalXPosition++;
|
|
}
|
|
}
|
|
else {
|
|
NumWords--;
|
|
Buffer++;
|
|
switch (Char) {
|
|
case UNICODE_BELL:
|
|
if (Echo)
|
|
goto CtrlChar;
|
|
break;
|
|
case UNICODE_BACKSPACE:
|
|
case UNICODE_LINEFEED:
|
|
case UNICODE_CARRIAGERETURN:
|
|
break;
|
|
case UNICODE_TAB:
|
|
TabSize = NUMBER_OF_SPACES_IN_TAB(OriginalXPosition);
|
|
OriginalXPosition = (SHORT)(OriginalXPosition + TabSize);
|
|
if (NumBytes < TabSize)
|
|
return TRUE;
|
|
NumBytes -= TabSize;
|
|
break;
|
|
default:
|
|
if (Echo) {
|
|
CtrlChar:
|
|
if (NumBytes < 2)
|
|
return TRUE;
|
|
NumBytes -= 2;
|
|
OriginalXPosition += 2;
|
|
} else {
|
|
NumBytes--;
|
|
OriginalXPosition++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
else {
|
|
return CheckBisectStringW(ScreenInfo,
|
|
CodePage,
|
|
Buffer,
|
|
NumWords,
|
|
NumBytes);
|
|
}
|
|
}
|
|
#endif // FE_SB
|