windows-nt/Source/XPSP1/NT/net/tcpip/services/telnet/client/trmio.c

5487 lines
185 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//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);
}