[CONSRV] Miscellaneous console fixes for CJK support and screenbuffer iteration....
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 9 Feb 2020 21:22:52 +0000 (22:22 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sat, 22 Feb 2020 18:50:17 +0000 (19:50 +0100)
+ popup.c!DrawBox(): Factor out setting the attribute value.

win32ss/user/winsrv/consrv/condrv/text.c
win32ss/user/winsrv/consrv/frontends/terminal.c
win32ss/user/winsrv/consrv/include/conio.h
win32ss/user/winsrv/consrv/popup.c

index 0d20b94..6f52d8c 100644 (file)
@@ -14,8 +14,6 @@
 #define NDEBUG
 #include <debug.h>
 
-#define COMMON_LEAD_TRAIL (COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE)
-
 /* GLOBALS ********************************************************************/
 
 /*
@@ -109,8 +107,8 @@ TEXTMODE_BUFFER_Initialize(OUT PCONSOLE_SCREEN_BUFFER* Buffer,
     NewBuffer->CursorInfo.bVisible = (TextModeInfo->IsCursorVisible && (TextModeInfo->CursorSize != 0));
     NewBuffer->CursorInfo.dwSize   = min(max(TextModeInfo->CursorSize, 0), 100);
 
-    NewBuffer->ScreenDefaultAttrib = TextModeInfo->ScreenAttrib;
-    NewBuffer->PopupDefaultAttrib  = TextModeInfo->PopupAttrib;
+    NewBuffer->ScreenDefaultAttrib = (TextModeInfo->ScreenAttrib & ~COMMON_LVB_SBCSDBCS);
+    NewBuffer->PopupDefaultAttrib  = (TextModeInfo->PopupAttrib  & ~COMMON_LVB_SBCSDBCS);
 
     /* Initialize buffer to be empty with default attributes */
     for (NewBuffer->CursorPosition.Y = 0 ; NewBuffer->CursorPosition.Y < NewBuffer->ScreenBufferSize.Y; NewBuffer->CursorPosition.Y++)
@@ -197,12 +195,14 @@ ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
                 PSMALL_RECT ClipRegion,
                 CHAR_INFO FillChar)
 {
-    int Width  = ConioRectWidth(SrcRegion);
-    int Height = ConioRectHeight(SrcRegion);
-    int SX, SY;
-    int DX, DY;
-    int XDelta, YDelta;
-    int i, j;
+    UINT Width  = ConioRectWidth(SrcRegion);
+    UINT Height = ConioRectHeight(SrcRegion);
+    INT SXOrg, SX, SY;
+    INT DXOrg, DX, DY;
+    INT XDelta, YDelta;
+    UINT i, j;
+    CHAR_INFO Cell;
+    PCHAR_INFO SRow, DRow;
 
     SY = SrcRegion->Top;
     DY = DstRegion->Top;
@@ -214,24 +214,31 @@ ConioMoveRegion(PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
         DY = DstRegion->Bottom;
         YDelta = -1;
     }
+
+    SXOrg = SrcRegion->Left;
+    DXOrg = DstRegion->Left;
+    XDelta = 1;
+    if (SXOrg < DXOrg)
+    {
+        /* Moving right: work from right to left */
+        SXOrg = SrcRegion->Right;
+        DXOrg = DstRegion->Right;
+        XDelta = -1;
+    }
+
     for (i = 0; i < Height; i++)
     {
-        PCHAR_INFO SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
-        PCHAR_INFO DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
+        SRow = ConioCoordToPointer(ScreenBuffer, 0, SY);
+        DRow = ConioCoordToPointer(ScreenBuffer, 0, DY);
+
+        SX = SXOrg;
+        DX = DXOrg;
+
+        // TODO: Correctly support "moving" full-width characters.
 
-        SX = SrcRegion->Left;
-        DX = DstRegion->Left;
-        XDelta = 1;
-        if (SX < DX)
-        {
-            /* Moving right: work from right to left */
-            SX = SrcRegion->Right;
-            DX = DstRegion->Right;
-            XDelta = -1;
-        }
         for (j = 0; j < Width; j++)
         {
-            CHAR_INFO Cell = SRow[SX];
+            Cell = SRow[SX];
             if (SX >= ClipRegion->Left && SX <= ClipRegion->Right &&
                 SY >= ClipRegion->Top  && SY <= ClipRegion->Bottom)
             {
@@ -265,14 +272,18 @@ ConioResizeBuffer(PCONSOLE Console,
                   COORD Size)
 {
     PCHAR_INFO Buffer;
-    DWORD Offset = 0;
-    PCHAR_INFO ptr;
+    PCHAR_INFO Ptr;
+    ULONG_PTR Offset = 0;
     WORD CurrentAttribute;
     USHORT CurrentY;
     PCHAR_INFO OldBuffer;
     DWORD i;
     DWORD diff;
 
+    /* Zero size is invalid */
+    if (Size.X == 0 || Size.Y == 0)
+        return STATUS_INVALID_PARAMETER;
+
     /* Buffer size is not allowed to be smaller than the view size */
     if (Size.X < ScreenBuffer->ViewSize.X || Size.Y < ScreenBuffer->ViewSize.Y)
         return STATUS_INVALID_PARAMETER;
@@ -298,36 +309,48 @@ ConioResizeBuffer(PCONSOLE Console,
     if (!Buffer) return STATUS_NO_MEMORY;
 
     DPRINT("Resizing (%d,%d) to (%d,%d)\n", ScreenBuffer->ScreenBufferSize.X, ScreenBuffer->ScreenBufferSize.Y, Size.X, Size.Y);
+
     OldBuffer = ScreenBuffer->Buffer;
 
     for (CurrentY = 0; CurrentY < ScreenBuffer->ScreenBufferSize.Y && CurrentY < Size.Y; CurrentY++)
     {
-        ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
+        Ptr = ConioCoordToPointer(ScreenBuffer, 0, CurrentY);
+
         if (Size.X <= ScreenBuffer->ScreenBufferSize.X)
         {
             /* Reduce size */
-            RtlCopyMemory(Buffer + Offset, ptr, Size.X * sizeof(CHAR_INFO));
+            RtlCopyMemory(Buffer + Offset, Ptr, Size.X * sizeof(CHAR_INFO));
             Offset += Size.X;
+
+            /* If we have cut a trailing full-width character in half, remove it completely */
+            Ptr = Buffer + Offset - 1;
+            if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
+            {
+                Ptr->Char.UnicodeChar = L' ';
+                /* Keep all the other original attributes intact */
+                Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+            }
         }
         else
         {
             /* Enlarge size */
-            RtlCopyMemory(Buffer + Offset, ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO));
+            RtlCopyMemory(Buffer + Offset, Ptr, ScreenBuffer->ScreenBufferSize.X * sizeof(CHAR_INFO));
             Offset += ScreenBuffer->ScreenBufferSize.X;
 
             /* The attribute to be used is the one of the last cell of the current line */
             CurrentAttribute = ConioCoordToPointer(ScreenBuffer,
                                                    ScreenBuffer->ScreenBufferSize.X - 1,
                                                    CurrentY)->Attributes;
+            CurrentAttribute &= ~COMMON_LVB_SBCSDBCS;
 
             diff = Size.X - ScreenBuffer->ScreenBufferSize.X;
 
             /* Zero-out the new part of the buffer */
             for (i = 0; i < diff; i++)
             {
-                ptr = Buffer + Offset;
-                ptr->Char.UnicodeChar = L' ';
-                ptr->Attributes = CurrentAttribute;
+                Ptr = Buffer + Offset;
+                Ptr->Char.UnicodeChar = L' ';
+                Ptr->Attributes = CurrentAttribute;
                 ++Offset;
             }
         }
@@ -340,9 +363,9 @@ ConioResizeBuffer(PCONSOLE Console,
         /* Zero-out the new part of the buffer */
         for (i = 0; i < diff; i++)
         {
-            ptr = Buffer + Offset;
-            ptr->Char.UnicodeChar = L' ';
-            ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib;
+            Ptr = Buffer + Offset;
+            Ptr->Char.UnicodeChar = L' ';
+            Ptr->Attributes = ScreenBuffer->ScreenDefaultAttrib;
             ++Offset;
         }
     }
@@ -391,7 +414,7 @@ ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
                                    IN USHORT NewScreenAttrib,
                                    IN USHORT NewPopupAttrib)
 {
-    ULONG X, Y, Length;
+    USHORT X, Y;
     PCHAR_INFO Ptr;
 
     COORD  TopLeft = {0};
@@ -406,50 +429,42 @@ ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
     /* Validity check */
     ASSERT(Console == Buffer->Header.Console);
 
+    /* Sanitize the new attributes */
+    NewScreenAttrib &= ~COMMON_LVB_SBCSDBCS;
+    NewPopupAttrib  &= ~COMMON_LVB_SBCSDBCS;
+
     NumCodesToWrite = Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y;
     OldScreenAttrib = Buffer->ScreenDefaultAttrib;
     OldPopupAttrib  = Buffer->PopupDefaultAttrib;
 
-    X = TopLeft.X;
-    Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-    Length = NumCodesToWrite;
-
-    while (Length--)
+    for (Y = 0; Y < Buffer->ScreenBufferSize.Y; ++Y)
     {
-        Ptr = ConioCoordToPointer(Buffer, X, Y);
-
-        /*
-         * Change the current colors only if they are the old ones.
-         */
-
-        /* Foreground color */
-        if ((Ptr->Attributes & 0x0F) == (OldScreenAttrib & 0x0F))
-            Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewScreenAttrib & 0x0F);
-        if ((Ptr->Attributes & 0x0F) == (OldPopupAttrib & 0x0F))
-            Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewPopupAttrib & 0x0F);
-
-        /* Background color */
-        if ((Ptr->Attributes & 0xF0) == (OldScreenAttrib & 0xF0))
-            Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewScreenAttrib & 0xF0);
-        if ((Ptr->Attributes & 0xF0) == (OldPopupAttrib & 0xF0))
-            Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewPopupAttrib & 0xF0);
-
-        // ++Ptr;
-
-        if (++X == Buffer->ScreenBufferSize.X)
+        Ptr = ConioCoordToPointer(Buffer, 0, Y);
+        for (X = 0; X < Buffer->ScreenBufferSize.X; ++X)
         {
-            X = 0;
+            /*
+             * Change the current colors only if they are the old ones.
+             */
+
+            /* Foreground color */
+            if ((Ptr->Attributes & 0x0F) == (OldScreenAttrib & 0x0F))
+                Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewScreenAttrib & 0x0F);
+            if ((Ptr->Attributes & 0x0F) == (OldPopupAttrib & 0x0F))
+                Ptr->Attributes = (Ptr->Attributes & 0xFFF0) | (NewPopupAttrib & 0x0F);
+
+            /* Background color */
+            if ((Ptr->Attributes & 0xF0) == (OldScreenAttrib & 0xF0))
+                Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewScreenAttrib & 0xF0);
+            if ((Ptr->Attributes & 0xF0) == (OldPopupAttrib & 0xF0))
+                Ptr->Attributes = (Ptr->Attributes & 0xFF0F) | (NewPopupAttrib & 0xF0);
 
-            if (++Y == Buffer->ScreenBufferSize.Y)
-            {
-                Y = 0;
-            }
+            ++Ptr;
         }
     }
 
-    /* Save foreground and background colors for both screen and popup */
-    Buffer->ScreenDefaultAttrib = (NewScreenAttrib & 0x00FF);
-    Buffer->PopupDefaultAttrib  = (NewPopupAttrib  & 0x00FF);
+    /* Save foreground and background attributes for both screen and popup */
+    Buffer->ScreenDefaultAttrib = NewScreenAttrib;
+    Buffer->PopupDefaultAttrib  = NewPopupAttrib;
 
     /* Refresh the display if needed */
     if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
@@ -492,7 +507,7 @@ ConDrvReadConsoleOutput(IN PCONSOLE Console,
     ConioInitRect(&ScreenBuffer, 0, 0,
                   Buffer->ScreenBufferSize.Y - 1,
                   Buffer->ScreenBufferSize.X - 1);
-    if (!ConioGetIntersection(&CapturedReadRegion, &ScreenBuffer, &CapturedReadRegion))
+    if (!ConioGetIntersection(&CapturedReadRegion, &CapturedReadRegion, &ScreenBuffer))
     {
         /*
          * It is okay to have a ReadRegion completely outside
@@ -518,7 +533,12 @@ ConDrvReadConsoleOutput(IN PCONSOLE Console,
                 WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1,
                                     &CurCharInfo->Char.AsciiChar, 1, NULL, NULL);
             }
-            CurCharInfo->Attributes = (Ptr->Attributes & ~COMMON_LEAD_TRAIL);
+#if (_WIN32_WINNT < _WIN32_WINNT_WIN8)
+            /* NOTE: Windows < 8 compatibility: DBCS flags are filtered out */
+            CurCharInfo->Attributes = (Ptr->Attributes & ~COMMON_LVB_SBCSDBCS);
+#else
+            CurCharInfo->Attributes = Ptr->Attributes;
+#endif
             ++Ptr;
             ++CurCharInfo;
         }
@@ -556,7 +576,7 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console,
     ConioInitRect(&ScreenBuffer, 0, 0,
                   Buffer->ScreenBufferSize.Y - 1,
                   Buffer->ScreenBufferSize.X - 1);
-    if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
+    if (!ConioGetIntersection(&CapturedWriteRegion, &CapturedWriteRegion, &ScreenBuffer))
     {
         /*
          * It is okay to have a WriteRegion completely outside
@@ -580,6 +600,7 @@ ConDrvWriteConsoleOutput(IN PCONSOLE Console,
             {
                 ConsoleOutputAnsiToUnicodeChar(Console, &Ptr->Char.UnicodeChar, &CurCharInfo->Char.AsciiChar);
             }
+            // TODO: Sanitize DBCS attributes?
             Ptr->Attributes = CurCharInfo->Attributes;
             ++Ptr;
             ++CurCharInfo;
@@ -625,7 +646,7 @@ ConDrvWriteConsoleOutputVDM(IN PCONSOLE Console,
     ConioInitRect(&ScreenBuffer, 0, 0,
                   Buffer->ScreenBufferSize.Y - 1,
                   Buffer->ScreenBufferSize.X - 1);
-    if (!ConioGetIntersection(&CapturedWriteRegion, &ScreenBuffer, &CapturedWriteRegion))
+    if (!ConioGetIntersection(&CapturedWriteRegion, &CapturedWriteRegion, &ScreenBuffer))
     {
         /*
          * It is okay to have a WriteRegion completely outside
@@ -687,7 +708,7 @@ ConDrvWriteConsole(IN PCONSOLE Console,
                                      (PCHAR)StringBuffer,
                                      NumCharsToWrite,
                                      NULL, 0);
-        Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
+        Buffer = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
         if (Buffer)
         {
             MultiByteToWideChar(Console->OutputCodePage, 0,
@@ -717,7 +738,7 @@ ConDrvWriteConsole(IN PCONSOLE Console,
             }
         }
 
-        if (!Unicode) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
+        if (!Unicode) ConsoleFreeHeap(Buffer);
     }
 
     if (NumCharsWritten) *NumCharsWritten = Written;
@@ -725,113 +746,67 @@ ConDrvWriteConsole(IN PCONSOLE Console,
     return Status;
 }
 
-NTSTATUS FASTCALL
-IntReadConsoleOutputStringAscii(IN PCONSOLE Console,
-                                IN PTEXTMODE_SCREEN_BUFFER Buffer,
-                                OUT PVOID StringBuffer,
-                                IN ULONG NumCodesToRead,
-                                IN PCOORD ReadCoord,
-                                OUT PULONG NumCodesRead OPTIONAL)
+static NTSTATUS
+IntReadConsoleOutputStringChars(
+    IN PCONSOLE Console,
+    IN PTEXTMODE_SCREEN_BUFFER Buffer,
+    OUT PVOID StringBuffer,
+    IN BOOLEAN Unicode,
+    IN ULONG NumCodesToRead,
+    IN PCOORD ReadCoord,
+    OUT PULONG NumCodesRead OPTIONAL)
 {
-    ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
+    ULONG CodeSize;
     LPBYTE ReadBuffer = StringBuffer;
-    SHORT Xpos = ReadCoord->X;
-    SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-    ULONG i;
+    SHORT X, Y;
+    SHORT XStart = ReadCoord->X;
+    ULONG nNumChars = 0;
     PCHAR_INFO Ptr;
     BOOLEAN bCJK = Console->IsCJK;
 
-    for (i = 0; i < NumCodesToRead; ++i)
-    {
-        Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
-
-        ConsoleOutputUnicodeToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
-        ReadBuffer += CodeSize;
+    CodeSize = (Unicode ? RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar)
+                        : RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar));
 
-        Xpos++;
-        if (Xpos == Buffer->ScreenBufferSize.X)
+    for (Y = ReadCoord->Y; Y < Buffer->ScreenBufferSize.Y; ++Y)
+    {
+        Ptr = ConioCoordToPointer(Buffer, XStart, Y);
+        for (X = XStart; X < Buffer->ScreenBufferSize.X; ++X)
         {
-            Xpos = 0;
-            Ypos++;
-            if (Ypos == Buffer->ScreenBufferSize.Y)
+            if (nNumChars >= NumCodesToRead)
+                goto Quit;
+
+            /*
+             * For Chinese, Japanese and Korean.
+             * For full-width characters: copy only the character specified
+             * in the leading-byte cell, skipping the trailing-byte cell.
+             */
+            if (bCJK && (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE))
             {
-                Ypos = 0;
+                /*
+                 * Windows "compensates" for the fact this is a full-width
+                 * character by reducing the amount of characters to be read.
+                 * The understanding being that the specified amount of
+                 * characters is also in "units" of (half-width) cells.
+                 */
+                if (NumCodesToRead > 0) --NumCodesToRead;
+                ++Ptr;
+                continue;
             }
-        }
 
-        /* For Chinese, Japanese and Korean */
-        if (bCJK && (Ptr->Attributes & COMMON_LVB_LEADING_BYTE))
-        {
-            Xpos++;
-            if (Xpos == Buffer->ScreenBufferSize.X)
-            {
-                Xpos = 0;
-                Ypos++;
-                if (Ypos == Buffer->ScreenBufferSize.Y)
-                {
-                    Ypos = 0;
-                }
-            }
-            ++i;
-        }
-    }
-
-    if (NumCodesRead)
-        *NumCodesRead = i;
-
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS FASTCALL
-IntReadConsoleOutputStringUnicode(IN PCONSOLE Console,
-                                  IN PTEXTMODE_SCREEN_BUFFER Buffer,
-                                  OUT PVOID StringBuffer,
-                                  IN ULONG NumCodesToRead,
-                                  IN PCOORD ReadCoord,
-                                  OUT PULONG NumCodesRead OPTIONAL)
-{
-    ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
-    LPBYTE ReadBuffer = StringBuffer;
-    SHORT Xpos = ReadCoord->X;
-    SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-    ULONG i, nNumChars = 0;
-    PCHAR_INFO Ptr;
-    BOOLEAN bCJK = Console->IsCJK;
-
-    for (i = 0; i < NumCodesToRead; ++i, ++nNumChars)
-    {
-        Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
-
-        *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
-        ReadBuffer += CodeSize;
+            if (Unicode)
+                *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
+            else
+                ConsoleOutputUnicodeToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
 
-        Xpos++;
-        if (Xpos == Buffer->ScreenBufferSize.X)
-        {
-            Xpos = 0;
-            Ypos++;
-            if (Ypos == Buffer->ScreenBufferSize.Y)
-            {
-                Ypos = 0;
-            }
-        }
+            ++Ptr;
 
-        /* For Chinese, Japanese and Korean */
-        if (bCJK && (Ptr->Attributes & COMMON_LVB_LEADING_BYTE))
-        {
-            Xpos++;
-            if (Xpos == Buffer->ScreenBufferSize.X)
-            {
-                Xpos = 0;
-                Ypos++;
-                if (Ypos == Buffer->ScreenBufferSize.Y)
-                {
-                    Ypos = 0;
-                }
-            }
-            ++i;
+            ReadBuffer += CodeSize;
+            ++nNumChars;
         }
+        /* Restart at the beginning of the next line */
+        XStart = 0;
     }
+Quit:
 
     if (NumCodesRead)
         *NumCodesRead = nNumChars;
@@ -839,60 +814,54 @@ IntReadConsoleOutputStringUnicode(IN PCONSOLE Console,
     return STATUS_SUCCESS;
 }
 
-NTSTATUS FASTCALL
-IntReadConsoleOutputStringAttributes(IN PCONSOLE Console,
-                                     IN PTEXTMODE_SCREEN_BUFFER Buffer,
-                                     OUT PVOID StringBuffer,
-                                     IN ULONG NumCodesToRead,
-                                     IN PCOORD ReadCoord,
-                                     OUT PULONG NumCodesRead OPTIONAL)
+static NTSTATUS
+IntReadConsoleOutputStringAttributes(
+    IN PCONSOLE Console,
+    IN PTEXTMODE_SCREEN_BUFFER Buffer,
+    OUT PWORD StringBuffer,
+    IN ULONG NumCodesToRead,
+    IN PCOORD ReadCoord,
+    OUT PULONG NumCodesRead OPTIONAL)
 {
-    ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
-    LPBYTE ReadBuffer = StringBuffer;
-    SHORT Xpos = ReadCoord->X;
-    SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-    ULONG i;
+    SHORT X, Y;
+    SHORT XStart = ReadCoord->X;
+    ULONG nNumChars = 0;
     PCHAR_INFO Ptr;
 
-    for (i = 0; i < NumCodesToRead; ++i)
+    for (Y = ReadCoord->Y; Y < Buffer->ScreenBufferSize.Y; ++Y)
     {
-        Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
+        Ptr = ConioCoordToPointer(Buffer, XStart, Y);
+        for (X = XStart; X < Buffer->ScreenBufferSize.X; ++X)
+        {
+            if (nNumChars >= NumCodesToRead)
+                goto Quit;
 
-        *(PWORD)ReadBuffer = Ptr->Attributes;
-        ReadBuffer += CodeSize;
+            *StringBuffer = Ptr->Attributes;
+            ++Ptr;
 
-        Xpos++;
-        if (Xpos == Buffer->ScreenBufferSize.X)
-        {
-            Xpos = 0;
-            Ypos++;
-            if (Ypos == Buffer->ScreenBufferSize.Y)
-            {
-                Ypos = 0;
-            }
+            ++StringBuffer;
+            ++nNumChars;
         }
+        /* Restart at the beginning of the next line */
+        XStart = 0;
     }
-
-    if (Xpos > 0 && Console->IsCJK)
-    {
-        ReadBuffer -= CodeSize;
-        *(PWORD)ReadBuffer &= ~COMMON_LVB_LEADING_BYTE;
-    }
+Quit:
 
     if (NumCodesRead)
-        *NumCodesRead = NumCodesToRead;
+        *NumCodesRead = nNumChars;
 
     return STATUS_SUCCESS;
 }
 
 NTSTATUS NTAPI
-ConDrvReadConsoleOutputString(IN PCONSOLE Console,
-                              IN PTEXTMODE_SCREEN_BUFFER Buffer,
-                              IN CODE_TYPE CodeType,
-                              OUT PVOID StringBuffer,
-                              IN ULONG NumCodesToRead,
-                              IN PCOORD ReadCoord,
-                              OUT PULONG NumCodesRead OPTIONAL)
+ConDrvReadConsoleOutputString(
+    IN PCONSOLE Console,
+    IN PTEXTMODE_SCREEN_BUFFER Buffer,
+    IN CODE_TYPE CodeType,
+    OUT PVOID StringBuffer,
+    IN ULONG NumCodesToRead,
+    IN PCOORD ReadCoord,
+    OUT PULONG NumCodesRead OPTIONAL)
 {
     if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
     {
@@ -906,31 +875,52 @@ ConDrvReadConsoleOutputString(IN PCONSOLE Console,
     if (NumCodesRead)
         *NumCodesRead = 0;
 
+    if (!StringBuffer || (NumCodesToRead == 0))
+        return STATUS_SUCCESS; // Nothing to do!
+
+    /* Do nothing if the reading starting point is outside of the screen buffer */
+    if ( ReadCoord->X < 0 || ReadCoord->X >= Buffer->ScreenBufferSize.X ||
+         ReadCoord->Y < 0 || ReadCoord->Y >= Buffer->ScreenBufferSize.Y )
+    {
+        return STATUS_SUCCESS;
+    }
+
+    NumCodesToRead = min(NumCodesToRead, (ULONG)Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y);
+
     switch (CodeType)
     {
         case CODE_ASCII:
-            return IntReadConsoleOutputStringAscii(Console,
+        {
+            return IntReadConsoleOutputStringChars(Console,
                                                    Buffer,
                                                    StringBuffer,
+                                                   FALSE,
                                                    NumCodesToRead,
                                                    ReadCoord,
                                                    NumCodesRead);
+        }
 
         case CODE_UNICODE:
-            return IntReadConsoleOutputStringUnicode(Console,
-                                                     Buffer,
-                                                     StringBuffer,
-                                                     NumCodesToRead,
-                                                     ReadCoord,
-                                                     NumCodesRead);
+        {
+            return IntReadConsoleOutputStringChars(Console,
+                                                   Buffer,
+                                                   StringBuffer,
+                                                   TRUE,
+                                                   NumCodesToRead,
+                                                   ReadCoord,
+                                                   NumCodesRead);
+        }
 
         case CODE_ATTRIBUTE:
+        {
+            C_ASSERT(RTL_FIELD_SIZE(CODE_ELEMENT, Attribute) == sizeof(WORD));
             return IntReadConsoleOutputStringAttributes(Console,
                                                         Buffer,
-                                                        StringBuffer,
+                                                        (PWORD)StringBuffer,
                                                         NumCodesToRead,
                                                         ReadCoord,
                                                         NumCodesRead);
+        }
 
         default:
             return STATUS_INVALID_PARAMETER;
@@ -938,133 +928,106 @@ ConDrvReadConsoleOutputString(IN PCONSOLE Console,
 }
 
 static NTSTATUS
-IntWriteConsoleOutputStringUnicode(
+IntWriteConsoleOutputStringChars(
     IN PCONSOLE Console,
     IN PTEXTMODE_SCREEN_BUFFER Buffer,
     IN PVOID StringBuffer,
+    IN BOOLEAN Unicode,
     IN ULONG NumCodesToWrite,
     IN PCOORD WriteCoord,
     OUT PULONG NumCodesWritten OPTIONAL)
 {
     NTSTATUS Status = STATUS_SUCCESS;
-    PWCHAR WriteBuffer = StringBuffer;
-    ULONG i, X, Y, Length;
+    PWCHAR WriteBuffer = NULL;
+    PWCHAR tmpString = NULL;
+    ULONG Length;
+    SHORT X, Y;
+    SHORT XStart = WriteCoord->X;
+    ULONG nNumChars = 0;
     PCHAR_INFO Ptr;
     BOOLEAN bCJK = Console->IsCJK;
 
-    if (!StringBuffer)
-        goto Cleanup;
-
-    X = WriteCoord->X;
-    Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-    Length = NumCodesToWrite;
-
-    for (i = 0; i < Length; ++i)
+    /* Convert the string to UNICODE */
+    if (Unicode)
     {
-        Ptr = ConioCoordToPointer(Buffer, X, Y);
-
-        Ptr->Char.UnicodeChar = *WriteBuffer;
-        ++WriteBuffer;
-
-        ++X;
-        if (X == Buffer->ScreenBufferSize.X)
+        WriteBuffer = StringBuffer;
+    }
+    else
+    {
+        /* Convert the ASCII string into Unicode before writing it to the console */
+        Length = MultiByteToWideChar(Console->OutputCodePage, 0,
+                                     (PCHAR)StringBuffer,
+                                     NumCodesToWrite,
+                                     NULL, 0);
+        tmpString = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
+        if (!tmpString)
         {
-            X = 0;
-            ++Y;
-            if (Y == Buffer->ScreenBufferSize.Y)
-            {
-                Y = 0;
-            }
+            Status = STATUS_NO_MEMORY;
+            goto Quit;
         }
 
-        /* For Chinese, Japanese and Korean */
-        if (bCJK && Ptr->Char.UnicodeChar >= 0x80 &&
-            mk_wcwidth_cjk(Ptr->Char.UnicodeChar) == 2)
+        MultiByteToWideChar(Console->OutputCodePage, 0,
+                            (PCHAR)StringBuffer,
+                            NumCodesToWrite,
+                            tmpString, Length);
+
+        NumCodesToWrite = Length;
+        WriteBuffer = tmpString;
+    }
+
+    for (Y = WriteCoord->Y; Y < Buffer->ScreenBufferSize.Y; ++Y)
+    {
+        Ptr = ConioCoordToPointer(Buffer, XStart, Y);
+        for (X = XStart; X < Buffer->ScreenBufferSize.X; ++X)
         {
-            /* A full-width character cannot cross a line boundary */
-            if (X == Buffer->ScreenBufferSize.X - 1)
+            if (nNumChars >= NumCodesToWrite)
+                goto Quit;
+
+            /* For Chinese, Japanese and Korean */
+            if (bCJK && IS_FULL_WIDTH(*WriteBuffer))
             {
-                /* go to next line */
-                X = 0;
-                ++Y;
-                if (Y == Buffer->ScreenBufferSize.Y)
+                /* A full-width character cannot cross a line boundary */
+                if (X >= Buffer->ScreenBufferSize.X - 1)
                 {
-                    Y = 0;
+                    /* Go to next line */
+                    break; // Break the X-loop only.
                 }
-                Ptr = ConioCoordToPointer(Buffer, X, Y);
-            }
 
-            /* the leading byte */
-            Ptr->Attributes = Buffer->ScreenDefaultAttrib;
-            Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
-            ++i;
+                /* Set the leading byte */
+                Ptr->Char.UnicodeChar = *WriteBuffer;
+                Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+                Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
+                ++Ptr;
 
-            /* the trailing byte */
-            Ptr = ConioCoordToPointer(Buffer, X, Y);
-            Ptr->Attributes = Buffer->ScreenDefaultAttrib;
-            Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
-
-            ++X;
-            if (X == Buffer->ScreenBufferSize.X)
+                /* Set the trailing byte */
+                Ptr->Char.UnicodeChar = L' ';
+                Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+                Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
+            }
+            else
             {
-                X = 0;
-                ++Y;
-                if (Y == Buffer->ScreenBufferSize.Y)
-                {
-                    Y = 0;
-                }
+                Ptr->Char.UnicodeChar = *WriteBuffer;
             }
-        }
-    }
 
-Cleanup:
-    if (NumCodesWritten)
-        *NumCodesWritten = NumCodesToWrite;
-    return Status;
-}
+            ++Ptr;
 
-static NTSTATUS
-IntWriteConsoleOutputStringAscii(
-    IN PCONSOLE Console,
-    IN PTEXTMODE_SCREEN_BUFFER Buffer,
-    IN PVOID StringBuffer,
-    IN ULONG NumCodesToWrite,
-    IN PCOORD WriteCoord,
-    OUT PULONG NumCodesWritten OPTIONAL)
-{
-    NTSTATUS Status;
-    PWCHAR tmpString;
-    ULONG Length;
+            ++WriteBuffer;
+            ++nNumChars;
+        }
+        /* Restart at the beginning of the next line */
+        XStart = 0;
+    }
+Quit:
 
-    if (!StringBuffer)
+    if (tmpString)
     {
-        if (NumCodesWritten)
-            *NumCodesWritten = NumCodesToWrite;
-
-        return STATUS_SUCCESS;
+        ASSERT(!Unicode);
+        ConsoleFreeHeap(tmpString);
     }
 
-    /* Convert the ASCII string into Unicode before writing it to the console */
-    Length = MultiByteToWideChar(Console->OutputCodePage, 0,
-                                 StringBuffer,
-                                 NumCodesToWrite,
-                                 NULL, 0);
-    tmpString = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
-    if (!tmpString)
-        return STATUS_NO_MEMORY;
-
-    MultiByteToWideChar(Console->OutputCodePage, 0,
-                        StringBuffer,
-                        NumCodesToWrite,
-                        tmpString, Length);
-
-    Status = IntWriteConsoleOutputStringUnicode(Console,
-                                                Buffer,
-                                                tmpString,
-                                                Length,
-                                                WriteCoord,
-                                                NumCodesWritten);
-    ConsoleFreeHeap(tmpString);
+    if (NumCodesWritten)
+        *NumCodesWritten = nNumChars;
+
     return Status;
 }
 
@@ -1072,46 +1035,41 @@ static NTSTATUS
 IntWriteConsoleOutputStringAttribute(
     IN PCONSOLE Console,
     IN PTEXTMODE_SCREEN_BUFFER Buffer,
-    IN PVOID StringBuffer,
+    IN PWORD StringBuffer,
     IN ULONG NumCodesToWrite,
     IN PCOORD WriteCoord,
     OUT PULONG NumCodesWritten OPTIONAL)
 {
-    NTSTATUS Status = STATUS_SUCCESS;
-    PWORD WriteBuffer = StringBuffer;
-    ULONG i, X, Y, Length;
+    SHORT X, Y;
+    SHORT XStart = WriteCoord->X;
+    ULONG nNumChars = 0;
     PCHAR_INFO Ptr;
 
-    if (!StringBuffer)
-        goto Cleanup;
-
-    X = WriteCoord->X;
-    Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-    Length = NumCodesToWrite;
-
-    for (i = 0; i < Length; ++i)
+    for (Y = WriteCoord->Y; Y < Buffer->ScreenBufferSize.Y; ++Y)
     {
-        Ptr = ConioCoordToPointer(Buffer, X, Y);
+        Ptr = ConioCoordToPointer(Buffer, XStart, Y);
+        for (X = XStart; X < Buffer->ScreenBufferSize.X; ++X)
+        {
+            if (nNumChars >= NumCodesToWrite)
+                goto Quit;
 
-        Ptr->Attributes = (*WriteBuffer & ~COMMON_LEAD_TRAIL);
-        ++WriteBuffer;
+            Ptr->Attributes &= COMMON_LVB_SBCSDBCS;
+            Ptr->Attributes |= (*StringBuffer & ~COMMON_LVB_SBCSDBCS);
 
-        ++X;
-        if (X == Buffer->ScreenBufferSize.X)
-        {
-            X = 0;
-            ++Y;
-            if (Y == Buffer->ScreenBufferSize.Y)
-            {
-                Y = 0;
-            }
+            ++Ptr;
+
+            ++StringBuffer;
+            ++nNumChars;
         }
+        /* Restart at the beginning of the next line */
+        XStart = 0;
     }
+Quit:
 
-Cleanup:
     if (NumCodesWritten)
-        *NumCodesWritten = NumCodesToWrite;
-    return Status;
+        *NumCodesWritten = nNumChars;
+
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS NTAPI
@@ -1125,7 +1083,6 @@ ConDrvWriteConsoleOutputString(
     OUT PULONG NumCodesWritten OPTIONAL)
 {
     NTSTATUS Status;
-    SMALL_RECT UpdateRect;
 
     if (Console == NULL || Buffer == NULL || WriteCoord == NULL /* || EndCoord == NULL */)
     {
@@ -1139,30 +1096,65 @@ ConDrvWriteConsoleOutputString(
     if (NumCodesWritten)
         *NumCodesWritten = 0;
 
+    if (!StringBuffer || (NumCodesToWrite == 0))
+        return STATUS_SUCCESS; // Nothing to do!
+
+    /* Do nothing if the writing starting point is outside of the screen buffer */
+    if ( WriteCoord->X < 0 || WriteCoord->X >= Buffer->ScreenBufferSize.X ||
+         WriteCoord->Y < 0 || WriteCoord->Y >= Buffer->ScreenBufferSize.Y )
+    {
+        return STATUS_SUCCESS;
+    }
+
+    NumCodesToWrite = min(NumCodesToWrite, (ULONG)Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y);
+
     switch (CodeType)
     {
         case CODE_ASCII:
-            Status = IntWriteConsoleOutputStringAscii(
-                Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
+        {
+            C_ASSERT(RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar) == sizeof(CHAR));
+            Status = IntWriteConsoleOutputStringChars(Console,
+                                                      Buffer,
+                                                      StringBuffer,
+                                                      FALSE,
+                                                      NumCodesToWrite,
+                                                      WriteCoord,
+                                                      NumCodesWritten);
             break;
+        }
 
         case CODE_UNICODE:
-            Status = IntWriteConsoleOutputStringUnicode(
-                Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
+        {
+            C_ASSERT(RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar) == sizeof(WCHAR));
+            Status = IntWriteConsoleOutputStringChars(Console,
+                                                      Buffer,
+                                                      StringBuffer,
+                                                      TRUE,
+                                                      NumCodesToWrite,
+                                                      WriteCoord,
+                                                      NumCodesWritten);
             break;
+        }
 
         case CODE_ATTRIBUTE:
-            Status = IntWriteConsoleOutputStringAttribute(
-                Console, Buffer, StringBuffer, NumCodesToWrite, WriteCoord, NumCodesWritten);
+        {
+            C_ASSERT(RTL_FIELD_SIZE(CODE_ELEMENT, Attribute) == sizeof(WORD));
+            Status = IntWriteConsoleOutputStringAttribute(Console,
+                                                          Buffer,
+                                                          (PWORD)StringBuffer,
+                                                          NumCodesToWrite,
+                                                          WriteCoord,
+                                                          NumCodesWritten);
             break;
+        }
 
         default:
-            Status = STATUS_INVALID_PARAMETER;
-            break;
+            return STATUS_INVALID_PARAMETER;
     }
 
     if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
     {
+        SMALL_RECT UpdateRect;
         ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
         TermDrawRegion(Console, &UpdateRect);
     }
@@ -1179,7 +1171,9 @@ ConDrvFillConsoleOutput(IN PCONSOLE Console,
                         IN PCOORD WriteCoord,
                         OUT PULONG NumCodesWritten OPTIONAL)
 {
-    ULONG X, Y, i;
+    SHORT X, Y;
+    SHORT XStart;
+    ULONG nNumChars = 0;
     PCHAR_INFO Ptr;
     BOOLEAN bLead, bFullwidth;
 
@@ -1191,11 +1185,20 @@ ConDrvFillConsoleOutput(IN PCONSOLE Console,
     /* Validity check */
     ASSERT(Console == Buffer->Header.Console);
 
-    //
-    // FIXME: Make overflow checks on WriteCoord !!!!!!
-    //
+    if (NumCodesWritten)
+        *NumCodesWritten = 0;
+
+    if (NumCodesToWrite == 0)
+        return STATUS_SUCCESS; // Nothing to do!
+
+    /* Do nothing if the writing starting point is outside of the screen buffer */
+    if ( WriteCoord->X < 0 || WriteCoord->X >= Buffer->ScreenBufferSize.X ||
+         WriteCoord->Y < 0 || WriteCoord->Y >= Buffer->ScreenBufferSize.Y )
+    {
+        return STATUS_SUCCESS;
+    }
 
-    if (NumCodesWritten) *NumCodesWritten = 0;
+    NumCodesToWrite = min(NumCodesToWrite, (ULONG)Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y);
 
     if (CodeType == CODE_ASCII)
     {
@@ -1205,85 +1208,86 @@ ConDrvFillConsoleOutput(IN PCONSOLE Console,
         Code = tmp;
     }
 
-    X = WriteCoord->X;
-    Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-    // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
-    // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
+    XStart = WriteCoord->X;
 
     /* For Chinese, Japanese and Korean */
+    X = XStart;
+    Y = WriteCoord->Y;
     bLead = TRUE;
     bFullwidth = FALSE;
     if (Console->IsCJK)
     {
-        bFullwidth = (mk_wcwidth_cjk(Code.UnicodeChar) == 2);
+        bFullwidth = IS_FULL_WIDTH(Code.UnicodeChar);
         if (X > 0)
         {
             Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
             if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
             {
                 Ptr->Char.UnicodeChar = L' ';
-                Ptr->Attributes &= ~COMMON_LVB_LEADING_BYTE;
+                Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
             }
         }
     }
 
-    for (i = 0; i < NumCodesToWrite; ++i)
+    for (Y = WriteCoord->Y; Y < Buffer->ScreenBufferSize.Y; ++Y)
     {
-        Ptr = ConioCoordToPointer(Buffer, X, Y);
-
-        switch (CodeType)
+        Ptr = ConioCoordToPointer(Buffer, XStart, Y);
+        for (X = XStart; X < Buffer->ScreenBufferSize.X; ++X)
         {
-            case CODE_ASCII:
-            case CODE_UNICODE:
-                Ptr->Char.UnicodeChar = Code.UnicodeChar;
-                Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
-                if (bFullwidth)
-                {
-                    if (bLead)
-                        Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
-                    else
-                        Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
-                }
-                break;
+            if (nNumChars >= NumCodesToWrite)
+                goto Quit;
 
-            case CODE_ATTRIBUTE:
-                Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
-                Ptr->Attributes |= (Code.Attribute & ~COMMON_LEAD_TRAIL);
-                break;
-        }
-
-        ++X;
-        if (X == Buffer->ScreenBufferSize.X)
-        {
-            X = 0;
-            ++Y;
-            if (Y == Buffer->ScreenBufferSize.Y)
+            switch (CodeType)
             {
-                Y = 0;
+                case CODE_ASCII:
+                case CODE_UNICODE:
+                    Ptr->Char.UnicodeChar = Code.UnicodeChar;
+                    Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+                    if (bFullwidth)
+                    {
+                        if (bLead)
+                            Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
+                        else
+                            Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
+                    }
+                    bLead = !bLead;
+                    break;
+
+                case CODE_ATTRIBUTE:
+                    Ptr->Attributes &= COMMON_LVB_SBCSDBCS;
+                    Ptr->Attributes |= (Code.Attribute & ~COMMON_LVB_SBCSDBCS);
+                    break;
             }
-        }
 
-        bLead = !bLead;
+            ++Ptr;
+
+            ++nNumChars;
+        }
+        /* Restart at the beginning of the next line */
+        XStart = 0;
     }
+Quit:
 
-    if ((NumCodesToWrite & 1) & bFullwidth)
+    if ((nNumChars & 1) & bFullwidth)
     {
         if (X + Y * Buffer->ScreenBufferSize.X > 0)
         {
             Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
             Ptr->Char.UnicodeChar = L' ';
-            Ptr->Attributes &= ~COMMON_LEAD_TRAIL;
+            Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
         }
     }
 
+    if (NumCodesWritten)
+        *NumCodesWritten = nNumChars;
+
     if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
     {
         SMALL_RECT UpdateRect;
-        ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, NumCodesToWrite);
+        ConioComputeUpdateRect(Buffer, &UpdateRect, WriteCoord, nNumChars);
         TermDrawRegion(Console, &UpdateRect);
     }
 
-    if (NumCodesWritten) *NumCodesWritten = NumCodesToWrite; // Written;
     return STATUS_SUCCESS;
 }
 
@@ -1338,7 +1342,7 @@ ConDrvSetConsoleTextAttribute(IN PCONSOLE Console,
     /* Validity check */
     ASSERT(Console == Buffer->Header.Console);
 
-    Buffer->ScreenDefaultAttrib = Attributes;
+    Buffer->ScreenDefaultAttrib = (Attributes & ~COMMON_LVB_SBCSDBCS);
     return STATUS_SUCCESS;
 }
 
@@ -1393,7 +1397,7 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
     ConioInitRect(&ScreenBuffer, 0, 0,
                   Buffer->ScreenBufferSize.Y - 1,
                   Buffer->ScreenBufferSize.X - 1);
-    if (!ConioGetIntersection(&SrcRegion, &ScreenBuffer, ScrollRectangle))
+    if (!ConioGetIntersection(&SrcRegion, ScrollRectangle, &ScreenBuffer))
     {
         return STATUS_SUCCESS;
     }
@@ -1433,6 +1437,8 @@ ConDrvScrollConsoleScreenBuffer(IN PCONSOLE Console,
         ConsoleOutputAnsiToUnicodeChar(Console, &tmp, &FillChar.Char.AsciiChar);
         FillChar.Char.UnicodeChar = tmp;
     }
+    /* Sanitize the attribute */
+    FillChar.Attributes &= ~COMMON_LVB_SBCSDBCS;
 
     ConioMoveRegion(Buffer, &SrcRegion, &DstRegion, &CapturedClipRectangle, FillChar);
 
index e6f0482..4d20af2 100644 (file)
@@ -510,13 +510,18 @@ ConioWriteConsole(PFRONTEND FrontEnd,
     SMALL_RECT UpdateRect;
     SHORT CursorStartX, CursorStartY;
     UINT ScrolledLines;
-    BOOL bCJK = Console->IsCJK;
+    BOOLEAN bFullwidth;
+    BOOLEAN bCJK = Console->IsCJK;
+
+    /* If nothing to write, bail out now */
+    if (Length == 0)
+        return STATUS_SUCCESS;
 
     CursorStartX = Buff->CursorPosition.X;
     CursorStartY = Buff->CursorPosition.Y;
     UpdateRect.Left = Buff->ScreenBufferSize.X;
-    UpdateRect.Top = Buff->CursorPosition.Y;
-    UpdateRect.Right = -1;
+    UpdateRect.Top  = Buff->CursorPosition.Y;
+    UpdateRect.Right  = -1;
     UpdateRect.Bottom = Buff->CursorPosition.Y;
     ScrolledLines = 0;
 
@@ -532,28 +537,58 @@ ConioWriteConsole(PFRONTEND FrontEnd,
             if (Buffer[i] == L'\r')
             {
                 Buff->CursorPosition.X = 0;
-                UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
+                CursorStartX = Buff->CursorPosition.X;
+                UpdateRect.Left  = min(UpdateRect.Left , Buff->CursorPosition.X);
                 UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
                 continue;
             }
             /* --- LF --- */
             else if (Buffer[i] == L'\n')
             {
-                Buff->CursorPosition.X = 0;
+                Buff->CursorPosition.X = 0; // TODO: Make this behaviour optional!
+                CursorStartX = Buff->CursorPosition.X;
                 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
                 continue;
             }
             /* --- BS --- */
             else if (Buffer[i] == L'\b')
             {
-                /* Only handle BS if we're not on the first pos of the first line */
-                if (0 != Buff->CursorPosition.X || 0 != Buff->CursorPosition.Y)
+                /* Only handle BS if we are not on the first position of the first line */
+                if (Buff->CursorPosition.X == 0 && Buff->CursorPosition.Y == 0)
+                    continue;
+
+                if (Buff->CursorPosition.X == 0)
+                {
+                    /* Slide virtual position up */
+                    Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
+                    Buff->CursorPosition.Y--;
+                    // TODO? : Update CursorStartY = Buff->CursorPosition.Y;
+                    UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
+                }
+                else
                 {
-                    if (0 == Buff->CursorPosition.X)
+                    Buff->CursorPosition.X--;
+                }
+                Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+
+                if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
+                {
+                    /*
+                     * The cursor just moved on the leading byte of the same
+                     * current character. We should go one position before to
+                     * go to the actual previous character to erase.
+                     */
+
+                    /* Only handle BS if we are not on the first position of the first line */
+                    if (Buff->CursorPosition.X == 0 && Buff->CursorPosition.Y == 0)
+                        continue;
+
+                    if (Buff->CursorPosition.X == 0)
                     {
-                        /* slide virtual position up */
+                        /* Slide virtual position up */
                         Buff->CursorPosition.X = Buff->ScreenBufferSize.X - 1;
                         Buff->CursorPosition.Y--;
+                        // TODO? : Update CursorStartY = Buff->CursorPosition.Y;
                         UpdateRect.Top = min(UpdateRect.Top, Buff->CursorPosition.Y);
                     }
                     else
@@ -561,22 +596,31 @@ ConioWriteConsole(PFRONTEND FrontEnd,
                         Buff->CursorPosition.X--;
                     }
                     Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
-                    Ptr->Char.UnicodeChar = L' ';
+                }
 
-                    if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
-                    {
-                        /* Delete a full-width character */
-                        Ptr->Attributes  = Buff->ScreenDefaultAttrib;
-                        if (Buff->CursorPosition.X > 0)
-                            Buff->CursorPosition.X--;
-                        Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
-                        Ptr->Char.UnicodeChar = L' ';
-                    }
+                if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+                {
+                    /* The cursor is on the trailing byte of a full-width character */
 
-                    Ptr->Attributes  = Buff->ScreenDefaultAttrib;
-                    UpdateRect.Left  = min(UpdateRect.Left, Buff->CursorPosition.X);
-                    UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
+                    /* Delete its trailing byte... */
+                    Ptr->Char.UnicodeChar = L' ';
+                    if (Attrib)
+                        Ptr->Attributes = Buff->ScreenDefaultAttrib;
+                    Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+
+                    if (Buff->CursorPosition.X > 0)
+                        Buff->CursorPosition.X--;
+                    /* ... and now its leading byte */
+                    Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
                 }
+
+                Ptr->Char.UnicodeChar = L' ';
+                if (Attrib)
+                    Ptr->Attributes = Buff->ScreenDefaultAttrib;
+                Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+
+                UpdateRect.Left  = min(UpdateRect.Left , Buff->CursorPosition.X);
+                UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
                 continue;
             }
             /* --- TAB --- */
@@ -584,28 +628,60 @@ ConioWriteConsole(PFRONTEND FrontEnd,
             {
                 UINT EndX;
 
+                Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+
+                if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+                {
+                    /*
+                     * The cursor is on the trailing byte of a full-width character.
+                     * Go back one position to be on its leading byte.
+                     */
+                    if (Buff->CursorPosition.X > 0)
+                        Buff->CursorPosition.X--;
+                    Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+                }
+
                 UpdateRect.Left = min(UpdateRect.Left, Buff->CursorPosition.X);
+
                 EndX = (Buff->CursorPosition.X + TAB_WIDTH) & ~(TAB_WIDTH - 1);
                 EndX = min(EndX, (UINT)Buff->ScreenBufferSize.X);
-                Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+
                 while ((UINT)Buff->CursorPosition.X < EndX)
                 {
                     Ptr->Char.UnicodeChar = L' ';
-                    Ptr->Attributes = Buff->ScreenDefaultAttrib;
+                    if (Attrib)
+                        Ptr->Attributes = Buff->ScreenDefaultAttrib;
+                    Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+
                     ++Ptr;
                     Buff->CursorPosition.X++;
                 }
-                UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X - 1);
-                if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
+                if (Buff->CursorPosition.X < Buff->ScreenBufferSize.X)
+                {
+                    /* If the following cell is the trailing byte of a full-width character, reset it */
+                    if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+                    {
+                        Ptr->Char.UnicodeChar = L' ';
+                        if (Attrib)
+                            Ptr->Attributes = Buff->ScreenDefaultAttrib;
+                        Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+                    }
+                }
+                UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
+
+                if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X)
                 {
                     if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
                     {
+                        /* Wrapping mode: Go to next line */
                         Buff->CursorPosition.X = 0;
+                        CursorStartX = Buff->CursorPosition.X;
                         ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
                     }
                     else
                     {
-                        Buff->CursorPosition.X--;
+                        /* The cursor wraps back to its starting position on the same line */
+                        Buff->CursorPosition.X = CursorStartX;
                     }
                 }
                 continue;
@@ -617,87 +693,129 @@ ConioWriteConsole(PFRONTEND FrontEnd,
                 continue;
             }
         }
-        UpdateRect.Left  = min(UpdateRect.Left, Buff->CursorPosition.X);
+        UpdateRect.Left  = min(UpdateRect.Left , Buff->CursorPosition.X);
         UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
 
         /* For Chinese, Japanese and Korean */
-        if (bCJK && Buffer[i] >= 0x80 && mk_wcwidth_cjk(Buffer[i]) == 2)
-        {
-            /* Buffer[i] is a fullwidth character */
+        bFullwidth = (bCJK && IS_FULL_WIDTH(Buffer[i]));
 
-            if (Buff->CursorPosition.X > 0)
-            {
-                /* Kill the previous leading byte */
-                Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X - 1, Buff->CursorPosition.Y);
-                if (Ptr->Attributes & COMMON_LVB_LEADING_BYTE)
-                {
-                    Ptr->Char.UnicodeChar = L' ';
-                    if (Attrib)
-                        Ptr->Attributes &= ~COMMON_LVB_LEADING_BYTE;
-                }
-            }
-
-            if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X - 1)
+        /* Check whether we can insert the full-width character */
+        if (bFullwidth)
+        {
+            /* It spans two cells and should all fit on the current line */
+            if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X - 1)
             {
-                /* New line */
                 if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
                 {
+                    /* Wrapping mode: Go to next line */
                     Buff->CursorPosition.X = 0;
+                    CursorStartX = Buff->CursorPosition.X;
                     ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
                 }
                 else
                 {
+                    /* The cursor wraps back to its starting position on the same line */
                     Buff->CursorPosition.X = CursorStartX;
                 }
             }
 
-            /* Set leading */
+            /*
+             * Now be sure we can fit the full-width character.
+             * If the screenbuffer is one cell wide we cannot display
+             * the full-width character, so just skip it.
+             */
+            if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X - 1)
+            {
+                DPRINT1("Cannot display full-width character! CursorPosition.X = %d, ScreenBufferSize.X = %d\n",
+                        Buff->CursorPosition.X, Buff->ScreenBufferSize.X);
+                continue;
+            }
+        }
+
+        Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+
+        /*
+         * Check whether we are overwriting part of a full-width character,
+         * in which case we need to invalidate it.
+         */
+        if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+        {
+            /*
+             * The cursor is on the trailing byte of a full-width character.
+             * Go back one position to kill the previous leading byte.
+             */
+            if (Buff->CursorPosition.X > 0)
+            {
+                Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X - 1, Buff->CursorPosition.Y);
+                Ptr->Char.UnicodeChar = L' ';
+                if (Attrib)
+                    Ptr->Attributes = Buff->ScreenDefaultAttrib;
+                Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+            }
             Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+        }
+
+        /* Insert the character */
+        if (bFullwidth)
+        {
+            ASSERT(Buff->CursorPosition.X < Buff->ScreenBufferSize.X - 1);
+
+            /* Set the leading byte */
             Ptr->Char.UnicodeChar = Buffer[i];
             if (Attrib)
-                Ptr->Attributes = Buff->ScreenDefaultAttrib | COMMON_LVB_LEADING_BYTE;
+                Ptr->Attributes = Buff->ScreenDefaultAttrib;
+            Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+            Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
 
-            /* Set trailing */
+            /* Set the trailing byte */
             Buff->CursorPosition.X++;
             Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+            // Ptr->Char.UnicodeChar = Buffer[i]; // L' ';
             if (Attrib)
-                Ptr->Attributes = Buff->ScreenDefaultAttrib | COMMON_LVB_TRAILING_BYTE;
+                Ptr->Attributes = Buff->ScreenDefaultAttrib;
+            Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+            Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
         }
         else
         {
-            Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
             Ptr->Char.UnicodeChar = Buffer[i];
             if (Attrib)
                 Ptr->Attributes = Buff->ScreenDefaultAttrib;
+            Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
         }
 
+        ++Ptr;
         Buff->CursorPosition.X++;
-        if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
+
+        if (Buff->CursorPosition.X < Buff->ScreenBufferSize.X)
+        {
+            /* If the following cell is the trailing byte of a full-width character, reset it */
+            if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
+            {
+                Ptr->Char.UnicodeChar = L' ';
+                if (Attrib)
+                    Ptr->Attributes = Buff->ScreenDefaultAttrib;
+                Ptr->Attributes &= ~COMMON_LVB_SBCSDBCS;
+            }
+        }
+
+        if (Buff->CursorPosition.X >= Buff->ScreenBufferSize.X)
         {
             if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
             {
+                /* Wrapping mode: Go to next line */
                 Buff->CursorPosition.X = 0;
+                CursorStartX = Buff->CursorPosition.X;
                 ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
             }
             else
             {
+                /* The cursor wraps back to its starting position on the same line */
                 Buff->CursorPosition.X = CursorStartX;
             }
         }
     }
 
-    if (bCJK && Buff->CursorPosition.X > 0)
-    {
-        /* Delete trailing */
-        Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
-        if (Ptr->Attributes & COMMON_LVB_TRAILING_BYTE)
-        {
-            Ptr->Char.UnicodeChar = L' ';
-            if (Attrib)
-                Ptr->Attributes = Buff->ScreenDefaultAttrib;
-        }
-    }
-
     if (!ConioIsRectEmpty(&UpdateRect) && (PCONSOLE_SCREEN_BUFFER)Buff == Console->ActiveBuffer)
     {
         // TermWriteStream(Console, &UpdateRect, CursorStartX, CursorStartY,
index ad1b226..87f22a7 100644 (file)
@@ -372,4 +372,9 @@ NTSTATUS ConioResizeBuffer(PCONSOLE /*PCONSRV_CONSOLE*/ Console,
 /* wcwidth.c */
 int mk_wcwidth_cjk(wchar_t ucs);
 
+// NOTE: The check against 0x80 is to avoid calling the helper function
+// for characters that we already know are not full-width.
+#define IS_FULL_WIDTH(wch)  \
+    (((USHORT)(wch) >= 0x0080) && (mk_wcwidth_cjk(wch) == 2))
+
 /* EOF */
index 46d3af5..665813f 100644 (file)
@@ -58,9 +58,9 @@ DrawBox(PTEXTMODE_SCREEN_BUFFER Buffer,
 
     /* Set screen attributes */
     coPos.X = xLeft;
+    Code.Attribute = Buffer->PopupDefaultAttrib;
     for (coPos.Y = yTop; coPos.Y < yTop + Height; coPos.Y++)
     {
-        Code.Attribute = Buffer->PopupDefaultAttrib;
         ConDrvFillConsoleOutput(Buffer->Header.Console,
                                 Buffer,
                                 CODE_ATTRIBUTE,