Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2928 lines
82 KiB

/*++
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 {
UserAssert(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 doesn'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;
InputThreadInfo = TlsGetValue(InputThreadTlsIndex);
if (InputThreadInfo != NULL) {
LRESULT lResult;
/*
* We're being called on the Console Input Thread, so we're
* clear to pump messages.
*/
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 {
/*
* We're being called from an LPC worker thread, so we cannot
* pump messages.
*/
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 DBG && defined(DBG_KATTR)
BeginKAttrCheck(ScreenInfo);
#endif
#ifdef FE_SB
//
// This buffer must be in textmode.
//
UserAssert(!(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 DBG && defined(DBG_KATTR)
BeginKAttrCheck(ScreenInfo);
#endif
#ifdef FE_SB
//
// This buffer must be in textmode.
//
UserAssert(!(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
//
UserAssert(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 DBG && defined(DBG_KATTR)
BeginKAttrCheck(ScreenInfo);
#endif
#ifdef FE_SB
//
// This buffer must be in textmode.
//
UserAssert(!(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) {
RIPMSGF1(RIP_WARNING,
"GetTextMetricsW failed with error 0x%x",
GetLastError());
return FALSE;
}
if (IS_ANY_DBCS_CHARSET(tmi.tmCharSet)) {
tmi.tmMaxCharWidth /= 2;
}
ret = GetCharWidth32(hDC, wch, wch, &Width);
if (!ret) {
RIPMSGF1(RIP_WARNING,
"GetCharWidth32 failed with error 0x%x",
GetLastError());
return FALSE;
}
if (Width == tmi.tmMaxCharWidth) {
return FALSE;
} else if (Width == tmi.tmMaxCharWidth*2) {
return TRUE;
}
}
UserAssert(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 {
UserAssert(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 = ConsoleHeapAlloc(TMP_TAG, SourceLength);
if (pTemp == NULL) {
return STATUS_NO_MEMORY;
}
pwTemp = ConsoleHeapAlloc(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
//
// This buffer must be in textmode.
//
UserAssert(!(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 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 = (SHORT)abs(FontSize.X - FontInfo[i].Size.X);
FontDelta.Y = (SHORT)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;
static BOOL bDBCSInitialized = FALSE;
if (bDBCSInitialized) {
return STATUS_SUCCESS;
} else {
bDBCSInitialized = TRUE;
}
UserAssert(gTTFontList.Next == NULL);
UserAssert(gRegFullScreenCodePage.Next == NULL);
/*
* Get TrueType Font Face name from registry.
*/
Status = MyRegOpenKey(NULL,
MACHINE_REGISTRY_CONSOLE_TTFONT,
&hkRegistry);
if (!NT_SUCCESS(Status)) {
RIPMSG2(RIP_VERBOSE,
"NtOpenKey(%ws) failed with status 0x%x",
MACHINE_REGISTRY_CONSOLE_TTFONT,
Status);
} 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(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)) {
RIPMSG2(RIP_VERBOSE,
"NtOpenKey(%ws) failed with status 0x%x",
MACHINE_REGISTRY_CONSOLE_FULLSCREEN,
Status);
} 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(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(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(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(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)) {
RIPMSG2(RIP_VERBOSE,
"NtOpenKey(%ws) failed with status 0x%x",
MACHINE_REGISTRY_FS_CODEPAGE,
Status);
} 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(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;
}
/*
* This routine converts a unicode string from the real unicode characters
* to the NEC OS/2 unicode characters.
*/
#if defined(i386)
NTSTATUS
RealUnicodeToNEC_OS2_Unicode(
IN OUT LPWSTR Source,
IN int SourceLength // in chars
)
{
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 = ConsoleHeapAlloc(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;
}
UserAssert(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 = ConsoleHeapAlloc(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 = ConsoleHeapAlloc(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(IntToPtr(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;
}
hwndConIme = pConsole->InputThreadInfo->hWndConsoleIME;
if (pConsole->InputThreadInfo->hWndConsoleIME != NULL) {
LRESULT lResult;
Status = ConsoleImeMessagePumpWorker(pConsole,
CONIME_CREATE,
(WPARAM)pConsole->ConsoleHandle,
(LPARAM)pConsole->hWnd,
&lResult);
if (!NT_SUCCESS(Status)) {
goto TerminateConsoleIme;
}
if (lResult) {
if (!CONSOLE_IS_DBCS_CP(pConsole)) {
pConsole->InputBuffer.ImeMode.Disable = TRUE;
}
CreateConvAreaModeSystem(pConsole);
if ((pConsole->Flags & CONSOLE_HAS_FOCUS) ||
(pConsole->FullScreenFlags & CONSOLE_FULLSCREEN_HARDWARE)) {
Status = ConsoleImeMessagePump(pConsole,
CONIME_SETFOCUS,
(WPARAM)pConsole->ConsoleHandle,
(LPARAM)pConsole->hklActive);
if (!NT_SUCCESS(Status)) {
goto TerminateConsoleIme;
}
}
if (pConsole->CurrentScreenBuffer->Flags & CONSOLE_TEXTMODE_BUFFER) {
Status = ConsoleImeMessagePump(pConsole,
CONIME_NOTIFY_SCREENBUFFERSIZE,
(WPARAM)pConsole->ConsoleHandle,
MAKELPARAM(pConsole->CurrentScreenBuffer->ScreenBufferSize.X,
pConsole->CurrentScreenBuffer->ScreenBufferSize.Y));
if (!NT_SUCCESS(Status)) {
goto TerminateConsoleIme;
}
}
Status = ConsoleImeMessagePump(pConsole,
CONIME_NOTIFY_CODEPAGE,
(WPARAM)pConsole->ConsoleHandle,
MAKELPARAM(FALSE, pConsole->CP));
if (!NT_SUCCESS(Status)) {
goto TerminateConsoleIme;
}
Status = ConsoleImeMessagePump(pConsole,
CONIME_NOTIFY_CODEPAGE,
(WPARAM)pConsole->ConsoleHandle,
MAKELPARAM(TRUE, pConsole->OutputCP));
if (!NT_SUCCESS(Status)) {
goto TerminateConsoleIme;
}
Status = GetImeKeyState(pConsole, NULL);
if (!NT_SUCCESS(Status)) {
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,
FALSE);
if (!NT_SUCCESS(Status)) {
RIPMSG1(RIP_WARNING,
"QueueThreadMessage(CM_CONIME_CREATE) failed (0x%x)",
Status);
}
}
UnlockConsole(pConsole);
return;
TerminateConsoleIme:
RIPMSG1(RIP_WARNING,
"ProcessCreateConsoleIme failing with status 0x%x",
Status);
if (IsWindow(hwndConIme)) {
PostMessage(hwndConIme, CONIME_DESTROY, (WPARAM)ConsoleHandle, (LPARAM)NULL);
}
UnlockConsole(pConsole);
}
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) {
RIPMSG0(RIP_WARNING, "InitConsoleIMEStuff is skipping conime loading");
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) {
RIPMSGF1(RIP_WARNING,
"CreateRemoteThread failed with error 0x%x",
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)) {
RIPMSGF1(RIP_WARNING,
"QueueThreadMessage(CM_CONIME_CREATE) failed with status 0x%x",
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)) {
RIPMSGF1(RIP_WARNING,
"QueueThreadMessage failed with status 0x%x",
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)) {
RIPMSGF1(RIP_WARNING,
"QueueThreadMessage failed with status 0x%x",
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;
*lplResult = 0;
if (hWndConsoleIME == NULL) {
return STATUS_SUCCESS;
}
InputThreadInfo = TlsGetValue(InputThreadTlsIndex);
if (InputThreadInfo != NULL) {
HWND hWnd = Console->hWnd;
/*
* We're being called on the Console Input Thread, so we can pump
* messages safely.
*/
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.
//
}
/*
* We're being called from an LPC worker thread, so we cannot safely
* pump messages.
*/
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(TMP_DBCS_TAG, sizeof(STRINGBITMAP) + BuffSize);
if (StringBitmap == NULL) {
RIPMSGF1(RIP_WARNING,
"Cannot allocate 0n%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(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 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++) {
UserAssert(Row->CharRow.KAttrs);
if (++RowIndex == ScreenInfo->ScreenBufferSize.Y) {
RowIndex = 0;
}
}
}
#endif
#endif