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
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
|