Windows2000/private/ntos/w32/ntcon/server/dbcs.c
2020-09-30 17:12:32 +02:00

2727 lines
79 KiB
C

/*++
Copyright (c) 1985 - 1999, Microsoft Corporation
Module Name:
dbcs.c
Abstract:
Author:
KazuM Mar.05.1992
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#pragma alloc_text(FE_TEXT, CheckBisectStringA)
#pragma alloc_text(FE_TEXT, BisectWrite)
#pragma alloc_text(FE_TEXT, BisectClipbrd)
#pragma alloc_text(FE_TEXT, BisectWriteAttr)
#pragma alloc_text(FE_TEXT, IsDBCSLeadByteConsole)
#pragma alloc_text(FE_TEXT, TextOutEverything)
#pragma alloc_text(FE_TEXT, TextOutCommonLVB)
#ifdef i386
#pragma alloc_text(FE_TEXT, RealUnicodeToNEC_OS2_Unicode)
#pragma alloc_text(FE_TEXT, InitializeNEC_OS2_CP)
#endif
#pragma alloc_text(FE_TEXT, ProcessCreateConsoleIME)
#pragma alloc_text(FE_TEXT, InitConsoleIMEStuff)
#pragma alloc_text(FE_TEXT, WaitConsoleIMEStuff)
#pragma alloc_text(FE_TEXT, ConSrvRegisterConsoleIME)
#pragma alloc_text(FE_TEXT, RemoveConsoleIME)
#pragma alloc_text(FE_TEXT, ConsoleImeMessagePump)
#pragma alloc_text(FE_TEXT, RegisterKeisenOfTTFont)
#pragma alloc_text(FE_TEXT, ImmConversionToConsole)
#pragma alloc_text(FE_TEXT, ImmConversionFromConsole)
#pragma alloc_text(FE_TEXT, TranslateUnicodeToOem)
#if defined(FE_SB)
SINGLE_LIST_ENTRY gTTFontList; // This list contain TTFONTLIST data.
#if defined(i386)
ULONG gdwMachineId;
#endif
LPTHREAD_START_ROUTINE ConsoleIMERoutine; // client side console IME routine
CRITICAL_SECTION ConIMEInitWindowsLock;
#if defined(i386)
/*
* NEC PC-98 OS/2 OEM character set
* When FormatID is 0 or 80, Convert SBCS (00h-1Fh) font.
*/
PCPTABLEINFO pGlyph_NEC_OS2_CP;
PUSHORT pGlyph_NEC_OS2_Table;
#endif // i386
#if defined(FE_IME)
#if defined(i386)
NTSTATUS ImeWmFullScreen(IN BOOL Foreground, IN PCONSOLE_INFORMATION Console, IN PSCREEN_INFORMATION ScreenInfo)
{
NTSTATUS Status = STATUS_SUCCESS;
if(Foreground) {
ULONG ModeIndex;
PCONVERSIONAREA_INFORMATION ConvAreaInfo;
if (!NT_SUCCESS(ConsoleImeMessagePump(Console, CONIME_SETFOCUS, (WPARAM)Console->ConsoleHandle, (LPARAM)Console->hklActive))) {
return STATUS_INVALID_HANDLE;
}
if (ConvAreaInfo = Console->ConsoleIme.ConvAreaRoot) {
if (!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER))
ModeIndex = ScreenInfo->BufferInfo.TextInfo.ModeIndex;
else if (!(Console->CurrentScreenBuffer->Flags & CONSOLE_GRAPHICS_BUFFER))
ModeIndex = Console->CurrentScreenBuffer->BufferInfo.TextInfo.ModeIndex;
else
ModeIndex = 0;
do {
#ifdef FE_SB
// Check code for must CONSOLE_TEXTMODE_BUFFER !!
if (! (ConvAreaInfo->ScreenBuffer->Flags & CONSOLE_GRAPHICS_BUFFER))
ConvAreaInfo->ScreenBuffer->BufferInfo.TextInfo.ModeIndex = ModeIndex;
else
ASSERT(FALSE);
#else
ConvAreaInfo->ScreenBuffer->BufferInfo.TextInfo.ModeIndex = ModeIndex;
#endif
} while (ConvAreaInfo = ConvAreaInfo->ConvAreaNext);
}
}
else
{
if (!NT_SUCCESS(ConsoleImeMessagePump(Console, CONIME_KILLFOCUS, (WPARAM)Console->ConsoleHandle, (LPARAM)Console->hklActive))) {
return STATUS_INVALID_HANDLE;
}
}
return Status;
}
#endif // i386
NTSTATUS GetImeKeyState(IN PCONSOLE_INFORMATION Console, IN PDWORD pdwConversion)
/*++
Routine Description:
This routine get IME mode for KEY_EVENT_RECORD.
Arguments:
ConsoleInfo - Pointer to console information structure.
Return Value:
--*/
{
DWORD dwDummy;
/*
* If pdwConversion is NULL, the caller doensn't want
* the result but for code efficiency, let it
* point to the dummy dword variable, so that
* we don't have to care from here.
*/
if (pdwConversion == NULL) {
pdwConversion = &dwDummy;
}
if (Console->InputBuffer.ImeMode.Disable)
{
*pdwConversion = 0;
}
else
{
PINPUT_THREAD_INFO InputThreadInfo; // console thread info
InputThreadInfo = TlsGetValue(InputThreadTlsIndex);
if (InputThreadInfo != NULL)
{
LRESULT lResult;
/*
* This thread is in InputThread()
* We can try message pump.
*/
if (!NT_SUCCESS(ConsoleImeMessagePumpWorker(Console, CONIME_GET_NLSMODE, (WPARAM)Console->ConsoleHandle, (LPARAM)0, &lResult))) {
*pdwConversion = IME_CMODE_DISABLE;
return STATUS_INVALID_HANDLE;
}
*pdwConversion = (DWORD)lResult;
if (Console->InputBuffer.ImeMode.ReadyConversion == FALSE)
Console->InputBuffer.ImeMode.ReadyConversion = TRUE;
}
else
{
/*
* This thread is in CsrApiRequestThread()
* We can not try message pump.
*/
if (Console->InputBuffer.ImeMode.ReadyConversion == FALSE) {
*pdwConversion = 0;
return STATUS_SUCCESS;
}
*pdwConversion = Console->InputBuffer.ImeMode.Conversion;
}
if (*pdwConversion & IME_CMODE_OPEN)
Console->InputBuffer.ImeMode.Open = TRUE;
else
Console->InputBuffer.ImeMode.Open = FALSE;
if (*pdwConversion & IME_CMODE_DISABLE)
Console->InputBuffer.ImeMode.Disable = TRUE;
else
Console->InputBuffer.ImeMode.Disable = FALSE;
Console->InputBuffer.ImeMode.Conversion = *pdwConversion;
}
return STATUS_SUCCESS;
}
NTSTATUS SetImeKeyState(IN PCONSOLE_INFORMATION Console, IN DWORD fdwConversion)
/*++
Routine Description:
This routine get IME mode for KEY_EVENT_RECORD.
Arguments:
Console - Pointer to console information structure.
fdwConversion - IME conversion status.
Return Value:
--*/
{
PCONVERSIONAREA_INFORMATION ConvAreaInfo;
if ( (fdwConversion & IME_CMODE_DISABLE) && (! Console->InputBuffer.ImeMode.Disable) ) {
Console->InputBuffer.ImeMode.Disable = TRUE;
if ( Console->InputBuffer.ImeMode.Open ) {
ConvAreaInfo = Console->ConsoleIme.ConvAreaMode;
if (ConvAreaInfo)
ConvAreaInfo->ConversionAreaMode |= CA_HIDDEN;
ConvAreaInfo = Console->ConsoleIme.ConvAreaSystem;
if (ConvAreaInfo)
ConvAreaInfo->ConversionAreaMode |= CA_HIDDEN;
if (Console->InputBuffer.ImeMode.Open && CONSOLE_IS_DBCS_OUTPUTCP(Console))
ConsoleImePaint(Console, Console->ConsoleIme.ConvAreaRoot);
}
}
else if ( (! (fdwConversion & IME_CMODE_DISABLE)) && Console->InputBuffer.ImeMode.Disable) {
Console->InputBuffer.ImeMode.Disable = FALSE;
if ( fdwConversion & IME_CMODE_OPEN ) {
ConvAreaInfo = Console->ConsoleIme.ConvAreaMode;
if (ConvAreaInfo)
ConvAreaInfo->ConversionAreaMode &= ~CA_HIDDEN;
ConvAreaInfo = Console->ConsoleIme.ConvAreaSystem;
if (ConvAreaInfo)
ConvAreaInfo->ConversionAreaMode &= ~CA_HIDDEN;
if (Console->InputBuffer.ImeMode.Open && CONSOLE_IS_DBCS_OUTPUTCP(Console))
ConsoleImePaint(Console, Console->ConsoleIme.ConvAreaRoot);
}
}
else if ( (fdwConversion & IME_CMODE_DISABLE) && (Console->InputBuffer.ImeMode.Disable) ) {
return STATUS_SUCCESS;
}
if ( (fdwConversion & IME_CMODE_OPEN) && (! Console->InputBuffer.ImeMode.Open)) {
Console->InputBuffer.ImeMode.Open = TRUE;
}
else if ( (! (fdwConversion & IME_CMODE_OPEN)) && Console->InputBuffer.ImeMode.Open) {
Console->InputBuffer.ImeMode.Open = FALSE;
}
Console->InputBuffer.ImeMode.Conversion = fdwConversion;
if (Console->InputBuffer.ImeMode.ReadyConversion == FALSE)
Console->InputBuffer.ImeMode.ReadyConversion = TRUE;
if (!NT_SUCCESS(ConsoleImeMessagePump(Console, CONIME_SET_NLSMODE, (WPARAM)Console->ConsoleHandle, (LPARAM)fdwConversion))) {
return STATUS_INVALID_HANDLE;
}
return STATUS_SUCCESS;
}
NTSTATUS SetImeCodePage(IN PCONSOLE_INFORMATION Console)
{
DWORD CodePage = Console->OutputCP;
DWORD fdwConversion;
if (!CONSOLE_IS_DBCS_CP(Console))
{
if (!NT_SUCCESS(GetImeKeyState(Console, &fdwConversion))) {
return STATUS_INVALID_HANDLE;
}
fdwConversion |= IME_CMODE_DISABLE;
}
else {
fdwConversion = Console->InputBuffer.ImeMode.Conversion & ~IME_CMODE_DISABLE;
}
if (!NT_SUCCESS(SetImeKeyState(Console, fdwConversion))) {
return STATUS_INVALID_HANDLE;
}
if (CONSOLE_IS_IME_ENABLED()) {
if (!NT_SUCCESS(ConsoleImeMessagePump(Console, CONIME_NOTIFY_CODEPAGE, (WPARAM)Console->ConsoleHandle, (LPARAM)MAKELPARAM(FALSE, CodePage)))) {
return STATUS_INVALID_HANDLE;
}
}
return STATUS_SUCCESS;
}
NTSTATUS SetImeOutputCodePage(IN PCONSOLE_INFORMATION Console, IN PSCREEN_INFORMATION ScreenInfo, IN DWORD PrevCodePage)
{
DWORD CodePage = Console->OutputCP;
// Output code page
if ((ScreenInfo->Flags & CONSOLE_TEXTMODE_BUFFER) && (IsAvailableFarEastCodePage(CodePage) || IsAvailableFarEastCodePage(PrevCodePage)))
{
ConvertToCodePage(Console, PrevCodePage);
AdjustFont(Console, CodePage);
}
// load special ROM font, if necessary
#ifdef i386
if ( (Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) && !(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER))
{
SetROMFontCodePage(CodePage, ScreenInfo->BufferInfo.TextInfo.ModeIndex);
SetCursorInformationHW(ScreenInfo, ScreenInfo->BufferInfo.TextInfo.CursorSize, ScreenInfo->BufferInfo.TextInfo.CursorVisible);
WriteRegionToScreenHW(ScreenInfo, &ScreenInfo->Window);
}
#endif
if (CONSOLE_IS_IME_ENABLED()) {
if (!NT_SUCCESS(ConsoleImeMessagePump(Console, CONIME_NOTIFY_CODEPAGE, (WPARAM)Console->ConsoleHandle, (LPARAM)MAKELPARAM(TRUE, CodePage)))) {
return STATUS_INVALID_HANDLE;
}
}
return STATUS_SUCCESS;
}
#endif // FE_IME
VOID SetLineChar(IN PSCREEN_INFORMATION ScreenInfo)
/*++
Routine Description:
This routine setup of line character code.
Arguments:
ScreenInfo - Pointer to screen information structure.
Return Value:
none.
--*/
{
if (CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console))
{
if (OEMCP == JAPAN_CP || OEMCP == KOREAN_CP)
{
/*
* This is Japanese/Korean case,
* These characters maps grid of half width.
* so, same as U+2500.
*/
ScreenInfo->LineChar[UPPER_LEFT_CORNER] = 0x0001;
ScreenInfo->LineChar[UPPER_RIGHT_CORNER] = 0x0002;
ScreenInfo->LineChar[HORIZONTAL_LINE] = 0x0006;
ScreenInfo->LineChar[VERTICAL_LINE] = 0x0005;
ScreenInfo->LineChar[BOTTOM_LEFT_CORNER] = 0x0003;
ScreenInfo->LineChar[BOTTOM_RIGHT_CORNER] = 0x0004;
}
else
{
/*
* This is FE case,
* FE don't uses U+2500 because these grid characters
* maps to full width.
*/
ScreenInfo->LineChar[UPPER_LEFT_CORNER] = L'+';
ScreenInfo->LineChar[UPPER_RIGHT_CORNER] = L'+';
ScreenInfo->LineChar[HORIZONTAL_LINE] = L'-';
ScreenInfo->LineChar[VERTICAL_LINE] = L'|';
ScreenInfo->LineChar[BOTTOM_LEFT_CORNER] = L'+';
ScreenInfo->LineChar[BOTTOM_RIGHT_CORNER] = L'+';
}
}
else {
ScreenInfo->LineChar[UPPER_LEFT_CORNER] = 0x250c;
ScreenInfo->LineChar[UPPER_RIGHT_CORNER] = 0x2510;
ScreenInfo->LineChar[HORIZONTAL_LINE] = 0x2500;
ScreenInfo->LineChar[VERTICAL_LINE] = 0x2502;
ScreenInfo->LineChar[BOTTOM_LEFT_CORNER] = 0x2514;
ScreenInfo->LineChar[BOTTOM_RIGHT_CORNER] = 0x2518;
}
}
BOOL CheckBisectStringA(IN DWORD CodePage, IN PCHAR Buffer, IN DWORD NumBytes, IN LPCPINFO lpCPInfo)
/*++
Routine Description:
This routine check bisected on Ascii string end.
Arguments:
CodePage - Value of code page.
Buffer - Pointer to Ascii string buffer.
NumBytes - Number of Ascii string.
Return Value:
TRUE - Bisected character.
FALSE - Correctly.
--*/
{
UNREFERENCED_PARAMETER(CodePage);
while(NumBytes) {
if (IsDBCSLeadByteConsole(*Buffer,lpCPInfo)) {
if (NumBytes <= 1)
return TRUE;
else {
Buffer += 2;
NumBytes -= 2;
}
}
else {
Buffer++;
NumBytes--;
}
}
return FALSE;
}
VOID BisectWrite(IN SHORT StringLength, IN COORD TargetPoint, IN PSCREEN_INFORMATION ScreenInfo)
/*++
Routine Description:
This routine write buffer with bisect.
Arguments:
Return Value:
--*/
{
SHORT RowIndex;
PROW Row;
PROW RowPrev;
PROW RowNext;
#if defined(DBG) && defined(DBG_KATTR)
BeginKAttrCheck(ScreenInfo);
#endif
#ifdef FE_SB
// Check code for must CONSOLE_TEXTMODE_BUFFER !!
ASSERT(!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER));
#endif
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
if (RowIndex > 0) {
RowPrev = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex-1];
} else {
RowPrev = &ScreenInfo->BufferInfo.TextInfo.Rows[ScreenInfo->ScreenBufferSize.Y-1];
}
if (RowIndex+1 < ScreenInfo->ScreenBufferSize.Y) {
RowNext = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex+1];
} else {
RowNext = &ScreenInfo->BufferInfo.TextInfo.Rows[0];
}
// Check start position of strings
if (Row->CharRow.KAttrs[TargetPoint.X] & ATTR_TRAILING_BYTE)
{
if (TargetPoint.X == 0) {
RowPrev->CharRow.Chars[ScreenInfo->ScreenBufferSize.X-1] = UNICODE_SPACE;
RowPrev->CharRow.KAttrs[ScreenInfo->ScreenBufferSize.X-1] = 0;
ScreenInfo->BisectFlag |= BISECT_TOP;
}
else {
Row->CharRow.Chars[TargetPoint.X-1] = UNICODE_SPACE;
Row->CharRow.KAttrs[TargetPoint.X-1] = 0;
ScreenInfo->BisectFlag |= BISECT_LEFT;
}
}
// Check end position of strings
if (TargetPoint.X+StringLength < ScreenInfo->ScreenBufferSize.X) {
if (Row->CharRow.KAttrs[TargetPoint.X+StringLength] & ATTR_TRAILING_BYTE)
{
Row->CharRow.Chars[TargetPoint.X+StringLength] = UNICODE_SPACE;
Row->CharRow.KAttrs[TargetPoint.X+StringLength] = 0;
ScreenInfo->BisectFlag |= BISECT_RIGHT;
}
}
else if (TargetPoint.Y+1 < ScreenInfo->ScreenBufferSize.Y) {
if (RowNext->CharRow.KAttrs[0] & ATTR_TRAILING_BYTE)
{
RowNext->CharRow.Chars[0] = UNICODE_SPACE;
RowNext->CharRow.KAttrs[0] = 0;
ScreenInfo->BisectFlag |= BISECT_BOTTOM;
}
}
}
VOID
BisectClipbrd(
IN SHORT StringLength,
IN COORD TargetPoint,
IN PSCREEN_INFORMATION ScreenInfo,
OUT PSMALL_RECT SmallRect
)
/*++
Routine Description:
This routine check bisect for clipboard process.
Arguments:
Return Value:
--*/
{
SHORT RowIndex;
PROW Row;
PROW RowNext;
#if defined(DBG) && defined(DBG_KATTR)
// BeginKAttrCheck(ScreenInfo);
#endif
#ifdef FE_SB
// Check code for must CONSOLE_TEXTMODE_BUFFER !!
ASSERT(!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER));
#endif
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
if (RowIndex+1 < ScreenInfo->ScreenBufferSize.Y) {
RowNext = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex+1];
} else {
RowNext = &ScreenInfo->BufferInfo.TextInfo.Rows[0];
}
// Check start position of strings
ASSERT(CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console));
if (Row->CharRow.KAttrs[TargetPoint.X] & ATTR_TRAILING_BYTE)
{
if (TargetPoint.X == 0) {
SmallRect->Left++;
}
else {
SmallRect->Left--;
}
}
// Check end position of strings
if (TargetPoint.X+StringLength < ScreenInfo->ScreenBufferSize.X) {
if (Row->CharRow.KAttrs[TargetPoint.X+StringLength] & ATTR_TRAILING_BYTE)
{
SmallRect->Right++;
}
}
else if (TargetPoint.Y+1 < ScreenInfo->ScreenBufferSize.Y) {
if (RowNext->CharRow.KAttrs[0] & ATTR_TRAILING_BYTE)
{
SmallRect->Right--;
}
}
}
VOID
BisectWriteAttr(
IN SHORT StringLength,
IN COORD TargetPoint,
IN PSCREEN_INFORMATION ScreenInfo
)
/*++
Routine Description:
This routine write buffer with bisect.
Arguments:
Return Value:
--*/
{
SHORT RowIndex;
PROW Row;
PROW RowNext;
#if defined(DBG) && defined(DBG_KATTR)
BeginKAttrCheck(ScreenInfo);
#endif
#ifdef FE_SB
// Check code for must CONSOLE_TEXTMODE_BUFFER !!
ASSERT(!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER));
#endif
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow+TargetPoint.Y) % ScreenInfo->ScreenBufferSize.Y;
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
if (RowIndex+1 < ScreenInfo->ScreenBufferSize.Y) {
RowNext = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex+1];
} else {
RowNext = &ScreenInfo->BufferInfo.TextInfo.Rows[0];
}
// Check start position of strings
if (Row->CharRow.KAttrs[TargetPoint.X] & ATTR_TRAILING_BYTE){
if (TargetPoint.X == 0) {
ScreenInfo->BisectFlag |= BISECT_TOP;
}
else {
ScreenInfo->BisectFlag |= BISECT_LEFT;
}
}
// Check end position of strings
if (TargetPoint.X+StringLength < ScreenInfo->ScreenBufferSize.X) {
if (Row->CharRow.KAttrs[TargetPoint.X+StringLength] & ATTR_TRAILING_BYTE){
ScreenInfo->BisectFlag |= BISECT_RIGHT;
}
}
else if (TargetPoint.Y+1 < ScreenInfo->ScreenBufferSize.Y) {
if (RowNext->CharRow.KAttrs[0] & ATTR_TRAILING_BYTE){
ScreenInfo->BisectFlag |= BISECT_BOTTOM;
}
}
}
/*
* BOOL IsConsoleFullWidth(HDC hDC,DWORD CodePage,WCHAR wch)
* Determine if the given Unicode char is fullwidth or not.
* Return:
* FASLE : half width. Uses 1 column per one character
* TRUE : full width. Uses 2 columns per one character
* History:
* 04-08-92 ShunK Created.
* Jul-27-1992 KazuM Added Screen Information and Code Page Information.
* Jan-29-1992 V-Hirots Substruct Screen Information.
* Oct-06-1996 KazuM Not use RtlUnicodeToMultiByteSize and WideCharToMultiByte
* Because 950 only defined 13500 chars,
* and unicode defined almost 18000 chars.
* So there are almost 4000 chars can not be mapped to big5 code.
*/
BOOL IsConsoleFullWidth(
IN HDC hDC,
IN DWORD CodePage,
IN WCHAR wch
)
{
INT Width;
TEXTMETRIC tmi;
if (! IsAvailableFarEastCodePage(CodePage))
return FALSE;
if (0x20 <= wch && wch <= 0x7e)
/* ASCII */
return FALSE;
else if (0x3041 <= wch && wch <= 0x3094)
/* Hiragana */
return TRUE;
else if (0x30a1 <= wch && wch <= 0x30f6)
/* Katakana */
return TRUE;
else if (0x3105 <= wch && wch <= 0x312c)
/* Bopomofo */
return TRUE;
else if (0x3131 <= wch && wch <= 0x318e)
/* Hangul Elements */
return TRUE;
else if (0xac00 <= wch && wch <= 0xd7a3)
/* Korean Hangul Syllables */
return TRUE;
else if (0xff01 <= wch && wch <= 0xff5e)
/* Fullwidth ASCII variants */
return TRUE;
else if (0xff61 <= wch && wch <= 0xff9f)
/* Halfwidth Katakana variants */
return FALSE;
else if ( (0xffa0 <= wch && wch <= 0xffbe) ||
(0xffc2 <= wch && wch <= 0xffc7) ||
(0xffca <= wch && wch <= 0xffcf) ||
(0xffd2 <= wch && wch <= 0xffd7) ||
(0xffda <= wch && wch <= 0xffdc) )
/* Halfwidth Hangule variants */
return FALSE;
else if (0xffe0 <= wch && wch <= 0xffe6)
/* Fullwidth symbol variants */
return TRUE;
else if (0x4e00 <= wch && wch <= 0x9fa5)
/* Han Ideographic */
return TRUE;
else if (0xf900 <= wch && wch <= 0xfa2d)
/* Han Compatibility Ideographs */
return TRUE;
else
{
BOOL ret;
/* Unknown character */
ret = GetTextMetricsW(hDC, &tmi);
if (! ret) {
KdPrint(("CONSRV: IsConsoleFullWidth: GetTextMetricsW failed 0x%x\n",GetLastError()));
return FALSE;
}
if (IS_ANY_DBCS_CHARSET(tmi.tmCharSet))
tmi.tmMaxCharWidth /= 2;
ret = GetCharWidth32(hDC, wch, wch, &Width);
if (! ret) {
KdPrint(("CONSRV: IsConsoleFullWidth: GetCharWidth32 failed 0x%x\n",GetLastError()));
return FALSE;
}
if (Width == tmi.tmMaxCharWidth)
return FALSE;
else if (Width == tmi.tmMaxCharWidth*2)
return TRUE;
}
ASSERT(FALSE);
return FALSE;
}
/*++
Routine Description:
This routine remove DBCS padding code.
Arguments:
Dst - Pointer to destination.
Src - Pointer to source.
NumBytes - Number of string.
OS2OemFormat -
Return Value:
--*/
DWORD
RemoveDbcsMark(
IN PWCHAR Dst,
IN PWCHAR Src,
IN DWORD NumBytes,
IN PCHAR SrcA,
IN BOOL OS2OemFormat
)
{
PWCHAR Tmp = Dst;
if (NumBytes == 0 || NumBytes >= 0xffffffff)
return( 0 );
#if defined(i386)
if (OS2OemFormat) {
RealUnicodeToNEC_OS2_Unicode(Src, NumBytes);
}
#endif
if (SrcA) {
while (NumBytes--)
{
if (!(*SrcA++ & ATTR_TRAILING_BYTE))
*Dst++ = *Src;
Src++;
}
return (ULONG)(Dst - Tmp);
}
else {
RtlCopyMemory(Dst,Src,NumBytes * sizeof(WCHAR)) ;
return(NumBytes) ;
}
#if !defined(i386)
UNREFERENCED_PARAMETER(OS2OemFormat);
#endif
}
/*++
Routine Description:
This routine remove DBCS padding code for cell format.
Arguments:
Dst - Pointer to destination.
Src - Pointer to source.
NumBytes - Number of string.
Return Value:
--*/
DWORD
RemoveDbcsMarkCell(
IN PCHAR_INFO Dst,
IN PCHAR_INFO Src,
IN DWORD NumBytes
)
{
PCHAR_INFO Tmp = Dst;
DWORD TmpByte;
TmpByte = NumBytes;
while (NumBytes--) {
if (!(Src->Attributes & COMMON_LVB_TRAILING_BYTE)){
*Dst = *Src;
Dst->Attributes &= ~COMMON_LVB_SBCSDBCS;
Dst++;
}
Src++;
}
NumBytes = (ULONG)(TmpByte - (Dst - Tmp));
RtlZeroMemory(Dst, NumBytes * sizeof(CHAR_INFO));
Dst += NumBytes;
return (ULONG)(Dst - Tmp);
}
DWORD
RemoveDbcsMarkAll(
IN PSCREEN_INFORMATION ScreenInfo,
IN PROW Row,
IN PSHORT LeftChar,
IN PRECT TextRect,
IN int *TextLeft,
IN PWCHAR Buffer,
IN SHORT NumberOfChars
)
{
BOOL OS2OemFormat = FALSE;
#if defined(i386)
if ((ScreenInfo->Console->Flags & CONSOLE_OS2_REGISTERED) &&
(ScreenInfo->Console->Flags & CONSOLE_OS2_OEM_FORMAT) &&
(ScreenInfo->Console->OutputCP == OEMCP)) {
OS2OemFormat = TRUE;
}
#endif // i386
if (NumberOfChars <= 0)
return NumberOfChars;
if ( !CONSOLE_IS_DBCS_OUTPUTCP(ScreenInfo->Console))
{
return RemoveDbcsMark(Buffer,
&Row->CharRow.Chars[*LeftChar],
NumberOfChars,
NULL,
OS2OemFormat
);
}
else if ( *LeftChar > ScreenInfo->Window.Left && Row->CharRow.KAttrs[*LeftChar] & ATTR_TRAILING_BYTE)
{
TextRect->left -= SCR_FONTSIZE(ScreenInfo).X;
--*LeftChar;
if (TextLeft)
*TextLeft = TextRect->left;
return RemoveDbcsMark(Buffer,
&Row->CharRow.Chars[*LeftChar],
NumberOfChars+1,
&Row->CharRow.KAttrs[*LeftChar],
OS2OemFormat
);
}
else if (*LeftChar == ScreenInfo->Window.Left && Row->CharRow.KAttrs[*LeftChar] & ATTR_TRAILING_BYTE)
{
*Buffer = UNICODE_SPACE;
return RemoveDbcsMark(Buffer+1,
&Row->CharRow.Chars[*LeftChar+1],
NumberOfChars-1,
&Row->CharRow.KAttrs[*LeftChar+1],
OS2OemFormat
) + 1;
}
else
{
return RemoveDbcsMark(Buffer,
&Row->CharRow.Chars[*LeftChar],
NumberOfChars,
&Row->CharRow.KAttrs[*LeftChar],
OS2OemFormat
);
}
}
BOOL
IsDBCSLeadByteConsole(
IN BYTE AsciiChar,
IN LPCPINFO lpCPInfo
)
{
int i;
i = 0;
while (lpCPInfo->LeadByte[i]) {
if (lpCPInfo->LeadByte[i] <= AsciiChar && AsciiChar <= lpCPInfo->LeadByte[i+1])
return TRUE;
i += 2;
}
return FALSE;
}
NTSTATUS
AdjustFont(
IN PCONSOLE_INFORMATION Console,
IN UINT CodePage
)
{
PSCREEN_INFORMATION ScreenInfo = Console->CurrentScreenBuffer;
ULONG FontIndex;
static const COORD NullCoord = {0, 0};
TEXT_BUFFER_FONT_INFO TextFontInfo;
NTSTATUS Status;
Status = FindTextBufferFontInfo(ScreenInfo,
CodePage,
&TextFontInfo);
if (NT_SUCCESS(Status)) {
FontIndex = FindCreateFont(TextFontInfo.Family,
TextFontInfo.FaceName,
TextFontInfo.FontSize,
TextFontInfo.Weight,
CodePage);
}
else {
FontIndex = FindCreateFont(0,
SCR_FACENAME(ScreenInfo),
NullCoord, // sets new font by FontSize=0
0,
CodePage);
}
#ifdef i386
if (! (Console->FullScreenFlags & CONSOLE_FULLSCREEN)) {
SetScreenBufferFont(Console->CurrentScreenBuffer,FontIndex, CodePage);
}
else {
BOOL fChange = FALSE;
if ((Console->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE) &&
(GetForegroundWindow() == Console->hWnd) )
{
ChangeDispSettings(Console, Console->hWnd, 0);
fChange = TRUE;
}
SetScreenBufferFont(Console->CurrentScreenBuffer,FontIndex, CodePage);
ConvertToFullScreen(Console);
if (fChange &&
(GetForegroundWindow() == Console->hWnd))
ChangeDispSettings(Console, Console->hWnd, CDS_FULLSCREEN);
}
#else
SetScreenBufferFont(Console->CurrentScreenBuffer,FontIndex, CodePage);
#endif
return STATUS_SUCCESS;
}
NTSTATUS
ConvertToCodePage(
IN PCONSOLE_INFORMATION Console,
IN UINT PrevCodePage
)
{
PSCREEN_INFORMATION Cur;
if (Console->OutputCP != OEMCP && PrevCodePage == OEMCP)
{
for (Cur=Console->ScreenBuffers;Cur!=NULL;Cur=Cur->Next) {
if (Cur->Flags & CONSOLE_GRAPHICS_BUFFER) {
continue;
}
ConvertOutputOemToNonOemUnicode(
Cur->BufferInfo.TextInfo.TextRows,
Cur->BufferInfo.TextInfo.DbcsScreenBuffer.KAttrRows,
Cur->ScreenBufferSize.X * Cur->ScreenBufferSize.Y,
Console->OutputCP);
if ((Cur->Flags & CONSOLE_OEMFONT_DISPLAY) &&
((Console->FullScreenFlags & CONSOLE_FULLSCREEN) == 0)) {
RealUnicodeToFalseUnicode(
Cur->BufferInfo.TextInfo.TextRows,
Cur->ScreenBufferSize.X * Cur->ScreenBufferSize.Y,
Console->OutputCP);
}
}
if (Console->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) {
PCONVERSIONAREA_INFORMATION ConvAreaInfo;
ConvAreaInfo = Console->ConsoleIme.ConvAreaRoot;
while (ConvAreaInfo) {
Cur = ConvAreaInfo->ScreenBuffer;
if (!(Cur->Flags & CONSOLE_GRAPHICS_BUFFER)) {
ConvertOutputOemToNonOemUnicode(
Cur->BufferInfo.TextInfo.TextRows,
Cur->BufferInfo.TextInfo.DbcsScreenBuffer.KAttrRows,
Cur->ScreenBufferSize.X * Cur->ScreenBufferSize.Y,
Console->OutputCP);
if ((Cur->Flags & CONSOLE_OEMFONT_DISPLAY) &&
((Console->FullScreenFlags & CONSOLE_FULLSCREEN) == 0)) {
RealUnicodeToFalseUnicode(
Cur->BufferInfo.TextInfo.TextRows,
Cur->ScreenBufferSize.X * Cur->ScreenBufferSize.Y,
Console->OutputCP);
}
}
ConvAreaInfo = ConvAreaInfo->ConvAreaNext;
}
Console->CurrentScreenBuffer->BufferInfo.TextInfo.Flags &= ~TEXT_VALID_HINT;
}
#ifdef FE_SB
else
{
// Check code for must CONSOLE_TEXTMODE_BUFFER !!
ASSERT(FALSE);
}
#endif
SetWindowSize(Console->CurrentScreenBuffer);
WriteToScreen(Console->CurrentScreenBuffer,&Console->CurrentScreenBuffer->Window);
}
return STATUS_SUCCESS;
}
NTSTATUS
ConvertOutputOemToNonOemUnicode(
IN OUT LPWSTR Source,
IN OUT PBYTE KAttrRows,
IN int SourceLength, // in chars
IN UINT Codepage
)
{
NTSTATUS Status;
LPSTR pTemp;
LPWSTR pwTemp;
ULONG TempLength;
ULONG Length;
BOOL NormalChars;
int i;
if (SourceLength == 0 )
return STATUS_SUCCESS;
NormalChars = TRUE;
for (i=0;i<SourceLength;i++) {
if (Source[i] > 0x7f) {
NormalChars = FALSE;
break;
}
}
if (NormalChars) {
return STATUS_SUCCESS;
}
pTemp = (LPSTR)ConsoleHeapAlloc(MAKE_TAG( TMP_TAG ),SourceLength);
if (pTemp == NULL) {
return STATUS_NO_MEMORY;
}
pwTemp = (LPWSTR)ConsoleHeapAlloc(MAKE_TAG( TMP_TAG ),SourceLength * sizeof(WCHAR));
if (pwTemp == NULL) {
ConsoleHeapFree(pTemp);
return STATUS_NO_MEMORY;
}
TempLength = RemoveDbcsMark(pwTemp,
Source,
SourceLength,
KAttrRows,
FALSE);
Status = RtlUnicodeToOemN(pTemp,
(ULONG)ConsoleHeapSize(pTemp),
&Length,
pwTemp,
TempLength * sizeof(WCHAR)
);
if (!NT_SUCCESS(Status)) {
ConsoleHeapFree(pTemp);
ConsoleHeapFree(pwTemp);
return Status;
}
MultiByteToWideChar(Codepage,
0,
pTemp,
Length,
Source,
SourceLength
);
ConsoleHeapFree(pTemp);
ConsoleHeapFree(pwTemp);
if (!NT_SUCCESS(Status)) {
return Status;
} else {
if (KAttrRows) {
RtlZeroMemory(KAttrRows, SourceLength);
}
return STATUS_SUCCESS;
}
}
VOID
TextOutEverything(
IN PCONSOLE_INFORMATION Console,
IN PSCREEN_INFORMATION ScreenInfo,
IN SHORT LeftWindowPos,
IN OUT PSHORT RightWindowPos,
IN OUT PSHORT CountOfAttr,
IN SHORT CountOfAttrOriginal,
IN OUT PBOOL DoubleColorDBCS,
IN BOOL LocalEUDCFlag,
IN PROW Row,
IN PATTR_PAIR Attr,
IN SHORT LeftTextPos,
IN SHORT RightTextPos,
IN int WindowRectLeft,
IN RECT WindowRect,
IN SHORT NumberOfChars
)
/*++
Routine Description:
This routine text out everything.
Arguments:
Return Value:
--*/
{
int j = LeftWindowPos;
int TextLeft = WindowRectLeft;
RECT TextRect = WindowRect;
SHORT LeftChar = LeftTextPos;
SHORT RightChar = RightTextPos;
BOOL DoubleColorDBCSBefore;
BOOL LocalEUDCFlagBefore;
PEUDC_INFORMATION EudcInfo;
int RightPos = j + *CountOfAttr - 1;
int RightText = LeftChar + *CountOfAttr - 1;
BOOL OS2OemFormat = FALSE;
#ifdef FE_SB
// Check code for must CONSOLE_TEXTMODE_BUFFER !!
ASSERT(!(ScreenInfo->Flags & CONSOLE_GRAPHICS_BUFFER));
#endif
#if defined(i386)
if ((ScreenInfo->Console->Flags & CONSOLE_OS2_REGISTERED) &&
(ScreenInfo->Console->Flags & CONSOLE_OS2_OEM_FORMAT) &&
(ScreenInfo->Console->OutputCP == OEMCP)) {
OS2OemFormat = TRUE;
}
#endif // i386
#if defined(DBG) && defined(DBG_KATTR)
BeginKAttrCheck(ScreenInfo);
#endif
RightText = min(RightText,(ScreenInfo->ScreenBufferSize.X-1));
LocalEUDCFlagBefore = LocalEUDCFlag ;
EudcInfo = (PEUDC_INFORMATION)Console->EudcInformation;
DoubleColorDBCSBefore = *DoubleColorDBCS ;
if (DoubleColorDBCSBefore){
RECT TmpRect;
if (Console->FonthDC == NULL) {
Console->FonthDC = CreateCompatibleDC(Console->hDC);
Console->hBitmap = CreateBitmap(DEFAULT_FONTSIZE, DEFAULT_FONTSIZE, BITMAP_PLANES, BITMAP_BITS_PIXEL, NULL);
SelectObject(Console->FonthDC, Console->hBitmap);
}
if (LocalEUDCFlagBefore){
if (EudcInfo->hDCLocalEudc == NULL) {
EudcInfo->hDCLocalEudc = CreateCompatibleDC(Console->hDC);
EudcInfo->hBmpLocalEudc = CreateBitmap(EudcInfo->LocalEudcSize.X,
EudcInfo->LocalEudcSize.Y,
BITMAP_PLANES, BITMAP_BITS_PIXEL, NULL);
SelectObject(EudcInfo->hDCLocalEudc, EudcInfo->hBmpLocalEudc);
}
GetFitLocalEUDCFont(Console,
Row->CharRow.Chars[LeftChar-1]);
BitBlt(Console->hDC,
TextRect.left,
TextRect.top,
SCR_FONTSIZE(ScreenInfo).X,
SCR_FONTSIZE(ScreenInfo).Y,
EudcInfo->hDCLocalEudc,
SCR_FONTSIZE(ScreenInfo).X,
0,
SRCCOPY
);
TextRect.left += SCR_FONTSIZE(ScreenInfo).X;
TextLeft += SCR_FONTSIZE(ScreenInfo).X;
TextRect.right += SCR_FONTSIZE(ScreenInfo).X;
(*CountOfAttr)++;
NumberOfChars = 0;
}
else{
TmpRect.left = 0;
TmpRect.top = 0;
TmpRect.right = SCR_FONTSIZE(ScreenInfo).X;
TmpRect.bottom = SCR_FONTSIZE(ScreenInfo).Y;
SelectObject(Console->FonthDC,
FontInfo[SCR_FONTNUMBER(ScreenInfo)].hFont
);
ExtTextOutW(Console->FonthDC,
0,
0,
ETO_OPAQUE,
&TmpRect,
&Row->CharRow.Chars[LeftChar-1],
1,
NULL
);
BitBlt(Console->hDC,
TextRect.left,
TextRect.top,
SCR_FONTSIZE(ScreenInfo).X,
SCR_FONTSIZE(ScreenInfo).Y,
Console->FonthDC,
SCR_FONTSIZE(ScreenInfo).X,
0,
SRCCOPY
);
TextRect.left += SCR_FONTSIZE(ScreenInfo).X;
TextLeft += SCR_FONTSIZE(ScreenInfo).X;
NumberOfChars = (SHORT)RemoveDbcsMark(ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferCharacter,
&Row->CharRow.Chars[LeftChar+1],
NumberOfChars-1,
&Row->CharRow.KAttrs[LeftChar+1],
OS2OemFormat);
}
}
else {
NumberOfChars = (SHORT)RemoveDbcsMarkAll(ScreenInfo,
Row,
&LeftChar,
&TextRect,
&TextLeft,
ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferCharacter,
NumberOfChars);
}
*DoubleColorDBCS = FALSE ;
if ((NumberOfChars != 0) && (Row->CharRow.KAttrs[RightText] & ATTR_LEADING_BYTE)){
if (RightPos >= ScreenInfo->Window.Right)
*(ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferCharacter+NumberOfChars-1) = UNICODE_SPACE;
else if(TextRect.right <= ScreenInfo->Window.Right * SCR_FONTSIZE(ScreenInfo).X) {
*DoubleColorDBCS = TRUE;
TextRect.right += SCR_FONTSIZE(ScreenInfo).X;
if((j == *RightWindowPos)&&
(*RightWindowPos < ScreenInfo->Window.Right))
*RightWindowPos++;
}
}
if( TextRect.left < TextRect.right){
ExtTextOutW(Console->hDC,
TextLeft,
TextRect.top,
ETO_OPAQUE,
&TextRect,
ScreenInfo->BufferInfo.TextInfo.DbcsScreenBuffer.TransBufferCharacter,
NumberOfChars,
NULL
);
}
if (LocalEUDCFlagBefore){
DWORD dwFullWidth = (IsConsoleFullWidth(Console->hDC,
Console->OutputCP,
Row->CharRow.Chars[RightText+1]) ? 2 : 1);
if (EudcInfo->hDCLocalEudc == NULL) {
EudcInfo->hDCLocalEudc = CreateCompatibleDC(Console->hDC);
EudcInfo->hBmpLocalEudc = CreateBitmap(EudcInfo->LocalEudcSize.X,
EudcInfo->LocalEudcSize.Y,
BITMAP_PLANES, BITMAP_BITS_PIXEL, NULL);
SelectObject(EudcInfo->hDCLocalEudc, EudcInfo->hBmpLocalEudc);
}
GetFitLocalEUDCFont(Console,
Row->CharRow.Chars[RightText+1]);
BitBlt(Console->hDC, // hdcDest
TextRect.right, // nXDest
TextRect.top, // nYDest
SCR_FONTSIZE(ScreenInfo).X * dwFullWidth, // nWidth
SCR_FONTSIZE(ScreenInfo).Y, // nHeight
EudcInfo->hDCLocalEudc, // hdcSrc
0, // nXSrc
0, // nYSrc
SRCCOPY
);
TextRect.right += (SCR_FONTSIZE(ScreenInfo).X * dwFullWidth);
(*CountOfAttr) += (SHORT)dwFullWidth;
if (CountOfAttrOriginal < *CountOfAttr ){
*DoubleColorDBCS = TRUE ;
(*CountOfAttr)--;
TextRect.right -= SCR_FONTSIZE(ScreenInfo).X;
}
}
if (DoubleColorDBCSBefore){
TextRect.left -= SCR_FONTSIZE(ScreenInfo).X;
}
TextOutCommonLVB(Console, Attr->Attr, TextRect);
}
VOID
TextOutCommonLVB(
IN PCONSOLE_INFORMATION Console,
IN WORD Attributes,
IN RECT CommonLVBRect
)
{
HBRUSH hbrSave;
HGDIOBJ hbr;
int GridX;
if (Attributes & (COMMON_LVB_GRID_HORIZONTAL |
COMMON_LVB_GRID_LVERTICAL |
COMMON_LVB_GRID_RVERTICAL |
COMMON_LVB_UNDERSCORE )
)
{
if(Attributes & COMMON_LVB_UNDERSCORE){
if(Attributes & COMMON_LVB_REVERSE_VIDEO)
hbr = CreateSolidBrush(ConvertAttrToRGB(Console, LOBYTE(Attributes >> 4)));
else
hbr = CreateSolidBrush(ConvertAttrToRGB(Console, LOBYTE(Attributes)));
hbrSave = SelectObject(Console->hDC, hbr);
PatBlt(Console->hDC,
CommonLVBRect.left,
CommonLVBRect.bottom-1,
CommonLVBRect.right-CommonLVBRect.left,
1,
PATCOPY
);
SelectObject(Console->hDC, hbrSave);
DeleteObject(hbr);
}
if(Attributes & (COMMON_LVB_GRID_HORIZONTAL | COMMON_LVB_GRID_LVERTICAL | COMMON_LVB_GRID_RVERTICAL)){
hbr = CreateSolidBrush(ConvertAttrToRGB(Console, 0x0007));
hbrSave = SelectObject(Console->hDC, hbr);
if(Attributes & COMMON_LVB_GRID_HORIZONTAL){
PatBlt(Console->hDC,
CommonLVBRect.left,
CommonLVBRect.top,
CommonLVBRect.right-CommonLVBRect.left,
1,
PATCOPY
);
}
if(Attributes & COMMON_LVB_GRID_LVERTICAL){
for ( GridX = CommonLVBRect.left ;
GridX < CommonLVBRect.right ;
GridX += CON_FONTSIZE(Console).X){
PatBlt(Console->hDC,
GridX,
CommonLVBRect.top,
1,
CON_FONTSIZE(Console).Y,
PATCOPY
);
}
}
if(Attributes & COMMON_LVB_GRID_RVERTICAL){
for ( GridX = CommonLVBRect.left + CON_FONTSIZE(Console).X-1 ;
GridX < CommonLVBRect.right ;
GridX += CON_FONTSIZE(Console).X){
PatBlt(Console->hDC,
GridX,
CommonLVBRect.top,
1,
CON_FONTSIZE(Console).Y,
PATCOPY
);
}
}
SelectObject(Console->hDC, hbrSave);
DeleteObject(hbr);
}
}
}
NTSTATUS
MakeAltRasterFont(
UINT CodePage,
COORD DefaultFontSize,
COORD *AltFontSize,
BYTE *AltFontFamily,
ULONG *AltFontIndex,
LPWSTR AltFaceName
)
{
DWORD i;
DWORD Find;
ULONG FontIndex;
COORD FontSize = DefaultFontSize;
COORD FontDelta;
BOOL fDbcsCharSet = IsAvailableFarEastCodePage(CodePage);
FontIndex = 0;
Find = (DWORD)-1;
for (i=0; i < NumberOfFonts; i++)
{
if (!TM_IS_TT_FONT(FontInfo[i].Family) &&
IS_ANY_DBCS_CHARSET(FontInfo[i].tmCharSet) == fDbcsCharSet
)
{
FontDelta.X = abs(FontSize.X - FontInfo[i].Size.X);
FontDelta.Y = abs(FontSize.Y - FontInfo[i].Size.Y);
if (Find > (DWORD)(FontDelta.X + FontDelta.Y))
{
Find = (DWORD)(FontDelta.X + FontDelta.Y);
FontIndex = i;
}
}
}
*AltFontIndex = FontIndex;
wcscpy(AltFaceName, FontInfo[*AltFontIndex].FaceName);
*AltFontSize = FontInfo[*AltFontIndex].Size;
*AltFontFamily = FontInfo[*AltFontIndex].Family;
DBGFONTS(("MakeAltRasterFont : AltFontIndex = %ld\n", *AltFontIndex));
return STATUS_SUCCESS;
}
NTSTATUS
InitializeDbcsMisc(
VOID
)
{
HANDLE hkRegistry = NULL;
NTSTATUS Status;
WCHAR awchValue[ 512 ];
WCHAR awchData[ 512 ];
BYTE Buffer[ 512 ];
DWORD Length;
DWORD dwIndex;
LPWSTR pwsz;
ASSERT(gTTFontList.Next==NULL);
ASSERT(gRegFullScreenCodePage.Next==NULL);
gTTFontList.Next = NULL;
gRegFullScreenCodePage.Next = NULL;
/*
* Get TrueType Font Face name from registry.
*/
Status = MyRegOpenKey(NULL, MACHINE_REGISTRY_CONSOLE_TTFONT, &hkRegistry);
if (!NT_SUCCESS( Status )) {
DBGPRINT(("CONSRV: NtOpenKey failed %ws\n", MACHINE_REGISTRY_CONSOLE_TTFONT));
}
else {
LPTTFONTLIST pTTFontList;
for( dwIndex = 0; ; dwIndex++) {
Status = MyRegEnumValue(hkRegistry, dwIndex, sizeof(awchValue), (LPWSTR)&awchValue, sizeof(awchData), (PBYTE)&awchData);
if (!NT_SUCCESS( Status )) {
break;
}
pTTFontList = ConsoleHeapAlloc(MAKE_TAG( SCREEN_DBCS_TAG ), sizeof(TTFONTLIST));
if (pTTFontList == NULL) {
break;
}
pTTFontList->List.Next = NULL;
pTTFontList->CodePage = ConvertStringToDec(awchValue, NULL);
pwsz = awchData;
if (*pwsz == BOLD_MARK) {
pTTFontList->fDisableBold = TRUE;
pwsz++;
}
else
pTTFontList->fDisableBold = FALSE;
wcscpy(pTTFontList->FaceName1, pwsz);
pwsz += wcslen(pwsz) + 1;
if (*pwsz == BOLD_MARK) {
pTTFontList->fDisableBold = TRUE;
pwsz++;
}
wcscpy(pTTFontList->FaceName2, pwsz);
PushEntryList(&gTTFontList, &(pTTFontList->List));
}
NtClose(hkRegistry);
}
/*
* Get Full Screen from registry.
*/
Status = MyRegOpenKey(NULL,
MACHINE_REGISTRY_CONSOLE_FULLSCREEN,
&hkRegistry);
if (!NT_SUCCESS( Status )) {
DBGPRINT(("CONSRV: NtOpenKey failed %ws\n", MACHINE_REGISTRY_CONSOLE_FULLSCREEN));
}
else {
/*
* InitialPalette
*/
Status = MyRegQueryValueEx(hkRegistry, MACHINE_REGISTRY_INITIAL_PALETTE, sizeof( Buffer ), Buffer, &Length);
if (NT_SUCCESS( Status ) && Length > sizeof(DWORD)) {
DWORD PaletteLength = ((LPDWORD)Buffer)[0];
PUSHORT Palette;
if (PaletteLength * sizeof(USHORT) >= (Length - sizeof(DWORD)))
{
Palette = ConsoleHeapAlloc(MAKE_TAG( BUFFER_TAG ), Length);
if (Palette != NULL)
{
RtlCopyMemory(Palette, Buffer, Length);
RegInitialPalette = Palette;
}
}
}
/*
* ColorBuffer
*/
Status = MyRegQueryValueEx(hkRegistry, MACHINE_REGISTRY_COLOR_BUFFER, sizeof( Buffer ), Buffer, &Length);
if (NT_SUCCESS( Status ) && Length > sizeof(DWORD)) {
DWORD ColorBufferLength = ((LPDWORD)Buffer)[0];
PUCHAR Color;
if (ColorBufferLength * sizeof(DWORD) >= (Length - sizeof(DWORD)))
{
Color = ConsoleHeapAlloc(MAKE_TAG( BUFFER_TAG ), Length);
if (Color != NULL)
{
RtlCopyMemory(Color, Buffer, Length);
RegColorBuffer = Color;
}
}
}
/*
* ColorBufferNoTranslate
*/
Status = MyRegQueryValueEx(hkRegistry, MACHINE_REGISTRY_COLOR_BUFFER_NO_TRANSLATE, sizeof( Buffer ), Buffer, &Length);
if (NT_SUCCESS( Status ) && Length > sizeof(DWORD)) {
DWORD ColorBufferLength = ((LPDWORD)Buffer)[0];
PUCHAR Color;
if (ColorBufferLength * sizeof(DWORD) >= (Length - sizeof(DWORD)))
{
Color = ConsoleHeapAlloc(MAKE_TAG( BUFFER_TAG ), Length);
if (Color != NULL)
{
RtlCopyMemory(Color, Buffer, Length);
RegColorBufferNoTranslate = Color;
}
}
}
/*
* ModeFontPairs
*/
Status = MyRegQueryValueEx(hkRegistry, MACHINE_REGISTRY_MODE_FONT_PAIRS, sizeof( Buffer ), Buffer, &Length);
if (NT_SUCCESS( Status ) && Length > sizeof(DWORD)) {
DWORD NumOfEntries = ((LPDWORD)Buffer)[0];
PMODE_FONT_PAIR ModeFont;
if (NumOfEntries * sizeof(MODE_FONT_PAIR) >= (Length - sizeof(DWORD)))
{
ModeFont = ConsoleHeapAlloc(MAKE_TAG( BUFFER_TAG ), Length);
if (ModeFont != NULL)
{
Length -= sizeof(DWORD);
RtlCopyMemory(ModeFont, &Buffer[sizeof(DWORD)], Length);
RegModeFontPairs = ModeFont;
NUMBER_OF_MODE_FONT_PAIRS = NumOfEntries;
}
}
}
/*
* FullScreen\CodePage
*/
{
HANDLE hkRegCP = NULL;
Status = MyRegOpenKey(hkRegistry, MACHINE_REGISTRY_FS_CODEPAGE, &hkRegCP);
if (!NT_SUCCESS( Status )) {
DBGPRINT(("CONSRV: NtOpenKey failed %ws\n", MACHINE_REGISTRY_FS_CODEPAGE));
}
else {
PFS_CODEPAGE pFsCodePage;
for( dwIndex = 0; ; dwIndex++) {
Status = MyRegEnumValue(hkRegCP, dwIndex, sizeof(awchValue), (LPWSTR)&awchValue, sizeof(awchData), (PBYTE)&awchData);
if (!NT_SUCCESS( Status )) {
break;
}
pFsCodePage = ConsoleHeapAlloc(MAKE_TAG( BUFFER_TAG ), sizeof(FS_CODEPAGE));
if (pFsCodePage == NULL) {
break;
}
pFsCodePage->List.Next = NULL;
pFsCodePage->CodePage = ConvertStringToDec(awchValue, NULL);
PushEntryList(&gRegFullScreenCodePage, &(pFsCodePage->List));
}
NtClose(hkRegCP);
}
}
NtClose(hkRegistry);
}
#if defined(i386)
Status = NtGetMachineIdentifierValue(&gdwMachineId);
if (!NT_SUCCESS(Status)) {
gdwMachineId = MACHINEID_MS_PCAT;
}
#endif
Status = RtlInitializeCriticalSectionAndSpinCount(&ConIMEInitWindowsLock,
0x80000000);
return Status;
}
#if defined(i386)
NTSTATUS
RealUnicodeToNEC_OS2_Unicode(
IN OUT LPWSTR Source,
IN int SourceLength // in chars
)
/*
this routine converts a unicode string from the real unicode characters
to the NEC OS/2 unicode characters.
*/
{
NTSTATUS Status;
LPSTR Temp;
ULONG TempLength;
ULONG Length;
CHAR StackBuffer[STACK_BUFFER_SIZE];
BOOL NormalChars;
int i;
DBGCHARS(("RealUnicodeToNEC_OS2_Unicode U->ACP:???->U %.*ls\n",
SourceLength > 10 ? 10 : SourceLength, Source));
NormalChars = TRUE;
if (pGlyph_NEC_OS2_CP == NULL || pGlyph_NEC_OS2_CP->MultiByteTable == NULL) {
DBGCHARS(("RealUnicodeToNEC_OS2_Unicode xfer buffer null\n"));
return STATUS_SUCCESS; // there's nothing we can do
}
/*
* Test for characters < 0x20. If none are found, we don't have
* any conversion to do!
*/
for (i=0;i<SourceLength;i++) {
if ((USHORT)(Source[i]) < 0x20) {
NormalChars = FALSE;
break;
}
}
if (NormalChars) {
return STATUS_SUCCESS;
}
TempLength = SourceLength;
if (TempLength > STACK_BUFFER_SIZE) {
Temp = (LPSTR)ConsoleHeapAlloc(MAKE_TAG( TMP_TAG ),TempLength);
if (Temp == NULL) {
return STATUS_NO_MEMORY;
}
} else {
Temp = StackBuffer;
}
Status = RtlUnicodeToMultiByteN(Temp,
TempLength,
&Length,
Source,
SourceLength * sizeof(WCHAR)
);
if (!NT_SUCCESS(Status)) {
if (TempLength > STACK_BUFFER_SIZE) {
ConsoleHeapFree(Temp);
}
return Status;
}
ASSERT(pGlyph_NEC_OS2_CP != NULL && pGlyph_NEC_OS2_CP->MultiByteTable != NULL);
Status = RtlCustomCPToUnicodeN(pGlyph_NEC_OS2_CP,
Source,
SourceLength * sizeof(WCHAR),
&Length,
Temp,
TempLength
);
if (TempLength > STACK_BUFFER_SIZE) {
ConsoleHeapFree(Temp);
}
if (!NT_SUCCESS(Status)) {
return Status;
} else {
return STATUS_SUCCESS;
}
}
BOOL
InitializeNEC_OS2_CP(
VOID
)
{
PPEB pPeb;
pPeb = NtCurrentPeb();
if ((pPeb == NULL) || (pPeb->OemCodePageData == NULL)) {
return FALSE;
}
/*
* Fill in the CPTABLEINFO struct
*/
if (pGlyph_NEC_OS2_CP == NULL) {
pGlyph_NEC_OS2_CP = (PCPTABLEINFO)ConsoleHeapAlloc( MAKE_TAG(SCREEN_DBCS_TAG), sizeof(CPTABLEINFO));
if (pGlyph_NEC_OS2_CP == NULL) {
return FALSE;
}
}
RtlInitCodePageTable(pPeb->OemCodePageData, pGlyph_NEC_OS2_CP);
/*
* Make a copy of the MultiByteToWideChar table
*/
if (pGlyph_NEC_OS2_Table == NULL) {
pGlyph_NEC_OS2_Table = (PUSHORT)ConsoleHeapAlloc( MAKE_TAG(SCREEN_DBCS_TAG), 256 * sizeof(USHORT));
if (pGlyph_NEC_OS2_Table == NULL) {
return FALSE;
}
}
RtlCopyMemory(pGlyph_NEC_OS2_Table, pGlyph_NEC_OS2_CP->MultiByteTable, 256 * sizeof(USHORT));
/*
* Modify the first 0x20 bytes so that they are glyphs.
*/
MultiByteToWideChar(CP_OEMCP, MB_USEGLYPHCHARS,
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20"
"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x1E\x1F\x1C\x07",
0x20, pGlyph_NEC_OS2_Table, 0x20);
/*
* Point the Custom CP at the glyph table
*/
pGlyph_NEC_OS2_CP->MultiByteTable = pGlyph_NEC_OS2_Table;
return TRUE;
}
#endif // i386
BYTE
CodePageToCharSet(
UINT CodePage
)
{
CHARSETINFO csi;
if (!TranslateCharsetInfo((DWORD *)CodePage, &csi, TCI_SRCCODEPAGE))
csi.ciCharset = OEM_CHARSET;
return (BYTE)csi.ciCharset;
}
BOOL
IsAvailableFarEastCodePage(
UINT CodePage
)
{
BYTE CharSet = CodePageToCharSet(CodePage);
return IS_ANY_DBCS_CHARSET(CharSet);
}
LPTTFONTLIST
SearchTTFont(
LPWSTR pwszFace,
BOOL fCodePage,
UINT CodePage
)
{
PSINGLE_LIST_ENTRY pTemp = gTTFontList.Next;
if (pwszFace) {
while (pTemp != NULL) {
LPTTFONTLIST pTTFontList = (LPTTFONTLIST)pTemp;
if (wcscmp(pwszFace, pTTFontList->FaceName1) == 0 ||
wcscmp(pwszFace, pTTFontList->FaceName2) == 0 ) {
if (fCodePage)
if (pTTFontList->CodePage == CodePage )
return pTTFontList;
else
return NULL;
else
return pTTFontList;
}
pTemp = pTemp->Next;
}
}
return NULL;
}
BOOL
IsAvailableTTFont(
LPWSTR pwszFace
)
{
if (SearchTTFont(pwszFace, FALSE, 0))
return TRUE;
else
return FALSE;
}
BOOL
IsAvailableTTFontCP(
LPWSTR pwszFace,
UINT CodePage
)
{
if (SearchTTFont(pwszFace, TRUE, CodePage))
return TRUE;
else
return FALSE;
}
LPWSTR
GetAltFaceName(
LPWSTR pwszFace
)
{
LPTTFONTLIST pTTFontList;
pTTFontList = SearchTTFont(pwszFace, FALSE, 0);
if (pTTFontList != NULL) {
if (wcscmp(pwszFace, pTTFontList->FaceName1) == 0) {
return pTTFontList->FaceName2;
}
if (wcscmp(pwszFace, pTTFontList->FaceName2) == 0) {
return pTTFontList->FaceName1;
}
return NULL;
}
else
return NULL;
}
BOOL
IsAvailableFsCodePage(
UINT CodePage
)
{
PSINGLE_LIST_ENTRY pTemp = gRegFullScreenCodePage.Next;
while (pTemp != NULL) {
PFS_CODEPAGE pFsCodePage = (PFS_CODEPAGE)pTemp;
if (pFsCodePage->CodePage == CodePage) {
return TRUE;
}
pTemp = pTemp->Next;
}
return FALSE;
}
#if defined(FE_IME)
/*
* Console IME executing logic.
* KERNEL32:ConDllInitialize
* If Reason is DLL_PROCESS_ATTACH
* |
* V
* WINSRV:ConsoleClientConnectRoutine
* |
* V
* SetUpConsole
* |
* V
* AllocateConsole
* PostThreadMessage(CM_CREATE_CONSOLE_WINDOW)
* |
* V
* UnlockConsoleHandleTable
* InitConsoleIMEStuff
* |
* V
* If never register console IME
* hThread = InternalCreateCallbackThread(ConsoleIMERoutine)
* QueueThreadMessage(CM_WAIT_CONIME_PROCESS)
* |
* V
* QueueThreadMessage(CM_CONIME_CREATE)
* |
* V
* KERNEL32:NtWaitForMultipleObjects(InitEvents)
* WINSRV:InputThread
* |
* V
* GetMessage
* Receive CM_CREATE_CONSOLE_WINDOW
* |
* V
* ProcessCreateConsoleWindow
* |
* V
* CreateWindowsWindow
* |
* V
* CreateWindowEx
* NtSetEvent(InitEvents)
* |
* V
* GetMessage
* Receive CM_WAIT_CONIME_PROCESS (this case is never register console IME)
* |
* V
* WaitConsoleIMEStuff
* If never register console IME
* NtWaitForSingleObject(hThread, 20 sec)
* KERNEL32:ConsoleIMERoutine
* |
* V
* hEvent = CreateEvent(CONSOLEIME_EVENT)
* If not exist named event
* CreateProcess(conime.exe)
* WaitForSingleObject(hEvent, 10 sec)
* If WAIT_TIMEOUT
* TerminateProcess
* |
* V
* TerminateThread(hThread)
* CONIME:WinMain
* |
* V
* CreateWindow
* RegisterConsoleIME
* |
* V
* WINSRV:ConSrvRegisterConsoleIME
* |
* V
* QueueThreadMessage(CM_SET_CONSOLEIME_WINDOW)
* |
* V
* AttachThreadInput
* SetEvent(CONSOLEIME_EVENT)
* WINSRV:InputThread
* |
* V
* GetMessage
* Receive CM_CONIME_CREATE
* |
* V
* ProcessCreateConsoleIME
* If available hWndConsoleIME
* hIMC = SendMessage(console IME, CONIME_CREATE)
* Else
* PostMessage(CM_CONIME_CREATE)
* |
* V
* GetMessage
* Receive CM_SET_CONSOLEIME_WINDOW
* TlsGetValue()->hWndConsoleIME = wParam
* TerminateProcess of Console IME
* WINSRV:ConsoleClientDisconnectRoutine
* |
* V
* RemoveConsoleIME
*/
VOID
ProcessCreateConsoleIME(
IN LPMSG lpMsg,
DWORD dwConsoleThreadId
)
{
NTSTATUS Status;
HANDLE ConsoleHandle = (HANDLE)lpMsg->wParam;
PCONSOLE_INFORMATION pConsole;
HWND hwndConIme;
Status = RevalidateConsole(ConsoleHandle, &pConsole);
if (!NT_SUCCESS(Status)) {
return; // STATUS_PROCESS_IS_TERMINATING
}
hwndConIme = pConsole->InputThreadInfo->hWndConsoleIME;
if (pConsole->InputThreadInfo->hWndConsoleIME != NULL) {
LRESULT lResult;
if (!NT_SUCCESS(ConsoleImeMessagePumpWorker(pConsole,
CONIME_CREATE,
(WPARAM)pConsole->ConsoleHandle,
(LPARAM)pConsole->hWnd,
&lResult
))) {
goto TerminateConsoleIme;
}
if (lResult)
{
DBGPRINT(("ConsoleIME connected(Create)\n")) ;
if (!CONSOLE_IS_DBCS_CP(pConsole))
pConsole->InputBuffer.ImeMode.Disable = TRUE;
CreateConvAreaModeSystem(pConsole);
if ((pConsole->Flags & CONSOLE_HAS_FOCUS) ||
(pConsole->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE))
{
if (!NT_SUCCESS(ConsoleImeMessagePump(pConsole,
CONIME_SETFOCUS,
(WPARAM)pConsole->ConsoleHandle,
(LPARAM)pConsole->hklActive
))) {
goto TerminateConsoleIme;
}
}
if (pConsole->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER)
{
if (!NT_SUCCESS(ConsoleImeMessagePump(pConsole,
CONIME_NOTIFY_SCREENBUFFERSIZE,
(WPARAM)pConsole->ConsoleHandle,
(LPARAM)MAKELPARAM(pConsole->CurrentScreenBuffer->ScreenBufferSize.X,
pConsole->CurrentScreenBuffer->ScreenBufferSize.Y)
))) {
goto TerminateConsoleIme;
}
}
if (!NT_SUCCESS(ConsoleImeMessagePump(pConsole,
CONIME_NOTIFY_CODEPAGE,
(WPARAM)pConsole->ConsoleHandle,
(LPARAM)MAKELPARAM(FALSE, pConsole->CP)
))) {
goto TerminateConsoleIme;
}
if (!NT_SUCCESS(ConsoleImeMessagePump(pConsole,
CONIME_NOTIFY_CODEPAGE,
(WPARAM)pConsole->ConsoleHandle,
(LPARAM)MAKELPARAM(TRUE, pConsole->OutputCP)
))) {
goto TerminateConsoleIme;
}
if (!NT_SUCCESS(GetImeKeyState(pConsole, NULL))) {
goto TerminateConsoleIme;
}
}
}
else if (lpMsg->lParam) {
/*
* This case, First = TRUE
* Again post message of CM_CONIME_CREATE.
* Becase hWndConsoleIME available when CM_SET_CONSOLEIME_WINDOW message
* and it message will be run after this.
*/
Status = QueueThreadMessage(dwConsoleThreadId,
CM_CONIME_CREATE,
(WPARAM)ConsoleHandle,
(LPARAM)FALSE
);
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING, "QueueThreadMessage(CM_CONIME_CREATE) failed (%08x)\n", Status);
}
}
UnlockConsole(pConsole);
return;
TerminateConsoleIme:
if (IsWindow(hwndConIme)) {
PostMessage(hwndConIme, CONIME_DESTROY, (WPARAM)ConsoleHandle, (LPARAM)NULL);
}
}
NTSTATUS InitConsoleIMEStuff(HDESK hDesktop, DWORD dwConsoleThreadId, PCONSOLE_INFORMATION Console)
{
NTSTATUS Status = STATUS_SUCCESS;
CONSOLE_REGISTER_CONSOLEIME RegConIMEInfo;
HANDLE hThread = NULL;
BOOL First = FALSE;
if (!gfLoadConIme) {
KdPrint(("CONSRV: InitConsoleIMEStuff is skipping conime loading\n"));
return STATUS_UNSUCCESSFUL; // the return value does not really matter...
}
RtlEnterCriticalSection(&ConIMEInitWindowsLock);
RegConIMEInfo.hdesk = hDesktop;
RegConIMEInfo.dwThreadId = 0;
RegConIMEInfo.dwAction = REGCONIME_QUERY;
NtUserConsoleControl(ConsoleRegisterConsoleIME, &RegConIMEInfo, sizeof(RegConIMEInfo));
if (RegConIMEInfo.dwThreadId == 0)
{
/*
* Create a Remote Thread on client side.
* This remote thread do create a console IME process.
*/
hThread = InternalCreateCallbackThread(CONSOLE_CLIENTPROCESSHANDLE(), (ULONG_PTR)ConsoleIMERoutine, (ULONG_PTR)0);
if (hThread == NULL) {
KdPrint(("CONSRV: CreateRemoteThread failed %x\n",GetLastError()));
}
else
{
/*
* CM_WAIT_CONIME_PROCESS
* This message wait for ready to go console IME process.
*/
Status = QueueThreadMessage(dwConsoleThreadId, CM_WAIT_CONIME_PROCESS, (WPARAM)hDesktop, (LPARAM)hThread);
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING, "QueueThreadMessage(CM_WAIT_CONIME_PROCESS) failed (%08x)\n", Status);
} else {
First = TRUE;
}
}
}
Status = QueueThreadMessage(dwConsoleThreadId, CM_CONIME_CREATE, (WPARAM)Console->ConsoleHandle, (LPARAM)First);
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING, "InitConsoleIMEStuff: QueueThreadMessage(CM_CONIME_CREATE) failed (%08x)\n", Status);
}
RtlLeaveCriticalSection(&ConIMEInitWindowsLock);
return Status;
}
NTSTATUS WaitConsoleIMEStuff(HDESK hDesktop, HANDLE hThread)
{
NTSTATUS Status = STATUS_SUCCESS;
CONSOLE_REGISTER_CONSOLEIME RegConIMEInfo;
RtlEnterCriticalSection(&ConIMEInitWindowsLock);
RegConIMEInfo.hdesk = hDesktop;
RegConIMEInfo.dwThreadId = 0;
RegConIMEInfo.dwAction = REGCONIME_QUERY;
NtUserConsoleControl(ConsoleRegisterConsoleIME, &RegConIMEInfo, sizeof(RegConIMEInfo));
RtlLeaveCriticalSection(&ConIMEInitWindowsLock);
if (RegConIMEInfo.dwThreadId == 0)
{
int cLoops;
LARGE_INTEGER li;
/*
* Do wait for ready to go console IME process.
* This wait code should after the CreateWindowsWindow
* because doesn't finish DLL attach on client side
* for wait a Console->InitEvents.
*/
cLoops = 80;
li.QuadPart = (LONGLONG)-10000 * 250;
while (cLoops--)
{
/*
* Sleep for a second.
*/
Status = NtWaitForSingleObject(hThread, FALSE, &li);
if (Status != STATUS_TIMEOUT) {
break;
}
RtlEnterCriticalSection(&ConIMEInitWindowsLock);
RegConIMEInfo.hdesk = hDesktop;
RegConIMEInfo.dwThreadId = 0;
RegConIMEInfo.dwAction = REGCONIME_QUERY;
NtUserConsoleControl(ConsoleRegisterConsoleIME, &RegConIMEInfo, sizeof(RegConIMEInfo));
RtlLeaveCriticalSection(&ConIMEInitWindowsLock);
if (RegConIMEInfo.dwThreadId != 0) {
break;
}
}
}
NtClose(hThread);
return Status;
}
NTSTATUS
ConSrvRegisterConsoleIME(
PCSR_PROCESS Process,
HDESK hDesktop,
HWINSTA hWinSta,
HWND hWndConsoleIME,
DWORD dwConsoleIMEThreadId,
DWORD dwAction,
DWORD *dwConsoleThreadId
)
{
NTSTATUS Status;
CONSOLE_REGISTER_CONSOLEIME RegConIMEInfo;
PCONSOLE_PER_PROCESS_DATA ProcessData;
RtlEnterCriticalSection(&ConIMEInitWindowsLock);
ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process);
RegConIMEInfo.hdesk = hDesktop;
RegConIMEInfo.dwThreadId = 0;
RegConIMEInfo.dwAction = REGCONIME_QUERY;
NtUserConsoleControl(ConsoleRegisterConsoleIME, &RegConIMEInfo, sizeof(RegConIMEInfo));
if (RegConIMEInfo.dwConsoleInputThreadId == 0)
{
Status = STATUS_UNSUCCESSFUL;
goto ErrorExit;
}
if (RegConIMEInfo.dwThreadId == 0)
{
/*
* never registered console ime thread.
*/
if (dwAction == REGCONIME_REGISTER)
{
/*
* register
*/
RegConIMEInfo.hdesk = hDesktop;
RegConIMEInfo.dwThreadId = dwConsoleIMEThreadId;
RegConIMEInfo.dwAction = dwAction;
Status = NtUserConsoleControl(ConsoleRegisterConsoleIME, &RegConIMEInfo, sizeof(RegConIMEInfo));
if (NT_SUCCESS(Status)) {
Status = QueueThreadMessage(RegConIMEInfo.dwConsoleInputThreadId,
CM_SET_CONSOLEIME_WINDOW,
(WPARAM)hWndConsoleIME,
0
);
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING, "ConSrvRegisterConsoleIME: QueueThreadMessage failed (%08x)\n", Status);
Status = STATUS_UNSUCCESSFUL;
goto ErrorExit;
}
ProcessData->hDesk = hDesktop;
ProcessData->hWinSta = hWinSta;
if (dwConsoleThreadId)
*dwConsoleThreadId = RegConIMEInfo.dwConsoleInputThreadId;
}
}
else
{
Status = STATUS_UNSUCCESSFUL;
goto ErrorExit;
}
}
else
{
/*
* do registered console ime thread.
*/
if ( (dwAction == REGCONIME_UNREGISTER) || (dwAction == REGCONIME_TERMINATE) )
{
/*
* unregister
*/
RegConIMEInfo.hdesk = hDesktop;
RegConIMEInfo.dwThreadId = dwConsoleIMEThreadId;
RegConIMEInfo.dwAction = dwAction;
Status = NtUserConsoleControl(ConsoleRegisterConsoleIME, &RegConIMEInfo, sizeof(RegConIMEInfo));
if (NT_SUCCESS(Status)) {
Status = QueueThreadMessage(RegConIMEInfo.dwConsoleInputThreadId, CM_SET_CONSOLEIME_WINDOW, (WPARAM)NULL, 0);
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING, "ConSrvRegisterConsoleIME: QueueThreadMessage failed (%08x)\n", Status);
Status = STATUS_UNSUCCESSFUL;
goto ErrorExit;
}
CloseDesktop(ProcessData->hDesk);
CloseWindowStation(ProcessData->hWinSta);
ProcessData->hDesk = NULL;
ProcessData->hWinSta = NULL;
if (dwConsoleThreadId)
*dwConsoleThreadId = RegConIMEInfo.dwConsoleInputThreadId;
}
}
else
{
Status = STATUS_UNSUCCESSFUL;
goto ErrorExit;
}
}
ErrorExit:
if (! NT_SUCCESS(Status))
{
CloseDesktop(hDesktop);
CloseWindowStation(hWinSta);
}
RtlLeaveCriticalSection(&ConIMEInitWindowsLock);
return Status;
}
VOID RemoveConsoleIME(PCSR_PROCESS Process, DWORD dwConsoleIMEThreadId)
{
NTSTATUS Status;
CONSOLE_REGISTER_CONSOLEIME RegConIMEInfo;
PCONSOLE_PER_PROCESS_DATA ProcessData;
ProcessData = CONSOLE_FROMPROCESSPERPROCESSDATA(Process);
// This is console IME process
RtlEnterCriticalSection(&ConIMEInitWindowsLock);
RegConIMEInfo.hdesk = ProcessData->hDesk;
RegConIMEInfo.dwThreadId = 0;
RegConIMEInfo.dwAction = REGCONIME_QUERY;
NtUserConsoleControl(ConsoleRegisterConsoleIME, &RegConIMEInfo, sizeof(RegConIMEInfo));
if (RegConIMEInfo.dwConsoleInputThreadId == 0)
{
Status = STATUS_UNSUCCESSFUL;
}
else
if (dwConsoleIMEThreadId == RegConIMEInfo.dwThreadId)
{
/*
* Unregister console IME
*/
Status = ConSrvRegisterConsoleIME(Process, ProcessData->hDesk, ProcessData->hWinSta, NULL, dwConsoleIMEThreadId, REGCONIME_TERMINATE, NULL);
}
RtlLeaveCriticalSection(&ConIMEInitWindowsLock);
}
/*
* Console IME message pump.
* Note for NT5 this function is build on bogus assumptions
* (also has some nasty workaround for sloppy conime).
* There's a chance that pConsole goes away while sendmessage
* is processed by conime.
* Keep in mind, anybody who calls this function should validate
* the return status as appropriate.
*/
NTSTATUS
ConsoleImeMessagePumpWorker(
PCONSOLE_INFORMATION Console,
UINT Message,
WPARAM wParam,
LPARAM lParam,
LRESULT* lplResult)
{
HWND hWndConsoleIME = Console->InputThreadInfo->hWndConsoleIME;
LRESULT fNoTimeout;
PINPUT_THREAD_INFO InputThreadInfo; // console thread info
*lplResult = 0;
if (hWndConsoleIME == NULL)
{
return STATUS_SUCCESS;
}
InputThreadInfo = TlsGetValue(InputThreadTlsIndex);
if (InputThreadInfo != NULL)
{
HWND hWnd = Console->hWnd;
/*
* This thread is in InputThread()
* We can try message pump.
*/
fNoTimeout = SendMessageTimeout(hWndConsoleIME,
Message,
wParam,
lParam,
SMTO_ABORTIFHUNG | SMTO_NORMAL,
CONIME_SENDMSG_TIMEOUT,
lplResult);
if (fNoTimeout)
{
return STATUS_SUCCESS;
}
if ((Console = GetWindowConsole(hWnd)) == NULL ||
(Console->Flags & CONSOLE_TERMINATING)) {
// This console is terminated.
// ConsoleImeMessagePump gives up SendMessage to conime.
return STATUS_INVALID_HANDLE;
}
/*
* Timeout return from SendMessageTimeout
* Or, Hung hWndConsoleIME.
*/
}
/*
* This thread is in CsrApiRequestThread()
* We can not try message pump.
*/
DBGPRINT(("ConsoleImeMessagePumpWorker::PostMessage(0x%x)\n",Message));
PostMessage(hWndConsoleIME,
Message,
wParam,
lParam);
return STATUS_SUCCESS;
}
NTSTATUS
ConsoleImeMessagePump(
PCONSOLE_INFORMATION Console,
UINT Message,
WPARAM wParam,
LPARAM lParam
)
{
LRESULT lResultDummy;
return ConsoleImeMessagePumpWorker(Console, Message, wParam, lParam, &lResultDummy);
}
#endif // FE_IME
BOOL RegisterKeisenOfTTFont(IN PSCREEN_INFORMATION ScreenInfo)
{
NTSTATUS Status;
COORD FontSize;
DWORD BuffSize;
LPSTRINGBITMAP StringBitmap;
WCHAR wChar;
WCHAR wCharBuf[2];
ULONG ulNumFonts;
DWORD dwFonts;
PCONSOLE_INFORMATION Console = ScreenInfo->Console;
GetNumFonts(&ulNumFonts);
for (dwFonts=0; dwFonts < ulNumFonts; dwFonts++) {
if (!TM_IS_TT_FONT(FontInfo[dwFonts].Family) &&
IS_ANY_DBCS_CHARSET(FontInfo[dwFonts].tmCharSet)
) {
GetFontSize(dwFonts, &FontSize);
BuffSize = CalcBitmapBufferSize(FontSize,BYTE_ALIGN);
StringBitmap = ConsoleHeapAlloc( MAKE_TAG( TMP_DBCS_TAG ), sizeof(STRINGBITMAP) + BuffSize);
if (StringBitmap == NULL) {
RIPMSG1(RIP_WARNING, "RegisterKeisenOfTTFont: cannot allocate memory (%d bytes)",
sizeof(STRINGBITMAP) + BuffSize);
return FALSE;
}
if (SelectObject(Console->hDC,FontInfo[dwFonts].hFont)==0) {
goto error_return;
}
for (wChar=0; wChar < UNICODE_SPACE; wChar++) {
wCharBuf[0] = wChar;
wCharBuf[1] = TEXT('\0');;
if (GetStringBitmapW(Console->hDC,
wCharBuf,
1,
sizeof(STRINGBITMAP) + BuffSize,
(BYTE*)StringBitmap
) == 0) {
goto error_return;
}
FontSize.X = (WORD)StringBitmap->uiWidth;
FontSize.Y = (WORD)StringBitmap->uiHeight;
Status = RegisterLocalEUDC(Console,wChar,FontSize,StringBitmap->ajBits);
if (! NT_SUCCESS(Status)) {
error_return:
ConsoleHeapFree(StringBitmap);
return FALSE;
}
}
ConsoleHeapFree(StringBitmap);
}
((PEUDC_INFORMATION)(Console->EudcInformation))->LocalKeisenEudcMode = TRUE ;
}
return TRUE;
}
ULONG
TranslateUnicodeToOem(
IN PCONSOLE_INFORMATION Console,
IN PWCHAR UnicodeBuffer,
IN ULONG UnicodeCharCount,
OUT PCHAR AnsiBuffer,
IN ULONG AnsiByteCount,
OUT PINPUT_RECORD DbcsLeadInpRec
)
{
ULONG i,j;
PWCHAR TmpUni;
BYTE AsciiDbcs[2];
ULONG NumBytes;
TmpUni = ConsoleHeapAlloc(MAKE_TAG( TMP_DBCS_TAG ),UnicodeCharCount*sizeof(WCHAR));
if (TmpUni == NULL)
return 0;
memcpy(TmpUni,UnicodeBuffer,UnicodeCharCount*sizeof(WCHAR));
AsciiDbcs[1] = 0;
for (i=0,j=0; i<UnicodeCharCount; i++,j++) {
if (IsConsoleFullWidth(Console->hDC,Console->CP,TmpUni[i])) {
NumBytes = sizeof(AsciiDbcs);
ConvertToOem(Console->CP,
&TmpUni[i],
1,
&AsciiDbcs[0],
NumBytes
);
if (IsDBCSLeadByteConsole(AsciiDbcs[0],&Console->CPInfo)) {
if (j < AnsiByteCount-1) { // -1 is safe DBCS in buffer
AnsiBuffer[j] = AsciiDbcs[0];
j++;
AnsiBuffer[j] = AsciiDbcs[1];
AsciiDbcs[1] = 0;
}
else if (j == AnsiByteCount-1) {
AnsiBuffer[j] = AsciiDbcs[0];
j++;
break;
}
else {
AsciiDbcs[1] = 0;
break;
}
}
else {
AnsiBuffer[j] = AsciiDbcs[0];
AsciiDbcs[1] = 0;
}
}
else {
ConvertToOem(Console->CP,
&TmpUni[i],
1,
&AnsiBuffer[j],
1
);
}
}
if (DbcsLeadInpRec) {
if (AsciiDbcs[1]) {
DbcsLeadInpRec->EventType = KEY_EVENT;
DbcsLeadInpRec->Event.KeyEvent.uChar.AsciiChar = AsciiDbcs[1];
}
else {
RtlZeroMemory(DbcsLeadInpRec,sizeof(INPUT_RECORD));
}
}
ConsoleHeapFree(TmpUni);
return j;
}
DWORD ImmConversionToConsole(DWORD fdwConversion)
{
DWORD dwNlsMode;
if (GetKeyState(VK_KANA) & KEY_TOGGLED) {
fdwConversion = (fdwConversion & ~IME_CMODE_LANGUAGE) | (IME_CMODE_NATIVE | IME_CMODE_KATAKANA);
}
dwNlsMode = 0;
if (fdwConversion & IME_CMODE_NATIVE) {
if (fdwConversion & IME_CMODE_KATAKANA)
dwNlsMode |= NLS_KATAKANA;
else
dwNlsMode |= NLS_HIRAGANA;
}
else {
dwNlsMode |= NLS_ALPHANUMERIC;
}
if (fdwConversion & IME_CMODE_FULLSHAPE)
dwNlsMode |= NLS_DBCSCHAR;
if (fdwConversion & IME_CMODE_ROMAN)
dwNlsMode |= NLS_ROMAN;
if (fdwConversion & IME_CMODE_OPEN)
dwNlsMode |= NLS_IME_CONVERSION;
if (fdwConversion & IME_CMODE_DISABLE)
dwNlsMode |= NLS_IME_DISABLE;
return dwNlsMode;
}
DWORD ImmConversionFromConsole(DWORD dwNlsMode)
{
DWORD fdwConversion;
fdwConversion = 0;
if (dwNlsMode & (NLS_KATAKANA | NLS_HIRAGANA)) {
fdwConversion |= IME_CMODE_NATIVE;
if (dwNlsMode & NLS_KATAKANA)
fdwConversion |= IME_CMODE_KATAKANA;
}
if (dwNlsMode & NLS_DBCSCHAR)
fdwConversion |= IME_CMODE_FULLSHAPE;
if (dwNlsMode & NLS_ROMAN)
fdwConversion |= IME_CMODE_ROMAN;
if (dwNlsMode & NLS_IME_CONVERSION)
fdwConversion |= IME_CMODE_OPEN;
if (dwNlsMode & NLS_IME_DISABLE)
fdwConversion |= IME_CMODE_DISABLE;
return fdwConversion;
}
#if defined(DBG) && defined(DBG_KATTR)
VOID BeginKAttrCheck(IN PSCREEN_INFORMATION ScreenInfo)
{
SHORT RowIndex;
PROW Row;
SHORT i;
RowIndex = (ScreenInfo->BufferInfo.TextInfo.FirstRow) % ScreenInfo->ScreenBufferSize.Y;
Row = &ScreenInfo->BufferInfo.TextInfo.Rows[RowIndex];
for (i = 0; i < ScreenInfo->ScreenBufferSize.Y; i++) {
ASSERT(Row->CharRow.KAttrs);
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
}
}
#endif // DBG && DBG_KATTR
#endif