[WIN32SS][WINSRV] Fullwidth character handling for Asian console (#2231)
authorKatayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
Tue, 7 Jan 2020 06:26:58 +0000 (15:26 +0900)
committerGitHub <noreply@github.com>
Tue, 7 Jan 2020 06:26:58 +0000 (15:26 +0900)
Far-East Asian language (Chinese, Japanese and Korean; CJK) needs special handling in console.
Especially a fullwidth character (mk_wcwidth_cjk(ch) == 2) needs a double width space. A fullwidth character on the console window is treated as a pair of a leading byte and a trailing byte (COMMON_LVB_LEADING_BYTE and COMMON_LVB_TRAILING_BYTE). CORE-12451

win32ss/user/winsrv/consrv/condrv/console.c
win32ss/user/winsrv/consrv/condrv/text.c
win32ss/user/winsrv/consrv/frontends/gui/conwnd.c
win32ss/user/winsrv/consrv/frontends/gui/guiterm.h
win32ss/user/winsrv/consrv/frontends/gui/text.c
win32ss/user/winsrv/consrv/frontends/terminal.c
win32ss/user/winsrv/consrv/include/conio.h
win32ss/user/winsrv/consrv/settings.c

index d088f31..f888b75 100644 (file)
@@ -6,18 +6,18 @@
  * PROGRAMMERS:     Gé van Geldorp
  *                  Jeffrey Morlan
  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
+ *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
  */
 
 /* INCLUDES *******************************************************************/
 
 #include <consrv.h>
-
 #include <coninput.h>
+#include "../../concfg/font.h"
 
 #define NDEBUG
 #include <debug.h>
 
-
 /* GLOBALS ********************************************************************/
 
 static ULONG CurrentConsoleID = 0;
@@ -220,6 +220,8 @@ ConDrvInitConsole(OUT PCONSOLE* NewConsole,
     if (IsValidCodePage(ConsoleInfo->CodePage))
         Console->InputCodePage = Console->OutputCodePage = ConsoleInfo->CodePage;
 
+    Console->IsCJK = IsCJKCodePage(Console->OutputCodePage);
+
     /* Initialize a new text-mode screen buffer with default settings */
     ScreenBufferInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize;
     ScreenBufferInfo.ScreenAttrib     = ConsoleInfo->ScreenAttrib;
@@ -531,9 +533,14 @@ ConDrvSetConsoleCP(IN PCONSOLE Console,
         return STATUS_INVALID_PARAMETER;
 
     if (OutputCP)
+    {
         Console->OutputCodePage = CodePage;
+        Console->IsCJK = IsCJKCodePage(CodePage);
+    }
     else
+    {
         Console->InputCodePage = CodePage;
+    }
 
     return STATUS_SUCCESS;
 }
index 5b4d415..de0c740 100644 (file)
@@ -408,13 +408,9 @@ ConDrvChangeScreenBufferAttributes(IN PCONSOLE Console,
     Y = (TopLeft.Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
     Length = NumCodesToWrite;
 
-    // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
-    // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
-
     while (Length--)
     {
-        // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
-        Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
+        Ptr = ConioCoordToPointer(Buffer, X, Y);
 
         /*
          * Change the current colors only if they are the old ones.
@@ -516,7 +512,8 @@ ConDrvReadConsoleOutput(IN PCONSOLE Console,
                 WideCharToMultiByte(Console->OutputCodePage, 0, &Ptr->Char.UnicodeChar, 1,
                                     &CurCharInfo->Char.AsciiChar, 1, NULL, NULL);
             }
-            CurCharInfo->Attributes = Ptr->Attributes;
+            CurCharInfo->Attributes =
+                (Ptr->Attributes & ~(COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE));
             ++Ptr;
             ++CurCharInfo;
         }
@@ -723,102 +720,147 @@ ConDrvWriteConsole(IN PCONSOLE Console,
     return Status;
 }
 
-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 PCOORD EndCoord,
-                              OUT PULONG NumCodesRead OPTIONAL)
+NTSTATUS FASTCALL
+IntReadConsoleOutputStringAscii(IN PCONSOLE Console,
+                                IN PTEXTMODE_SCREEN_BUFFER Buffer,
+                                OUT PVOID StringBuffer,
+                                IN ULONG NumCodesToRead,
+                                IN PCOORD ReadCoord,
+                                OUT PULONG NumCodesRead OPTIONAL)
 {
-    SHORT Xpos, Ypos;
-    PVOID ReadBuffer;
+    ULONG CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
+    LPBYTE ReadBuffer = StringBuffer;
+    SHORT Xpos = ReadCoord->X;
+    SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
     ULONG i;
-    ULONG CodeSize;
     PCHAR_INFO Ptr;
+    BOOL bCJK = Console->IsCJK;
 
-    if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
+    for (i = 0; i < NumCodesToRead; ++i)
     {
-        return STATUS_INVALID_PARAMETER;
+        Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
+
+        ConsoleOutputUnicodeToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
+        ReadBuffer += CodeSize;
+
+        Xpos++;
+        if (Xpos == Buffer->ScreenBufferSize.X)
+        {
+            Xpos = 0;
+            Ypos++;
+            if (Ypos == Buffer->ScreenBufferSize.Y)
+            {
+                Ypos = 0;
+            }
+        }
+
+        /* 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;
+        }
     }
 
-    /* Validity checks */
-    ASSERT(Console == Buffer->Header.Console);
-    ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
+    if (NumCodesRead)
+        *NumCodesRead = i;
 
-    //
-    // FIXME: Make overflow checks on ReadCoord !!!!!!
-    //
+    return STATUS_SUCCESS;
+}
 
-    if (NumCodesRead) *NumCodesRead = 0;
+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;
+    BOOL bCJK = Console->IsCJK;
 
-    switch (CodeType)
+    for (i = 0; i < NumCodesToRead; ++i, ++nNumChars)
     {
-        case CODE_ASCII:
-            CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, AsciiChar);
-            break;
+        Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
 
-        case CODE_UNICODE:
-            CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, UnicodeChar);
-            break;
+        *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
+        ReadBuffer += CodeSize;
 
-        case CODE_ATTRIBUTE:
-            CodeSize = RTL_FIELD_SIZE(CODE_ELEMENT, Attribute);
-            break;
+        Xpos++;
+        if (Xpos == Buffer->ScreenBufferSize.X)
+        {
+            Xpos = 0;
+            Ypos++;
+            if (Ypos == Buffer->ScreenBufferSize.Y)
+            {
+                Ypos = 0;
+            }
+        }
 
-        default:
-            return STATUS_INVALID_PARAMETER;
+        /* 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 = StringBuffer;
-    Xpos = ReadCoord->X;
-    Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
+    if (NumCodesRead)
+        *NumCodesRead = nNumChars;
 
-    /*
-     * MSDN (ReadConsoleOutputAttribute and ReadConsoleOutputCharacter) :
-     *
-     * If the number of attributes (resp. characters) to be read from extends
-     * beyond the end of the specified screen buffer row, attributes (resp.
-     * characters) are read from the next row. If the number of attributes
-     * (resp. characters) to be read from extends beyond the end of the console
-     * screen buffer, attributes (resp. characters) up to the end of the console
-     * screen buffer are read.
-     *
-     * TODO: Do NOT loop up to NumCodesToRead, but stop before
-     * if we are going to overflow...
-     */
-    // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work
-    for (i = 0; i < min(NumCodesToRead, (ULONG)Buffer->ScreenBufferSize.X * Buffer->ScreenBufferSize.Y); ++i)
-    {
-        // Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos); // Doesn't work either
-        Ptr = &Buffer->Buffer[Xpos + Ypos * Buffer->ScreenBufferSize.X];
+    return STATUS_SUCCESS;
+}
 
-        switch (CodeType)
-        {
-            case CODE_ASCII:
-                ConsoleOutputUnicodeToAnsiChar(Console, (PCHAR)ReadBuffer, &Ptr->Char.UnicodeChar);
-                break;
+NTSTATUS FASTCALL
+IntReadConsoleOutputStringAttributes(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, Attribute);
+    LPBYTE ReadBuffer = StringBuffer;
+    SHORT Xpos = ReadCoord->X;
+    SHORT Ypos = (ReadCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
+    ULONG i;
+    PCHAR_INFO Ptr;
 
-            case CODE_UNICODE:
-                *(PWCHAR)ReadBuffer = Ptr->Char.UnicodeChar;
-                break;
+    for (i = 0; i < NumCodesToRead; ++i)
+    {
+        Ptr = ConioCoordToPointer(Buffer, Xpos, Ypos);
 
-            case CODE_ATTRIBUTE:
-                *(PWORD)ReadBuffer = Ptr->Attributes;
-                break;
-        }
-        ReadBuffer = (PVOID)((ULONG_PTR)ReadBuffer + CodeSize);
-        // ++Ptr;
+        *(PWORD)ReadBuffer = Ptr->Attributes;
+        ReadBuffer += CodeSize;
 
         Xpos++;
-
         if (Xpos == Buffer->ScreenBufferSize.X)
         {
             Xpos = 0;
             Ypos++;
-
             if (Ypos == Buffer->ScreenBufferSize.Y)
             {
                 Ypos = 0;
@@ -826,16 +868,70 @@ ConDrvReadConsoleOutputString(IN PCONSOLE Console,
         }
     }
 
-    // EndCoord->X = Xpos;
-    // EndCoord->Y = (Ypos - Buffer->VirtualY + Buffer->ScreenBufferSize.Y) % Buffer->ScreenBufferSize.Y;
+    if (Xpos > 0 && Console->IsCJK)
+    {
+        ReadBuffer -= CodeSize;
+        *(PWORD)ReadBuffer &= ~COMMON_LVB_LEADING_BYTE;
+    }
 
     if (NumCodesRead)
-        *NumCodesRead = (ULONG)((ULONG_PTR)ReadBuffer - (ULONG_PTR)StringBuffer) / CodeSize;
-    // <= NumCodesToRead
+        *NumCodesRead = NumCodesToRead;
 
     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)
+{
+    if (Console == NULL || Buffer == NULL || ReadCoord == NULL /* || EndCoord == NULL */)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Validity checks */
+    ASSERT(Console == Buffer->Header.Console);
+    ASSERT((StringBuffer != NULL) || (StringBuffer == NULL && NumCodesToRead == 0));
+
+    if (NumCodesRead)
+        *NumCodesRead = 0;
+
+    switch (CodeType)
+    {
+        case CODE_ASCII:
+            return IntReadConsoleOutputStringAscii(Console,
+                                                   Buffer,
+                                                   StringBuffer,
+                                                   NumCodesToRead,
+                                                   ReadCoord,
+                                                   NumCodesRead);
+
+        case CODE_UNICODE:
+            return IntReadConsoleOutputStringUnicode(Console,
+                                                     Buffer,
+                                                     StringBuffer,
+                                                     NumCodesToRead,
+                                                     ReadCoord,
+                                                     NumCodesRead);
+
+        case CODE_ATTRIBUTE:
+            return IntReadConsoleOutputStringAttributes(Console,
+                                                        Buffer,
+                                                        StringBuffer,
+                                                        NumCodesToRead,
+                                                        ReadCoord,
+                                                        NumCodesRead);
+
+        default:
+            return STATUS_INVALID_PARAMETER;
+    }
+}
+
 NTSTATUS NTAPI
 ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
                                IN PTEXTMODE_SCREEN_BUFFER Buffer,
@@ -923,13 +1019,10 @@ ConDrvWriteConsoleOutputString(IN PCONSOLE Console,
     X = WriteCoord->X;
     Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
     Length = NumCodesToWrite;
-    // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
-    // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
 
     while (Length--)
     {
-        // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
-        Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
+        Ptr = ConioCoordToPointer(Buffer, X, Y);
 
         switch (CodeType)
         {
@@ -983,8 +1076,9 @@ ConDrvFillConsoleOutput(IN PCONSOLE Console,
                         IN PCOORD WriteCoord,
                         OUT PULONG NumCodesWritten OPTIONAL)
 {
-    ULONG X, Y, Length; // , Written = 0;
+    ULONG X, Y, i;
     PCHAR_INFO Ptr;
+    BOOL bLead, bFullwidth;
 
     if (Console == NULL || Buffer == NULL || WriteCoord == NULL)
     {
@@ -1010,24 +1104,48 @@ ConDrvFillConsoleOutput(IN PCONSOLE Console,
 
     X = WriteCoord->X;
     Y = (WriteCoord->Y + Buffer->VirtualY) % Buffer->ScreenBufferSize.Y;
-    Length = NumCodesToWrite;
     // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work
     // Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X]; // May work
 
-    while (Length--)
+    /* For Chinese, Japanese and Korean */
+    bLead = TRUE;
+    bFullwidth = FALSE;
+    if (Console->IsCJK)
     {
-        // Ptr = ConioCoordToPointer(Buffer, X, Y); // Doesn't work either
-        Ptr = &Buffer->Buffer[X + Y * Buffer->ScreenBufferSize.X];
+        bFullwidth = (mk_wcwidth_cjk(Code.UnicodeChar) == 2);
+        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;
+            }
+        }
+    }
+
+    for (i = 0; i < NumCodesToWrite; ++i)
+    {
+        Ptr = ConioCoordToPointer(Buffer, X, Y);
 
         switch (CodeType)
         {
             case CODE_ASCII:
             case CODE_UNICODE:
                 Ptr->Char.UnicodeChar = Code.UnicodeChar;
+                Ptr->Attributes &= ~(COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE);
+                if (bFullwidth)
+                {
+                    if (bLead)
+                        Ptr->Attributes |= COMMON_LVB_LEADING_BYTE;
+                    else
+                        Ptr->Attributes |= COMMON_LVB_TRAILING_BYTE;
+                }
                 break;
 
             case CODE_ATTRIBUTE:
-                Ptr->Attributes = Code.Attribute;
+                Ptr->Attributes &= ~0xFF;
+                Ptr->Attributes |= (Code.Attribute & 0xFF);
                 break;
         }
         // ++Ptr;
@@ -1042,6 +1160,18 @@ ConDrvFillConsoleOutput(IN PCONSOLE Console,
                 Y = 0;
             }
         }
+
+        bLead = !bLead;
+    }
+
+    if ((NumCodesToWrite & 1) & bFullwidth)
+    {
+        if (X + Y * Buffer->ScreenBufferSize.X > 0)
+        {
+            Ptr = ConioCoordToPointer(Buffer, X - 1, Y);
+            Ptr->Char.UnicodeChar = L' ';
+            Ptr->Attributes &= ~(COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE);
+        }
     }
 
     if ((PCONSOLE_SCREEN_BUFFER)Buffer == Console->ActiveBuffer)
index b785920..eda0e82 100644 (file)
@@ -993,7 +993,7 @@ OnPaint(PGUI_CONSOLE_DATA GuiData)
         {
             if (IsCJKCodePage(ActiveBuffer->Header.Console->OutputCodePage))
             {
-                /* For Chinese, Japanese and Korean: */
+                /* For Chinese, Japanese and Korean */
                 GuiPaintTextModeBufferCJK((PTEXTMODE_SCREEN_BUFFER)ActiveBuffer,
                                           GuiData, &ps.rcPaint, &rcPaint);
             }
index bd28b2b..2e4a6df 100644 (file)
@@ -121,7 +121,7 @@ GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
                        PRECT rcView,
                        PRECT rcFramebuffer);
 
-/* For Chinese, Japanese and Korean: */
+/* For Chinese, Japanese and Korean */
 VOID
 GuiPaintTextModeBufferCJK(PTEXTMODE_SCREEN_BUFFER Buffer,
                           PGUI_CONSOLE_DATA GuiData,
index 2b62c3d..8b12645 100644 (file)
@@ -494,7 +494,7 @@ GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
     LeaveCriticalSection(&Console->Lock);
 }
 
-/* For Chinese, Japanese and Korean: */
+/* For Chinese, Japanese and Korean */
 VOID
 GuiPaintTextModeBufferCJK(PTEXTMODE_SCREEN_BUFFER Buffer,
                           PGUI_CONSOLE_DATA GuiData,
index c4ca197..6603d84 100644 (file)
@@ -492,8 +492,6 @@ ConioNextLine(PTEXTMODE_SCREEN_BUFFER Buff, PSMALL_RECT UpdateRect, PUINT Scroll
     UpdateRect->Bottom = Buff->CursorPosition.Y;
 }
 
-int mk_wcwidth_cjk(wchar_t ucs);
-
 static NTSTATUS
 ConioWriteConsole(PFRONTEND FrontEnd,
                   PTEXTMODE_SCREEN_BUFFER Buff,
@@ -508,7 +506,7 @@ ConioWriteConsole(PFRONTEND FrontEnd,
     SMALL_RECT UpdateRect;
     SHORT CursorStartX, CursorStartY;
     UINT ScrolledLines;
-    BOOL bCJK = IsCJKCodePage(Console->OutputCodePage);
+    BOOL bCJK = Console->IsCJK;
 
     CursorStartX = Buff->CursorPosition.X;
     CursorStartY = Buff->CursorPosition.Y;
@@ -607,16 +605,56 @@ ConioWriteConsole(PFRONTEND FrontEnd,
         UpdateRect.Left  = min(UpdateRect.Left, Buff->CursorPosition.X);
         UpdateRect.Right = max(UpdateRect.Right, Buff->CursorPosition.X);
 
-        Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
-
+        /* For Chinese, Japanese and Korean */
         if (bCJK && Buffer[i] >= 0x80 && mk_wcwidth_cjk(Buffer[i]) == 2)
         {
             /* Buffer[i] is a fullwidth character */
-            /* FIXME */
-        }
 
-        Ptr->Char.UnicodeChar = Buffer[i];
-        if (Attrib) Ptr->Attributes = Buff->ScreenDefaultAttrib;
+            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)
+            {
+                /* New line */
+                if (Buff->Mode & ENABLE_WRAP_AT_EOL_OUTPUT)
+                {
+                    Buff->CursorPosition.X = 0;
+                    ConioNextLine(Buff, &UpdateRect, &ScrolledLines);
+                }
+                else
+                {
+                    Buff->CursorPosition.X = CursorStartX;
+                }
+            }
+
+            /* Set leading */
+            Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+            Ptr->Char.UnicodeChar = Buffer[i];
+            if (Attrib)
+                Ptr->Attributes = Buff->ScreenDefaultAttrib | COMMON_LVB_LEADING_BYTE;
+
+            /* Set trailing */
+            Buff->CursorPosition.X++;
+            Ptr = ConioCoordToPointer(Buff, Buff->CursorPosition.X, Buff->CursorPosition.Y);
+            if (Attrib)
+                Ptr->Attributes = Buff->ScreenDefaultAttrib | 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;
+        }
 
         Buff->CursorPosition.X++;
         if (Buff->CursorPosition.X == Buff->ScreenBufferSize.X)
@@ -633,6 +671,18 @@ ConioWriteConsole(PFRONTEND FrontEnd,
         }
     }
 
+    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 3e7f96d..ad1b226 100644 (file)
@@ -345,7 +345,7 @@ typedef struct _CONSOLE
 /****************************** Other properties ******************************/
     COORD   ConsoleSize;                    /* The current size of the console, for text-mode only */
     BOOLEAN FixedSize;                      /* TRUE if the console is of fixed size */
-
+    BOOLEAN IsCJK;                          /* TRUE if Chinese, Japanese or Korean (CJK) */
 } CONSOLE; // , *PCONSOLE;
 
 /* console.c */
@@ -369,4 +369,7 @@ NTSTATUS ConioResizeBuffer(PCONSOLE /*PCONSRV_CONSOLE*/ Console,
                            PTEXTMODE_SCREEN_BUFFER ScreenBuffer,
                            COORD Size);
 
+/* wcwidth.c */
+int mk_wcwidth_cjk(wchar_t ucs);
+
 /* EOF */
index 1cfd4d3..879c152 100644 (file)
@@ -10,6 +10,7 @@
 /* INCLUDES *******************************************************************/
 
 #include "consrv.h"
+#include "../concfg/font.h"
 
 #define NDEBUG
 #include <debug.h>
@@ -59,6 +60,8 @@ ConSrvApplyUserSettings(IN PCONSOLE Console,
         Console->InputCodePage = Console->OutputCodePage = ConsoleInfo->CodePage;
         // ConDrvSetConsoleCP(Console, ConsoleInfo->CodePage, TRUE);    // Output
         // ConDrvSetConsoleCP(Console, ConsoleInfo->CodePage, FALSE);   // Input
+
+        Console->IsCJK = IsCJKCodePage(Console->OutputCodePage);
     }
 
     // FIXME: Check ConsoleInfo->WindowSize with respect to