//Copyright (c) Microsoft Corporation.  All rights reserved.
#include <windows.h>                    //required for all Windows applications 
#pragma warning (disable: 4201)			// disable "nonstandard extension used : nameless struct/union"
#include <commdlg.h>
#pragma warning (default: 4201)
#include <stdlib.h>
#include <stdio.h>

#include <ctype.h>
#include <string.h>

#pragma warning( disable: 4100 )
#pragma warning( disable: 4244 )

#include <imm.h>

#include "WinTel.h"                     // specific to this program 
#include "debug.h"
#include "trmio.h"
#include "vtnt.h"

static UCHAR pchNBBuffer[ READ_BUF_SZ ];
static void NewLineUp(WI *, TRM *);
static void NewLine(WI *pwi, TRM *);
static void SetBufferStart(TRM *);
static BOOL FAddTabToBuffer( TRM *, DWORD );
static BOOL FAddCharToBuffer(TRM *, UCHAR);
static void FlushBuffer(WI *pwi, TRM *);
static void CursorUp(TRM *);
static void CursorDown(TRM *);
static void CursorRight(TRM *);
static void CursorLeft(TRM *);
static void ClearLine(WI *pwi, TRM *, DWORD);
static void SetMargins(TRM *, DWORD, DWORD);

//For eg: home key: ^[[2~. 'x' needs replacement for each particular key
static CHAR szVt302KeySequence[] = { 0x1B, '[', 'x', '~', 0 }; 
static CHAR szVt302LongKeySequence[] = { 0x1B, '[', 'x', 'x', '~', 0 }; 
static CHAR szVt302ShortKeySequence[] = { 0x1B, '[', 'x', 0 }; 

UCHAR uchOutPrev = 0;
UCHAR uchInPrev = 0;

#define IsEUCCode(uch)  (((uch) > 0xa0) ? TRUE : FALSE)
#define IsKatakana(uch) (((uch) > 0xa0) ? ((uch < 0xe0) ? TRUE : FALSE) : FALSE)

void jistosjis( UCHAR *, UCHAR *);
void euctosjis( UCHAR *, UCHAR *);
void sjistojis( UCHAR *, UCHAR *);
void sjistoeuc( UCHAR *, UCHAR *);
//void DBCSTextOut( HDC, int, int, LPCSTR, int, int);
void ForceJISRomanSend( WI *);

VOID SetImeWindow(TRM *ptrm);
void PrepareForNAWS( );
void DoNawsSubNegotiation( WI * );

extern POINT ptWindowMaxSize;

#define MAX_TABSTOPS 100         //Max tabstops

extern WI gwi;
SMALL_RECT srOldClientWindow = { 0, 0, 0, 0 };
CONSOLE_SCREEN_BUFFER_INFO consoleBufferInfo;
DWORD g_rgdwHTS[ MAX_TABSTOPS ];  //Array of tab stops
WORD g_iHTS = 0;                  //Index in to the tab stops array
WORD wSaveCurrentLine = 0;

static BOOL g_bIsToBeLogged = FALSE;

void WriteCharInfoToLog( CHAR_INFO pCharInfo[], COORD coSize )
{
   WORD  wRows    = 0;
   
   while( wRows < coSize.Y )
   {
       DWORD nBytes   = 0;
       DWORD length   = 0;
       UCHAR *pcTmp   = NULL;
       WORD  wSrc     = 0;
       WORD  wDst     = 0;
       
       while( wSrc < coSize.X )
       {           
           DWORD dwSize = 0;

           dwSize = WideCharToMultiByte( GetConsoleCP(), 0, 
                        &( ( *( pCharInfo + wRows * coSize.X + wSrc ) ).Char.UnicodeChar ),
                        1, NULL, 0, NULL, NULL );

           if( !WideCharToMultiByte( GetConsoleCP(), 0, 
                &( ( *( pCharInfo + wRows * coSize.X + wSrc ) ).Char.UnicodeChar ),
                1, ( PCHAR ) ( g_rgchRow+wDst ), dwSize, NULL, NULL ) )
           {
                g_rgchRow[ wDst++ ] = 
                    ( *( pCharInfo + wRows * coSize.X + wSrc ) ).Char.AsciiChar;
	            wSrc++;
           }
           else
           {
                wDst += ( WORD )dwSize;
                if( (*(pCharInfo + wRows * coSize.X + wSrc )).Attributes & COMMON_LVB_LEADING_BYTE )
                {
                    ++wSrc;
                }
                wSrc++ ; 
           }
           
       }

       pcTmp = g_rgchRow + ( coSize.X  - 1 );

       //
       //   Find the last non space character in the string.
       //
       while ( pcTmp != g_rgchRow && *pcTmp == ' ' )
       {
          pcTmp -= 1;
       }

       length = (DWORD)( pcTmp - g_rgchRow ) + 1;

       WriteFile(ui.hLogFile, g_rgchRow, length, &nBytes, NULL);

       WriteFile(ui.hLogFile, ( PUCHAR )szNewLine, strlen( ( const char * ) szNewLine), &nBytes, NULL);
       wRows++ ;
   }
}

void WriteToLog( DWORD dwLine )
{
   SMALL_RECT srRead = { 0, 0, 0, 0};
   COORD coSize = { 0, 1 }, coOrigin = { 0, 0 };

   if( !g_bIsToBeLogged )
   {
        return;       
   }

   coSize.X     = ( WORD )ui.dwMaxCol;
   srRead.Top   = ( WORD )dwLine, srRead.Bottom = ( WORD ) ( dwLine + 1 );
   srRead.Left  = 0, srRead.Right = ( WORD ) ( ui.dwMaxCol - 1 );           

   if( ReadConsoleOutput( gwi.hOutput, g_rgciCharInfo, coSize, coOrigin, &srRead ) )
   {
        coSize.Y = srRead.Bottom - srRead.Top + 1;
        coSize.X = srRead.Right - srRead.Left + 1;
        WriteCharInfoToLog( g_rgciCharInfo, coSize );               
   }

   g_bIsToBeLogged = FALSE;

}

void GetWindowCoordinates( SMALL_RECT  *srClientWindow, COORD* coordSize )
{
    CONSOLE_SCREEN_BUFFER_INFO csbiRestore;

    ASSERT( srClientWindow );

    if( GetConsoleScreenBufferInfo( gwi.hOutput, &csbiRestore ) )
    {
        *srClientWindow = csbiRestore.srWindow;
        if( coordSize )
        { 
            *coordSize = csbiRestore.dwSize;
        }
    }
    else
    {
        srClientWindow->Bottom = 0;
        srClientWindow->Top = 0;
        srClientWindow->Right = 0;
        srClientWindow->Left = 0;
        if( coordSize )
        {
            coordSize->X = 0;
            coordSize->Y = 0;
        }
    }
}

void SetWindowSize( HANDLE hConsoleToBeChanged )
{
    COORD coordSize = { 0, 0 };
    SMALL_RECT srPromptWindow = { 0, 0, 0, 0 };
    HANDLE hOldConsole = NULL;
    COORD coordLargest = { 0, 0 };

    hOldConsole = gwi.hOutput;
    gwi.hOutput = hConsoleToBeChanged;
    GetWindowCoordinates( &srPromptWindow, &coordSize );
    gwi.hOutput = hOldConsole;

    //if error, return
    if( coordSize.X == 0 || srPromptWindow.Bottom == 0 )
    {
        return;
    }

    if( srPromptWindow.Bottom - srPromptWindow.Top != gwi.sbi.srWindow.Bottom - gwi.sbi.srWindow.Top ||
      srPromptWindow.Right - srPromptWindow.Left != gwi.sbi.srWindow.Right - gwi.sbi.srWindow.Left ) 
    {

        srPromptWindow.Right  += ( gwi.sbi.srWindow.Right - gwi.sbi.srWindow.Left ) -
                                ( srPromptWindow.Right - srPromptWindow.Left );
        srPromptWindow.Bottom += ( gwi.sbi.srWindow.Bottom - gwi.sbi.srWindow.Top ) -
                                ( srPromptWindow.Bottom - srPromptWindow.Top );    

        coordLargest = GetLargestConsoleWindowSize( gwi.hOutput );
        if( srPromptWindow.Right  - srPromptWindow.Left >= coordLargest.X )
        {
            srPromptWindow.Right = srPromptWindow.Left + coordLargest.X  - 1;
        }
        if( srPromptWindow.Bottom -  srPromptWindow.Top >= coordLargest.Y )
        {
            srPromptWindow.Bottom = srPromptWindow.Top + coordLargest.Y  - 1;
        }        
    }


    if ( ( coordSize.X < gwi.sbi.dwSize.X ) || ( coordSize.Y < gwi.sbi.dwSize.Y ) )
    {
        COORD coordTmpSize = { 0, 0 };

        coordTmpSize .X = ( coordSize.X < gwi.sbi.dwSize.X ) ? gwi.sbi.dwSize.X : coordSize.X ;
        coordTmpSize .Y = ( coordSize.Y < gwi.sbi.dwSize.Y ) ? gwi.sbi.dwSize.Y : coordSize.Y ;

        SetConsoleScreenBufferSize( hConsoleToBeChanged, coordTmpSize );
        SetConsoleWindowInfo( hConsoleToBeChanged, TRUE, &srPromptWindow );
        SetConsoleScreenBufferSize ( hConsoleToBeChanged, gwi.sbi.dwSize );
    }
    else
    {
        SetConsoleWindowInfo( hConsoleToBeChanged, TRUE, &srPromptWindow );
        SetConsoleScreenBufferSize( hConsoleToBeChanged, gwi.sbi.dwSize );
    }

}


void CheckForChangeInWindowSize()
{
    SMALL_RECT srClientWindow = { 0, 0, 0, 0 };
    COORD coordSize = { 0, 0 };

    GetWindowCoordinates( &srClientWindow, &coordSize );

    if( gwi.nd.fRespondedToDoNAWS  && !g_bDontNAWSReceived && 
             ( srClientWindow.Bottom - srClientWindow.Top != srOldClientWindow.Bottom - srOldClientWindow.Top ||
              srOldClientWindow.Right - srOldClientWindow.Left != srClientWindow.Right - srClientWindow.Left ) )
    {
        //We found that window size has changed and we already did naws. 
        //Do naws again

        COORD coordLargest = { 0, 0 };
        BOOL  fChangedFromUserSetting  = FALSE;

        coordLargest = GetLargestConsoleWindowSize( gwi.hOutput );
        if( srClientWindow.Right  - srOldClientWindow.Left >= coordLargest.X )
        {
            srClientWindow.Right = srClientWindow.Left + coordLargest.X  - 1;
            fChangedFromUserSetting = TRUE;
        }
        if( srClientWindow.Bottom -  srOldClientWindow.Top >= coordLargest.Y )
        {
            srClientWindow.Bottom = srClientWindow.Top + coordLargest.Y  - 1;
            fChangedFromUserSetting = TRUE;
        }        

        if( fChangedFromUserSetting )
        {
            //The max window size that can be set through the ui on cmd is larger than what GetLargestConsoleWindowSize
            //returns. In that case, force the window size to be smaller 
            SetConsoleWindowInfo( gwi.hOutput, TRUE, &srClientWindow );

            if( srClientWindow.Bottom - srClientWindow.Top == srOldClientWindow.Bottom - srOldClientWindow.Top &&
              srOldClientWindow.Right - srOldClientWindow.Left == srClientWindow.Right - srClientWindow.Left ) 
            {
                //This is needed so that we don't do NAWS when unnecessary
                return;
            }
        }

        if( srClientWindow.Bottom < srOldClientWindow.Bottom )
        {
            WORD wDifference = ( srOldClientWindow.Bottom - srClientWindow.Bottom );
            if( srClientWindow.Bottom + wDifference < coordSize.Y )
            {
                //Move the window to bottom
                srClientWindow.Top    = srClientWindow.Top + wDifference;
                srClientWindow.Bottom = srOldClientWindow.Bottom;
                SetConsoleWindowInfo( gwi.hOutput, TRUE,  &srClientWindow );
            }

            if( ( WORD ) gwi.trm.dwCurLine > srClientWindow.Bottom )
            {
               gwi.trm.dwCurLine = srClientWindow.Bottom;
            }
        }

        srOldClientWindow = srClientWindow;

        if( FGetCodeMode(eCodeModeIMEFarEast) )
        {
            srOldClientWindow.Bottom--; //Last row for IME status
        }

        gwi.sbi.srWindow  = srOldClientWindow;
        gwi.sbi.dwSize    = coordSize;
        PrepareForNAWS();
        DoNawsSubNegotiation( &gwi );
        SetMargins( &(gwi.trm), 1, gwi.sbi.dwSize.Y );
        SetWindowSize( g_hTelnetPromptConsoleBuffer );
    }
    else
    {
        //if the buffer size has changed
        if( gwi.sbi.dwSize.X != coordSize.X || gwi.sbi.dwSize.Y != coordSize.Y )
        {
            gwi.sbi.dwSize    = coordSize;
            srOldClientWindow = srClientWindow; //window changes
            PrepareForNAWS();
            SetMargins( &(gwi.trm), 1, gwi.sbi.dwSize.Y );
            if( ( WORD ) gwi.trm.dwCurLine > srClientWindow.Bottom )
            {
               gwi.trm.dwCurLine = srClientWindow.Bottom;
            }
        }

    }
}

void SaveCurrentWindowCoords()
{
    SMALL_RECT srClientWindow = { 0, 0, 0, 0 };

    GetWindowCoordinates( &srClientWindow, NULL );
    srOldClientWindow = srClientWindow;
}

void RestoreWindowCoordinates( )
{
    SMALL_RECT srClientWindow = { 0, 0, 0, 0 };

    GetWindowCoordinates( &srClientWindow, NULL );

    if( ( srClientWindow.Bottom != 0 )  &&//valid values of srClientWindow?
        ( srOldClientWindow.Bottom != 0 ) &&
        ( srOldClientWindow.Top  != srClientWindow.Top ||
          srOldClientWindow.Left != srClientWindow.Left )  )    //Window position over the buffer changed ?
    {
        SetConsoleWindowInfo( gwi.hOutput, TRUE, &srOldClientWindow );
    }

    if( srOldClientWindow.Bottom == 0 )
    {
        srOldClientWindow = srClientWindow;
    }
}

void
ReSizeWindow(HWND hwnd, long cx, long cy)
{
  BOOL bScrollBars;
  NONCLIENTMETRICS NonClientMetrics;

  ASSERT( ( 0, 0 ) );
  NonClientMetrics.cbSize = sizeof( NonClientMetrics );

  SystemParametersInfo( SPI_GETNONCLIENTMETRICS,
                        0,
                        &NonClientMetrics,
                        FALSE );

  //
  //  if cx and cy are -1, then set the window size to the desktop
  //  minus the offset of the window.  This sets the window to the
  //  maximum size that will still be contained on the desktop
  //

  if ( cx == -1 && cy == -1 )
  {
    RECT rect;

    GetWindowRect( hwnd, &rect );

    cx = (SHORT) (GetSystemMetrics( SM_CXFULLSCREEN ) - rect.left);
    cy = (SHORT) (GetSystemMetrics( SM_CYFULLSCREEN ) - rect.top);
  }

  if (( ui.dwClientRow < ui.dwMaxRow ) &&
      ( ui.dwClientCol < ui.dwMaxCol ) &&
      ( (( cy + NonClientMetrics.iScrollHeight ) ) == (LONG)ui.dwMaxRow ) &&
      ( (( cx + NonClientMetrics.iScrollWidth ) ) == (LONG)ui.dwMaxCol ) )
  {
    cy += NonClientMetrics.iScrollHeight;
    cx += NonClientMetrics.iScrollWidth;
  }

  ui.dwClientRow = cy;
  ui.dwClientCol = cx;

  ui.dwClientRow = min ( ui.dwClientRow, ui.dwMaxRow);
  ui.dwClientCol = min ( ui.dwClientCol, ui.dwMaxCol);

  if ( (ui.dwClientRow < ui.dwMaxRow) ||
       (ui.dwClientCol < ui.dwMaxCol) )
  {
    ui.nScrollMaxRow = (SHORT)(ui.dwMaxRow - ui.dwClientRow);
    ui.nScrollRow = ( WORD )min (ui.nScrollRow, ui.nScrollMaxRow);
    ui.nScrollMaxCol = (SHORT)(ui.dwMaxCol - ui.dwClientCol);
    ui.nScrollCol = ( WORD )min (ui.nScrollCol, ui.nScrollMaxCol);
    bScrollBars = TRUE;
  }
  else
  {
    ui.nScrollRow = 0;
    ui.nScrollMaxRow = 0;
    ui.nScrollCol = 0;
    ui.nScrollMaxCol = 0;
    bScrollBars = FALSE;
  }

}

static void
InsertLine(WI *pwi, TRM *ptrm, DWORD iLine)
{
    COORD dwDest;
    SMALL_RECT rect;
    
    rect.Top    = ( short )( iLine );
    rect.Bottom = ( short )( ptrm->dwScrollBottom - 1 - 1 );
        
    rect.Left   = 0;
    rect.Right  = ( short )( ui.nCxChar * ui.dwMaxCol );

    dwDest.X = 0; 
    dwDest.Y = ( short )( iLine + 1 );

    pwi->cinfo.Attributes = pwi->sbi.wAttributes;
    ScrollConsoleScreenBuffer( pwi->hOutput, &rect, NULL, dwDest, &pwi->cinfo );

}


static void
NewLineUp( WI* pwi, TRM* ptrm )
{
    if (ui.bLogging)
    {        
        WriteToLog( ptrm->dwCurLine );
    }

    if( ptrm->dwCurLine <= ptrm->dwScrollTop )
    {
        ptrm->dwCurLine = ptrm->dwScrollTop;
        InsertLine( pwi, ptrm, ptrm->dwScrollTop );
    }
    else
    {
        ptrm->dwCurLine -= 1;

        if( ( SHORT )ptrm->dwCurLine < srOldClientWindow.Top )
        {
            /*SetConsoleWindowInfo should fail when the top reaches buffer top*/

            srOldClientWindow.Top  -= 1;
            srOldClientWindow.Bottom  -= 1;
            SetConsoleWindowInfo( gwi.hOutput, TRUE, &srOldClientWindow );
        }
    }
}

static void
DeleteLine(WI *pwi, TRM *ptrm, DWORD iLine)
{
    SMALL_RECT rect;
    COORD dwDest;

    rect.Top    = ( WORD )( iLine + 1 * iCursorHeight );
    rect.Bottom = ( WORD )( ( ptrm->dwScrollBottom - 1 ) * iCursorHeight );
    rect.Left   = 0;
    rect.Right  = ( WORD )( ui.nCxChar * ui.dwMaxCol );

    dwDest.X = 0;
    dwDest.Y = ( WORD ) ( iLine + 1 - 1 );

    pwi->cinfo.Attributes = pwi->sbi.wAttributes;
    ScrollConsoleScreenBuffer( pwi->hOutput, &rect, NULL, dwDest, &pwi->cinfo );
}

void MoveOneLineDownTheBuffer( WI *pwi, TRM *ptrm )
{
    DWORD dwNumWritten = 0;
    COORD coCursorPosition = { 0, 0 };
/* SetConsoleWindowInfo should fail when the bottom reaches buffer bottom*/

    srOldClientWindow.Top  += 1;
    srOldClientWindow.Bottom  += 1;

    //To avoid the color flickering paint it first and then scroll
    coCursorPosition.X=0; coCursorPosition.Y=srOldClientWindow.Bottom;
    FillConsoleOutputAttribute( pwi->hOutput, pwi->sbi.wAttributes,   
        srOldClientWindow.Right - srOldClientWindow.Left + 1, 
        coCursorPosition, &dwNumWritten );

    SetConsoleWindowInfo( gwi.hOutput, TRUE, &srOldClientWindow );
}

static void
NewLine(WI *pwi, TRM *ptrm)
{
    if (ui.bLogging)
    {        
        WriteToLog( ptrm->dwCurLine );
    }

    if(( ptrm->dwCurLine + 1 ) >= ptrm->dwScrollBottom )
    {
     //   DeleteLines( pwi, ptrm, ptrm->dwScrollTop, 1 );
        DeleteLine( pwi, ptrm, ptrm->dwScrollTop );
    }
    else
    {
        WORD bottom = srOldClientWindow.Bottom;
        if( FGetCodeMode( eCodeModeFarEast ) )
        {
            bottom--;
        }
        ptrm->dwCurLine += 1;

        if( ptrm->dwCurLine > bottom )
        {
            MoveOneLineDownTheBuffer( pwi, ptrm);
        }
    }

    if(( ptrm->dwCurLine > ( ui.dwMaxRow - ( ui.nScrollMaxRow - ui.nScrollRow ))) &&
        ( ui.nScrollRow < ui.nScrollMaxRow ) ) 
    {
        ui.nScrollRow += 1;
        //ScrollWindow(hwnd, 0, -ui.nCyChar, NULL, NULL);
    }
}

static void
SetBufferStart(TRM *ptrm)
{
    ptrm->dwCurCharBT = ptrm->dwCurChar;
    ptrm->dwCurLineBT = ptrm->dwCurLine;
    ptrm->fInverseBT = ptrm->fInverse;
}

static BOOL
FAddCharToBuffer(TRM *ptrm, UCHAR uch)
{
    if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
    {
        if(FIsVT80(ptrm) || GetACP() == KOR_CODEPAGE ) 
        {
            if( FIsJISKanji(ptrm) || FIsJIS78Kanji(ptrm) || FIsNECKanji(ptrm) || FIsACOSKanji(ptrm) ) 
            {
                if( !(GetKanjiStatus(ptrm) & JIS_KANJI_CODE) ) 
                {
                    if( GetKanjiStatus(ptrm) & (SINGLE_SHIFT_2|SINGLE_SHIFT_3) )
                    {
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
                        ptrm->dwCurChar++;

                        ClearKanjiStatus(ptrm,(SINGLE_SHIFT_2|SINGLE_SHIFT_3));
                        PopCharSet(ptrm,GRAPHIC_LEFT);
                        PopCharSet(ptrm,GRAPHIC_RIGHT);
                        uchOutPrev = 0;

                    } 
                    else 
                    {
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
                        ptrm->dwCurChar++;
                        uchOutPrev = 0;
                    }
                } 
                else
                {
                    if ( uchOutPrev == 0 ) 
                    {
                        uchOutPrev = uch;
                    } 
                    else
                    {
                        jistosjis(&uchOutPrev,&uch);
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uchOutPrev;
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
                        ptrm->dwCurChar+=2;
                        uchOutPrev = 0;
                    }
                }

            } 
            else if( FIsSJISKanji(ptrm) || GetACP() == KOR_CODEPAGE ) 
            {
                if( uchOutPrev == 0 && IsDBCSLeadByte(uch) ) 
                {
                    /* do not write only LeadByte into buffer.
                       keep current leadbyte character */

                    uchOutPrev = uch;

                }
                else
                {
                    if( uchOutPrev == 0 ) 
                    {
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
                        ptrm->dwCurChar++;
                    }
                    else 
                    {
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uchOutPrev;
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
                        ptrm->dwCurChar+=2;
                        uchOutPrev = 0;
                    }
                }
            } 
            else if( FIsEUCKanji(ptrm) || FIsDECKanji(ptrm) ) 
            {
                if( GetKanjiStatus(ptrm) & (SINGLE_SHIFT_2|SINGLE_SHIFT_3) ) 
                {
                    ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
                    ptrm->dwCurChar++;

                    ClearKanjiStatus(ptrm,(SINGLE_SHIFT_2|SINGLE_SHIFT_3));
                    PopCharSet(ptrm,GRAPHIC_LEFT);
                    PopCharSet(ptrm,GRAPHIC_RIGHT);
                    uchOutPrev = 0;
                }
                else if( IsEUCCode(uch) || uchOutPrev != 0 ) 
                {
                    if( uchOutPrev == 0 ) 
                    {
                        uchOutPrev = uch;
                    }
                    else 
                    {
                        euctosjis(&uchOutPrev,&uch);
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uchOutPrev;
                        ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
                        ptrm->dwCurChar+=2;
                        uchOutPrev = 0;
                    }
                }
                else 
                {
                    ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
                    ptrm->dwCurChar++;
                    uchOutPrev = 0;
                }
            }
        }
        else
        {
            ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
            ptrm->dwCurChar++;
        }
        return (ptrm->cchBufferText >= sizeof(ptrm->rgchBufferText));
    }
    ASSERT(!(FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)));
    ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
    return (ptrm->cchBufferText >= sizeof(ptrm->rgchBufferText));
}

static BOOL FAddTabToBuffer(TRM *ptrm, DWORD wSpaces)
{
    (void)memset((void *)(ptrm->rgchBufferText+ptrm->cchBufferText), (int)' ', (size_t)wSpaces);
    ptrm->cchBufferText += wSpaces;

    return (ptrm->cchBufferText >= sizeof(ptrm->rgchBufferText));
}

void ResetColors( WI* pwi )
{
    pwi->sbi.wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
}


void SetForegroundColor( WI* pwi, UCHAR color )
{
    pwi->sbi.wAttributes = ( WORD )( ( pwi->sbi.wAttributes & ~( ( UCHAR )( FOREGROUND_RED |
        FOREGROUND_GREEN | FOREGROUND_BLUE ))) | color );
}

void SetBackgroundColor( WI* pwi, UCHAR color )
{
    pwi->sbi.wAttributes =( WORD ) ( ( pwi->sbi.wAttributes & ~( ( UCHAR )( BACKGROUND_RED | 
        BACKGROUND_GREEN | BACKGROUND_BLUE ))) | (( UCHAR) ( color << 4 )) );
}

void NegativeImageOn( WI* pwi )
{
    //pwi->sbi.wAttributes = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
    pwi->sbi.wAttributes = ( WORD )( (( pwi->sbi.wAttributes & 
        ( BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE )) >> 4 ) |
        (( pwi->sbi.wAttributes & ( FOREGROUND_RED | FOREGROUND_GREEN | 
        FOREGROUND_BLUE )) << 4 ) | ( pwi->sbi.wAttributes & 
        FOREGROUND_INTENSITY ) | ( pwi->sbi.wAttributes & 
        BACKGROUND_INTENSITY ) ); 
}

void NegativeImageOff( WI* pwi )
{
    //pwi->sbi.wAttributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
    pwi->sbi.wAttributes = ( WORD ) ( (( pwi->sbi.wAttributes & 
        ( BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE )) >> 4 ) |
        (( pwi->sbi.wAttributes & ( FOREGROUND_RED | FOREGROUND_GREEN | 
        FOREGROUND_BLUE )) << 4 ) | ( pwi->sbi.wAttributes & 
        FOREGROUND_INTENSITY ) | ( pwi->sbi.wAttributes & 
        BACKGROUND_INTENSITY ) );  
}


void BoldOff( WI* pwi )
{
    pwi->sbi.wAttributes &= (UCHAR) ~( FOREGROUND_INTENSITY );
}

void BoldOn( WI* pwi )
{
    pwi->sbi.wAttributes |= (UCHAR) FOREGROUND_INTENSITY;
}


void SetLightBackground( WI* pwi )
{
    WORD* pAttribs = NULL; 
    COORD co = { 0, 0 };
    DWORD dwNumRead;
    DWORD dwNumWritten;
    int j;
    DWORD dwStatus;
    CONSOLE_SCREEN_BUFFER_INFO cSBInfo;
    COORD dwSize;
    
    GetConsoleScreenBufferInfo( gwi.hOutput, &cSBInfo ); 
    dwSize.X = ( WORD ) ( cSBInfo.srWindow.Bottom - cSBInfo.srWindow.Top + 1 );
    dwSize.Y = ( WORD ) ( cSBInfo.srWindow.Right - cSBInfo.srWindow.Left + 1 );

    pAttribs = ( WORD* ) malloc( sizeof( WORD ) * dwSize.X * dwSize.Y );
    if( !pAttribs) 
        return;

    co.X = cSBInfo.srWindow.Left; 
    co.Y = cSBInfo.srWindow.Top;

    dwStatus = ReadConsoleOutputAttribute( pwi->hOutput, pAttribs, 
        ( DWORD ) dwSize.X * ( DWORD ) dwSize.Y , co, &dwNumRead );
#ifdef DEBUG
    if( !dwStatus )
    {
        _snwprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, L"Error: SetLightBackground() -- %d", 
                GetLastError() );
        OutputDebugString(rgchDbgBfr);
    }
#endif
    
    for( j = 0; j < dwSize.X * dwSize.Y; j++ )
    {
        pAttribs[j] |= (UCHAR) BACKGROUND_INTENSITY;
    }

    dwStatus = WriteConsoleOutputAttribute( pwi->hOutput, pAttribs, 
        ( DWORD )dwSize.Y * ( DWORD )dwSize.X, co, &dwNumWritten );
#ifdef DEBUG
    if( !dwStatus )
    {
        _snwprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, L"Error: SetLightBackground() -- %d", 
                GetLastError() );
        OutputDebugString(rgchDbgBfr);
    }
#endif

    pwi->sbi.wAttributes |= (UCHAR) BACKGROUND_INTENSITY;
    free( pAttribs );
}

void SetDarkBackground( WI* pwi )
{
    //I am doing this for the whole console screen buffer
    //beacuse right now we don't support scrolling and expect
    //the console screen buffer size to be same as window size
    //but if and when we implement scrolling then we can optimize
    //this stuff so that we change the attributes only for the
    //current visible part of the screen buffer
    WORD* pAttribs = ( WORD* ) malloc( sizeof( WORD) * pwi->sbi.dwSize.X 
        * pwi->sbi.dwSize.Y );
    DWORD dwNumRead;
    DWORD dwNumWritten;
    int j;
    COORD co = { 0, 0 };

    if (!pAttribs)
        return;

    ReadConsoleOutputAttribute( pwi->hOutput, pAttribs, 
        ( DWORD ) ( pwi->sbi.dwSize.X ) * ( DWORD ) ( pwi->sbi.dwSize.Y ),
        co, &dwNumRead );
    
    for( j = 0; j < ( pwi->sbi.dwSize.X ) * ( pwi->sbi.dwSize.Y ); j++ )
    {
        pAttribs[j] &= (UCHAR) ~( BACKGROUND_INTENSITY );
    }

    WriteConsoleOutputAttribute( pwi->hOutput, pAttribs, 
        ( DWORD ) ( pwi->sbi.dwSize.Y ) * ( DWORD )( pwi->sbi.dwSize.X ),
        co, &dwNumWritten );

    pwi->sbi.wAttributes &= (UCHAR) ~( BACKGROUND_INTENSITY );
    free( pAttribs );
}


static void FlushBuffer( WI* pwi, TRM* ptrm )
{
    if( ptrm->cchBufferText != 0 )
    {
        DWORD dwNumWritten;
        COORD dwCursorPosition;

        if( ui.bLogging )
        {                        
            g_bIsToBeLogged = TRUE; //There is data to be logged
        }

        dwCursorPosition.X = ( short ) ( ptrm->dwCurCharBT - ui.nScrollCol );
        dwCursorPosition.Y = ( short ) ( ptrm->dwCurLineBT - ui.nScrollRow);
        
        //WriteConsole is a tty ( kind of sending to stdout ) function.
        //When you write on the right most bottom char on a window, it makes the        
        //widow scroll. It can make the screen look ugly in the presence of 
        //colors. So unless, 81st char on the bottom row is a DBCS char, 
        //use WriteConsoleOutPutCharacter. 

        //Each DBCS char requires two cells on the console screen
        if( FGetCodeMode(eCodeModeFarEast ) &&
            ( srOldClientWindow.Bottom - 1 ==  ( WORD )ptrm->dwCurLine ) &&                
            ptrm->dwCurCharBT + ptrm->cchBufferText > ui.dwMaxCol
          )
        {
            //This is the bottom of the fareast client windows
            DeleteLine( pwi, ptrm, ptrm->dwScrollTop );
            dwCursorPosition.Y--;
            ptrm->dwCurLine--;
        }

        SetConsoleCursorPosition( pwi->hOutput, dwCursorPosition );
        if( srOldClientWindow.Bottom == ( WORD )ptrm->dwCurLine )
        {
            //This will never happen on non FE lang m/cs since status line will be 
            //present at the bottom
            WriteConsoleOutputCharacterA( pwi->hOutput, (PCHAR)ptrm->rgchBufferText, 
                ptrm->cchBufferText, dwCursorPosition, &dwNumWritten );
        }
        else
        {
            WriteConsoleA( pwi->hOutput, ptrm->rgchBufferText, 
                ptrm->cchBufferText, &dwNumWritten, NULL );
        }
        FillConsoleOutputAttribute( pwi->hOutput, pwi->sbi.wAttributes,   
            ptrm->cchBufferText, dwCursorPosition, &dwNumWritten );

        //part of fix for Bug 1470 - DBCS char disappearance at 81 column.
        if( FGetCodeMode(eCodeModeFarEast ) )
        {
            CONSOLE_SCREEN_BUFFER_INFO  csbiCurrent;
            if( GetConsoleScreenBufferInfo( gwi.hOutput, &csbiCurrent ) )
            {
                if( csbiCurrent.dwCursorPosition.Y > dwCursorPosition.Y )
                {
                    //Occupied some space even on next row
                    ptrm->dwCurChar = csbiCurrent.dwCursorPosition.X;
                }
            }
        }

        // Reset parameters 
        ptrm->cchBufferText = 0;
        ptrm->dwCurCharBT = 0;
        ptrm->dwCurLineBT = 0;
        ptrm->fInverseBT = FALSE;
    }
}


void
DoTermReset(WI *pwi, TRM *ptrm)
{
    ptrm->dwVT100Flags = 0;

    //ui.dwCrLf ? SetLineMode(ptrm): ClearLineMode(ptrm);

    SetVTWrap(ptrm);

    ptrm->fSavedState = FALSE;
    ptrm->fRelCursor = FALSE;
    SetMargins( ptrm, 1, ui.dwMaxRow );

    ptrm->cchBufferText = 0;
    ptrm->dwCurCharBT = 0;
    ptrm->dwCurLineBT = 0;
    ptrm->fInverseBT = FALSE;
    if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
        {
        ClearKanjiFlag(ptrm);
        ClearKanjiStatus(ptrm,CLEAR_ALL);
        SetupCharSet( ptrm );
        }
    else
        {
        ptrm->puchCharSet = rgchNormalChars;
        ptrm->currCharSet = 'B';
        ptrm->G0 = 'B';
        ptrm->G1 = 'B';
        }
    ptrm->fEsc = 0;
    ptrm->cEscParams = 0;
    ptrm->fFlushToEOL = FALSE;
    ptrm->fLongLine = FALSE;
}

static void
CursorUp(TRM *ptrm)
{
	if( ui.bLogging )
	{
		WriteToLog( ptrm->dwCurLine );
	}
    if( ptrm->dwEscCodes[0] == 0 )
    {
        ptrm->dwEscCodes[0] = 1;
    }

    if( ptrm->dwCurLine < (DWORD)ptrm->dwEscCodes[0] )
    {
        ptrm->dwCurLine = 0;
    }
    else
    {
        ptrm->dwCurLine -= ptrm->dwEscCodes[0];
    }

    if(( ptrm->fRelCursor == TRUE ) && ( ptrm->dwCurLine < ptrm->dwScrollTop ))
    {
        ptrm->dwCurLine = ptrm->dwScrollTop;
    }

    ptrm->fEsc = 0;
}


static void
CursorDown(TRM *ptrm)
{
	if( ui.bLogging )
	{
		WriteToLog( ptrm->dwCurLine );
	}

    if (ptrm->dwEscCodes[0] == 0)
            ptrm->dwEscCodes[0]=1;
    ptrm->dwCurLine += ptrm->dwEscCodes[0];
    if (ptrm->dwCurLine >= ui.dwMaxRow)
            ptrm->dwCurLine = ui.dwMaxRow - 1;
    if ((ptrm->fRelCursor == TRUE) &&
            (ptrm->dwCurLine >= ptrm->dwScrollBottom))
    {
            ptrm->dwCurLine = ptrm->dwScrollBottom-1;
    }
    ptrm->fEsc = 0;
}

static void
CursorRight(TRM *ptrm)
{
    if( ptrm->dwEscCodes[0] == 0 )
    {
        ptrm->dwEscCodes[0] = 1;
    }
    
    ptrm->dwCurChar += ptrm->dwEscCodes[0];
    
    if( ptrm->dwCurChar >= ui.dwMaxCol )
    {
        ptrm->dwCurChar = ui.dwMaxCol - 1;
    }

    ptrm->fEsc = 0;
}

static void
CursorLeft(TRM *ptrm)
{
    if( ptrm->dwEscCodes[0] == 0 )
    {
        ptrm->dwEscCodes[0] = 1;
    }
    if( ptrm->dwCurChar < ( DWORD ) ptrm->dwEscCodes[0] )
    {
        ptrm->dwCurChar = 0;
    }
    else
    {
        ptrm->dwCurChar -= ptrm->dwEscCodes[0];
    }
    ptrm->fEsc = 0;
    ptrm->fFlushToEOL = FALSE;
}

void
ClearScreen(WI *pwi, TRM *ptrm, DWORD dwType)
{
    DWORD dwNumWritten;
    COORD dwWriteCoord;

    if( dwType <= fdwEntireScreen )
    {
        ptrm->fInverse = FALSE;

        /*
         * If the cursor is already at the top-left corner
         * and we're supposed to clear from the cursor
         * to the end of the screen, then just clear
         * the entire screen.
         */
        if(( ptrm->dwCurChar == 0 ) && ( ptrm->dwCurLine == 0 ) &&
            ( dwType == fdwCursorToEOS ))
        {
            dwType = fdwEntireScreen;
        }

        if (dwType == fdwEntireScreen)
        {
            /* Clear entire screen */
            ptrm->dwCurChar = srOldClientWindow.Left;
            ptrm->dwCurLine = srOldClientWindow.Top;

//            if (ui.nScrollRow > 0) 
            {
                dwWriteCoord.X = 0; dwWriteCoord.Y = 0;

                FillConsoleOutputCharacter( pwi->hOutput,
                    ' ', ( pwi->sbi.dwSize.X ) * ( pwi->sbi.dwSize.Y ),
                    dwWriteCoord, &dwNumWritten );
                FillConsoleOutputAttribute( pwi->hOutput, pwi->sbi.wAttributes,
                    ( pwi->sbi.dwSize.X ) * ( pwi->sbi.dwSize.Y ), dwWriteCoord,
                    &dwNumWritten );

                ui.nScrollRow = 0;
            }
        }
        else if( dwType == fdwBOSToCursor )
        {
         // Clear from beginning of screen to cursor 

            dwWriteCoord.X = 0; 
            dwWriteCoord.Y = 0;

            FillConsoleOutputCharacter( pwi->hOutput, ' ',
                ptrm->dwCurLine * pwi->sbi.dwSize.X + ptrm->dwCurChar + 1,
                dwWriteCoord, &dwNumWritten );
            FillConsoleOutputAttribute( pwi->hOutput, pwi->sbi.wAttributes,
                ptrm->dwCurLine * pwi->sbi.dwSize.X + ptrm->dwCurChar + 1,
                dwWriteCoord, &dwNumWritten );
        }
        else
        {
            // Clear from cursor to end of screen 

            dwWriteCoord.X = ( short ) ptrm->dwCurChar; 
            dwWriteCoord.Y = ( short ) ptrm->dwCurLine;

            FillConsoleOutputCharacter( pwi->hOutput, ' ',
                ( pwi->sbi.dwSize.Y - ( ptrm->dwCurLine + 1 )) * pwi->sbi.dwSize.X + 
                ( pwi->sbi.dwSize.X - ptrm->dwCurChar ), dwWriteCoord,
                &dwNumWritten );
            FillConsoleOutputAttribute( pwi->hOutput, pwi->sbi.wAttributes,
                ( pwi->sbi.dwSize.Y - ( ptrm->dwCurLine + 1 )) * pwi->sbi.dwSize.X + 
                ( pwi->sbi.dwSize.X - ptrm->dwCurChar ), dwWriteCoord,
                &dwNumWritten );
        }

    }
    ptrm->fEsc = 0;
}


// Fill Screen With E's
void
DECALN(WI *pwi, TRM *ptrm )
{
    DWORD dwNumWritten;
    COORD dwWriteCoord;

    ptrm->fInverse = FALSE;

    ptrm->dwCurLine = ptrm->dwCurChar = 0;
//  if (ui.nScrollRow > 0) 
    {
        dwWriteCoord.X = 0; dwWriteCoord.Y = 0;

        FillConsoleOutputCharacter( pwi->hOutput, 'E',
            ( pwi->sbi.dwSize.X ) * ( pwi->sbi.dwSize.Y ), dwWriteCoord,
            &dwNumWritten );

            ui.nScrollRow = 0;
    }

    ptrm->fEsc = 0;
}


static void
ClearLine(WI *pwi, TRM *ptrm, DWORD dwType)
{
    DWORD   dwStart;
    DWORD   cch;
    COORD   dwWriteCoord;
    DWORD   dwNumWritten;

    if (dwType <= fdwEntireLine)
    {
        ptrm->fInverse = FALSE;

        /* Set starting point and # chars to clear
         *
         * fdwCursorToEOL (0) = from cursor to end of line (inclusive)
         * fdwBOLToCursor (1) = from beginning of line to cursor (inclusive)
         * fdwEntireLine  (2) = entire line
         */

        dwStart = (dwType == fdwCursorToEOL) ? ptrm->dwCurChar : 0;
        cch = (dwType == fdwBOLToCursor)
                                        ? ptrm->dwCurChar+1 : ui.dwMaxCol-dwStart;

        dwWriteCoord.X = (short)(dwStart-ui.nScrollCol);
        dwWriteCoord.Y = (short)(ptrm->dwCurLine-ui.nScrollRow);

        FillConsoleOutputCharacter( pwi->hOutput,
                                        ' ',
                                        cch,
                                        dwWriteCoord,
                                        &dwNumWritten );

        FillConsoleOutputAttribute( pwi->hOutput, pwi->sbi.wAttributes,
            cch, dwWriteCoord, &dwNumWritten );
    }
    ptrm->fEsc = 0;
}

static void
SetMargins(TRM* ptrm, DWORD dwMarginTop, DWORD dwMarginBottom )
{
    if( dwMarginTop > 0 )
    {
        ptrm->dwScrollTop = dwMarginTop - 1;
    }

    if( dwMarginBottom <= ui.dwMaxRow )
    {
        ptrm->dwScrollBottom = dwMarginBottom ;
    }
}

#define MAX_VTNT_BUF_SIZE   81920
#define MAX_ROWS  300
#define MAX_COLS  300
static int dwCurBufSize = 0;
static UCHAR szBuffer[MAX_VTNT_BUF_SIZE];
BOOL bDoVtNTFirstTime = 1;

BOOL
DoVTNTOutput( WI* pwi, TRM* ptrm, int cbTermOut, UCHAR* pchTermOut )
{
    COORD coDest = { 0, 0 };
    CHAR_INFO *pCharInfo; 
    int dwRequire;
    VTNT_CHAR_INFO* pOutCharInfo;
    CONSOLE_SCREEN_BUFFER_INFO csbInfo;
    CHAR pTmp[4];
    DWORD dwWritten = 0;

    RestoreWindowCoordinates( );
    do 
    {
        // we should wait atleast until we get the whole VTNT_CHAR_INFO struct.
        if ( (cbTermOut + dwCurBufSize) < sizeof(VTNT_CHAR_INFO) )
        {
            if( bDoVtNTFirstTime )
            {
                //This hack is meant to work well with SUN.
                //This is necessary because SUN accepts to talk in VTNT but
                //sends out vt100/ansi
                bDoVtNTFirstTime = 0;
                if( !strncmp( ( CHAR * )pchTermOut,"\r\n\r\nSunOS ", 10 ) )
                {
                    return FALSE;
                }
            }
            // we copy all the data that we are called with.
            if(MAX_VTNT_BUF_SIZE > dwCurBufSize+cbTermOut)
            {
            	//copy maximum 'n' bytes where 'n' is the available buffer size
            	memcpy(szBuffer + dwCurBufSize, pchTermOut, cbTermOut); 
	            dwCurBufSize += cbTermOut;
           	}
            SaveCurrentWindowCoords();
            return TRUE;
        }
        
        if ( dwCurBufSize == 0 )
            pOutCharInfo = (VTNT_CHAR_INFO*) pchTermOut;
        else 
        {
            if ( dwCurBufSize < sizeof(VTNT_CHAR_INFO) )
            {
                memcpy(szBuffer + dwCurBufSize, pchTermOut, sizeof(VTNT_CHAR_INFO) - dwCurBufSize );//no overflow. Check already present.
                cbTermOut -= (sizeof(VTNT_CHAR_INFO) - dwCurBufSize);
                pchTermOut += (sizeof(VTNT_CHAR_INFO) - dwCurBufSize);
                dwCurBufSize = sizeof(VTNT_CHAR_INFO);
            }
            pOutCharInfo = (VTNT_CHAR_INFO *) szBuffer;
        }

        if( pOutCharInfo->coSizeOfData.X > MAX_COLS || pOutCharInfo->coSizeOfData.X < 0 )
            return FALSE;

        if( pOutCharInfo->coSizeOfData.Y > MAX_ROWS || pOutCharInfo->coSizeOfData.Y < 0 )
            return FALSE;

        dwRequire = sizeof(VTNT_CHAR_INFO) + 
            pOutCharInfo->coSizeOfData.X * pOutCharInfo->coSizeOfData.Y * sizeof(CHAR_INFO);

        if( dwRequire > MAX_VTNT_BUF_SIZE )
            return FALSE;

        // we also wait until we get all of the CHAR_INFO structures.
        if ( (cbTermOut + dwCurBufSize) < dwRequire )
        {
            // we copy all the data that we are called with.
            memcpy(szBuffer + dwCurBufSize, pchTermOut, cbTermOut);//no overflow. Check present.
            dwCurBufSize += cbTermOut;

            SaveCurrentWindowCoords();
            return TRUE;
        }

        if ( dwCurBufSize == 0 )
        {
            pCharInfo = (CHAR_INFO *)(pchTermOut + sizeof(VTNT_CHAR_INFO));

            // adjust the pointers for one more go around the while loop.
            // we are consuming as much as we require
            cbTermOut -= dwRequire;
            pchTermOut += dwRequire;            
        }
        else
        {
        	if(MAX_VTNT_BUF_SIZE>dwRequire-dwCurBufSize)
       		{
	            memcpy(szBuffer + dwCurBufSize, pchTermOut, dwRequire - dwCurBufSize);

		   	     // adjust the pointers for one more go around the while loop.
	            // we are consuming only what we require which is dwRequire - dwCurBufSize.
	            cbTermOut -= (dwRequire - dwCurBufSize);
	            pchTermOut += (dwRequire - dwCurBufSize);
	            
	            pCharInfo = (CHAR_INFO *)(szBuffer + sizeof(VTNT_CHAR_INFO));
       		}
        }

        if ( !GetConsoleScreenBufferInfo( pwi->hOutput, &csbInfo ) )
        {
            csbInfo.srWindow.Top = csbInfo.srWindow.Bottom = 0;
            csbInfo.srWindow.Left = csbInfo.srWindow.Right = 0;
        }

        if( FGetCodeMode(eCodeModeFarEast) )
        {
            //Last line is meant for IME status
            csbInfo.srWindow.Bottom--;
        }

        //Update cursor Position
        pOutCharInfo->coCursorPos.Y += csbInfo.srWindow.Top ;                                               
        pOutCharInfo->coCursorPos.X += csbInfo.srWindow.Left;
                
        //check if there is data
        if( !( pOutCharInfo->coSizeOfData.X == 0 && pOutCharInfo->coSizeOfData.Y == 0 ))
        {       
            //See if we have to scroll

            //csbi.wAttributes is filled by v2 server with following meaning
            //When a scrolling case is detected, this is set to 1.
            if( pOutCharInfo->csbi.wAttributes == ABSOLUTE_COORDS )                
            {
                //No scroling at all                           
                //Update rectangle to write to
                pOutCharInfo->srDestRegion.Top    += csbInfo.srWindow.Top ; 
                pOutCharInfo->srDestRegion.Left   += csbInfo.srWindow.Left;
                pOutCharInfo->srDestRegion.Right  += csbInfo.srWindow.Left;
                pOutCharInfo->srDestRegion.Bottom += csbInfo.srWindow.Top;               
            }

            if( pOutCharInfo->csbi.wAttributes == RELATIVE_COORDS ) 
            {
                if( pOutCharInfo->srDestRegion.Left > 0 && pOutCharInfo->coSizeOfData.Y == 1 &&
                    pOutCharInfo->srDestRegion.Top < csbInfo.srWindow.Bottom - csbInfo.srWindow.Top + 1)
                {
                    //This condition is for VTNT stream mode.
                    //Append to the last row
                    pOutCharInfo->srDestRegion.Top    = csbInfo.srWindow.Bottom; 
                    pOutCharInfo->srDestRegion.Left   += csbInfo.srWindow.Left;
                    pOutCharInfo->srDestRegion.Right  += pOutCharInfo->coSizeOfData.X - 1;
                    pOutCharInfo->srDestRegion.Bottom =  csbInfo.srWindow.Bottom;

                    //Update cursor Position                
                    pOutCharInfo->coCursorPos.Y = csbInfo.srWindow.Bottom;
                                                      
                }
                else if( csbInfo.srWindow.Bottom + pOutCharInfo->coSizeOfData.Y > csbInfo.dwSize.Y - 1 )
                {
                    //need to scroll the buffer itself
                    SMALL_RECT srRect = { 0, 0, 0, 0 };
                    COORD      coDestination = { 0, 0 };
                    CHAR_INFO  cInfo;

                    srRect.Top    = pOutCharInfo->coSizeOfData.Y;
                    srRect.Left   = 0;
                    srRect.Bottom = csbInfo.dwSize.Y - 1;
                    srRect.Right  = csbInfo.dwSize.X - 1;

                    if( FGetCodeMode(eCodeModeFarEast) )
                    {
                        //Last line is meant for IME status
                        srRect.Bottom++;
                    }


                    cInfo.Char.UnicodeChar    =  L' ';
                    cInfo.Attributes          =  csbInfo.wAttributes;
                
                    //We have to scroll screen buffer. we need space to write.
                    ScrollConsoleScreenBuffer( pwi->hOutput,
                                               &srRect, 
                                               NULL, 
                                               coDestination, 
                                               &cInfo );

                    pOutCharInfo->srDestRegion.Top    = csbInfo.srWindow.Bottom - pOutCharInfo->coSizeOfData.Y + 1;
                    pOutCharInfo->srDestRegion.Bottom = csbInfo.srWindow.Bottom;

                    //Update cursor Position                
                    pOutCharInfo->coCursorPos.Y = csbInfo.srWindow.Bottom;
                }
                else
                {
                    //Update rectangle to write to
                    //Append to the bootom of the screen
                    pOutCharInfo->srDestRegion.Top    = csbInfo.srWindow.Bottom + 1 ; 
                    pOutCharInfo->srDestRegion.Left   = csbInfo.srWindow.Left;
                    pOutCharInfo->srDestRegion.Right  = pOutCharInfo->coSizeOfData.X - 1;
                    pOutCharInfo->srDestRegion.Bottom = ( csbInfo.srWindow.Bottom + 1 ) +
                                                            ( pOutCharInfo->coSizeOfData.Y - 1 );
                    //Update cursor Position                
                    pOutCharInfo->coCursorPos.Y = csbInfo.srWindow.Bottom + pOutCharInfo->coSizeOfData.Y;

                    if( FGetCodeMode(eCodeModeFarEast) )
                    {
                        if( csbInfo.srWindow.Bottom + pOutCharInfo->coSizeOfData.Y < csbInfo.dwSize.Y )
                        {
                            csbInfo.srWindow.Top    += pOutCharInfo->coSizeOfData.Y;
                            csbInfo.srWindow.Bottom += pOutCharInfo->coSizeOfData.Y;
                        }
                        else
                        {
                            SHORT sDiff = csbInfo.srWindow.Bottom - csbInfo.srWindow.Top;
                            csbInfo.srWindow.Bottom = csbInfo.dwSize.Y - 1;
                            csbInfo.srWindow.Top    = csbInfo.srWindow.Bottom - sDiff;
                        }
                    }
                }
            }

            WriteConsoleOutput( pwi->hOutput, pCharInfo,
                pOutCharInfo->coSizeOfData, coDest, 
                &pOutCharInfo->srDestRegion );

            if( ui.bLogging )
            {
                WriteCharInfoToLog( pCharInfo, pOutCharInfo->coSizeOfData );
            }
        }

        if( FGetCodeMode(eCodeModeFarEast) )
        {
            //Last line is meant for IME status
            csbInfo.srWindow.Bottom ++;
            SetConsoleWindowInfo( pwi->hOutput, TRUE, &csbInfo.srWindow );
        }

        SetConsoleCursorPosition( pwi->hOutput, pOutCharInfo->coCursorPos );

        // reset for the new loop.
        dwCurBufSize = 0;
    } while ( cbTermOut >= 0 );

    // cbTermOut is negative, that is impossible.
    return FALSE;
}

void SetGraphicRendition( WI *pwi, TRM *ptrm, INT iIndex, 
        DWORD rgdwGraphicRendition[] )
{
    INT i=0;
    for( i=0; i<= iIndex; i++ )
    {
        switch ( rgdwGraphicRendition[i] )
        {
        case 40:  
            //black
            SetBackgroundColor( pwi, 0 );
            break;

        case 41:
            //red
            SetBackgroundColor( pwi, FOREGROUND_RED );
            break;

        case 42:
            //green
            SetBackgroundColor( pwi, FOREGROUND_GREEN );
            break;

        case 43:
            SetBackgroundColor( pwi, ( FOREGROUND_RED | 
                FOREGROUND_GREEN ) );
            break;

        case 44:
            SetBackgroundColor( pwi, FOREGROUND_BLUE );
            break;

        case 45:
            SetBackgroundColor( pwi, ( FOREGROUND_RED | 
                FOREGROUND_BLUE ) );
            break;

        case 46:
             SetBackgroundColor( pwi, ( FOREGROUND_BLUE | 
                FOREGROUND_GREEN ) );
            break;

        case 47:
             //white
            SetBackgroundColor( pwi, ( FOREGROUND_RED | 
                FOREGROUND_BLUE | FOREGROUND_GREEN ) );
            break;
        
            
        case 30:  
            //black
            SetForegroundColor( pwi, 0 );
            break;

        case 31:
            //red
            SetForegroundColor( pwi, FOREGROUND_RED );
            break;

        case 32:
            //green
            SetForegroundColor( pwi, FOREGROUND_GREEN );
            break;

        case 33:
            SetForegroundColor( pwi, ( FOREGROUND_RED | 
                FOREGROUND_GREEN ) );
            break;

        case 34:
            SetForegroundColor( pwi, FOREGROUND_BLUE );
            break;

        case 35:
            SetForegroundColor( pwi, ( FOREGROUND_RED | 
                FOREGROUND_BLUE ) );
            break;

        case 36:
            SetForegroundColor( pwi, ( FOREGROUND_BLUE | 
                FOREGROUND_GREEN ) );
            break;

        case 37:
            //white
            SetForegroundColor( pwi, ( FOREGROUND_RED | 
                FOREGROUND_BLUE | FOREGROUND_GREEN ) );
            break;

        case 21:                             
        case 22: 
            BoldOff( pwi );
            break; 

        case 24: // Underscore off
            break;

        case 25: // Blink off
            break;
            
        case 27: // Negative (reverse) image off
            if( ptrm->fInverse == TRUE )
            {
                ptrm->fInverse = FALSE;
                NegativeImageOff( pwi );
            }
            break; 
        case 10:
            break;

        case 11:
            break;

        case 12:
            break;

        case 8:
            break;

        case 7: // Negative (reverse) image; reverse video
            ptrm->fInverse = TRUE;
            NegativeImageOn( pwi );
            break;

        case 5: // Blink 
            //have to wait until WIN32 console provides
            //a way to do this :-(
            break;

        case 4: // Underscore / underline 
            //have to wait until WIN32 console provides
            //a way to do this :-(
            break;

        case 2: // low video
            BoldOff( pwi );
            break;

        case 1: // Bold or increased intensity; high video
            BoldOn( pwi );
            break;

        case 0: // Attributes Off; normal video
            if( ptrm->fInverse == TRUE )
            {
                ptrm->fInverse = FALSE;
                NegativeImageOff( pwi );
                //BoldOff( pwi );
            }
            BoldOff( pwi );
            ResetColors( pwi );
            break;

        default:
            //ptrm->fInverse = FALSE;

            if( ptrm->fInverse == TRUE )
            {
                ptrm->fInverse = FALSE;
                NegativeImageOff( pwi );
                //BoldOff( pwi );
            }   
            BoldOff( pwi );
            break;  
        }
    }
    return;
}


/* This is meant only for FAREAST IME. In this case, there will be one blank 
 * line at the bottom whose presence is not known to the server. i.e; During 
 * NAWS we gave window size - 1 as our actual size. To maintain this during 
 * scrolling we need to write extra blank line. When the cursor is at the 
 * bottom, if we try to write one char just down the buffer, we get a blank line
 * Otherwise, no effect.*/

void WriteOneBlankLine( HANDLE hOutput, WORD wRow )
{
    COORD coWrite = { 0, 0 };
    if( wRow <= gwi.trm.dwScrollBottom )
    {
        coWrite.Y = wRow;
        SetConsoleCursorPosition( hOutput, coWrite );
    }
}


/*///////////////////////////////////////////////////////////////////////////////
VT100 NOTES:

This info was obatined from 
http://www.cs.utk.edu/~shuford/terminal/vt100_codes_news.txt


  The following describes information needed for controlling the VT100 terminal
from a remote computer.  All of the information was derived from the VT100 
user's manual, Programmer's Information section.  Full documentation can be 
obtain from DIGITAL'S Accessory and Supplies Group.


[The notation  <ESC>  denotes a single ASCII Escape character, 1Bx.]

                                ANSI mode w/cursor      ANSI mode w/cursor
Cursor Key      VT52 mode       key mode reset          key mode set
--------------------------------------------------------------------------
   UP           <ESC>A          <ESC>[A                 <ESC>OA
  DOWN          <ESC>B          <ESC>[B                 <ESC>OB
  RIGHT         <ESC>C          <ESC>[C                 <ESC>OC
  LEFT          <ESC>D          <ESC>[D                 <ESC>OD


 --------------------------
| Terminal Control Commands |
 --------------------------

    Control Characters
    ------------------
        look for details in code below





    The VT100 is an upward and downward software-compatible terminal;
that is, previous Digital video terminals have Digital's private standards
for control sequences. The American National Standards Institute has since
standardized escape and control sequences in terminals in documents X3.41-1974
and X3.64-1977.

    The VT100 is compatible with both the previous Digital standard and
ANSI standards.  Customers may use existing Digital software designed around
the VT52 or new VT100 software.  The VT100 has a "VT52 compatible" mode in
which the VT100 responds to control sequences like a VT52.  In this mode, most
of the new VT100 features cannot be used.

        Throughout this document references will be made to "VT52 mode" or
"ANSI mode".  These two terms are used to indicate the VT100's software
compatibility.

NOTE: The ANSI standards allow the manufacturer flexibility in implementing
each function.  This document describes how the VT100 will respond to the
implemented ANSI central function.

NOTE: ANSI standards may be obtained by writing:

                American National Standards Institute
                Sales Department 
                1430 Broadway
                New York, NY, 10018

        [July 1995 update:  current address for ordering ANSI standards:
        
        American National Standards Institute 
        Attn: Customer Service
        11 West 42nd Street 
        New York, NY  10036 
        USA
        
        ANSI's fax number for placing publication orders is +1 212/302-1286.]

        [Further update, from Tim Lasko <lasko@regent.enet.dec.com>:
        "ANSI X3.64 has been withdrawn in favor of the more complete and
         updated ISO standard 6429. (ECMA-48 is equivalent to ISO DP6429,
         last I checked.) X3.64 has been out of date for some time. At the
         time when I was on the relevant committee, we couldn't get enough
         resources to  really do a good job of updating the standard.
         Later, the proposal came up to withdraw it in favor of the ISO
         standard.]



Definitions
-----------

        Control Sequence Introducer (CSI) - An escape sequence that provides
                supplementary controls and is itself a prefix affecting the
                interpretation of a limited number of contiguous characters.
                In the VT100, the CSI is: <ESC>[

        Parameter:  (1) A string of zero or more decimal characters which
                represent a single value.  Leading zeros are ignored.  The
                decimal characters have a range of 0 (060) to 9 (071).
                (2) The value so represented.

        Numeric Parameter:  A parameter that represents a number, designated by
                Pn.

        Selective Parameter:  A parameter that selects a subfunction from a
                specified set of subfunctions, designated by Ps.  In general, a
                control sequence with more than one selective parameter causes
                the same effect as several control sequences, each with one
                selective parameter, e.g., CSI Psa; Psb; Psc F is identical to
                CSI Psa F CSI Psb F CSI Psc F.

        Parameter String:  A string of parameters separated by a semicolon.

        Default: A function-dependent value that is assumed when no explicit
                value, or a value of 0, is specified.

        Final character:  A character whose bit combination terminates an
                escape or control sequence.

        EXAMPLE:  Control sequence to turn off all character attributes, then
        turn on underscore and blink attributes (SGR).  <ESC>[0;4;5m


                Sequence:
                
                  
                        Delimiters
                          / \
                         /   \
                         |   | 
                        \ / \ /
                <ESC>[ 0 ; 4 ; 5 m
                ^^^^^^ ^   ^   ^ ^
                |||||| |   |   | |
                \||||/  \  |  /  +------Final character
                 \||/    \ | /
                 CSI   Selective
                       Parameters

                The octal representation of this string is:

                        033 0133 060 073 064 073 065 0155
                      <ESC>   [   0   ;   4   ;   5    m


                Alternate sequences which will accomplish the same thing:

                        1) <ESC>[;4;m 

                        2) <ESC>[m
                           <ESC>[4m 
                           <ESC>[5m

                        3) <ESC>[0;04;005m


Control Sequences
-----------------

    All of the following control sequences are transmitted from the Host to
VT100 unless otherwise noted.  All of the control sequences are a subset of
those defined in ANSI X 3.64 1977 and ANSI X 3.41 1974.

    The following text conforms to these formatting conventions:

        1) Control characters are designated by angle brackets (e.g.
            the Escape character is <ESC>).

        2) Parameters are indicated by curly braces.

        3) Parameter types usually are indicated as one of:
            
            {Pn}    A string of digits representing a numerical
                    value.
            
            {Ps}    A character that selects an item from a list.

            {a-z}   Any lowercase sequence of one44 or more
                    characters in braces represent a value to be
                    entered (as in {Pn}), and the name in the
                    braces will be referred to in explanatory text.

        4) Spaces in the control sequence are present for clarity and
           may be omitted.  Spaces which are required will be
           surrounded by single quotes: ' '.
        
        5) All other characters are literals.


    look for details in code below

    CPR     Cursor Position Report          VT100 to Host

        <ESC>[ {Pn} ; {Pn} R            Default Value: 1

        The CPR sequence reports the active position by means of the
        parameters.  This sequence has two parameter values, the first
        specifying the line and the second specifying the column.  The default
        condition with no parameters present, or parameters of 0, is equivelent
        to a cursor at home position.

        The numbering of the lines depends upon the state of the Origin Mode
        (DECOM).

        This control sequence is sent in reply to a device status report (DSR)
        command sent from the host.

    CUB
    
    CUD

    CUF

    CUP

    CUU

    DA




    "I doubt if a lot of these DEC commands work..a few do.. (like scroll areas)"
    I think that this guy means that he doubts whether they even work on a real 
    vt100

    DECALN  

    DECANM 
    
    DECARM

    DECAWM

    DECCKM
    
    DECCOLM

    DECDHL

    DECDWL    

    DECID

    DECINLM

    DECKPAM    

    DECKNPNM

    DECLL

    DECOM

    DECRC

    DECREPTPARM     Report Terminal Parameters      VT100 to Host

        <ESC>[ {sol} ; {par} ; {nbits} ; {xspd} ; {rspd} ; {cmul} ; {flags} x

        This sequence is generated by the VT100 to notify the host of the
        status of selected terminal parameters.  The status sequence may be
        sent when requested by the host (via DECREQTPARM) or at the terminal's
        discretion.  On power up or reset, the VT100 is inhibited from sending
        unsolicited reports.      
        
        The meanings of the sequence paramters are:
        Parameter       Value   Meaning
        ------------------------------------------------------------------
          {sol}           1     This message is a report.
                          2     This message is a report, and the terminal is
                                only reporting on request.

          {par}           1     No parity set
                          4     Parity set and odd
                          5     Parity set and even

         {nbits}          1     8 bits per character
                          2     7 bits per character

         {xspd}           0     Speed set to 50 bps
         -and-            8     Speed set to 75 bps
         {rspd}          16     Speed set to 110 bps
                         24     Speed set to 134.5 bps
         {xspd}=         32     Speed set to 150 bps
          Transmit       40     Speed set to 200 bps
          Speed          48     Speed set to 300 bps
                         56     Speed set to 600 bps
         {rspd}=         64     Speed set to 1200 bps
          Recieve        72     Speed set to 1800 bps
          Speed          80     Speed set to 2000 bps
                         88     Speed set to 2400 bps
                         96     Speed set to 3600 bps
                        104     Speed set to 4800 bps
                        112     Speed set to 9600 bps
                        120     Speed set tp 19200 bps

        {cmul}            1     The bit rate multiplier is 16

        {flags}        0-15     This value communicates the four switch values
                                in block 5 of SET-UP B, which are only visible
                                to the user when an STP option is installed.

        
    DECREQTPARM 

    DECSC

    DECSCLM

    DECSCNM

    DECSTBM

    DECSWL

    DECTST

    DSR

    ED

    EL

    HTS

    HVP

    IND

    LNM

    MODES   The Following is a list of VT100 modes which may be changed with Set
            Mode (SM) and Reset Mode (RM) controls. 
            
            ANSI Specified Modes

            Parameter       Mnemonic        Function
            ------------------------------------------------------------------
                0                           Error (Ignored)
                20             LNM           Line Feed/New Line Mode

            DEC Private Modes

            If the first character in the parameter string is ? (077), the
            parameters are interpreted as DEC private parameters according to the
            following:
            
            Parameter       Mnemonic        Function
            -------------------------------------------------------------------
                0                           Error (Ignored)
                1            DECCKM         Cursor Key
                2            DECANM         ANSI/VT52
                3            DECCOLM        Column
                4            DECSCLM        Scrolling
                5            DECSCNM        Screen
                6            DECOM          Origin
                7            DECAWM         Auto Wrap
                8            DECARM         Auto Repeat
                9            DECINLM        Interlace


            Any other parameter values are ignored.

            The following modes, which are specified in the ANSI standard, may be
            considered to be permanently set, permanently reset, or not applicable,
            as noted. 
            
            Mnemonic        Function                        State
            ------------------------------------------------------
            CRM             Control Representation          Reset
            EBM             Editing Boundary                Reset
            ERM             Erasure                         Set
            FEAM            Format Effector Action          Reset
            FETM            Format Effector Transfer        Reset
            GATM            Guarded Area Transfer           NA
            HEM             Horizontal Editing              NA
            IRM             Insertion-replacement           Reset
            KAM             Keyboard Action                 Reset
            MATM            Multiple area transfer          NA
            PUM             Positioning Unit                Reset
            SATM            Selected Area Transfer          NA
            SRTM            Status Reporting Transfer       Reset
            TSM             Tabulation Stop                 Reset
            TTM             Transfer Termination            NA
            VEM             Vertical Editing                NA


    NEL

    RI

    RIS

    RM

    SCS

    SGR

    SM

    TBC

*////////////////////////////////////////////////////////////////////////////////

/*///////////////////////////////////////////////////////////////////////////////
  DoIBMANSIOutput

    Purpose:
    Interpret any IBM ANSI escape sequences in the output stream
    and perform the correct terminal emulation in response.
    Normal text is just output to the screen.

    Changes for v4.1:
        - now support Clear to end of display ESC[J
        - better support for the FTCU machine by "eating" certain
    unknown escape sequences, namely ESC)0 and ESC[?7h.
*////////////////////////////////////////////////////////////////////////////////

void
DoIBMANSIOutput( WI *pwi, TRM *ptrm, DWORD cbTermOut, UCHAR *pchTermOut )
{
    DWORD ich;
    DWORD i = 0;
    DWORD dwDECMode = 0;
    UCHAR *pchT;
    COORD cp;
    COORD dwSize, dwMaximumWindowSize;
    DWORD dwSavedCurPos;
    CHAR *pchTemp = NULL;

    //* suppress cursor on screen 
    ptrm->fHideCursor = TRUE;

    ptrm->cTilde = 0;
    
    RestoreWindowCoordinates( );
    CheckForChangeInWindowSize( );

    for( ich = 0, pchT = pchTermOut; ich < cbTermOut; ++ich, ++pchT )
    {
               
        if( ( !FGetCodeMode(eCodeModeFarEast) && !FGetCodeMode(eCodeModeVT80)) 
            && IS_EXTENDED_CHAR( *pchT ) )
        {
            DWORD dwNumWritten;
            COORD dwCursorPosition;

            FlushBuffer( pwi, ptrm );

            dwCursorPosition.X = ( short ) ( ptrm->dwCurChar - ui.nScrollCol );
            dwCursorPosition.Y = ( short ) ( ptrm->dwCurLine - ui.nScrollRow);
            ptrm->dwCurChar++;

            SetConsoleCursorPosition( pwi->hOutput, dwCursorPosition );
            
            WriteConsoleA( pwi->hOutput,  (CHAR *)pchT, 1, &dwNumWritten, NULL );       
                       
            FillConsoleOutputAttribute( pwi->hOutput, pwi->sbi.wAttributes,
                                        1, dwCursorPosition, &dwNumWritten );
            if( ui.bLogging )
            {
                g_bIsToBeLogged = TRUE; //There is data to be logged
            }

            continue;
        }

        // process character 
        switch ( ptrm->fEsc )
        {
        case 0: // normal processing 

        /*
        Control Characters
        ------------------

        The control characters recognized by the VT100 are listed below. All 
        other control characters cause no action to be taken.

            Control characters (codes 00 - 037 inclusive) are specifically 
        excluded from the control sequence syntax, but may be embedded within a 
        control sequence. Embedded control characters are executed as soon as 
        they are encountered by the VT100.  The processing of the control 
        sequence then continues with the next character recieved. The exceptions
        are: if the <ESC> character occurs, the current control sequence is
        aborted, and a new one commences beginning with the <ESC> just recieved.
        If the character <CAN> (030) or the character <SUB> (032) occurs, the 
        current control sequence is aborted.  The ability to embed control 
        characters allows the synchronization characters XON and XOFF to be 
        interpreted properly without affecting the control sequence.

        detailed comments below are in the format
        // Control Character; Octal Code; Action Taken

        */

            switch( *pchT )
            {


            case 0x1B:      // ESC? 
                //<ESC>; 0033; Introduces a control sequence.
                ptrm->fEsc = 1;
                break;

            case 0:
                //<NUL>; 0000; Ignored on input, not stored in buffer
                break;

            case 0x05 :
                //<ENQ>; 0005; Transmit ANSWERBACK message
                break;

            case 0x08: // Backspace 
                //<BS>; 0010; Move cursor to the left one position, unless it is
                //at the left margin, in which case no action is taken.

                if( ptrm->dwCurChar > 0 )
                {
                    --ptrm->dwCurChar;
                }
                FlushBuffer( pwi, ptrm );
                break;

            case 0x07:      
                //<BEL>; 0007; Sound bell
                MessageBeep( ( UINT ) (~0) );
                break;

            case 0x09:      // TAB 
                //<HT>; 0011; Move cursor to the next tab stop, or to the right
                //margin if no further tabs are set.

                dwSavedCurPos = ptrm->dwCurChar;
                if( g_iHTS )
                {
                    int x=0;
                    while( x < g_iHTS )
                    {
                        if( g_rgdwHTS[ x ] > ptrm->dwCurChar 
                                && g_rgdwHTS[ x ] != -1 ) 
                        {
                            break;
                        }
                        x++;
                    }
                    while( x < g_iHTS && g_rgdwHTS[ x ] == -1 )
                    {
                        x++;
                    }
                    if( x < g_iHTS )
                    {
                        ptrm->dwCurChar = g_rgdwHTS[ x ];

                    }
                    else
                    {
                        ptrm->dwCurChar += TAB_LENGTH;
                        ptrm->dwCurChar -= ptrm->dwCurChar % TAB_LENGTH;
                    }
                }
                else
                {
                    ptrm->dwCurChar += TAB_LENGTH;
                    ptrm->dwCurChar -= ptrm->dwCurChar % TAB_LENGTH;
                }

                if( ui.fDebug & fdwTABtoSpaces )
                {
                    if( ptrm->cchBufferText == 0 )
                    {
                        SetBufferStart( ptrm );
                    }
                    if( FAddTabToBuffer( ptrm, ptrm->dwCurChar-dwSavedCurPos ) )
                    {
                        FlushBuffer( pwi, ptrm );
                    }
                }

                if( !( ui.fDebug & fdwTABtoSpaces ) )
                {
                    FlushBuffer(pwi, ptrm);
                }
                if( ptrm->dwCurChar >= ui.dwMaxCol )
                {
                    if( ui.fDebug & fdwTABtoSpaces )
                    {
                        FlushBuffer( pwi, ptrm );
                    }
                    ptrm->dwCurChar = 0;
                    NewLine( pwi, ptrm );
                }
                break;

            case '\r': // Carriage Return 
                //<CR>; 0015 ;Move the cursor to the left margin of the current
                //line.
                ptrm->dwCurChar = 0;
                ptrm->fFlushToEOL = FALSE;
                FlushBuffer( pwi, ptrm );
                break;
            
            case 11:
                //<VT>; 0013; Same as <LF>.

            case 12: // Form feed
                //<FF>; 0014 ;Same as <LF>.

            case '\n': //Line Feed 
                //<LF>; 0012; Causes either a line feed or new line operation 
                //(See new line mode.)

                if( ptrm->fFlushToEOL ) 
                {
                    ptrm->fLongLine = FALSE;
                    ptrm->fFlushToEOL = FALSE;
                    break;
                }
                if( ptrm->fLongLine )
                {
                    ptrm->fLongLine = FALSE;
                    break;
                }
                FlushBuffer( pwi, ptrm );
                NewLine( pwi, ptrm );
                break;

            case 0x0F:
                //<SI>; 0017; Invoke the G0 character set, as selected by the <ESC>(
                //sequence.
                
                ptrm->currCharSet = 0; // 0 signifies G0

                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                    {
                    if(FIsVT80(ptrm)) {
                        SetCharSet(ptrm,GRAPHIC_LEFT,ptrm->g0);
                    } else {
                        SetCharSet(ptrm,GRAPHIC_LEFT,rgchIBMAnsiChars);
                    }
                    break;
                    }
                ASSERT(!(FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)));
                switch( ptrm->G0 ) {
                case '0' :
                    ptrm->puchCharSet = rgchSpecialGraphicsChars;
                    break;
                case '1':
                    ptrm->puchCharSet = rgchNormalChars;
                    break;
                case '2' :
                    ptrm->puchCharSet = rgchSpecialGraphicsChars;
                    break;
                case 'A' :
                    ptrm->puchCharSet = rgchUKChars;
                    break;
                case 'B' :
                    ptrm->puchCharSet = rgchNormalChars;
                    break;
                default:
                    
                    break;
                }

                break;

            case 0x0E:
                //<SO>; 0016; Invoke the G1 character set, as designated by the
                //SCS control sequence.

                ptrm->currCharSet = 1;  // 1 signifies G1

                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                    {
                    if(FIsVT80(ptrm)) {
                        SetCharSet(ptrm,GRAPHIC_LEFT,ptrm->g1);
                    } else {
                         SetCharSet(ptrm,GRAPHIC_LEFT,rgchGraphicsChars);
                    }
                    break;
                    }
                ASSERT(!(FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)));
                switch( ptrm->G1 ) {
                case '0' :
                    ptrm->puchCharSet = rgchSpecialGraphicsChars;
                    break;
                case '1':
                    ptrm->puchCharSet = rgchNormalChars;
                    break;
                case '2' :
                    ptrm->puchCharSet = rgchSpecialGraphicsChars;
                    break;
                case 'A' :
                    ptrm->puchCharSet = rgchUKChars;
                    break;
                case 'B' :
                    ptrm->puchCharSet = rgchNormalChars;
                    break;
                default:
                    
                    break;
                }
                break;

            case 0x8E:
                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80) && FIsVT80(ptrm)) 
                {
                           if( !(GetKanjiStatus(ptrm) & JIS_KANJI_CODE) &&
                            (FIsJISKanji(ptrm) || FIsJIS78Kanji(ptrm) ||
                            FIsEUCKanji(ptrm) || FIsDECKanji(ptrm)      ) ) {
                            PushCharSet(ptrm,GRAPHIC_LEFT,ptrm->g2);
                            PushCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g2);
                            SetKanjiStatus(ptrm,SINGLE_SHIFT_2);
#ifdef DEBUG
                            wsprintf(rgchDbgBfr,"VT80 EUC/DEC/JIS SS2 Mode Enter\n");
                            OutputDebugString(rgchDbgBfr);
#endif /* DEBUG */
                        } else {
                            goto Fall_Through;
                        }
                    } else {
                        goto Fall_Through;
                    }
                break;
            case 0x8F:
                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80) )
                {
                   if( FIsVT80(ptrm) )
                    {
                    if( !(GetKanjiStatus(ptrm) & JIS_KANJI_CODE) &&
                        (FIsJISKanji(ptrm) || FIsJIS78Kanji(ptrm) ||
                        FIsEUCKanji(ptrm) || FIsDECKanji(ptrm)      ) ) {
                        PushCharSet(ptrm,GRAPHIC_LEFT,ptrm->g3);
                        PushCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g3);
                        SetKanjiStatus(ptrm,SINGLE_SHIFT_3);
#ifdef DEBUG
                        wsprintf(rgchDbgBfr,"VT80 EUC/DEC/JIS SS3 Mode Enter\n");
                        OutputDebugString(rgchDbgBfr);
#endif /* DEBUG */
                    } else {
                        goto Fall_Through;
                    }
                } else {
                    goto Fall_Through;
                }
                }
                break;
            case 0x1A:
                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                    {
                    if (FIsACOSKanji(ptrm) && (ui.fAcosSupportFlag & fAcosSupport)) {
                        ptrm->fEsc = 7;
                    } else {
                        //goto Fall_Through;
                        break;
                    }
                    }
                break;


            case 0021:
                //<DC1>; 0021; Causes terminal to resume transmission (XON).
                break;

            case 0023:
                //<DC3>; 0023; Causes terminal to stop transmitting all codes 
                //except XOFF and XON (XOFF).
                break;

//            case 0032:
            case 0030:
                //<CAN>; 0030; If sent during a control sequence, the sequence is
                //immediately terminated and not executed.  It also causes the
                //error character (checkerboard) to be displayed.
                break;

            case 0177:
                //<DEL>; 0177; Ignored on input; not stored in buffer.
                break;
                
            case '~':
                // optimization to detect ~~Begin TelXFer signature 
                ++ptrm->cTilde;
                // fall through 

            default:

Fall_Through:
                
                if ( ptrm->dwCurChar >= ui.dwMaxCol )
                {
                    ptrm->dwCurChar = 0;
                    FlushBuffer( pwi, ptrm );
                    NewLine( pwi, ptrm );
                    ptrm->fLongLine = TRUE;

                    if( !FIsVTWrap( ptrm )) 
                    {
                        ptrm->fFlushToEOL = TRUE;
                    }
                }

                if( ptrm->fFlushToEOL )
                {
                    break;
                }
                ptrm->fLongLine = FALSE;

                if( ptrm->cchBufferText == 0 )
                {
                    SetBufferStart( ptrm );
                }

                if( FAddCharToBuffer( ptrm, ptrm->puchCharSet[*pchT] )) 
                {
                    FlushBuffer( pwi, ptrm );
                }
                /* For FE Incremantation was done in FAddCharToBuffer() */
                if (!(FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)))
                   ( ptrm->dwCurChar) ++ ;

                break;
            }
            break;


    case 1: /* ESC entered, wait for [ */

            //If there is some data to be flushed
            if( ptrm->cchBufferText != 0 )
            {
                FlushBuffer(pwi, ptrm);
            }

            if (((*pchT) != '[') && ((*pchT) != '#'))
                    ptrm->fEsc = 0;

            switch (*pchT)
            {
            case '1': 
                break;
            
            case '2':
                break;

            case '7':
                //
                // DECSC
                // Save cursor position, origin mode etc.
                //
                //DECSC   Save Cursor (DEC Private)  
                
                //<ESC>7

                //Causes the cursor position, graphic rendition, and character 
                //set to be saved.  (See DECRC)

                GetConsoleScreenBufferInfo( gwi.hOutput, &consoleBufferInfo ); 

                ptrm->fSavedState = TRUE;
                ptrm->dwSaveChar = ptrm->dwCurChar;
                ptrm->dwSaveLine = ptrm->dwCurLine;
                ptrm->dwSaveRelCursor = ptrm->fRelCursor;
                ptrm->pSaveUchCharSet = ptrm->puchCharSet;
                ptrm->iSaveCurrCharSet = ptrm->currCharSet;
                ptrm->cSaveG0 = ptrm->G0;
                ptrm->cSaveG1 = ptrm->G1;
                ptrm->dwSaveIndexOfGraphicRendition = 
                    ptrm->dwIndexOfGraphicRendition;
                for( i=0; ( WORD) i<= ptrm->dwSaveIndexOfGraphicRendition; i++ )
                {
                    ptrm->rgdwSaveGraphicRendition[i] = 
                        ptrm->rgdwGraphicRendition[i];
                }

                break;

            case '8':
                //
                // DECRC
                // Restore cursor position, etc. from DECSC

                //DECRC   Restore Cursor (DEC Private) 

                //<ESC>8
                //This sequence causes the previously saved cursor position, 
                //graphic rendition, and character set to be restored.
                //

                //Restore charset 
                if( ptrm->pSaveUchCharSet )
                {
                    ptrm->puchCharSet = ptrm->pSaveUchCharSet;
                    ptrm->currCharSet = ptrm->iSaveCurrCharSet;
                    ptrm->G0 = ptrm->cSaveG0;
                    ptrm->G1 = ptrm->cSaveG1;
                }
                
                //Restore Graphic rendition
                {
                    BOOL fNeedToRestore = 0;
                    if( ptrm->dwSaveIndexOfGraphicRendition != 
                            ptrm->dwIndexOfGraphicRendition )
                    {
                        fNeedToRestore = 1;
                    }
                    for( i=0; ( WORD )i<= ptrm->dwSaveIndexOfGraphicRendition && 
                            !fNeedToRestore; i++ )
                    {
                        if( ptrm->rgdwSaveGraphicRendition[i] != 
                                ptrm->rgdwGraphicRendition[i] )
                        {
                            fNeedToRestore = 1;
                        }
                    }
                    if( fNeedToRestore )
                    {
                        SetGraphicRendition( pwi, ptrm, 
                                ptrm->dwSaveIndexOfGraphicRendition, 
                                ptrm->rgdwSaveGraphicRendition );
                    }
                }
                
                //Restore Cursor position
                SetConsoleWindowInfo( gwi.hOutput, TRUE, &(consoleBufferInfo.
                                srWindow ) );

                if( ptrm->fSavedState == FALSE )
                {
                    ptrm->dwCurChar = 1;
                    ptrm->dwCurLine = ( ptrm->fRelCursor )
                        ? ptrm->dwScrollTop : 0;
                    break;
                }
                ptrm->dwCurChar = ptrm->dwSaveChar;
                ptrm->dwCurLine = ptrm->dwSaveLine;
                ptrm->fRelCursor = ( BOOL ) ( ptrm->dwSaveRelCursor );
                break;

            case '[':
                // VT102 - CSI Control Sequence Introducer 
                ptrm->fEsc = 2;
                ptrm->dwEscCodes[0] = 0xFFFFFFFF;
                ptrm->dwEscCodes[1] = 0xFFFFFFFF;
                ptrm->cEscParams = 0;
                ptrm->dwSum = 0xFFFFFFFF;
                dwDECMode = FALSE;
                break;

            case '#':
                ptrm->fEsc = 3;
                break;

            case 'A':
                if( FIsVT52( ptrm ) )
                {
                    // VT52 - Cursor up 
                    ptrm->dwEscCodes[0] = 1;
                    CursorUp( ptrm );
                }
                break;

            case 'B':
                if( FIsVT52( ptrm ) )
                {
                    // VT52 - Cursor down 
                    ptrm->dwEscCodes[0] = 1;
                    CursorDown( ptrm );
                }
                break;

            case 'C':
                if( FIsVT52(ptrm) )
                {
                    // VT52 - Cursor right 
                    ptrm->dwEscCodes[0] = 1;
                    CursorRight( ptrm );
                }
                break;

            case 'D':
                if( FIsVT52(ptrm) )
                {
                    // VT52 - Cursor left 
                    ptrm->dwEscCodes[0] = 1;
                    CursorLeft( ptrm );
                }
                else
                {
                    //VT102 - IND, Index cursor down 1 line, can scroll 
                    //IND     Index       

                    //<ESC>D

                    //This sequence causes the cursor to move downward one line
                    //without changing the column.  If the cursor is at the 
                    //bottom margin, a scroll up is performed.  Format Effector.

                    NewLine( pwi, ptrm );
                }
                break;

            case 'E': // Next Line  ; cr/lf
                //
                // VT102 - NEL, New Line
                // cursor to start of line below, can scroll
                //
                //NEL     Next Line 
                
                //<ESC>E

                //This causes the cursor to move to the first position of the 
                //next line down.  If the cursor is on the bottom line, a scroll
                //is performed. Format Effector.

                ptrm->dwCurChar = 0;
                NewLine( pwi, ptrm );
                break;

            case 'F':
                // VT52 - Enter graphics mode ; alternate graphics character set
                if( FIsVT52( ptrm ) )
                {
                    SetVT52Graphics( ptrm );
                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                    SetCharSet(ptrm,GRAPHIC_LEFT,rgchGraphicsChars);
                else    
                    ptrm->puchCharSet = rgchAlternateChars;
                }
                break;

            case 'G':
                // VT52 - Exit graphics mode ; ASCII character set
                if( FIsVT52( ptrm ))
                {
                    ClearVT52Graphics( ptrm );
                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                    SetCharSet(ptrm,GRAPHIC_LEFT,rgchIBMAnsiChars);
                else
                    ptrm->puchCharSet = rgchNormalChars;
                }
                break;

            case 'H':
                if ( (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)) && ( FIsVT80(ptrm) && FIsNECKanji(ptrm) ) )
                    {
                        /* NEC Kanji OUT (JIS Roman to G0(GL)) */
                        ClearKanjiStatus(ptrm,JIS_KANJI_CODE);
                        SetCharSet(ptrm,GRAPHIC_LEFT,rgchJISRomanChars);
                    }
                else
                if( FIsVT52( ptrm ) )
                {
                    // VT52 - Cursor Home 
                    CONSOLE_SCREEN_BUFFER_INFO info;
                    if( !GetConsoleScreenBufferInfo( gwi.hOutput,
                        &info ) )
                    {
                        info.srWindow.Top = 0;
                        info.srWindow.Left = 0;
                    }
                    ptrm->dwCurLine = info.srWindow.Top;
                    ptrm->dwCurChar = info.srWindow.Left;
                }
                else
                {
                    // VT102 - HTS Set Tab Stop 
                    //HTS     Horizontal Tab Set       

                    //<ESC>H

                    //Set a tab stop at the current cursor position.  
                    //Format Effector.
                    
                     if( g_iHTS < MAX_TABSTOPS )
                     {
                        g_rgdwHTS[ g_iHTS++ ] = ptrm->dwCurChar;
                     }
                    
                }
                break;

            case 'I':
                if ( FIsVT52(ptrm) )
                {
                    // VT52 - Reverse linefeed 
                    NewLineUp( pwi, ptrm );
                }
                break;

            case 'J':
                if( FIsVT52( ptrm ))
                {
                    // VT52 - Clears to end of screen 
                    ClearScreen( pwi, ptrm, fdwCursorToEOS );
                }
                break;

            case 'K':
                if ((FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)) && FIsVT80(ptrm) && FIsNECKanji(ptrm) )
                    {
                        /* NEC Kanji IN (Kanji to G0(GL)) */
                        SetKanjiStatus(ptrm,JIS_KANJI_CODE);
                        SetCharSet(ptrm,GRAPHIC_LEFT,rgchJISKanjiChars);
                    }
                else
                if( FIsVT52( ptrm ))
                {
                    // VT52 - Erases to end of line 
                    ClearLine( pwi, ptrm, fdwCursorToEOL );
                }
                break;

            case 'M':
                // VT102 - RI Reverse Index, cursor up 1 line, can scroll 

                //RI      Reverse Index       

                //<ESC>M

                //Move the cursor up one line without changing columns.  If the
                //cursor is on the top line, a scroll down is performed.


                NewLineUp( pwi, ptrm );
                break;

            case 'N':
                if ((FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)))
                    {
                    if(FIsVT80(ptrm)) {
                        if( !(GetKanjiStatus(ptrm) & JIS_KANJI_CODE) &&
                            (FIsJISKanji(ptrm) || FIsJIS78Kanji(ptrm) ||
                            FIsEUCKanji(ptrm) || FIsDECKanji(ptrm)      ) ) {
                            PushCharSet(ptrm,GRAPHIC_LEFT,ptrm->g2);
                            PushCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g2);
                            SetKanjiStatus(ptrm,SINGLE_SHIFT_2);
#ifdef DEBUG
                            wsprintf(rgchDbgBfr,"VT80 EUC/DEC/JIS SS2 Mode Enter\n");
                            OutputDebugString(rgchDbgBfr);
#endif /* DEBUG */
                        }
                    }
                    }
                break;
            case 'O':
                if ((FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)))
                    {
                    if(FIsVT80(ptrm)) {
                        if( !(GetKanjiStatus(ptrm) & JIS_KANJI_CODE) &&
                            (FIsJISKanji(ptrm) || FIsJIS78Kanji(ptrm) ||
                            FIsEUCKanji(ptrm) || FIsDECKanji(ptrm)      ) ) {
                            PushCharSet(ptrm,GRAPHIC_LEFT,ptrm->g3);
                            PushCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g3);
                            SetKanjiStatus(ptrm,SINGLE_SHIFT_3);
#ifdef DEBUG
                            wsprintf(rgchDbgBfr,"VT80 EUC/DEC/JIS SS3 Mode Enter\n");
                            OutputDebugString(rgchDbgBfr);
#endif /* DEBUG */
                        }
                    }
                    }
                    break;

            case 'Y':
                if ( FIsVT52(ptrm) )
                {
                    // VT52 - direct cursor address 
                    if(( ich + 3 ) <= cbTermOut )
                    {
                        DWORD dwNewLine = ptrm->dwCurLine;
                        dwNewLine = ( pchT[1] > 31 ) ? pchT[1]-32 : 0;
                        if (dwNewLine != ptrm->dwCurLine)
                        {
                            WriteToLog(ptrm->dwCurLine);
                        }
                        ptrm->dwCurLine = dwNewLine;
                        ptrm->dwCurChar = ( pchT[2] > 31 ) ? pchT[2]-32 : 0;
                        {
                            CONSOLE_SCREEN_BUFFER_INFO info;
                            if( !GetConsoleScreenBufferInfo( gwi.hOutput,
                                &info ) )
                            {
                                info.srWindow.Top = 0;
                                info.srWindow.Left = 0;
                            }
                            ptrm->dwCurLine += info.srWindow.Top;
                            ptrm->dwCurChar += info.srWindow.Left;
                        }


                        ich += 2;
                        pchT += 2;
                    }
                    else
                    {
                        ptrm->fEsc = 4;
                        ptrm->dwEscCodes[0] = 0xFFFFFFFF;
                        ptrm->dwEscCodes[1] = 0xFFFFFFFF;
                        ptrm->cEscParams = 0;
                    }
                }
                break;

            case 'Z':
                //DECID   Identify Terminal (DEC Private)
                
                //<ESC>Z

                //This sequence causes the same response as the DA sequence.
                //This sequence will not be supported in future models.

                if( !FIsVT52(ptrm) )
                {

                if ((FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80)) && ( FIsVT80(ptrm) ))
                    {
                        /* VT80 - DECID Identify terminal */
                        pchNBBuffer[0] = 0x1B;
                        pchNBBuffer[1] = '[';
                        pchNBBuffer[2] = '?';
                        pchNBBuffer[3] = '1';
                        pchNBBuffer[4] = '8';
                        pchNBBuffer[5] = ';';
                        pchNBBuffer[6] = '2';
                        pchNBBuffer[7] = 'c';
                        i = 8;
                    }
                    else
                    {
                    // VT102 - DECID Identify terminal 
                    pchNBBuffer[0] = 0x1B;
                    pchNBBuffer[1] = '[';
                    pchNBBuffer[2] = '?';
                    pchNBBuffer[3] = '1';
                    pchNBBuffer[4] = ';';
                    pchNBBuffer[5] = '0';
                    pchNBBuffer[6] = 'c';
                    i = 7;
                    }
                }
                else
                {
                    // VT52 - Identify terminal 
                    pchNBBuffer[0] = 0x1B;
                    pchNBBuffer[1] = '/';
                    pchNBBuffer[2] = 'Z';
                    i = 3;
                }
                ( void ) FWriteToNet( pwi, ( LPSTR ) pchNBBuffer, ( int ) i );
                break;

            case 'c':
                // VT102 RIS Hard reset, reset term to initial state 

                //RIS     Reset to Initial State        
                
                //<ESC>c

                //Resets the VT100 to the state is has upon power up.  This also
                //causes the execution of the POST and signal INT H to be
                //asserted briefly.

                FlushBuffer( pwi, ptrm );
    
    			DoTermReset( pwi, ptrm );

                
                break;

            case '=':
                // VT102 - DECKPAM Enter numeric keypad app mode 

                //DECKPAM Keypad Application Mode (DEC Private)   
                
                //<ESC>=

                //The auxiliary keypad keys will transmit control sequences.

                ClearVTKeypad( ptrm );
                break;

            case '>':
                // VT102 - DECKNPNM Enter numeric keypad numeric mode 

                //DECKPNM Keypad Numeric Mode (DEC Private)        

                //<ESC> >

                //The auxiliary keypad keys will send ASCII codes corresponding
                //to the characters engraved on their keys.

                SetVTKeypad( ptrm );
                break;

            case '<':
                // ENTER - ANSI Mode if in VT52. 
                if( FIsVT52(ptrm) )
                {
                    SetANSI(ptrm);
                }
                break;

            case '(':
                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                    {
                     if ( FIsVT80(ptrm) &&
                        (FIsJISKanji(ptrm) || FIsJIS78Kanji(ptrm))) {
                        // SetKanjiStatus(ptrm,JIS_INVOKE_MB);
                        ptrm->fEsc = 5;
                     }
                    break;
                     } 
                else
                    {
                        ++ich;
                        ++pchT;
                        ptrm->G0 = *pchT;
                        break;
                    }

            case '$':
                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                    {
           
                    if ( FIsVT80(ptrm) &&
                        (FIsJISKanji(ptrm) || FIsJIS78Kanji(ptrm))) {
                        // SetKanjiStatus(ptrm,JIS_INVOKE_SB);
                        ptrm->fEsc = 6;
#if DEBUG
                        _snwprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1,"VT80 JIS MB Invoke Enter\n");
                        OutputDebugString(rgchDbgBfr);
#endif /* DEBUG */
                    }
                   } 
                break;

            case ')':
                
                // VT102 SCS 
                //SCS     Select Character Set
                //The appropriate D0 and G1 character sets are 
                //designated from one of the five possible sets.  The G0
                //and G1 sets are invokedd by the characters <SI> and
                //<SO>, respectively.
                //G0 Sets         G1 Sets
                //Sequence        Sequence      Meaning
                //------------------------------------------------------
                //<ESC>(A         <ESC>)A       United Kingdom Set
                //<ESC>(B         <ESC>)B       ASCII Set
                //<ESC>(0         <ESC>)0       Special Graphics
                //<ESC>(1         <ESC>)1       Alternate Character ROM
                //                              Standard Character Set
                //<ESC>(2         <ESC>)2       Alternate Character ROM
                //                              Special Graphics
                //
                //
                //The United Kingdom and ASCII sets conform to the "ISO 
                //international register of character sets to be used 
                //with escape sequences".  The other sets are private 
                //character sets.  Special graphics means that the 
                //graphic characters fpr the codes 0137 to 0176 are 
                //replaced with other characters.  The specified 
                //character set will be used until another SCS is 
                //recieved.


                ++ich;
                ++pchT;
                ptrm->G1 = *pchT;
                break;

            case '%':
                break;

            case '~':
                if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                    {
                    if(FIsVT80(ptrm)) {
                        SetCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g1);
                    }
                    }
                else
                    break;

            default:
                // Is if a form feed? 
                if( *pchT == 12 )
                {
                    ptrm->dwCurChar = ptrm->dwCurLine = 0;
                    ClearScreen( pwi, ptrm, fdwCursorToEOS );
                }
                break;

            }
            break;



        case 2: // ESC [ entered 
            /*
             * HACK: Handle the problem where a number has been read
             * and then a letter. The number won't be in the dwEscCodes[]
             * since only on a ';' does it get put in there.
             * So, check to see if we have a character which
             * signifies an Control Sequence,
             * i.e. !(0...9) && !'?' && !';'
             *
             * Also, zero out the following element in the dwEscCodes[]
             * array to be safe.
             */
            if( ! (( '0' <= *pchT ) && ( *pchT <= '9' )) && 
                ( *pchT != '?' ) && ( *pchT != ';' ))
            {
                if( ptrm->dwSum == 0xFFFFFFFF )
                {
                    ptrm->dwSum = 0;
                }

                ptrm->dwEscCodes[ptrm->cEscParams++] = ptrm->dwSum;

                if( ptrm->cEscParams < 10 )
                {
                    ptrm->dwEscCodes[ptrm->cEscParams] = 0;
                }
            }

            switch( *pchT )
            {
            case 0x08:      // Backspace 
                if( ptrm->dwCurChar > 0 )
                {
                    --ptrm->dwCurChar;
                }
                break;

            case '\n': //Line Feed 
                //<LF>; 0012; Causes either a line feed or new line operation 
                //(See new line mode.)

                if( ptrm->fFlushToEOL ) 
                {
                    ptrm->fLongLine = FALSE;
                    ptrm->fFlushToEOL = FALSE;
                    break;
                }
                if( ptrm->fLongLine )
                {
                    ptrm->fLongLine = FALSE;
                    break;
                }
                FlushBuffer( pwi, ptrm );
                NewLine( pwi, ptrm );
                break;

            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                if( ptrm->dwSum == 0xFFFFFFFF )
                {
                    ptrm->dwSum = ( *pchT ) - '0';
                }
                else
                {
                    ptrm->dwSum = ( 10 * ptrm->dwSum ) + ( *pchT ) - '0';
                }
                break;

                    /////////////////////////////////////////////////////
                    // Hack for FTCU machine
                    // 'Eat' the Esc?7h escape sequence emitted from FTCU
                    /////////////////////////////////////////////////////
            case '?':
                    // Sets or resets DEC mode 
                    dwDECMode = TRUE;
                    break;

            case ';':

                if( ptrm->cEscParams < 9 )
                {
                    ptrm->dwEscCodes[ptrm->cEscParams++] = ptrm->dwSum;
                    ptrm->dwEscCodes[ptrm->cEscParams] = 0xFFFFFFFF;
                    ptrm->dwSum = 0xFFFFFFFF;
                    break;
                }
                break;

            case 'A':   // VT102 CUU cursor up 
                //CUU   Cursor Up       Host to VT100 & VT100 to Host

                //      <ESC>[ {Pn} A   Default Value: 1

                //Moves the cursor up without changing columns. The cursor is 
                //moved up a number of lines as indicated by the parameter. The
                //cursor cannot be moved beyond the top margin.  Editor Function.

                CursorUp( ptrm );
                break;

            case 'B':   // VT102 CUD cursor down 
            case 'e':
                //CUD   Cursor Down         Host to VT100 & VT100 to Host

                //      <ESC>[ {Pn} B       Default value: 1

                //Moves the cursor down a number of lines as specified in the
                //parameter without changing columns.  The cursor cannot be 
                //moved past the bottom margin.  Editor Function.
            
                CursorDown( ptrm );
                break;

            case 'C':   // VT102 CUF cursor right 
            case 'a':
                //CUF   Cursor Forward         Host to VT100 & VT100 to Host

                //      <ESC>[ {Pn} C                   Default Value: 1

                //The CUF sequence moves the cursor to the right a number of
                //positions specified in the parameter.  The cursor cannot be
                //moved past the right margin.  Editor Function.

            
                CursorRight( ptrm );
                break;

            case 'D':   // VT102 CUB cursor left 
                //CUB     Cursor Backward       Host to VT100 & VT100 to Host

                //         <ESC>[ {Pn} D        Default Value: 1
                
                //The CUB sequence move the cursor to the left.  The distance
                //moved is determined by the parameter.  If the parameter 
                //missing, zero, or one,the cursor is moved one position. 
                //The cursor cannot be moved past the left margin. 
                //Editor Function.

                CursorLeft( ptrm );
                break;
            
            case 'E':   // Move cursor to beginning of line, p lines down.
                
                break;

            case 'F':   // Move active position to beginning of line, p lines up
                
                break;
            
            case '`':   // move cursor to column p
            case 'G':

                break;

            case 'H':   // VT102 CUP position cursor 
                //HVP     Horizontal and Vertical Position        

                //<ESC>[ {Pn} ; {Pn} f

                //Moves the cursor to the position specified by the parameters.
                //The first parameter specifies the line, and the second 
                //specifies the column.  A parameter of 0 or 1 causes the active
                //position to move to the first line or column in the display.  
                //In the VT100, this control behaves identically with it's editor
                //counterpart, CUP.  The numbering of the lines depends upon the
                //state of the Origin Mode (DECOM).  Format Effector.

            case 'f':   // VT102 HVP position cursor 

                //CUP   Cursor Position         

                //<ESC>[ {Pn} ; {Pn} H            Default Value: 1

                //The CUP sequence moves the curor to the position specified by
                //the parameters.  The first parameter specifies the line, and 
                //the second specifies the column.  A value of zero for either 
                //line or column moves the cursor to the first line or column in
                //the display.  The default string (<ESC>H) homes the cursor. In
                //the VT100, this command behaves identically to it's format 
                //effector counterpart, HVP.The numbering of the lines depends 
                //upon the state of the Origin Mode (DECOM).  Editor Function.


                if( ptrm->dwEscCodes[0] == 0 )
                {
                    ptrm->dwEscCodes[0] = 1;
                }

                if( ptrm->dwEscCodes[1] == 0 )
                {
                    ptrm->dwEscCodes[1] = 1;
                }

                {
                    DWORD dwNewLine = 0;
                    CONSOLE_SCREEN_BUFFER_INFO info;

                    if( !GetConsoleScreenBufferInfo( gwi.hOutput, 
                        &info ) )
                    {
                        info.srWindow.Top = 0;
                        info.srWindow.Left = 0;
                    }
                    dwNewLine = info.srWindow.Top +
                                        ( ptrm->dwEscCodes[0] - 1 );
                    ptrm->dwCurChar = info.srWindow.Left +
                                    ( ptrm->dwEscCodes[1] - 1 );

                    if( ( SHORT )ptrm->dwCurChar >=  info.srWindow.Right )
                    {
                        ptrm->dwCurChar = info.srWindow.Right;
                    }

                    if( ( SHORT )dwNewLine >= info.srWindow.Bottom  )
                    {
                        dwNewLine = info.srWindow.Bottom;
                    }

                    if( ui.bLogging && dwNewLine != ptrm->dwCurLine )
                    {
                        WriteToLog( ptrm->dwCurLine );
                    }

                    ptrm->dwCurLine = dwNewLine;

                }


                if(( ptrm->fRelCursor == TRUE ) && ( ptrm->dwCurLine < ptrm->dwScrollTop ))
                {
                    ptrm->dwCurLine = ptrm->dwScrollTop;
                }
                if ((ptrm->fRelCursor == TRUE) && (ptrm->dwCurLine >= ptrm->dwScrollBottom))
                {
                    ptrm->dwCurLine = ptrm->dwScrollBottom - 1;
                }

                ptrm->fEsc = 0;
                ptrm->fFlushToEOL = FALSE;
                ptrm->fLongLine = FALSE;
                break;

            case 'J':       // VT102 ED erase display 

                //ED      Erase in Display

                //<ESC>[ {Ps} J         Default: 0

                //This sequence erases some or all of the characters in the 
                //display according to the parameter.  Any complete line erased
                //by this sequence will return that line to single width mode.  
                //Editor Function.

                //Parameter    Meaning
                //-------------------------------------------------------------
                //    0        Erase from the cursor to the end of the screen.
                //    1        Erase from the start of the screen to the cursor.
                //    2        Erase the entire screen.

                ClearScreen( pwi, ptrm, ptrm->dwEscCodes[0] );
                break;


            case 'K':       // VT102 EL erase line 
                //EL      Erase in Line

                //<ESC>[ {Ps} K                                   Default: 0

                //Erases some or all characters in the active line, according to
                //the parameter.  Editor Function.     

                //Parameter       Meaning
                //-------------------------------------------------------------
                //0               Erase from cursor to the end of the line.
                //1               Erase from the start of the line to the cursor.
                //2               Erase the entire line.

                ClearLine( pwi, ptrm, ptrm->dwEscCodes[0] );
                break;

            case 'L':       // VT102 IL insert lines 
            {
                int j;
                if( ptrm->dwEscCodes[0] == 0 )
                {
                    ptrm->dwEscCodes[0] = 1;
                }
                
                for( j = 0 ; ( WORD )j < ptrm->dwEscCodes[0]; j++ )
                {
                    InsertLine( pwi, ptrm, ptrm->dwCurLine );
                }

                ptrm->fEsc = 0;
                break;
            }
            case 'M':       // VT102 DL delete line 
            {
                int j;

                if( ptrm->dwEscCodes[0] == 0 )
                {
                    ptrm->dwEscCodes[0] = 1;
                }

                //DeleteLines( pwi, ptrm, ptrm->dwCurLine, ptrm->dwEscCodes[0] );
                for( j = 0 ; ( WORD )j < ptrm->dwEscCodes[0]; j++ )
                {
                    DeleteLine( pwi, ptrm, ptrm->dwCurLine );
                }


                ptrm->fEsc = 0;

                break;
            }
            case '@':       // VT102 ICH? insert characters 
                if( ptrm->dwEscCodes[0] == 0 )
                {
                        ptrm->dwEscCodes[0] = 1;
                }
                
                if( ptrm->dwEscCodes[0] > ( ui.dwMaxCol - ptrm->dwCurChar ))
                {
                    ptrm->dwEscCodes[0] = ui.dwMaxCol - ptrm->dwCurChar;
                }

                i = ptrm->dwCurChar+ptrm->dwEscCodes[0];

                if(( ui.dwMaxCol-i ) > 0 )
                {
                    SMALL_RECT  lineRect;
                    COORD       dwDest;

                    // Form a rectangle for the line.
                    lineRect.Bottom = ( short ) ptrm->dwCurLine;
                    lineRect.Top = ( short ) ptrm->dwCurLine;
                    lineRect.Left = ( short ) ptrm->dwCurChar; 
                    lineRect.Right = ( short ) ( ui.dwMaxCol );
                    
                    // Destination is one character to the right.
                    dwDest.X = ( short ) (i);
                    dwDest.Y = ( short ) ptrm->dwCurLine;

                    pwi->cinfo.Attributes = pwi->sbi.wAttributes;
                    ScrollConsoleScreenBuffer( pwi->hOutput, &lineRect, NULL, dwDest, &pwi->cinfo );
                }

                if( ui.bLogging )
                {
                    WriteToLog( ptrm->dwCurLine );
                }

                ptrm->fEsc = 0;
                break;

            case 'P':       // VT102 DCH delete chars 
                if( ptrm->dwEscCodes[0] == 0 )
                {
                    ptrm->dwEscCodes[0] = 1;
                }
                if( ptrm->dwEscCodes[0] > ( ui.dwMaxCol-ptrm->dwCurChar ))
                {
                    ptrm->dwEscCodes[0] = ui.dwMaxCol-ptrm->dwCurChar;
                }

                if(( ui.dwMaxCol - ptrm->dwCurChar - 1) > 0 )
                {
                    SMALL_RECT lineRect;
                    COORD      dwDest;
                    SMALL_RECT clipRect;

                    // Form a rectangle for the line.
                    lineRect.Bottom = ( short ) ptrm->dwCurLine;
                    lineRect.Top = ( short ) ptrm->dwCurLine;
                    lineRect.Left = ( short ) ptrm->dwCurChar; 
                    lineRect.Right = ( short )( ui.dwMaxCol );
                    
                    clipRect = lineRect;

                    // Destination is one character to the right.
                    dwDest.X = ( short ) ( ptrm->dwCurChar - ptrm->dwEscCodes[0] );
                    dwDest.Y = ( short ) ptrm->dwCurLine;

                    pwi->cinfo.Attributes = pwi->sbi.wAttributes;
                    ScrollConsoleScreenBuffer( pwi->hOutput, &lineRect, &clipRect, dwDest, &pwi->cinfo );
                }

                if( ui.bLogging )
                {
                    WriteToLog( ptrm->dwCurLine );
                }

                ptrm->fEsc = 0;
                break;

            case 'S':

                break;

            case 'T':
            
                break;

            case 'X':   // Erase p characters up to the end of line

                break;

            case 'Z':   // move back p tab stops

                break;

            case 'c':       // VT102 DA Same as DECID 

                //DA    Device Attributes       Host to VT100 & VT100 to Host

                //      <ESC>[ {Pn} c           Default Value: 0

                //1) The host requests the VT100 to send a DA sequence to 
                //indentify itself.  This is done by sending the DA sequence
                //with no parameters, or with a parameter of zero.

                //2) Response to the request described above (VT100 to host) is
                //generated by the VT100 as a DA control sequencewith the 
                //numeric parameters as follows: 
                
                //Option Present                  Sequence Sent
                //---------------------------------------------
                //No options                      <ESC>[?1;0c
                //Processor Option (STP)          <ESC>[?1;1c
                //Advanced Video Option (AVO)     <ESC>[?1;2c
                //AVO and STP                     <ESC>[?1;3c
                //Graphics Option (GPO)           <ESC>[?1;4c
                //GPO and STP                     <ESC>[?1;5c
                //GPO and AVO                     <ESC>[?1;6c
                //GPO, ACO, and STP               <ESC>[?1;7c


                pchNBBuffer[0] = 0x1B;
                pchNBBuffer[1] = '[';
                pchNBBuffer[2] = '?';
                pchNBBuffer[3] = '1';
                pchNBBuffer[4] = ';';
                pchNBBuffer[5] = '0';
                pchNBBuffer[6] = 'c';
                i = 7;

                ( void ) FWriteToNet( pwi, ( LPSTR ) pchNBBuffer, ( int ) i );
                ptrm->fEsc = 0;

                break;

            case 'd': // move to line p

                break;

            case 'g':       // VT102 TBC Clear Tabs 
                //TBC     Tabulation Clear     

                //<ESC>[ {Ps} g

                //If the parameter is missing or 0, this will clear the tab stop
                //at the cursor's position.  If it is 3, this will clear all of 
                //the tab stops. Any other parameter is ignored.  Format Effector.

                if( ptrm->dwEscCodes[0] == 3 )
                {
                    // Clear all tabs 
                    g_iHTS = 0; 
                }
                else if( ptrm->dwEscCodes[0] == 0 && g_iHTS )
                {
                    // Clear tab stop at current position 
                    int x=0;
                    while( x < g_iHTS )
                    {
                        if( g_rgdwHTS[ x ] >= ptrm->dwCurChar && 
                            g_rgdwHTS[ x ] != -1 )
                        {
                            if( g_rgdwHTS[ x ] == ptrm->dwCurChar )
                            {
                                g_rgdwHTS[ x ] = ( DWORD )-1; //clear the tab stop
                            }
                            break;
                        }

                        x++;
                    }
                }

                ptrm->fEsc = 0;
                break;

            case 'h':
                //SM      Set Mode     
                
                //<ESC> [ {Ps} ; {Ps} h

                //Causes one or more modes to be set within the VT100 as 
                //specified by each selective parameter string.  Each mode to be
                //set is specified by a seperate parameter.  A mode is 
                //considered set until it is reset by a Reset Mode (RM) control 
                //sequence.  See RM and MODES.

                //[Editor's note: The original DEC VT100 documentation 
                //EK-VT100-UG-003 erroneously omitted the "[" character from the
                //SM sequence.]

                for( i = 0; i < ptrm->cEscParams; ++i )
                {
                    if( dwDECMode == TRUE )
                    {
                        switch( ptrm->dwEscCodes[i] )
                        {       // Field specs 
                        
                        case 0:
                            //Error (ignored)
                            break;

                        case 1: // DECCKM  

                            //DECCKM  Cursor Keys Mode (DEC Private)
                            //This is a private parameter to the SM and RM 
                            //control requences. This mode is only effective 
                            //when the terminal is in keypad application mode
                            //(DECPAM) and the ANSI/VT52 mode (DECANM) is set. 
                            //Under these conditions, if this mode is reset, 
                            //the cursor keys will send ANSI cursor control 
                            //commands.  If setm the cursor keys will send 
                            //application function commands (See MODES, RM,
                            //and SM).

                            /*This is a hack so that in vt100, vi works properly
                             * */
                            {
                                CONSOLE_SCREEN_BUFFER_INFO info;
                                if( !GetConsoleScreenBufferInfo( gwi.hOutput,
                                        &info ) )
                                {
                                    consoleBufferInfo.srWindow.Top = 0;
                                    consoleBufferInfo.srWindow.Bottom = 0;
                                }
                                if( FGetCodeMode(eCodeModeFarEast) )
                                {
                                    SetMargins( ptrm, info.srWindow.Top,
                                            info.srWindow.Bottom );
                                }
                                else
                                {
                                    SetMargins( ptrm, info.srWindow.Top,
                                            info.srWindow.Bottom + 1);
                                }
                            }
                            
                            SetVTArrow( ptrm );
                            break;

                        case 2: // DECANM : ANSI/VT52 

                            //DECANM  ANSI/VT52 Mode (DEC Private)

                            //This is a private parameter to the SM and RM 
                            //control sequences. The reset state causes only 
                            //VT52 compatible escape sequences to be recognized.
                            //The set state causes only ANSI compatible escape 
                            //sequences to be recognized.  See the entries for 
                            //MODES, SM, and RM.


                            SetANSI( ptrm ); //ClearVT52(ptrm);
                            ClearVT52Graphics( ptrm );
                            if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))

                                SetCharSet(ptrm,GRAPHIC_LEFT,rgchIBMAnsiChars);
                            else
                                ptrm->puchCharSet = rgchNormalChars;
                            break;

                        case 3: // DECCOLM : Col = 132 
                            //DECCOLM Column Mode (DEC Private)
                            //This is a private parameter to the SM and RM 
                            //control sequences. The reset state causes an 80
                            //column screen to be used.  The set state causes a 
                            //132 column screen to be used.  See MODES, RM, and
                            //SM.
                        
                            SetDECCOLM(ptrm);

                            GetConsoleScreenBufferInfo( gwi.hOutput, 
                                    &consoleBufferInfo );
                            consoleBufferInfo.srWindow.Right = 131;
                            dwSize.X = 132;
                            dwSize.Y = consoleBufferInfo.dwSize.Y;
                            dwMaximumWindowSize = 
                                GetLargestConsoleWindowSize( gwi.hOutput );
                            if( 131 > dwMaximumWindowSize.X )
                            {
                                consoleBufferInfo.srWindow.Right = 
                                     ( SHORT )( dwMaximumWindowSize.X - 1 - 
                                    consoleBufferInfo.srWindow.Left );
                            }
                            if( consoleBufferInfo.dwSize.X <= 132 )
                            {
                                SetConsoleScreenBufferSize( gwi.hOutput,
                                    dwSize );
                                SetConsoleWindowInfo( gwi.hOutput, TRUE, 
                                    &(consoleBufferInfo.srWindow) );  
                            }
                            else
                            {
                                SetConsoleWindowInfo( gwi.hOutput, TRUE, 
                                    &(consoleBufferInfo.srWindow) ); 
                                SetConsoleScreenBufferSize( gwi.hOutput,
                                    dwSize );
                            }
                            //update global data structures
                            ui.dwMaxCol = 132;
                            gwi.sbi.dwSize.X = 132;
                            consoleBufferInfo.dwSize.X = 132;

                            ClearScreen( pwi, ptrm, fdwEntireScreen );
                            break;

                        case 4: // DECSCLM : smooth scroll
                            // Scrolling Mode (DEC Private)
                            // This is a private parameter to RM and 
                            // SM control sequences.  The reset
                            // state causes scrolls to "jump" 
                            // instantaneuously one line at a time.
                            // The set state causes the scrolls to be
                            // "smooth", and scrolls at a maximum rate 
                            // of siz lines/sec.  See MODES, RM, and SM.
                            
                            break;

                        case 5: // DECSCNM : Light background
                            //DECSCNM Screen Mode (DEC Private)
                            //This is a private parameter to RM and SM 
                            //control sequences.  The reset state causes 
                            //the screen to be black with white 
                            //characters; the set state causes the 
                            //screen to be white with black characters.
                            //See MODES, RM, and SM.
                            
                            if( FIsDECSCNM( ptrm ) )
                            {
                                break;
                            }
                            SetDECSCNM( ptrm );

                            SetLightBackground( pwi );
                            break;

                        case 6: // DECOM : Relative origin ; stay in margin
                            //DECOM   Origin Mode (DEC Private)
                            //This is a private parameter to SM and RM control
                            //sequences. The reset state causes the origin (or 
                            //home position) to be the upper left character 
                            //position of the screen.  Line and column numbers
                            //are, therefore, independent of current margin 
                            //settings.  The cursor may be positioned outside 
                            //the margins with a cursor position (CUP) or
                            //horizontal and vertical position (HVP) control.

                            //The set state causes the origin to be at the upper
                            //left character position within the current margins. 
                            //Line and column numbers are, therefore, relative 
                            //to the current margin settings.  The cursor cannot
                            //be positioned outside of the margins.

                            //The cursor is moved to the new home position when 
                            //this mode is set or reset.  Lines and columns are 
                            //numbered consecutively, with the origin being 
                            //line 1, column 1.

                            ptrm->fRelCursor = TRUE;
                            ptrm->dwCurChar = 0;
                            ptrm->dwCurLine = ptrm->dwScrollTop;

                            break;

                        case 7: // DECAWM 

                            //DECAWM  Autowrap Mode (DEC Private)
                            //This is a private parameter to the SM and RM
                            //control sequences. The reset state prevents the
                            //cursor from moving when characters are recieved 
                            //while at the right margin.  The set state causes
                            //these characters to advance to the next line, 
                            //causing a scroll up if required and permitted.  
                            //See MODES, SM, and RM.

                            SetVTWrap( ptrm );
                            break;

                        case 8: // DECARM : auto-repeat keys

                            //DECARM  Auto Repeat Mode (DEC Private)
                            //This is a private parameter to the SM and RM 
                            //control sequences. The reset state causes no 
                            //keyboard keys to auto-repeat, the set state
                            //causes most of them to.  See MODES, SM, and RM.

                            break;

                        case 9: // DECINLM 
                            //DECINLM Interlace Mode (DEC Private)

                            //This is a private parameter to the RM and SM 
                            //control sequences.  The reset state 
                            //(non-interlace) causes the video processor to 
                            //display 240 scan lines per frame.  The set state 
                            //causes the video processor to display 480 scan 
                            //lines per screen.  See MODES, RM, and SM.

                            break;

                        case 18: // Send FF to printer
                            break;

                        case 19: // Entire screen legal for printer
                            break;

                        case 25: // Visible cursor
                            break;

                        case 66: // Application numeric keypad
                            break;
            
                        default:
                            break;
                        }
                    }
                    else
                    {
                        switch( ptrm->dwEscCodes[i] )
                        {
                        case 0:
                            // Error (Ignored)
                            break;

                        case 2: // Keyboard locked 
                            SetKeyLock( ptrm );
                            break;

                        case 3: // act on control codes
                            break;

                        case 4: // Ansi insert mode  
                            SetInsertMode( ptrm );
                            break;

                        case 12: // Local echo off
                            break;

                        case 20: // Ansi linefeed mode ; Newline sends cr/lf
                            //LNM     Line Feed/New Line Mode
                            //This is a parameter to SM and RM control sequences.
                            //The reset state causes the interpretation of the 
                            //<LF> character to imply only vertical movement of 
                            //the cursor and causes the RETURN key to send the 
                            //single code <CR>.  The set state causes the <LF>
                            //character to imply movement to the first position
                            //of the following line, and causes the RETURN key
                            //to send the code pair <CR><LF>.  This is the New 
                            //Line option.

                            //This mode does not affect the Index (IND) or the 
                            //next line (NEL) format effectors.

                            SetLineMode( ptrm );
                            break;

                        default:
                            break;
                        }
                    }
                }

                ptrm->fEsc = 0;
                break;

            case 'l':       // Reset Mode ( unset extended mode )
                //RM      Reset Mode        

                //<ESC>[ {Ps} ; {Ps} l

                //Resets one or more VT100 modes as specified by each selective
                //parameter in the parameter string.  Each mode to be reset is 
                //specified by a separate parameter.  See MODES and SM.
                
                for( i = 0; i < ptrm->cEscParams; ++i )
                {
                    if( dwDECMode == TRUE )
                    {
                        switch( ptrm->dwEscCodes[i] )
                        {       // Field specs 
                        case 0:
                            //Error (Ignored)
                            break;

                        case 1: // DECCKM  : numeric cursor keys
                            //DECCKM  Cursor Keys Mode (DEC Private)
                            //This is a private parameter to the SM and RM 
                            //control requences. This mode is only effective 
                            //when the terminal is in keypad application mode
                            //(DECPAM) and the ANSI/VT52 mode (DECANM) is set. 
                            //Under these conditions, if this mode is reset, 
                            //the cursor keys will send ANSI cursor control 
                            //commands.  If setm the cursor keys will send 
                            //application function commands (See MODES, RM,
                            //and SM).

                            /* This is a hack so that you will scroll even after
                             * coming out of vi in vt100.
                             * In vt100, vi sets scroll regions. but does not
                             * reset when vi is exited */
                            {
                                CONSOLE_SCREEN_BUFFER_INFO info;
                                if( !GetConsoleScreenBufferInfo( gwi.hOutput,
                                        &info ) )
                                {
                                    consoleBufferInfo.dwSize.Y = 0;
                                }

                                SetMargins( ptrm, 1, info.dwSize.Y );
                            }

                            ClearVTArrow( ptrm );
                            break;

                        case 2: // DECANM : ANSI/VT52
                            //DECANM  ANSI/VT52 Mode (DEC Private)

                            //This is a private parameter to the SM and RM 
                            //control sequences. The reset state causes only 
                            //VT52 compatible escape sequences to be recognized.
                            //The set state causes only ANSI compatible escape 
                            //sequences to be recognized.  See the entries for 
                            //MODES, SM, and RM.

                            SetVT52( ptrm );
                            ClearVT52Graphics( ptrm );
                            break;

                        case 3: // DECCOLM : 80 col 
                            //DECCOLM Column Mode (DEC Private)
                            //This is a private parameter to the SM and RM 
                            //control sequences. The reset state causes an 80
                            //column screen to be used.  The set state causes a 
                            //132 column screen to be used.  See MODES, RM, and
                            //SM.
                        
                            ClearDECCOLM( ptrm );
                            
                            GetConsoleScreenBufferInfo( gwi.hOutput, 
                                    &consoleBufferInfo );
                            consoleBufferInfo.srWindow.Right = 79;
                            dwMaximumWindowSize = 
                                GetLargestConsoleWindowSize( gwi.hOutput );
                            if( 79 > dwMaximumWindowSize.X )
                            {
                                consoleBufferInfo.srWindow.Right = 
                                    ( SHORT ) ( dwMaximumWindowSize.X - 1 - 
                                    consoleBufferInfo.srWindow.Left );
                            }
                            dwSize.X = 80;
                            dwSize.Y = consoleBufferInfo.dwSize.Y;
                            if( consoleBufferInfo.dwSize.X <= 80 )
                            {
                                SetConsoleScreenBufferSize( gwi.hOutput,
                                    dwSize );
                                SetConsoleWindowInfo( gwi.hOutput, TRUE, 
                                    &(consoleBufferInfo.srWindow) ); 
                            }
                            else
                            {
                                SetConsoleWindowInfo( gwi.hOutput, TRUE, 
                                    &(consoleBufferInfo.srWindow) ); 
                                SetConsoleScreenBufferSize( gwi.hOutput,
                                    dwSize );
                            }
                            //Update global data structures.
                            ui.dwMaxCol = 80;
                            gwi.sbi.dwSize.X = 80;
                            consoleBufferInfo.dwSize.X = 80;

                            ClearScreen( pwi, ptrm, fdwEntireScreen );
                            break;

                        case 4: // DECSCLM : jump scroll
                            // Scrolling Mode (DEC Private)
                            // This is a private parameter to RM and 
                            // SM control sequences.  The reset
                            // state causes scrolls to "jump" 
                            // instantaneuously one line at a time.
                            // The set state causes the scrolls to be
                            // "smooth", and scrolls at a maximum rate 
                            // of siz lines/sec.  See MODES, RM, and SM.
                                break;

                        case 5: // DECSCNM ; dark background
                            //DECSCNM Screen Mode (DEC Private)
                            //This is a private parameter to RM and SM 
                            //control sequences.  The reset state causes 
                            //the screen to be black with white 
                            //characters; the set state causes the 
                            //screen to be white with black characters.
                            //See MODES, RM, and SM.
                                if( !FIsDECSCNM( ptrm ) )
                                {
                                    break;
                                }

                                //was setting instead of clearing
                                //SetDECSCNM( ptrm ); 
                                ClearDECSCNM( ptrm );

                                SetDarkBackground( pwi );
                                break;

                        case 6: // DECOM : Relative origin ; ignore margins
                            //DECOM   Origin Mode (DEC Private)
                            //This is a private parameter to SM and RM control
                            //sequences. The reset state causes the origin (or 
                            //home position) to be the upper left character 
                            //position of the screen.  Line and column numbers
                            //are, therefore, independent of current margin 
                            //settings.  The cursor may be positioned outside 
                            //the margins with a cursor position (CUP) or
                            //horizontal and vertical position (HVP) control.

                            //The set state causes the origin to be at the upper
                            //left character position within the current margins. 
                            //Line and column numbers are, therefore, relative 
                            //to the current margin settings.  The cursor cannot
                            //be positioned outside of the margins.

                            //The cursor is moved to the new home position when 
                            //this mode is set or reset.  Lines and columns are 
                            //numbered consecutively, with the origin being 
                            //line 1, column 1.

                            ptrm->fRelCursor = FALSE;
                            ptrm->dwCurChar = ptrm->dwCurLine = 0;
                            break;

                        case 7: // DECAWM 
                            //DECAWM  Autowrap Mode (DEC Private)
                            //This is a private parameter to the SM and RM
                            //control sequences. The reset state prevents the
                            //cursor from moving when characters are recieved 
                            //while at the right margin.  The set state causes
                            //these characters to advance to the next line, 
                            //causing a scroll up if required and permitted.  
                            //See MODES, SM, and RM.

                            ClearVTWrap( ptrm );
                            break;

                        case 8: // DECARM ; auto-repeat keys

                            //DECARM  Auto Repeat Mode (DEC Private)
                            //This is a private parameter to the SM and RM 
                            //control sequences. The reset state causes no 
                            //keyboard keys to auto-repeat, the set state
                            //causes most of them to.  See MODES, SM, and RM.

                                break;

                        case 9: // DECINLM 
                            //DECINLM Interlace Mode (DEC Private)

                            //This is a private parameter to the RM and SM 
                            //control sequences.  The reset state 
                            //(non-interlace) causes the video processor to 
                            //display 240 scan lines per frame.  The set state 
                            //causes the video processor to display 480 scan 
                            //lines per screen.  See MODES, RM, and SM.

                            break;
                        
                        case 19: // send only scrolling region to printer
                            break;

                        case 25: // cursor should be invisible
                            break;

                        case 66: // Numeric keypad
                            break;

                        default:
                            break;
                        }
                    }
                    else
                    {
                        switch ( ptrm->dwEscCodes[i] )
                        {
                        case 0:
                            //Error (Ignored)
                            break;

                        case 2: // Keyboard unlocked 
                            ClearKeyLock( ptrm );
                            break;

                        case 3: // display control codes

                        case 4: // Ansi insert mode ; set overtype mode
                            ClearInsertMode( ptrm );
                            break;

                        case 12: // local echo on
                            break;

                        case 20: // Ansi linefeed mode ; new-line sends only lf
                            //LNM     Line Feed/New Line Mode
                            //This is a parameter to SM and RM control sequences.
                            //The reset state causes the interpretation of the 
                            //<LF> character to imply only vertical movement of 
                            //the cursor and causes the RETURN key to send the 
                            //single code <CR>.  The set state causes the <LF>
                            //character to imply movement to the first position
                            //of the following line, and causes the RETURN key
                            //to send the code pair <CR><LF>.  This is the New 
                            //Line option.

                            //This mode does not affect the Index (IND) or the 
                            //next line (NEL) format effectors.

                            ClearLineMode( ptrm );
                            break;

                        default:
                            break;
                        }
                    }
                }
                ptrm->fEsc = 0;
                break;
            
            case 'i': // VT102 MC Media Copy ; print screen

                if( ptrm->dwEscCodes[0] == 5 )
                {
                    // Enter Media copy 
                }
                else if( ptrm->dwEscCodes[0] == 4 )
                {
                    // Exit Media copy 
                }
                ptrm->fEsc = 0;

            case '=':
                break;

            case '}':
            case 'm': // VT102 SGR Select graphic rendition ; set color
                //SGR     Select Graphic Rendition        
                //<ESC>[ {Ps} ; {Ps} m
                //Invoke the graphic rendition specified by the 
                //parameter(s).  All following characters transmitted 
                //to the VT100 are rendered according to the 
                //parameter(s) until the next occurrence of an SGR.  
                //FormatEffector. 
                //
                //Parameter       Meaning
                //---------------------------------------------
                //    0           Attributes Off
                //    1           Bold or increased intensity
                //    4           Underscore            
                //    5           Blink
                //    7           Negative (reverse) image
                //
                //All other parameter values are ignored.
                //
                //Without the Advanced Video Option, only one type of 
                //character attribute is possible, as determined by the
                //cursor selection; in that case specifying either 
                //underscore or reverse will activate the currently
                //selected attribute.
                //
                //[Update:  DP6429 defines parameters in the 30-37 range
                //to change foreground color and in the 40-47 range to 
                //change background.]

                for( i = 0; i < ( DWORD )ptrm->cEscParams; ++i )
                {
                    ptrm->rgdwGraphicRendition[i] = ptrm->dwEscCodes[i];
                    ptrm->dwIndexOfGraphicRendition = i;
                }
                SetGraphicRendition( pwi, ptrm, ptrm->dwIndexOfGraphicRendition,
                        ptrm->rgdwGraphicRendition );

                ptrm->fEsc = 0;
                break;

            case 'n': // VT102 DSR ; // report cursor position Row X Col

                //DSR     Device Status Report     Host to VT100 & VT100 to Host

                //<ESC>[ {Ps} n

                //Requests and reports the general status of the VT100 according
                //to the following parameters:       
                
                //Parameter       Meaning
                //--------------------------------------------------------------
                //  0            Response from VT100 - Ready, no faults detected
                //  3            Response from VT100 - Malfunction Detected
                //  5            Command from host - Report Status (using a DSR 
                //               control sequence)
                //  6            Command from host - Report Active Position 
                //               (using a CPR sequence)

                //DSR with a parameter of 0 or 3 is always sent as a response to
                //a requesting DSR with a parameter of 5.

                pchNBBuffer[0] = 0;
                if( ptrm->dwEscCodes[0] == 5 )
                {
                    // Terminal Status Report 
                    pchNBBuffer[0] = 0x1B;
                    pchNBBuffer[1] = '[';
                    pchNBBuffer[2] = 'c';
                    i = 3;
                }
                else if( ptrm->dwEscCodes[0] == 6 )
                {
                    CONSOLE_SCREEN_BUFFER_INFO info;
                    if( !GetConsoleScreenBufferInfo( gwi.hOutput,
                        &info ) )
                    {
                        info.srWindow.Top = 0;
                        info.srWindow.Left = 0;
                    }

                    i = _snprintf( ( CHAR * )pchNBBuffer,sizeof(pchNBBuffer)-1,"%c[%d;%dR", 
                        ( char ) 0x1B, 
			(ptrm->dwCurLine + 1 - info.srWindow.Top),
                        (ptrm->dwCurChar + 1 - info.srWindow.Left));
                }

                if( pchNBBuffer[0] != 0 )
                {
                    ( void ) FWriteToNet( pwi, ( LPSTR ) pchNBBuffer, 
                        ( int ) i );
                }

                // fall through 

            case 'q':       // Load LEDs 
                
                //DECLL   Load LEDs (DEC Private)

                //<ESC>[ {Ps} q                           Default Value: 0

                //Load the four programmable LEDs on the keyboard according to
                //theparameter(s).
                
                    //Parameter       Meaning
                    //-----------------------
                    //    0           Clear All LEDs
                    //    1           Light L1      
                    //    2           Light L2
                    //    3           Light L3
                    //    4           Light L4    

                ptrm->fEsc = 0;
                break;              // (nothing) 

            case 'p':
                break;
                
            case 'r': // VT102 DECSTBM ; scroll screen
                //DECSTBM Set Top and Bottom Margins (DEC Private)

                //<ESC>[ {Pn} ; {Pn} r      Default Values: See Below
                
                //This sequence sets the top and bottom margins to define the 
                //scrolling region.  The first parameter is the line number of 
                //the first line in the scrolling region; the second parameter 
                //is the line number of the bottom line of the scrolling region. 
                //Default is the entire screen (no margins).  The minimum region
                //allowed is two lines, i.e., the top line must be less than the
                //bottom.  The cursor is placed in the home position (See DECOM).
            
                if( ( ptrm->cEscParams < 2 ) || ( ptrm->dwEscCodes[1] == 0 ) )
                {
                    ptrm->dwEscCodes[1] = ui.dwMaxRow;
                }

                if( ptrm->dwEscCodes[0] == 0 )
                {
                    ptrm->dwEscCodes[0] = 1;
                }
                
                {
                    CONSOLE_SCREEN_BUFFER_INFO info;
                    if( !GetConsoleScreenBufferInfo( gwi.hOutput, 
                            &info ) )
                    {
                        consoleBufferInfo.srWindow.Top = 0;
                    }

                    if(( ptrm->dwEscCodes[0] > 0 ) &&
                        ( ptrm->dwEscCodes[0] < ptrm->dwEscCodes[1]) &&
                        ( ptrm->dwEscCodes[1] <= ui.dwMaxRow ))
                    {
                        SetMargins( ptrm, 
                            info.srWindow.Top + ptrm->dwEscCodes[0], 
                            info.srWindow.Top + ptrm->dwEscCodes[1] );
                        
                        ptrm->dwCurChar = 0;
                        ptrm->dwCurLine = ( ptrm->fRelCursor == TRUE ) 
                            ? ptrm->dwScrollTop : 0;
                        
                        ptrm->fFlushToEOL = FALSE;
                    }
                }
                ptrm->fEsc = 0;
                break;
            

            case 's': // ANSI.SYS save current cursor pos 
                ptrm->dwSaveChar = ptrm->dwCurChar;
                ptrm->dwSaveLine = ptrm->dwCurLine;
                ptrm->fEsc = 0;
                break;

            case 'u': // ANSI.SYS restore current cursor pos 
                ptrm->dwCurChar = ptrm->dwSaveChar;
                ptrm->dwCurLine = ptrm->dwSaveLine;
                ptrm->fEsc = 0;
                ptrm->fFlushToEOL = FALSE;
                break;
            
            case 'x': // DEC terminal report
                // DECREQTPARM     Request Terminal Parameters  
                // <ESC>[ {Ps} x
                //The host sends this sequence to request the VT100 to
                //send a DECREPTPARM sequence back. {Ps} can be either
                //0 or 1.  If 0, the terminal will be allowed to send
                //unsolicited DECREPTPARMs.  These reports will be
                //generated each time the terminal exits the SET-UP 
                //mode.  If {Ps} is 1, then the terminal will only 
                //generate DECREPTPARMs in response to a request.
                if( ptrm->dwEscCodes[0] )
                {
                    strncpy( pchNBBuffer,"\033[3;1;1;128;128;1;0x",sizeof(pchNBBuffer)-1);
                    i = strlen(pchNBBuffer);
                }
                else
                {
                    strncpy( pchNBBuffer,"\033[3;1;1;128;128;1;0x",sizeof(pchNBBuffer)-1 );
                    i = strlen(pchNBBuffer);
                }
                
                if( pchNBBuffer[0] != 0 )
                {
                    ( void ) FWriteToNet( pwi, ( LPSTR ) pchNBBuffer, i );
                }
                break;

            case 'y':
                //
                //DECTST  Invoke Confidence Test       
                    
                //    <ESC>[ 2 ; {Ps} y

                //Ps is the parameter indicating the test to be done.  It is 
                //computed by taking the weight indicated for each desired test
                //and adding them together.  If Ps is 0, no test is performed 
                //but the VT100 is reset.

                //Test                                                    Weight
                //--------------------------------------------------------------
                //POST (ROM checksum, RAM NVR, keyboardm and AVO)           1
                //Data Loop Back (Loopback connector required)              2
                //EIA Modem Control Test (Loopback connector req.)          4
                //Repeat Testing until failure                              8

                break;

            default:  // unhandled 
                ptrm->fEsc = 0;
            }
            break;



        case 3:
            // Handle VT102's Esc# 
            switch( *pchT )
            {
            case '8':   // Fill Screen with "E" 
                // DECALN  Screen Alignment Display (DEC private) 

                //  <ESC># 8

                //This command causes the VT100 to fill it's screen with 
                //uppercase Es for screen focus and alignment.

                DECALN( pwi, ptrm );
                break;
                
            //DECDHL  Double Height Line (DEC Private)

            //Top Half:       <ESC>#3
            //Bottom Half:    <ESC>#4

            //These sequences cause the line containing the cursor to become the
            //top or bottom half of a double-height, double width line. The
            //sequences should be used in pairs on adjacent lines with each line
            //containing the same character string.  If the line was single 
            //width single height, all characters to the right of the center of 
            //the screen will be lost.  The cursor remains over the same 
            //character position, unless it would be to the right of the right
            //margin, in which case it is moved to the right margin.    

            case 3:
                break;
            case 4:
                break;

            case 5:
                //DECSWL  Single-width Line (DEC Private)        
                
                //<ESC>#5

                //This causes the line which contains the cursor to become 
                //single-width, single-height.  The cursor remains on the same 
                //character position. This is the default condition for all new 
                //lines on the screen.
                break;

            case 6:
                //DECDWL  Double Width Line (DEC Private)     

                //<ESC>#6

                //This causes the line that contains the cursor to become 
                //double-width single height.  If the line was single width, all
                //characters ro the right of the center of the screen will be 
                //lost.  The cursor remains over the same character position, 
                //unless it would be to the right of the right margin, in which 
                //case it is moved to the right margin.

            default:
                break;
            }
            ptrm->fEsc = 0;
            break;

        case 4:
            // Handle VT52's Esc Y 
            if(( *pchT ) >= ' ')
            {
                ptrm->dwEscCodes[ptrm->cEscParams++] = *pchT - 0x20;
                if( ptrm->cEscParams == 2 )
                {
                    ptrm->dwCurLine = ptrm->dwEscCodes[0];
                    ptrm->dwCurChar = ptrm->dwEscCodes[1];
                    ptrm->fEsc = 0;
                    ptrm->fFlushToEOL = FALSE;
                }
            }
            else
            {
                ptrm->fEsc = 0;
            }
            break;



        case 5:
            if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                {
                /* Single-Byte char invoke */
                if (((*pchT) == 'B') || ((*pchT) =='J') || ((*pchT) == 'H'))
                {
                    ClearKanjiStatus(ptrm,JIS_KANJI_CODE);
                    SetCharSet(ptrm,GRAPHIC_LEFT,rgchJISRomanChars);
#ifdef DEBUG
                    _snwprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1,"VT80 JIS Roman Mode Enter\n");
                    OutputDebugString(rgchDbgBfr);
#endif /* DEBUG */
                }

                ptrm->fEsc = 0;
                }
            break;



        case 6:
            if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                {
                /* Multi-Byte char invoke */
                if (((*pchT) == '@') || ((*pchT) =='B'))
                {
                    SetKanjiStatus(ptrm,JIS_KANJI_CODE);
                    SetCharSet(ptrm,GRAPHIC_LEFT,rgchJISKanjiChars);
#ifdef DEBUG
                    _snwprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1,"VT80 JIS Kanji Mode Enter\n");
                    OutputDebugString(rgchDbgBfr);
#endif /* DEBUG */
                }

                ptrm->fEsc = 0;
                }
            break;



        case 7: /* SUB */
            if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
                {            
                switch( *pchT )
                {
                case 'p':
                  /* ACOS Kanji IN (Kanji to G0(GL)) */
                  SetKanjiStatus(ptrm,JIS_KANJI_CODE);
                  SetCharSet(ptrm,GRAPHIC_LEFT,rgchJISKanjiChars);
                  break;

                case 'q':
                  /* ACOS Kanji OUT (JIS Roman to G0(GL)) */
                  ClearKanjiStatus(ptrm,JIS_KANJI_CODE);
                  SetCharSet(ptrm,GRAPHIC_LEFT,rgchJISRomanChars);
                  break;

                default:
                    break;
                }

                ptrm->fEsc = 0;
                }
            break;

        default:
            break;

        }
    }

    FlushBuffer(pwi, ptrm);

    if( FGetCodeMode(eCodeModeIMEFarEast) )
    {
        if (ui.fDebug & fdwKanjiModeMask)
        {
            SetImeWindow(ptrm);
        }
    }

    cp.X = ( short )ptrm->dwCurChar;
    cp.Y = ( short )ptrm->dwCurLine;
    if( wSaveCurrentLine != cp.Y )
    {
        wSaveCurrentLine = cp.Y;
        if( FGetCodeMode( eCodeModeIMEFarEast ) )
        {
            WriteOneBlankLine( pwi->hOutput, ( WORD )( cp.Y + 1 ) );
        }
    }

    SetConsoleCursorPosition( pwi->hOutput, cp );
    ptrm->fHideCursor = FALSE;

    SaveCurrentWindowCoords();
}

void
HandleCharEvent(WI *pwi, CHAR AsciiChar, DWORD dwControlKeyState)
{
    DWORD   i;

    //This is for informing change in window size to server, if any, before sending a char
    CheckForChangeInWindowSize( );

    /* Map Alt-Control-C to Delete */
    if ((AsciiChar == 3) && ((dwControlKeyState & ALT_PRESSED) &&  (dwControlKeyState & CTRL_PRESSED)))
            AsciiChar = 0x7F;
    /*Map Ctrl-space to ASCII NUL (0) */
    if( (AsciiChar == ' ') && (dwControlKeyState & CTRL_PRESSED) && 
            !( dwControlKeyState & ( SHIFT_PRESSED | ALT_PRESSED ) ) )
    {
        AsciiChar = 0;
    }

    if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
        {

        //
        // Fix to bug 1149
        // if (GetKeyState(VK_CONTROL) < 0) {
        //
        if (dwControlKeyState & CTRL_PRESSED) {
            UCHAR RevChar = LOBYTE(LOWORD(AsciiChar));
            UCHAR SendChar;

            ForceJISRomanSend(pwi);

            if(RevChar == VK_SPACE) {
                /*
                * !!! This code is nessesary to control Unix IME
                */
                SendChar = 0x00;
                /* write to network */
                FWriteToNet(pwi, (LPSTR)&SendChar, 1);
                return;
            } else {
                if((RevChar >= '@') && (RevChar <= ']')) {
                    SendChar = ( UCHAR ) ( RevChar - '@' );
                    /* write to network */
                    FWriteToNet(pwi, (LPSTR)&SendChar, 1);
                    return;
                } else if((RevChar >= 'a') && (RevChar <= 'z')) {
                    SendChar = (UCHAR)toupper(RevChar);
                    SendChar -= (UCHAR)'@';
                    /* write to network */
                     FWriteToNet(pwi, (LPSTR)&SendChar, 1);
                     return;
                } else {
                    FWriteToNet(pwi, (LPSTR)&RevChar, 1);
                    return;
                }
            }

        } else if (FIsVT80(&pwi->trm)) {
            DWORD  j = 0;
            BOOL   bWriteToNet = TRUE;
            UCHAR *WriteBuffer = pchNBBuffer + 3; /* +3:room for escape sequence.*/

            /* INPUT SJIS -> */
            if (uchInPrev != 0) {
                WriteBuffer[0] = uchInPrev;
                WriteBuffer[1] = (CHAR)AsciiChar;
                uchInPrev = 0;
                j = 2;
            } else if(IsDBCSLeadByte((CHAR)AsciiChar) && uchInPrev == 0) {
                uchInPrev = (CHAR)AsciiChar;
                bWriteToNet = FALSE;        /* don't send only lead byte */
            } else {
                WriteBuffer[0] = (CHAR)AsciiChar;
                j = 1;
            }

            /* Do convert */

            if (bWriteToNet) {

                if (WriteBuffer[0] == 0x0D) {

                    //
                    // Automatically add a line feed to a carriage return
                    //
                    WriteBuffer[1] = 0x0A;
                    j = 2;

                } else if (FIsJISKanji(&pwi->trm) || FIsJIS78Kanji(&pwi->trm)) {

                /* OUTPUT -> JIS Kanji or JIS 78 Kanji */
                if(j==2) {
                    /* full width area code */
                    sjistojis( &(WriteBuffer[0]), &(WriteBuffer[1]) );

                    /* if we still not send Kanji esc. send it. */
                    if( !(GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) ) {
                        WriteBuffer -= 3;
                        if (FIsJISKanji(&pwi->trm)) {
                            WriteBuffer[0] = (UCHAR)0x1B; // Ecs
                            WriteBuffer[1] = (UCHAR)'$';
                            WriteBuffer[2] = (UCHAR)'B';  // JIS Kanji 1983
                        } else {
                            WriteBuffer[0] = (UCHAR)0x1B; // Ecs
                            WriteBuffer[1] = (UCHAR)'$';
                            WriteBuffer[2] = (UCHAR)'@';  // JIS Kanji 1978
                        }
                        SetKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 3;
                    }

                } else {

                    /* half width area code */
                    /* if we are in Kanji mode, clear it */
                    if( GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) {
                        WriteBuffer -= 3;
                        WriteBuffer[0] = (UCHAR)0x1B; // Ecs
                        WriteBuffer[1] = (UCHAR)'(';
                        WriteBuffer[2] = (UCHAR)'J';  // JIS Roman
                        ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 3;
                    }

                }

            } else if (FIsEUCKanji(&pwi->trm) || FIsDECKanji(&pwi->trm)) {
                /* OUTPUT -> Japanese EUC / DEC Kanji */
                if(j==2) {
                    /* full width area code */
                    sjistoeuc( &(WriteBuffer[0]), &(WriteBuffer[1]) );
                } else {
                    /* half width area code */
                    if(IsKatakana(WriteBuffer[0])) {
                        /* Add escape sequence for Katakana */
                        WriteBuffer--;
                        WriteBuffer[0] = (UCHAR)0x8E; // 0x8E == SS2
                        j++;
                    }
                }
            } else if (FIsNECKanji(&pwi->trm)) {
                /* OUTPUT -> NEC Kanji */
                if(j==2) {
                    /* full width area code */
                    sjistojis( &(WriteBuffer[0]), &(WriteBuffer[1]) );

                    /* if we still not send Kanji esc. send it. */
                    if( !(GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) ) {
                        WriteBuffer -= 2;
                        WriteBuffer[0] = (UCHAR)0x1B; // Ecs
                        WriteBuffer[1] = (UCHAR)'K';  // NEC Kanji IN
                        SetKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 2;
                    }
                } else {
                    /* half width area code */
                    /* if we are in Kanji mode, clear it */
                    if( GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) {
                        WriteBuffer -= 2;
                        WriteBuffer[0] = (UCHAR)0x1B; // Ecs
                        WriteBuffer[1] = (UCHAR)'H';  // NEC Kanji OUT
                        ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 2;
                    }
                }
            } else if (FIsACOSKanji(&pwi->trm)) {
                
                /* OUTPUT -> ACOS Kanji */
                if(j==2) {
                    /* full width area code */
                    sjistojis( &(WriteBuffer[0]), &(WriteBuffer[1]) );

                    /* if we still not send Kanji esc. send it. */
                    if( !(GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) ) {
                        WriteBuffer -= 2;
                        WriteBuffer[0] = (UCHAR)0x1A; // Sub
                        WriteBuffer[1] = (UCHAR)'p';  // ACOS Kanji IN
                        SetKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 2;
                    }

                } else {

                    /* half width area code */
                    /* if we are in Kanji mode, clear it */
                    if( GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) {
                        WriteBuffer -= 2;
                        WriteBuffer[0] = (UCHAR)0x1A; // Sub
                        WriteBuffer[1] = (UCHAR)'q';  // ACOS Kanji OUT
                        ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 2;
                    }

                }
                } else {

                    /* OUTPUT -> SJIS */
                    /* Nothing to do  */ ;

                }

                /* echo to local */
                if (ui.nottelnet || (ui.fDebug & fdwLocalEcho)) {
                    //InvalidateEntryLine(hwnd, &pwi->trm);
                    DoIBMANSIOutput(pwi, &pwi->trm, j, WriteBuffer);
                }

                /* write to network */
                FWriteToNet(pwi, (LPSTR)WriteBuffer, j);
            }

                return;
        }
    }


    pchNBBuffer[0] = (UCHAR)AsciiChar;

    //
    //  Automatically add a line feed to a carriage return
    //

    i = 1;
    if (pchNBBuffer[0] == ASCII_CR) // Check whether we need to translate cr->crlf
    {
        if (FIsLineMode(&(gwi.trm)) || ui.nottelnet)
        {
            pchNBBuffer[i++] = ASCII_LF;
        }
    }

    if (ui.nottelnet || (ui.fDebug & fdwLocalEcho))
    {
        DoIBMANSIOutput(pwi, &pwi->trm, i, pchNBBuffer);
    }

    FWriteToNet(pwi, (LPSTR)pchNBBuffer, i);
}

BOOL
FHandleKeyDownEvent(WI *pwi, CHAR AsciiChar, DWORD dwControlKeyState)
{
    int iIndex = 2;   //needed for forming vt302 key sequence
    
    //This is for informing change in window size to server, if any, before sending a char
    CheckForChangeInWindowSize( );

    switch( LOWORD(AsciiChar) )
    {
    case VK_PAUSE:
        szVt302ShortKeySequence[ iIndex ] = VT302_PAUSE;
        FWriteToNet(pwi, szVt302ShortKeySequence, strlen( szVt302ShortKeySequence ) );
        break;

    case VK_HOME:
        szVt302KeySequence[ iIndex ] = VT302_HOME;
        FWriteToNet(pwi, szVt302KeySequence, strlen( szVt302KeySequence ) );
        break;

    case VK_END:
        szVt302KeySequence[ iIndex ] = VT302_END;
        FWriteToNet(pwi, szVt302KeySequence, strlen( szVt302KeySequence ) );
        break;

    case VK_INSERT:
        szVt302KeySequence[ iIndex ] = VT302_INSERT;
        FWriteToNet(pwi, szVt302KeySequence, strlen( szVt302KeySequence ) );
        break;

    case VK_PRIOR:
        szVt302KeySequence[ iIndex ] = VT302_PRIOR;
        FWriteToNet(pwi, szVt302KeySequence, strlen( szVt302KeySequence ) );

        break;

    case VK_NEXT:
        szVt302KeySequence[ iIndex ] = VT302_NEXT;
        FWriteToNet(pwi, szVt302KeySequence, strlen( szVt302KeySequence ) );

        break;

    case VK_DELETE:
        {
            UCHAR ucCharToBeSent = 0;
            if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
            {
                ForceJISRomanSend(pwi);
            }

            ucCharToBeSent = ASCII_DEL; //0x7F;
            pchNBBuffer[0] = ucCharToBeSent;
            FWriteToNet(pwi, (LPSTR)pchNBBuffer, 1);
        }
        break;

    case VK_RETURN:
        if (FGetCodeMode(eCodeModeFarEast) && FGetCodeMode(eCodeModeVT80))
        {
            ForceJISRomanSend(pwi);
        }
        else
        {
            INT x = 0;

            pchNBBuffer[ x++ ] = ( UCHAR ) LOWORD(AsciiChar);
            if( FIsLineMode( &( gwi.trm ) ) )
            {
                pchNBBuffer[ x++ ] = ( UCHAR ) ASCII_LF;
            }

            FWriteToNet(pwi, (LPSTR)pchNBBuffer, x );
        }
        break;

    case VK_DIVIDE:
        FWriteToNet(pwi, "/", 1);
        break;

    /*F5 to F12 are not used in VT100. Using VT302 sequences*/
    case VK_F5:
        szVt302LongKeySequence[ iIndex ]    = CHAR_ONE;
        szVt302LongKeySequence[ iIndex+1 ]  = CHAR_FIVE;
        FWriteToNet(pwi, szVt302LongKeySequence, strlen( szVt302LongKeySequence ) );
        break;

    case VK_F6:
        szVt302LongKeySequence[ iIndex ]    = CHAR_ONE;
        szVt302LongKeySequence[ iIndex+1 ]  = CHAR_SEVEN;
        FWriteToNet(pwi, szVt302LongKeySequence, strlen( szVt302LongKeySequence ) );
        break;

    case VK_F7:
        szVt302LongKeySequence[ iIndex ]    = CHAR_ONE;
        szVt302LongKeySequence[ iIndex+1 ]  = CHAR_EIGHT;
        FWriteToNet(pwi, szVt302LongKeySequence, strlen( szVt302LongKeySequence ) );
        break;

    case VK_F8:
        szVt302LongKeySequence[ iIndex ]    = CHAR_ONE;
        szVt302LongKeySequence[ iIndex+1 ]  = CHAR_NINE;
        FWriteToNet(pwi, szVt302LongKeySequence, strlen( szVt302LongKeySequence ) );
        break;

    case VK_F9:
        szVt302LongKeySequence[ iIndex ]    = CHAR_TWO;
        szVt302LongKeySequence[ iIndex+1 ]  = CHAR_ZERO;
        FWriteToNet(pwi, szVt302LongKeySequence, strlen( szVt302LongKeySequence ) );
        break;

    case VK_F10:
        szVt302LongKeySequence[ iIndex ]    = CHAR_TWO;
        szVt302LongKeySequence[ iIndex+1 ]  = CHAR_ONE;
        FWriteToNet(pwi, szVt302LongKeySequence, strlen( szVt302LongKeySequence ) );
        break;

    case VK_F11:
        szVt302LongKeySequence[ iIndex ]    = CHAR_TWO;
        szVt302LongKeySequence[ iIndex+1 ]  = CHAR_THREE;
        FWriteToNet(pwi, szVt302LongKeySequence, strlen( szVt302LongKeySequence ) );
        break;

    case VK_F12:
        szVt302LongKeySequence[ iIndex ]    = CHAR_TWO;
        szVt302LongKeySequence[ iIndex+1 ]  = CHAR_FOUR;
        FWriteToNet(pwi, szVt302LongKeySequence, strlen( szVt302LongKeySequence ) );
        break;

    default:
    if ( !(ui.fDebug & fdwNoVT100Keys) )
    {
        /*
         * When F1-F4 or the up/down/right/left cursor keys
         * are hit, the bytes sent to the connected machine
         * depend on what mode the terminal emulator is in.
         * There are three relevant modes, VT102 Application,
         * VT102 Cursor, VT52.
         *
         * Mode                 Pattern sent
         * VT102 App    EscO* (3 bytes)
         * VT102 Cursor Esc[* (3 bytes)
         * VT52                 Esc*  (2 bytes)
         *
         * where '*' represents the byte to be sent and
         * is dependant upon the key that was hit.
         * For the function keys F1-F4, their VT102
         * Cursor mode is the same as their VT102 App mode.
         */

        DWORD   iPos     = (FIsVT52(&pwi->trm)) ? 1 : 2;
        DWORD   cch      = (FIsVT52(&pwi->trm)) ? 2 : 3;
        WORD    wKeyCode = LOWORD(AsciiChar);

        pchNBBuffer[0] = 0;
        pchNBBuffer[1] = ( UCHAR ) ( (FIsVTArrow(&pwi->trm)) ? 'O' : '[' );

        if ((wKeyCode == VK_F1) || (wKeyCode == VK_F2) ||
                        (wKeyCode == VK_F3) || (wKeyCode == VK_F4))
        {
            pchNBBuffer[0] = 0x1B;
            pchNBBuffer[1] = 'O';
            pchNBBuffer[iPos] = ( UCHAR ) ( ((UCHAR)'P'+(UCHAR)(wKeyCode-VK_F1)));
        }
        else if (wKeyCode == VK_UP)
        {
            pchNBBuffer[0] = 0x1B;
            pchNBBuffer[iPos] = 'A';
        }
        else if (wKeyCode == VK_DOWN)
        {
            pchNBBuffer[0] = 0x1B;
            pchNBBuffer[iPos] = 'B';
        }
        else if (wKeyCode == VK_RIGHT)
        {
            pchNBBuffer[0] = 0x1B;
            pchNBBuffer[iPos] = 'C';
        }
        else if (wKeyCode == VK_LEFT)
        {
            pchNBBuffer[0] = 0x1B;
            pchNBBuffer[iPos] = 'D';
        }

        if (pchNBBuffer[0] == 0x1B)
        {
            FWriteToNet(pwi, (LPSTR)pchNBBuffer, (int)cch);
        }
    }
    }
    return TRUE;
}

void SetCharSet( TRM *ptrm , INT iCodeArea , UCHAR *pSource )
{
    if( iCodeArea == GRAPHIC_LEFT )
        ptrm->CurrentCharSet[0] = pSource;
    else
        ptrm->CurrentCharSet[1] = pSource;
       
    RtlCopyMemory( (PBYTE)((ptrm->puchCharSet) + iCodeArea) ,
                   pSource ,
                   128
                 ); //Attack ? Size of destination not known.
}

void PushCharSet( TRM *ptrm , INT iCodeArea , UCHAR *pSource )
{
    if( iCodeArea == GRAPHIC_LEFT )
        ptrm->PreviousCharSet[0] = ptrm->CurrentCharSet[0];
     else
        ptrm->PreviousCharSet[1] = ptrm->CurrentCharSet[1];

    SetCharSet( ptrm , iCodeArea , pSource );
}

void PopCharSet( TRM *ptrm , INT iCodeArea )
{
    if( iCodeArea == GRAPHIC_LEFT )
        SetCharSet( ptrm , iCodeArea , ptrm->PreviousCharSet[0]);
     else
        SetCharSet( ptrm , iCodeArea , ptrm->PreviousCharSet[1]);
}

void SetupCharSet( TRM *ptrm )
{
    if( ui.fDebug & fdwVT80Mode ) {

        SetVT80(ptrm);

        ClearKanjiFlag(ptrm);

#ifdef DEBUG
        snprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, "VT80 - ");
        OutputDebugString(rgchDbgBfr);
#endif
        switch( ui.fDebug & fdwKanjiModeMask ) {
        case fdwJISKanjiMode :
        case fdwJIS78KanjiMode :

#ifdef DEBUG
            snprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, "JIS or JIS78 Kanji Mode\n");
            OutputDebugString(rgchDbgBfr);
#endif

            if((ui.fDebug & fdwKanjiModeMask) == fdwJIS78KanjiMode)
                SetJIS78Kanji(ptrm);
             else
                SetJISKanji(ptrm);

            ptrm->g0 = rgchJISRomanChars;
            ptrm->g1 = rgchKatakanaChars;
            ptrm->g2 = rgchJISKanjiChars;
            ptrm->g3 = rgchNullChars;     // rgchJISHojyoKanjiChars;

            SetCharSet(ptrm,GRAPHIC_LEFT ,ptrm->g0);
            SetCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g1);
            break;

        case fdwSJISKanjiMode :

#ifdef DEBUG
            snprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, "ShiftJIS Kanji Mode\n");
            OutputDebugString(rgchDbgBfr);
#endif
            SetSJISKanji(ptrm);

            ptrm->g0 = rgchJISRomanChars;
            ptrm->g1 = rgchKatakanaChars;
            ptrm->g2 = rgchNullChars;     // N/A
            ptrm->g3 = rgchNullChars;     // N/A

            SetCharSet(ptrm,GRAPHIC_LEFT ,ptrm->g0);
            SetCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g1);
            break;

        case fdwEUCKanjiMode :

#ifdef DEBUG
            snprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, "EUC Kanji Mode\n");
            OutputDebugString(rgchDbgBfr);
#endif
            SetEUCKanji(ptrm);

            ptrm->g0 = rgchJISRomanChars;
            ptrm->g1 = rgchEUCKanjiChars;
            ptrm->g2 = rgchKatakanaChars;
            ptrm->g3 = rgchNullChars;     // rgchEUCHojyoKanjiChars;

            SetCharSet(ptrm,GRAPHIC_LEFT ,ptrm->g0);
            SetCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g1);
            break;

        case fdwNECKanjiMode :

#ifdef DEBUG
            snprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, "NEC Kanji Mode\n");
            OutputDebugString(rgchDbgBfr);
#endif
            SetNECKanji(ptrm);

            ptrm->g0 = rgchJISRomanChars;
            ptrm->g1 = rgchKatakanaChars;
            ptrm->g2 = rgchJISKanjiChars;
            ptrm->g3 = rgchNullChars;     // rgchJISHojyoKanjiChars;

            SetCharSet(ptrm,GRAPHIC_LEFT ,ptrm->g0);
            SetCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g1);
            break;

        case fdwACOSKanjiMode :

#ifdef DEBUG
            snprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, "ACOS Kanji Mode\n");
            OutputDebugString(rgchDbgBfr);
#endif
            SetACOSKanji(ptrm);

            ptrm->g0 = rgchJISRomanChars;
            ptrm->g1 = rgchKatakanaChars;
            ptrm->g2 = rgchJISKanjiChars;
            ptrm->g3 = rgchNullChars;     // rgchJISHojyoKanjiChars;

            SetCharSet(ptrm,GRAPHIC_LEFT ,ptrm->g0);
            SetCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g1);
            break;

        case fdwDECKanjiMode :

#ifdef DEBUG
            snprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, "DEC Kanji Mode\n");
            OutputDebugString(rgchDbgBfr);
#endif
            SetDECKanji(ptrm);

            ptrm->g0 = rgchJISRomanChars;
            ptrm->g1 = rgchGraphicsChars;
            ptrm->g2 = rgchKatakanaChars;
            ptrm->g3 = rgchDECKanjiChars;

            SetCharSet(ptrm,GRAPHIC_LEFT ,ptrm->g0);
            SetCharSet(ptrm,GRAPHIC_RIGHT,ptrm->g3); // Kanji Terminal Mode
            break;
            }
    } else {

#ifdef DEBUG
        snprintf(rgchDbgBfr,sizeof(rgchDbgBfr)-1, "VT52/100 Non Kanji Mode\n");
        OutputDebugString(rgchDbgBfr);
#endif
        if( ui.fDebug & fdwVT52Mode ) SetVT52( ptrm );

        SetCharSet(ptrm,GRAPHIC_LEFT ,rgchIBMAnsiChars);
        SetCharSet(ptrm,GRAPHIC_RIGHT,rgchDefaultRightChars);
    }
}

void jistosjis( UCHAR *p1 , UCHAR *p2 )
{
    UCHAR c1 = *p1;
    UCHAR c2 = *p2;

    int rowOffset = c1 < 95 ? 112 : 176;
    int cellOffset = c1 % 2 ? (c2 > 95 ? 32 : 31) : 126;

    *p1 = ( UCHAR ) ( ((c1 + 1) >> 1) + rowOffset );
    *p2 = ( UCHAR ) ( *p2 + cellOffset );
}

void euctosjis( UCHAR *p1 , UCHAR *p2 )
{
    *p1 -= 128;
    *p2 -= 128;

    jistosjis( p1 , p2 );
}

void sjistojis( UCHAR *p1 , UCHAR *p2 )
{
    UCHAR c1 = *p1;
    UCHAR c2 = *p2;

    int adjust = c2 < 159;
    int rowOffset = c1 < 160 ? 112 : 176;
    int cellOffset = adjust ? (c2 > 127 ? 32 : 31) : 126;

    *p1 = ( UCHAR ) ( ((c1 - rowOffset) << 1) - adjust );
    *p2 = ( UCHAR ) ( *p2 - cellOffset );
}

void sjistoeuc( UCHAR *p1 , UCHAR *p2 )
{
    sjistojis( p1 , p2 );

    *p1 += 128;
    *p2 += 128;
}

/******
BOOL
IsDBCSCharPoint(
    POINT *ppt
)
{
    LPSTR lpstrRow;

    lpstrRow = apcRows[ppt->y];

    return(IsDBCSLeadByte(*(lpstrRow+ppt->x)));
}

void
AlignDBCSPosition(
    POINT *ppt,
    BOOL   bLeftAlign
)
{
    LPSTR lpstrRow;
    LONG  current = 0;
    BOOL  bDBCSChar;

    lpstrRow = apcRows[ppt->y];

    while( current < ppt->x ) {
        bDBCSChar = FALSE;
        if(IsDBCSLeadByte(*lpstrRow)) {
            bDBCSChar = TRUE;
            lpstrRow++;
            current++;
        }
        lpstrRow++;
        current++;
    }

    if(bLeftAlign) {
        if(bDBCSChar) {
            current -= 2;
        } else {
            current --;
        }
    }

    ppt->x = current;
}

void
AlignDBCSPosition2(
    POINT *ppt,
    LPCSTR pch,
    BOOL   bLeftAlign
)
{
    LPCSTR lpstrRow;
    LONG  current = 0;
    BOOL  bDBCSChar = FALSE;

    lpstrRow = pch;

    while( current < ppt->x ) {
        bDBCSChar = FALSE;
        if(IsDBCSLeadByte(*lpstrRow)) {
            bDBCSChar = TRUE;
            lpstrRow++;
            current++;
        }
        lpstrRow++;
        current++;
    }

    if(bLeftAlign) {
        if(bDBCSChar) {
            current -= 2;
        } else {
            current --;
        }
    }

    ppt->x = current;
}

void DBCSTextOut(HDC hdc, int j, int i, LPCSTR pch, int offset, int len)
{
    POINT pt;
    int x, y;
    int delta;

    pt.x = offset;
    pt.y = i;

    if(offset)
        AlignDBCSPosition2(&pt,pch,(fHSCROLL ? TRUE : FALSE));

    if( (delta = offset - pt.x) > 0 )
        x = aixPos(j) - aixPos(delta);
     else
        x = aixPos(j);
    y = aiyPos(i);

    (void)TextOut((HDC)hdc,x,y,pch+pt.x,len);
}

*****/


void ForceJISRomanSend(WI *pwi)
{
    CHAR Buffer[5];
    CHAR *WriteBuffer = Buffer;
    int  j = 0;

    if( FIsVT80(&pwi->trm) ) {

        if( GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) {

            if(FIsJISKanji(&pwi->trm) || FIsJIS78Kanji(&pwi->trm)) {
                *WriteBuffer++ = (UCHAR)0x1B; // Ecs
                *WriteBuffer++ = (UCHAR)'(';
                *WriteBuffer++ = (UCHAR)'J';  // JIS Roman
                ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                j = 3;

            } else if (FIsNECKanji(&pwi->trm)) {

                *WriteBuffer++ = (UCHAR)0x1B; // Ecs
                *WriteBuffer++ = (UCHAR)'H';  // NEC Kanji OUT
                ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                j = 2;
            } else if (FIsACOSKanji(&pwi->trm)) {

                *WriteBuffer++ = (UCHAR)0x1A; // Sub
                *WriteBuffer++ = (UCHAR)'q';  // ACOS Kanji OUT
                ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                j = 2;
            }

            if( j ) FWriteToNet(pwi, (LPSTR)Buffer, j);
        }
    }
}

void FWriteTextDataToNet(HWND hwnd, LPSTR szString, int c)
{
    WI *pwi = (WI *)GetWindowLongPtr(hwnd, WL_TelWI);

    if ( FIsVT80(&pwi->trm) && !FIsSJISKanji(&pwi->trm) )
    {
        DWORD  j = 0;
        UCHAR*  WriteBuffer = pchNBBuffer;

        if (FIsJISKanji(&pwi->trm) || FIsJIS78Kanji(&pwi->trm)) {

            while(c > 0) {

                /* OUTPUT -> JIS Kanji or JIS 78 Kanji */

                if (IsDBCSLeadByte(*szString)) {

                    /* full width area code */

                    if( !(GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) ) {
                        if (FIsJISKanji(&pwi->trm)) {
                            *WriteBuffer++ = (UCHAR)0x1B; // Ecs
                            *WriteBuffer++ = (UCHAR)'$';
                            *WriteBuffer++ = (UCHAR)'B';  // JIS Kanji 1983
                        } else {
                            *WriteBuffer++ = (UCHAR)0x1B; // Ecs
                            *WriteBuffer++ = (UCHAR)'$';  
                            *WriteBuffer++ = (UCHAR)'@';  // JIS Kanji 1978
                        }
                        SetKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 3;
                    }

                    *WriteBuffer = *szString++;
                    *(WriteBuffer+1) = *szString++;
                    c -= 2;

                    /* convert sjis -> jis */

                    sjistojis( WriteBuffer, WriteBuffer+1 );

                    WriteBuffer += 2;
                    j += 2;

                } else {

                    /* half width area code */
                    /* if we are in Kanji mode, clear it */

                    if( GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) {
                        *WriteBuffer++ = (UCHAR)0x1B; // Ecs
                        *WriteBuffer++ = (UCHAR)'(';
                        *WriteBuffer++ = (UCHAR)'J';  // JIS Roman
                        ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 3;
                    }

                    /* copy to destination */

                    *WriteBuffer++ = *szString++;
                    c--; j++;
                }
            }

        } else if (FIsEUCKanji(&pwi->trm) || FIsDECKanji(&pwi->trm)) {

            /* OUTPUT -> Japanese EUC / DEC Kanji */

            while(c > 0) {

                if (IsDBCSLeadByte(*szString)) {

                    /* full width area code */

                    *WriteBuffer = *szString++;
                    *(WriteBuffer+1) = *szString++;
                    c -= 2;

                    /* convert sjis -> euc */

                    sjistoeuc( WriteBuffer, WriteBuffer+1 );

                    WriteBuffer += 2;
                    j += 2;

                } else {

                    /* half width area code */

                    if(IsKatakana(*szString)) {
                        /* Add escape sequence for Katakana */
                        *WriteBuffer++ = (UCHAR)0x8E; // 0x8E == SS2
                        j++;
                    }

                    *WriteBuffer++ = *szString++;
                    c--; j++;

                }

            }

        } else if (FIsNECKanji(&pwi->trm)) {

            while(c > 0) {

                /* OUTPUT -> NEC Kanji */

                if (IsDBCSLeadByte(*szString)) {

                    /* full width area code */

                    if( !(GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) ) {
                        *WriteBuffer++ = (UCHAR)0x1B; // Ecs
                        *WriteBuffer++ = (UCHAR)'K';  // NEC Kanji IN
                        SetKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 2;
                    }

                    *WriteBuffer = *szString++;
                    *(WriteBuffer+1) = *szString++;
                    c -= 2;

                    /* convert sjis -> jis */

                    sjistojis( WriteBuffer, WriteBuffer+1 );

                    WriteBuffer += 2;
                    j += 2;

                } else {

                    /* half width area code */
                    /* if we are in Kanji mode, clear it */

                    if( GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) {
                        *WriteBuffer++ = (UCHAR)0x1B; // Ecs
                        *WriteBuffer++ = (UCHAR)'H';  // NEC Kanji OUT
                        ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 2;
                    }

                    /* copy to destination */

                    *WriteBuffer++ = *szString++;
                    c--; j++;
                }
            }
        } else if (FIsACOSKanji(&pwi->trm)) {

            while(c > 0) {

                /* OUTPUT -> NEC Kanji */

                if (IsDBCSLeadByte(*szString)) {

                    /* full width area code */

                    if( !(GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) ) {
                        *WriteBuffer++ = (UCHAR)0x1A; // Sub
                        *WriteBuffer++ = (UCHAR)'p';  // ACOS Kanji IN
                        SetKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 2;
                    }

                    *WriteBuffer = *szString++;
                    *(WriteBuffer+1) = *szString++;
                    c -= 2;

                    /* convert sjis -> jis */

                    sjistojis( WriteBuffer, WriteBuffer+1 );

                    WriteBuffer += 2;
                    j += 2;

                } else {

                    /* half width area code */
                    /* if we are in Kanji mode, clear it */

                    if( GetKanjiStatus(&pwi->trm) & JIS_SENDING_KANJI ) {
                        *WriteBuffer++ = (UCHAR)0x1A; // Sub
                        *WriteBuffer++ = (UCHAR)'q';  // ACOS Kanji OUT
                        ClearKanjiStatus(&pwi->trm,JIS_SENDING_KANJI);
                        j += 2;
                    }

                    /* copy to destination */

                    *WriteBuffer++ = *szString++;
                    c--; j++;
                }
            }
        }

        /* write to network */
        FWriteToNet( ( struct _WI * )hwnd, (LPSTR)pchNBBuffer, j);

    } else {

        /* write to network */
        FWriteToNet( ( struct _WI * )hwnd, (LPSTR)szString, c);

    }
}

VOID SetImeWindow(TRM *ptrm)
{
    COMPOSITIONFORM cf;

    cf.dwStyle = CFS_POINT;
    cf.ptCurrentPos.x = aixPos(ptrm->dwCurChar-ui.nScrollCol);
    cf.ptCurrentPos.y = aiyPos(ptrm->dwCurLine-ui.nScrollRow);
    
    SetRectEmpty(&cf.rcArea);

    ImmSetCompositionWindow(hImeContext,&cf);
}