1910 lines
44 KiB
C
1910 lines
44 KiB
C
/****************************************************************************
|
|
|
|
FILE: TrmIO.c
|
|
|
|
A lot of the implementation-related VT102/VT52 information
|
|
was taken from the source code for Kermit, specifically
|
|
the file ckocon.c. The book "Using C-Kermit" by Frank Da Cruz
|
|
and Christine M. Gianone devotes a few pages describing
|
|
the various VT102/VT52 escape and control sequences, etc.
|
|
|
|
TABS:
|
|
|
|
Set for 4 spaces.
|
|
|
|
****************************************************************************/
|
|
|
|
#include <windows.h> /* required for all Windows applications */
|
|
#include <commdlg.h>
|
|
#include <stdlib.h>
|
|
#include "NetBIOS.h"
|
|
#include "netobj.h"
|
|
#include "WinVTP.h" /* specific to this program */
|
|
#include "winvtpsz.h"
|
|
|
|
#define fdwCursorToEOS ((DWORD)0)
|
|
#define fdwBOSToCursor ((DWORD)1)
|
|
#define fdwEntireScreen ((DWORD)2)
|
|
|
|
#define fdwCursorToEOL ((DWORD)0)
|
|
#define fdwBOLToCursor ((DWORD)1)
|
|
#define fdwEntireLine ((DWORD)2)
|
|
|
|
static void InsertLines(HWND, TRM *, DWORD, DWORD);
|
|
static void NewLineUp(HWND, TRM *);
|
|
static void DeleteLines(HWND, TRM *, DWORD, DWORD);
|
|
static void NewLine(HWND, TRM *);
|
|
static void SetBufferStart(TRM *);
|
|
static BOOL FAddTabToBuffer( TRM * );
|
|
static BOOL FAddCharToBuffer(TRM *, UCHAR);
|
|
static void FlushBuffer(TRM *, HDC);
|
|
static void CursorUp(TRM *);
|
|
static void CursorDown(TRM *);
|
|
static void CursorRight(TRM *);
|
|
static void CursorLeft(TRM *);
|
|
static void ClearScreen(HWND, TRM *, HDC, DWORD);
|
|
static void ClearLine(TRM *, HDC, DWORD);
|
|
static void SetMargins(TRM *, DWORD, DWORD);
|
|
|
|
|
|
static LOGFONT lfBest;
|
|
static int dxBest;
|
|
static int dyBest;
|
|
#define ABS(x) ((x)<0 ? -(x) : (x))
|
|
#define MAX(x, y) ((x)<(y)?(y):(x))
|
|
#define MIN(x, y) ((x)>(y)?(y):(x))
|
|
|
|
long difffunc(int dx, int dy, LPARAM lpData)
|
|
{
|
|
long d;
|
|
d = ABS(dx-(long)(unsigned short)lpData) * ABS(dy-lpData>>16);
|
|
// d = dx*dy - (long)(unsigned short)lpData * (lpData>>16);
|
|
// if (d<0)
|
|
// d = -d;
|
|
return(d);
|
|
}
|
|
int CALLBACK
|
|
EnumFontsProc(LOGFONT *lplf, TEXTMETRIC *lptm, DWORD dwType, LPARAM lpData) {
|
|
int dx;
|
|
int dy;
|
|
dx = lptm->tmAveCharWidth *ui.dwMaxCol;
|
|
dy = ui.dwMaxRow * (lptm->tmHeight + lptm->tmExternalLeading);
|
|
if (difffunc(dx, dy, lpData) < difffunc(dxBest, dyBest, lpData))
|
|
{
|
|
dxBest = dx;
|
|
dyBest = dy;
|
|
lfBest = *lplf;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
void
|
|
SetWindowCoords(TEXTMETRIC *ptm)
|
|
{
|
|
DWORD wCharPos;
|
|
DWORD wCharDiff;
|
|
DWORD i;
|
|
|
|
|
|
/* Get the dimensions for the cursor */
|
|
iCursorHeight = ptm->tmHeight + ptm->tmExternalLeading;
|
|
|
|
/* Yes! I know I'm using Average Char Width for the cursor width
|
|
* rather than Max Char Width
|
|
*/
|
|
iCursorWidth = ptm->tmAveCharWidth;
|
|
|
|
/* Calculate the horizontal position for each column */
|
|
wCharDiff = ptm->tmAveCharWidth;
|
|
for (i=0, wCharPos=0; i<ui.dwMaxCol; ++i, wCharPos+=wCharDiff)
|
|
aixPos[i] = wCharPos;
|
|
|
|
/* Calculate the vertical position for each row */
|
|
wCharDiff = ptm->tmHeight + ptm->tmExternalLeading;
|
|
for (i=0, wCharPos=0; i<ui.dwMaxRow; ++i, wCharPos+=wCharDiff)
|
|
aiyPos[i] = wCharPos;
|
|
}
|
|
|
|
void
|
|
MakeClientRectThisSize(HWND hwnd, int dx, int dy)
|
|
{
|
|
RECT wrect;
|
|
RECT crect;
|
|
int i;
|
|
for (i = 0; i<2; i++) {
|
|
GetWindowRect(hwnd, &wrect);
|
|
GetClientRect(hwnd, &crect);
|
|
|
|
wrect.right += dx - (crect.right - crect.left);
|
|
wrect.bottom += dy - (crect.bottom - crect.top);
|
|
|
|
SetWindowPos(hwnd, NULL, 0, 0,
|
|
wrect.right - wrect.left, wrect.bottom - wrect.top,
|
|
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
}
|
|
|
|
void
|
|
ResizeWindow(HWND hwnd)
|
|
{
|
|
HFONT hfontOld;
|
|
TEXTMETRIC tm;
|
|
HDC hdc;
|
|
int dx, dy;
|
|
int ux, uy;
|
|
RECT wrect;
|
|
RECT crect;
|
|
static fResizing = 0;
|
|
HFONT hfontT;
|
|
|
|
if (fResizing) return;
|
|
fResizing++;
|
|
GetWindowRect(hwnd, &wrect);
|
|
SetScrollRange(hwnd, SB_HORZ, 0, 0, FALSE);
|
|
SetScrollRange(hwnd, SB_VERT, 0, 0, FALSE);
|
|
ux = wrect.right - wrect.left;
|
|
uy = wrect.bottom - wrect.top;
|
|
GetClientRect(hwnd, &crect);
|
|
dxBest = dyBest = 5000;
|
|
hdc = GetDC( hwnd );
|
|
if (ui.fPrompt &fdwAutoFonts)
|
|
{
|
|
/* the font picker doesnt seem to value size in raster fonts
|
|
* as much as I would like. this EnumFonts sort seems to
|
|
* bias the heuristic just enough to improve things */
|
|
EnumFonts(hdc, ui.lf.lfFaceName, &EnumFontsProc, (crect.bottom - crect.top)<<16 | (crect.right-crect.left));
|
|
if (dxBest != 5000)
|
|
{
|
|
dx = crect.right - crect.left;
|
|
dy = crect.bottom - crect.top;
|
|
ui.lf = lfBest;
|
|
if ((ABS(dx-dxBest)*10)/dx > 1 ||
|
|
(ABS(dy-dyBest) *10)/dy > 1)
|
|
{
|
|
ui.lf.lfWidth = dx/ui.dwMaxCol;
|
|
ui.lf.lfHeight = dy/ui.dwMaxRow;
|
|
}
|
|
|
|
hfontT = CreateFontIndirect(&ui.lf);
|
|
if (hfontT != NULL)
|
|
{
|
|
DeleteObject(hfontDisplay);
|
|
hfontDisplay = hfontT;
|
|
}
|
|
else
|
|
(void)MessageBox(hwnd, szNoFont, szAppName, MB_OK);
|
|
}
|
|
}
|
|
|
|
/* Get the font's metrics */
|
|
hfontOld = SelectObject(hdc, hfontDisplay);
|
|
GetTextMetrics(hdc, &tm);
|
|
(void)SelectObject(hdc, hfontOld);
|
|
ReleaseDC(hwnd, hdc);
|
|
|
|
if (ui.fPrompt &fdwAutoFonts)
|
|
SetWindowCoords(&tm);
|
|
dx = ui.dwMaxCol * tm.tmAveCharWidth;
|
|
dy = ui.dwMaxRow * (tm.tmHeight + tm.tmExternalLeading);
|
|
MakeClientRectThisSize(hwnd, dx, dy);
|
|
if (!(ui.fPrompt &fdwAutoFonts))
|
|
{
|
|
GetWindowRect(hwnd, &wrect);
|
|
if (wrect.right - wrect.left > ux)
|
|
wrect.right = wrect.left+ux;
|
|
if (wrect.bottom - wrect.top > uy)
|
|
{
|
|
/* note hack for detecting menu re-appearing */
|
|
int i = wrect.bottom - wrect.top - (uy + GetSystemMetrics(SM_CYMENU));
|
|
if (ABS(i) >= 2)
|
|
wrect.bottom = wrect.top+uy;
|
|
}
|
|
SetWindowPos(hwnd, NULL, 0, 0,
|
|
wrect.right - wrect.left, wrect.bottom - wrect.top,
|
|
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
|
GetClientRect(hwnd, &crect);
|
|
SetScrollRange(hwnd, SB_HORZ, 0, dx - (crect.right-crect.left), FALSE);
|
|
SetScrollRange(hwnd, SB_VERT, 0, dy - (crect.bottom-crect.top), FALSE);
|
|
// Second time is to compensate for loss of client space
|
|
GetClientRect(hwnd, &crect);
|
|
SetScrollRange(hwnd, SB_HORZ, 0, dx - (crect.right-crect.left), FALSE);
|
|
SetScrollRange(hwnd, SB_VERT, 0, dy - (crect.bottom-crect.top), FALSE);
|
|
hPos = MIN(dx - (crect.right-crect.left), hPos);
|
|
vPos = MIN(dy - (crect.bottom-crect.top), vPos);
|
|
}
|
|
else
|
|
hPos = vPos = 0;
|
|
/* Invalidate the whole window, so all of it gets redrawn */
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
fResizing--;
|
|
}
|
|
|
|
void
|
|
RecalcWindowSize(HWND hwnd)
|
|
{
|
|
HFONT hfontOld;
|
|
TEXTMETRIC tm;
|
|
HDC hdc;
|
|
DWORD wWidth;
|
|
DWORD wHeight;
|
|
|
|
SetScrollRange(hwnd, SB_HORZ, 0, 0, FALSE);
|
|
SetScrollRange(hwnd, SB_VERT, 0, 0, FALSE);
|
|
/* Get the font's metrics */
|
|
hdc = GetDC( hwnd );
|
|
hfontOld = SelectObject(hdc, hfontDisplay);
|
|
GetTextMetrics(hdc, &tm);
|
|
(void)SelectObject(hdc, hfontOld);
|
|
ReleaseDC(hwnd, hdc);
|
|
|
|
SetWindowCoords(&tm);
|
|
|
|
/* Calculate the size of the main window */
|
|
wHeight = (ui.dwMaxRow * tm.tmHeight+tm.tmExternalLeading) + GetSystemMetrics(SM_CYCAPTION) +
|
|
GetSystemMetrics(SM_CYMENU) + (2*GetSystemMetrics(SM_CYFRAME)) + 2;
|
|
wWidth = (ui.dwMaxCol * tm.tmAveCharWidth) +
|
|
(2*GetSystemMetrics(SM_CXFRAME)) + 2;
|
|
|
|
SetWindowPos(hwnd, NULL, 0, 0, wWidth, wHeight,
|
|
SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
|
|
|
/* Invalidate the whole window, so all of it gets redrawn */
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
}
|
|
|
|
static void
|
|
InsertLines(HWND hwnd, TRM *ptrm, DWORD iLine, DWORD cLines)
|
|
{
|
|
UCHAR *pc;
|
|
DWORD i;
|
|
DWORD j;
|
|
RECT rect;
|
|
|
|
for (j=0; j<cLines; ++j)
|
|
{
|
|
/* scroll lines down */
|
|
pc = apcRows[ptrm->dwScrollBottom-1];
|
|
|
|
for (i=ptrm->dwScrollBottom-1; i>iLine; --i)
|
|
apcRows[i] = apcRows[i-1];
|
|
apcRows[iLine] = pc;
|
|
|
|
/* now, clear top line */
|
|
memcpy(pc, rgchRowEmpty, 2*sizeof(UCHAR)*ui.dwMaxCol);
|
|
}
|
|
|
|
/* specify region of window to scroll */
|
|
/*
|
|
* for the bottom measurement, we subtract off the
|
|
* # of lines we inserted since those bottom "cLines"
|
|
* will be scrolled off the screen.
|
|
*/
|
|
GetClientRect(hwnd, &rect);
|
|
rect.top = MAX(0, iLine * iCursorHeight - vPos);
|
|
rect.bottom = MAX(0, (ptrm->dwScrollBottom-cLines) * iCursorHeight-vPos);
|
|
|
|
ScrollWindow(hwnd, 0, ((int)aiyPos[1]*cLines), &rect, NULL);
|
|
|
|
/* Erase the top cLines for better appearance */
|
|
if ( ui.fSmoothScroll )
|
|
{
|
|
HDC hdc = GetDC( hwnd );
|
|
|
|
if ( hdc )
|
|
{
|
|
rect.bottom = rect.top + (cLines*iCursorHeight);
|
|
|
|
SetBkColor(hdc, ui.clrBk);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
|
|
ValidateRect(hwnd, &rect);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
NewLineUp(HWND hwnd, TRM *ptrm)
|
|
{
|
|
if (ptrm->dwCurLine <= ptrm->dwScrollTop)
|
|
{
|
|
ptrm->dwCurLine = ptrm->dwScrollTop;
|
|
InsertLines(hwnd, ptrm, ptrm->dwScrollTop, 1);
|
|
}
|
|
else
|
|
{
|
|
ptrm->dwCurLine -= 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
DeleteLines(HWND hwnd, TRM *ptrm, DWORD iLine, DWORD cLines)
|
|
{
|
|
UCHAR *pc;
|
|
DWORD i;
|
|
DWORD j;
|
|
RECT rect;
|
|
|
|
for (j=0; j<cLines; ++j)
|
|
{
|
|
/* scroll lines up */
|
|
pc = apcRows[iLine];
|
|
|
|
for (i=iLine+1; i<ptrm->dwScrollBottom; ++i)
|
|
apcRows[i-1] = apcRows[i];
|
|
apcRows[ptrm->dwScrollBottom-1] = pc;
|
|
|
|
/* now, clear bottom line */
|
|
memcpy(pc, rgchRowEmpty, 2*sizeof(UCHAR)*ui.dwMaxCol);
|
|
}
|
|
|
|
/* specify region of window to scroll */
|
|
/*
|
|
* for the top measurement, we add on the
|
|
* # of lines we deleted since those top "cLines"
|
|
* will be scrolled off the screen.
|
|
*/
|
|
GetClientRect(hwnd, &rect);
|
|
rect.top = MAX(0, (iLine+cLines) * iCursorHeight - vPos);
|
|
rect.bottom = MAX(0, ptrm->dwScrollBottom * iCursorHeight - vPos);
|
|
|
|
ScrollWindow(hwnd, 0, -((int)aiyPos[1]*(int)cLines), &rect, NULL);
|
|
|
|
/* Erase the last cLines for better appearance */
|
|
if ( ui.fSmoothScroll )
|
|
{
|
|
HDC hdc = GetDC( hwnd );
|
|
|
|
if ( hdc )
|
|
{
|
|
rect.top = rect.bottom - (cLines*iCursorHeight);
|
|
|
|
SetBkColor(hdc, ui.clrBk);
|
|
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
|
|
|
|
ValidateRect(hwnd, &rect);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
NewLine(HWND hwnd, TRM *ptrm)
|
|
{
|
|
if ((ptrm->dwCurLine+1) >= ptrm->dwScrollBottom)
|
|
{
|
|
DeleteLines(hwnd, ptrm, ptrm->dwScrollTop, 1);
|
|
}
|
|
else
|
|
{
|
|
ptrm->dwCurLine += 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
SetBufferStart(TRM *ptrm)
|
|
{
|
|
ptrm->dwCurCharBT = ptrm->dwCurChar;
|
|
ptrm->dwCurLineBT = ptrm->dwCurLine;
|
|
ptrm->fInverseBT = ptrm->fInverse;
|
|
}
|
|
|
|
static BOOL
|
|
FAddCharToBuffer(TRM *ptrm, UCHAR uch)
|
|
{
|
|
ptrm->rgchBufferText[ptrm->cchBufferText++] = uch;
|
|
|
|
return (ptrm->cchBufferText >= sizeof(ptrm->rgchBufferText));
|
|
}
|
|
|
|
static BOOL
|
|
FAddTabToBuffer(TRM *ptrm)
|
|
{
|
|
WORD wSpaces = 8 - (WORD)((ptrm->dwCurCharBT + ptrm->cchBufferText) & 7);
|
|
|
|
memset(ptrm->rgchBufferText+ptrm->cchBufferText, ' ', wSpaces);
|
|
ptrm->cchBufferText += wSpaces;
|
|
|
|
return (ptrm->cchBufferText >= sizeof(ptrm->rgchBufferText));
|
|
}
|
|
|
|
void
|
|
MyTextOut(HDC hdc, int x, int y, LPSTR lpsz, int cb)
|
|
{
|
|
TextOut(hdc, aixPos[x] - hPos, aiyPos[y] - vPos, lpsz, cb);
|
|
}
|
|
|
|
static void
|
|
FlushBuffer(TRM *ptrm, HDC hdc)
|
|
{
|
|
if (ptrm->cchBufferText != 0)
|
|
{
|
|
UCHAR * puchText = apcRows[ptrm->dwCurLineBT];
|
|
UCHAR * puchAttr = puchText;
|
|
|
|
puchText += ptrm->dwCurCharBT;
|
|
puchAttr += ptrm->dwCurCharBT+ui.dwMaxCol;
|
|
|
|
/* Determine colours to use for text & background */
|
|
/* Also copy cached text into main buffers */
|
|
if ( ptrm->fInverseBT )
|
|
{
|
|
SetTextColor(hdc, ui.clrBk);
|
|
SetBkColor(hdc, ui.clrText);
|
|
|
|
memcpy(puchAttr, ptrm->rgchBufferText, ptrm->cchBufferText);
|
|
memset(puchText, 0, ptrm->cchBufferText);
|
|
}
|
|
else
|
|
{
|
|
SetTextColor(hdc, ui.clrText);
|
|
SetBkColor(hdc, ui.clrBk);
|
|
|
|
memcpy(puchText, ptrm->rgchBufferText, ptrm->cchBufferText);
|
|
memset(puchAttr, 0, ptrm->cchBufferText);
|
|
}
|
|
|
|
/* Output cached text */
|
|
MyTextOut(hdc, ptrm->dwCurCharBT, ptrm->dwCurLineBT,
|
|
ptrm->rgchBufferText, ptrm->cchBufferText);
|
|
|
|
/* Reset parameters */
|
|
ptrm->cchBufferText = 0;
|
|
ptrm->dwCurCharBT = 0;
|
|
ptrm->dwCurLineBT = 0;
|
|
ptrm->fInverseBT = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DoTermReset(HWND hwnd, TRM *ptrm, HDC hdc)
|
|
{
|
|
ptrm->dwVT100Flags = 0;
|
|
SetVTArrow(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;
|
|
|
|
ClearScreen(hwnd, ptrm, hdc, fdwEntireScreen);
|
|
}
|
|
|
|
static void
|
|
CursorUp(TRM *ptrm)
|
|
{
|
|
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 (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;
|
|
}
|
|
|
|
static void
|
|
ClearScreen(HWND hwnd, TRM *ptrm, HDC hdc, DWORD dwType)
|
|
{
|
|
DWORD dwStart;
|
|
DWORD dwEnd;
|
|
|
|
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;
|
|
}
|
|
|
|
dwEnd = (dwType == fdwBOSToCursor) ? ptrm->dwCurLine+1 : ui.dwMaxRow;
|
|
dwStart = (dwType == fdwCursorToEOS) ? ptrm->dwCurLine+1 : 0;
|
|
|
|
if (dwType == fdwEntireScreen)
|
|
{
|
|
/* Clear entire screen */
|
|
ptrm->dwCurLine = ptrm->dwCurChar = 0;
|
|
}
|
|
else if (dwType == fdwBOSToCursor)
|
|
{
|
|
/* Clear from beginning of screen to cursor */
|
|
memset(apcRows[ptrm->dwCurLine], ' ', ptrm->dwCurChar+1);
|
|
memset(apcRows[ptrm->dwCurLine]+ui.dwMaxCol, 0, ptrm->dwCurChar+1);
|
|
if (hdc != NULL)
|
|
{
|
|
MyTextOut(hdc, 0, ptrm->dwCurLine,
|
|
rgchRowEmpty, ptrm->dwCurChar+1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Clear from cursor to end of screen */
|
|
memset(apcRows[ptrm->dwCurLine]+ptrm->dwCurChar, ' ',
|
|
ui.dwMaxCol-ptrm->dwCurChar);
|
|
memset(apcRows[ptrm->dwCurLine]+ui.dwMaxCol+ptrm->dwCurChar,
|
|
0, ui.dwMaxCol-ptrm->dwCurChar);
|
|
if (hdc != NULL)
|
|
{
|
|
MyTextOut(hdc, ptrm->dwCurChar,
|
|
ptrm->dwCurLine,
|
|
rgchRowEmpty, ui.dwMaxCol-ptrm->dwCurChar);
|
|
}
|
|
}
|
|
|
|
for (; dwStart<dwEnd; ++dwStart)
|
|
memcpy(apcRows[dwStart], rgchRowEmpty, 2*ui.dwMaxCol);
|
|
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
}
|
|
ptrm->fEsc = 0;
|
|
}
|
|
|
|
static void
|
|
ClearLine(TRM *ptrm, HDC hdc, DWORD dwType)
|
|
{
|
|
DWORD dwStart;
|
|
DWORD cch;
|
|
|
|
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;
|
|
|
|
memset(apcRows[ptrm->dwCurLine]+dwStart, ' ', cch);
|
|
memset(apcRows[ptrm->dwCurLine]+ui.dwMaxCol+dwStart, 0, cch);
|
|
|
|
MyTextOut(hdc, dwStart, ptrm->dwCurLine, rgchRowEmpty, cch);
|
|
}
|
|
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;
|
|
}
|
|
|
|
void
|
|
ScrollToCursor(HWND hwnd, TRM *ptrm)
|
|
{
|
|
RECT rect;
|
|
BOOL fChanged = 0;
|
|
GetClientRect(hwnd, &rect);
|
|
if ((int)ptrm->dwCurChar * iCursorWidth < hPos)
|
|
{
|
|
SetScrollPos(hwnd, SB_HORZ, hPos = ptrm->dwCurChar* iCursorWidth, TRUE);
|
|
fChanged++;
|
|
}
|
|
else if ((int)ptrm->dwCurChar * iCursorWidth > hPos+(rect.right-rect.left))
|
|
{
|
|
hPos = MIN((ui.dwMaxCol* iCursorWidth)-(rect.right-rect.left), ptrm->dwCurChar * iCursorWidth);
|
|
SetScrollPos(hwnd, SB_HORZ, hPos, TRUE);
|
|
fChanged++;
|
|
}
|
|
if ((int)ptrm->dwCurLine * iCursorHeight < vPos)
|
|
{
|
|
SetScrollPos(hwnd, SB_VERT, vPos = ptrm->dwCurLine* iCursorHeight, TRUE);
|
|
fChanged++;
|
|
}
|
|
else if ((int)ptrm->dwCurLine * iCursorHeight > vPos+(rect.bottom-rect.top))
|
|
{
|
|
vPos = MIN((ui.dwMaxRow* iCursorHeight)-(rect.bottom-rect.top), ptrm->dwCurLine * iCursorHeight);
|
|
SetScrollPos(hwnd, SB_VERT, vPos, TRUE);
|
|
fChanged++;
|
|
}
|
|
if (fChanged)
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*
|
|
* Arguments:
|
|
* HWND
|
|
* TRM *
|
|
* DWORD
|
|
* char*
|
|
*
|
|
* Returns:
|
|
* Nothing.
|
|
*/
|
|
|
|
void
|
|
DoIBMANSIOutput(HWND hwnd, TRM *ptrm, DWORD cbTermOut, UCHAR *pchTermOut)
|
|
{
|
|
HDC hdc;
|
|
HFONT hfontOld;
|
|
DWORD ich;
|
|
DWORD i;
|
|
DWORD dwDECMode;
|
|
UCHAR *pchT;
|
|
WI *pwi;
|
|
|
|
#ifdef NBTEST
|
|
OutputDebugString("NN_RECV Display\n");
|
|
#endif
|
|
|
|
/* Display output stream on debug port */
|
|
if (ui.fDebug & fdwDebugOutput)
|
|
{
|
|
UCHAR *puch = ptrm->rgchBufferText;
|
|
|
|
wsprintf(puch, "\r\n\r\n");
|
|
OutputDebugString( puch );
|
|
|
|
for (i=0; i<((cbTermOut+19)/20); ++i)
|
|
{
|
|
DWORD cch;
|
|
|
|
/* Group output in 20s */
|
|
if (((i+1)*20) > cbTermOut)
|
|
cch = cbTermOut - (i*20);
|
|
else
|
|
cch = 20;
|
|
cch *= 3;
|
|
|
|
/*
|
|
* Display the ASCII values of characters, except
|
|
* for those <0x20, space, which are displayed in
|
|
* hex for better visibility.
|
|
*/
|
|
for(ich=0, pchT=pchTermOut+(i*20); ich<cch; ich+=3, ++pchT)
|
|
{
|
|
if ((*pchT) < ' ')
|
|
wsprintf(puch+ich, "%.2X ", *pchT);
|
|
else
|
|
wsprintf(puch+ich, "%c ", *pchT);
|
|
}
|
|
|
|
lstrcat(puch, "\r\n");
|
|
OutputDebugString( puch );
|
|
|
|
/* Display hex values of characters in output stream */
|
|
for(ich=0, pchT=pchTermOut+(i*20); ich<cch; ich+=3, ++pchT)
|
|
{
|
|
wsprintf(puch+ich, "%.2X ", *pchT);
|
|
}
|
|
lstrcat(puch, "\r\n");
|
|
OutputDebugString( puch );
|
|
}
|
|
}
|
|
|
|
ScrollToCursor(hwnd, ptrm);
|
|
/* suppress cursor on screen */
|
|
CursorOff( hwnd );
|
|
ptrm->fHideCursor = TRUE;
|
|
|
|
hdc = GetDC( hwnd );
|
|
|
|
ptrm->cTilde = 0;
|
|
|
|
hfontOld = SelectObject(hdc, hfontDisplay);
|
|
if (apcRows[ptrm->dwCurLine][ptrm->dwCurChar] != 0)
|
|
{
|
|
SetTextColor(hdc, ui.clrText);
|
|
SetBkColor(hdc, ui.clrBk);
|
|
}
|
|
else if (apcRows[ptrm->dwCurLine][ptrm->dwCurChar+ui.dwMaxCol] != 0)
|
|
{
|
|
SetTextColor(hdc, ui.clrBk);
|
|
SetBkColor(hdc, ui.clrText);
|
|
}
|
|
|
|
for(ich=0, pchT=pchTermOut; ich<cbTermOut; ++ich, ++pchT)
|
|
{
|
|
|
|
/* process character */
|
|
switch ( ptrm->fEsc )
|
|
{
|
|
case 0: /* normal processing */
|
|
switch( *pchT )
|
|
{
|
|
case 0x1B: /* ESC? */
|
|
ptrm->fEsc = 1;
|
|
break;
|
|
case 0:
|
|
break;
|
|
case 0x08: /* Backspace */
|
|
if (ptrm->dwCurChar > 0)
|
|
--ptrm->dwCurChar;
|
|
FlushBuffer(ptrm, hdc);
|
|
break;
|
|
case 0x07: /* BELL */
|
|
MessageBeep( 0xFFFFFFFF );
|
|
break;
|
|
case 0x09: /* TAB */
|
|
if (ui.fDebug & fdwTABtoSpaces)
|
|
{
|
|
if (ptrm->cchBufferText == 0)
|
|
SetBufferStart( ptrm );
|
|
if ( FAddTabToBuffer(ptrm) )
|
|
FlushBuffer(ptrm, hdc);
|
|
}
|
|
ptrm->dwCurChar += 8;
|
|
ptrm->dwCurChar &= -8;
|
|
if (!(ui.fDebug & fdwTABtoSpaces))
|
|
FlushBuffer(ptrm, hdc);
|
|
if (ptrm->dwCurChar >= ui.dwMaxCol)
|
|
{
|
|
if (ui.fDebug & fdwTABtoSpaces)
|
|
FlushBuffer(ptrm, hdc);
|
|
ptrm->dwCurChar = 0;
|
|
NewLine(hwnd, ptrm);
|
|
}
|
|
break;
|
|
case '\r': /* Carriage Return */
|
|
ptrm->dwCurChar = 0;
|
|
FlushBuffer(ptrm, hdc);
|
|
break;
|
|
case '\n': /* Line Feed */
|
|
FlushBuffer(ptrm, hdc);
|
|
NewLine(hwnd, ptrm);
|
|
break;
|
|
case 0x0F:
|
|
ptrm->puchCharSet = rgchNormalChars;
|
|
break;
|
|
case 0x0E:
|
|
ptrm->puchCharSet = rgchAlternateChars;
|
|
break;
|
|
|
|
case '~':
|
|
/* optimization to detect ~~Begin VtpXFer signature */
|
|
++ptrm->cTilde;
|
|
/* fall through */
|
|
|
|
default:
|
|
#ifdef DEBUG
|
|
if ((*pchT < 0x20) || (*pchT > 0x7e))
|
|
{
|
|
wsprintf(rgchDbgBfr,"Potentially bad character %x\n", *pchT);
|
|
OutputDebugString(rgchDbgBfr);
|
|
}
|
|
#endif
|
|
if (ptrm->cchBufferText == 0)
|
|
SetBufferStart( ptrm );
|
|
|
|
if ( FAddCharToBuffer(ptrm, ptrm->puchCharSet[*pchT]) )
|
|
FlushBuffer(ptrm, hdc);
|
|
|
|
if (++ptrm->dwCurChar >= ui.dwMaxCol)
|
|
{
|
|
ptrm->dwCurChar = 0;
|
|
FlushBuffer(ptrm, hdc);
|
|
NewLine(hwnd, ptrm);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 1: /* ESC entered, wait for [ */
|
|
FlushBuffer(ptrm, hdc);
|
|
if (((*pchT) != '[') && ((*pchT) != '#'))
|
|
ptrm->fEsc = 0;
|
|
|
|
switch (*pchT)
|
|
{
|
|
case '7':
|
|
/*
|
|
* DECSC
|
|
* Save cursor position, origin mode etc.
|
|
*/
|
|
ptrm->fSavedState = TRUE;
|
|
ptrm->dwSaveChar = ptrm->dwCurChar;
|
|
ptrm->dwSaveLine = ptrm->dwCurLine;
|
|
ptrm->dwSaveRelCursor = ptrm->fRelCursor;
|
|
break;
|
|
case '8':
|
|
/*
|
|
* DECRC
|
|
* Restore cursor position, etc. from DECSC
|
|
*/
|
|
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 = 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 */
|
|
NewLine(hwnd, ptrm);
|
|
}
|
|
break;
|
|
case 'E': /* Next Line */
|
|
/*
|
|
* VT102 - NEL, New Line
|
|
* cursor to start of line below, can scroll
|
|
*/
|
|
ptrm->dwCurChar = 0;
|
|
NewLine(hwnd, ptrm);
|
|
break;
|
|
case 'F':
|
|
/* VT52 - Enter graphics mode */
|
|
if ( FIsVT52(ptrm) )
|
|
{
|
|
SetVT52Graphics(ptrm);
|
|
ptrm->puchCharSet = rgchAlternateChars;
|
|
}
|
|
break;
|
|
case 'G':
|
|
/* VT52 - Exit graphics mode */
|
|
if ( FIsVT52(ptrm) )
|
|
{
|
|
ClearVT52Graphics(ptrm);
|
|
ptrm->puchCharSet = rgchNormalChars;
|
|
}
|
|
break;
|
|
case 'H':
|
|
if ( FIsVT52(ptrm) )
|
|
{
|
|
/* VT52 - Cursor Home */
|
|
ptrm->dwCurChar = ptrm->dwCurLine = 0;
|
|
}
|
|
else
|
|
{
|
|
/* VT102 - HTS Set Tab Stop */
|
|
}
|
|
break;
|
|
case 'I':
|
|
if ( FIsVT52(ptrm) )
|
|
{
|
|
/* VT52 - Reverse linefeed */
|
|
NewLineUp(hwnd, ptrm);
|
|
}
|
|
break;
|
|
case 'J':
|
|
if ( FIsVT52(ptrm) )
|
|
{
|
|
/* VT52 - Clears to end of screen */
|
|
ClearScreen(hwnd, ptrm, hdc, fdwCursorToEOS);
|
|
}
|
|
break;
|
|
case 'K':
|
|
if ( FIsVT52(ptrm) )
|
|
{
|
|
/* VT52 - Erases to end of line */
|
|
ClearLine(ptrm, hdc, fdwCursorToEOL);
|
|
}
|
|
break;
|
|
case 'M':
|
|
/* VT102 - RI Reverse Index, cursor up 1 line, can scroll */
|
|
NewLineUp(hwnd, ptrm);
|
|
break;
|
|
case 'Y':
|
|
if ( FIsVT52(ptrm) )
|
|
{
|
|
/* VT52 - direct cursor address */
|
|
if ((ich + 3) <= cbTermOut)
|
|
{
|
|
ptrm->dwCurLine = (pchT[1] > 31) ? pchT[1]-32 : 0;
|
|
ptrm->dwCurChar = (pchT[2] > 31) ? pchT[2]-32 : 0;
|
|
|
|
ich+=2;
|
|
pchT+=2;
|
|
}
|
|
else
|
|
{
|
|
ptrm->fEsc = 4;
|
|
ptrm->dwEscCodes[0] = 0xFFFFFFFF;
|
|
ptrm->dwEscCodes[1] = 0xFFFFFFFF;
|
|
ptrm->cEscParams = 0;
|
|
}
|
|
}
|
|
break;
|
|
case 'Z':
|
|
if ( !FIsVT52(ptrm) )
|
|
{
|
|
/* VT102 - DECID Identify terminal */
|
|
pchNBBuffer[0] = 0x1B;
|
|
pchNBBuffer[1] = '[';
|
|
pchNBBuffer[1] = '?';
|
|
pchNBBuffer[1] = '6';
|
|
pchNBBuffer[1] = 'c';
|
|
i = 5;
|
|
}
|
|
else
|
|
{
|
|
/* VT52 - Identify terminal */
|
|
pchNBBuffer[0] = 0x1B;
|
|
pchNBBuffer[1] = '/';
|
|
pchNBBuffer[1] = 'Z';
|
|
i = 3;
|
|
}
|
|
pwi = (WI *)GetWindowLong(hwnd, WL_VTPWI);
|
|
NetBIOSWrite(pwi->nd.SessionNumber, (LPSTR)pchNBBuffer, i);
|
|
break;
|
|
case 'c':
|
|
/* VT102 RIS Hard reset, reset term to initial state */
|
|
FlushBuffer(ptrm, hdc);
|
|
DoTermReset(hwnd, ptrm, NULL);
|
|
break;
|
|
|
|
case '=':
|
|
/* VT102 - DECKPAM Enter numeric keypad app mode */
|
|
ClearVTKeypad(ptrm);
|
|
break;
|
|
case '>':
|
|
/* VT102 - DECKNPNM Enter numeric keypad numeric mode */
|
|
SetVTKeypad(ptrm);
|
|
break;
|
|
case '<':
|
|
/* VT102 - Exit VT52 mode to ANSI (VT102) mode */
|
|
ClearVT52(ptrm);
|
|
break;
|
|
case '(':
|
|
#ifdef NEVER
|
|
readmchar_escape();
|
|
g0 = achar;
|
|
break;
|
|
#endif
|
|
case ')':
|
|
#ifdef NEVER
|
|
readmchar_escape();
|
|
g1 = achar;
|
|
#endif
|
|
/* VT102 SCS */
|
|
|
|
/* Skip over next character for now */
|
|
if (ich < cbTermOut)
|
|
{
|
|
++ich;
|
|
++pchT;
|
|
}
|
|
break;
|
|
default:
|
|
/* Is if a form feed? */
|
|
if (*pchT == 12)
|
|
{
|
|
ptrm->dwCurChar = ptrm->dwCurLine = 0;
|
|
ClearScreen(hwnd, ptrm, hdc, 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 '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;
|
|
}
|
|
#if 0
|
|
else
|
|
{
|
|
OutputDebugStringA("Too many escape codes\n");
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case 'A': /* VT102 CUU cursor up */
|
|
CursorUp( ptrm );
|
|
break;
|
|
case 'B': /* VT102 CUD cursor down */
|
|
CursorDown( ptrm );
|
|
break;
|
|
case 'C': /* VT102 CUF cursor right */
|
|
CursorRight( ptrm );
|
|
break;
|
|
case 'D': /* VT102 CUB cursor left */
|
|
CursorLeft( ptrm );
|
|
break;
|
|
case 'H': /* VT102 CUP position cursor */
|
|
case 'f': /* VT102 HVP position cursor */
|
|
if (ptrm->dwEscCodes[0] == 0)
|
|
ptrm->dwEscCodes[0] = (ptrm->fRelCursor)
|
|
? ptrm->dwScrollTop+1 : 1;
|
|
if (ptrm->dwEscCodes[1] == 0)
|
|
ptrm->dwEscCodes[1] = 1;
|
|
ptrm->dwCurLine = ptrm->dwEscCodes[0]-1;
|
|
ptrm->dwCurChar = ptrm->dwEscCodes[1]-1;
|
|
|
|
if (ptrm->dwCurChar >= ui.dwMaxCol)
|
|
ptrm->dwCurChar = ui.dwMaxCol - 1;
|
|
if (ptrm->dwCurLine >= ui.dwMaxRow)
|
|
ptrm->dwCurLine = ui.dwMaxRow - 1;
|
|
ptrm->fEsc = 0;
|
|
break;
|
|
|
|
case 'J': /* VT102 ED erase display */
|
|
ClearScreen(hwnd, ptrm, hdc, ptrm->dwEscCodes[0]);
|
|
break;
|
|
|
|
case 'K': /* VT102 EL erase line */
|
|
ClearLine(ptrm, hdc, ptrm->dwEscCodes[0]);
|
|
break;
|
|
|
|
case 'L': /* VT102 IL insert lines */
|
|
if (ptrm->dwEscCodes[0] == 0)
|
|
ptrm->dwEscCodes[0] = 1;
|
|
InsertLines(hwnd, ptrm, ptrm->dwCurLine, ptrm->dwEscCodes[0]);
|
|
ptrm->fEsc = 0;
|
|
break;
|
|
case 'M': /* VT102 DL delete line */
|
|
if (ptrm->dwEscCodes[0] == 0)
|
|
ptrm->dwEscCodes[0] = 1;
|
|
DeleteLines(hwnd, ptrm, ptrm->dwCurLine, ptrm->dwEscCodes[0]);
|
|
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)
|
|
{
|
|
memmove(apcRows[ptrm->dwCurLine]+i,
|
|
apcRows[ptrm->dwCurLine]+ptrm->dwCurChar,
|
|
ui.dwMaxCol - i);
|
|
memmove(apcRows[ptrm->dwCurLine]+i+ui.dwMaxCol,
|
|
apcRows[ptrm->dwCurLine]+ptrm->dwCurChar+ui.dwMaxCol,
|
|
ui.dwMaxCol - i);
|
|
}
|
|
|
|
memcpy(apcRows[ptrm->dwCurLine]+ptrm->dwCurChar,
|
|
rgchRowEmpty, ptrm->dwEscCodes[0]);
|
|
memcpy(apcRows[ptrm->dwCurLine]+ptrm->dwCurChar+ui.dwMaxCol,
|
|
rgchRowEmpty+ui.dwMaxCol, ptrm->dwEscCodes[0]);
|
|
{
|
|
RECT rect;
|
|
|
|
rect.top = aiyPos[ptrm->dwCurLine];
|
|
rect.bottom = rect.top+iCursorHeight;
|
|
rect.left = 0;
|
|
rect.right = ui.dwMaxCol*iCursorWidth;
|
|
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
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;
|
|
|
|
i = ptrm->dwCurChar+1-ptrm->dwEscCodes[0];
|
|
|
|
if ((ui.dwMaxCol - ptrm->dwCurChar - 1) > 0)
|
|
{
|
|
memmove(apcRows[ptrm->dwCurLine]+i,
|
|
apcRows[ptrm->dwCurLine]+ptrm->dwCurChar+1,
|
|
ui.dwMaxCol - ptrm->dwCurChar - 1);
|
|
memmove(apcRows[ptrm->dwCurLine]+i+ui.dwMaxCol,
|
|
apcRows[ptrm->dwCurLine]+ptrm->dwCurChar+1+ui.dwMaxCol,
|
|
ui.dwMaxCol - ptrm->dwCurChar - 1);
|
|
}
|
|
|
|
i = ui.dwMaxCol-ptrm->dwEscCodes[0];
|
|
memcpy(apcRows[ptrm->dwCurLine]+i,
|
|
rgchRowEmpty, ptrm->dwEscCodes[0]);
|
|
memcpy(apcRows[ptrm->dwCurLine]+i+ui.dwMaxCol,
|
|
rgchRowEmpty+ui.dwMaxCol, ptrm->dwEscCodes[0]);
|
|
{
|
|
RECT rect;
|
|
|
|
rect.top = aiyPos[ptrm->dwCurLine];
|
|
rect.bottom = rect.top+iCursorHeight;
|
|
rect.left = 0;
|
|
rect.right = ui.dwMaxCol*iCursorWidth;
|
|
|
|
InvalidateRect(hwnd, &rect, FALSE);
|
|
}
|
|
ptrm->fEsc = 0;
|
|
break;
|
|
|
|
case 'c': /* VT102 DA Same as DECID */
|
|
pchNBBuffer[0] = 0x1B;
|
|
pchNBBuffer[1] = '[';
|
|
pchNBBuffer[1] = '?';
|
|
pchNBBuffer[1] = '6';
|
|
pchNBBuffer[1] = 'c';
|
|
i = 5;
|
|
pwi = (WI *)GetWindowLong(hwnd, WL_VTPWI);
|
|
NetBIOSWrite(pwi->nd.SessionNumber, (LPSTR)pchNBBuffer, i);
|
|
ptrm->fEsc = 0;
|
|
break;
|
|
case 'g': /* VT102 TBC Clear Tabs */
|
|
if (ptrm->dwEscCodes[0] == 3)
|
|
{
|
|
/* Clear all tabs */
|
|
}
|
|
else if (ptrm->dwEscCodes[0] == 0)
|
|
{
|
|
/* Clear tab stop at current position */
|
|
}
|
|
ptrm->fEsc = 0;
|
|
break;
|
|
|
|
case 'h':
|
|
for (i = 0; i < ptrm->cEscParams; ++i)
|
|
{
|
|
if (dwDECMode == TRUE)
|
|
{
|
|
switch ( ptrm->dwEscCodes[i] )
|
|
{ /* Field specs */
|
|
case 1: /* DECCKM */
|
|
SetVTArrow(ptrm);
|
|
break;
|
|
case 2: /* DECANM : ANSI/VT52 */
|
|
ClearVT52(ptrm);
|
|
ClearVT52Graphics(ptrm);
|
|
ptrm->puchCharSet = rgchNormalChars;
|
|
break;
|
|
case 3: /* DECCOLM : Col = 132 */
|
|
SetDECCOLM(ptrm);
|
|
ClearScreen(hwnd, ptrm, hdc, fdwEntireScreen);
|
|
break;
|
|
case 4: /* DECSCLM */
|
|
break;
|
|
case 5: /* DECSCNM */
|
|
if ( FIsDECSCNM(ptrm) )
|
|
break;
|
|
SetDECSCNM(ptrm);
|
|
break;
|
|
case 6: /* DECOM : Relative origin */
|
|
ptrm->fRelCursor = TRUE;
|
|
ptrm->dwCurChar = 0;
|
|
ptrm->dwCurLine = ptrm->dwScrollTop;
|
|
break;
|
|
case 7: /* DECAWM */
|
|
SetVTWrap(ptrm);
|
|
break;
|
|
case 8: /* DECARM */
|
|
break;
|
|
case 9: /* DECINLM */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (ptrm->dwEscCodes[i])
|
|
{
|
|
case 2: /* Keyboard locked */
|
|
SetKeyLock(ptrm);
|
|
break;
|
|
case 4: /* Ansi insert mode */
|
|
SetInsertMode(ptrm);
|
|
break;
|
|
case 20: /* Ansi linefeed mode */
|
|
SetLineMode(ptrm);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
ptrm->fEsc = 0;
|
|
break;
|
|
case 'l': /* Reset Mode */
|
|
for (i = 0; i < ptrm->cEscParams; ++i)
|
|
{
|
|
if (dwDECMode == TRUE)
|
|
{
|
|
switch ( ptrm->dwEscCodes[i] )
|
|
{ /* Field specs */
|
|
case 1: /* DECCKM */
|
|
ClearVTArrow(ptrm);
|
|
break;
|
|
case 2: /* DECANM : ANSI/VT52 */
|
|
SetVT52(ptrm);
|
|
ClearVT52Graphics(ptrm);
|
|
break;
|
|
case 3: /* DECCOLM : 80 col */
|
|
ClearDECCOLM(ptrm);
|
|
ClearScreen(hwnd, ptrm, hdc, fdwEntireScreen);
|
|
break;
|
|
case 4: /* DECSCLM */
|
|
break;
|
|
case 5: /* DECSCNM */
|
|
if ( !FIsDECSCNM(ptrm) )
|
|
break;
|
|
SetDECSCNM(ptrm);
|
|
break;
|
|
case 6: /* DECOM : Relative origin */
|
|
ptrm->fRelCursor = FALSE;
|
|
ptrm->dwCurChar = ptrm->dwCurLine = 0;
|
|
break;
|
|
case 7: /* DECAWM */
|
|
ClearVTWrap(ptrm);
|
|
break;
|
|
case 8: /* DECARM */
|
|
break;
|
|
case 9: /* DECINLM */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch ( ptrm->dwEscCodes[i] )
|
|
{
|
|
case 2: /* Keyboard unlocked */
|
|
ClearKeyLock(ptrm);
|
|
break;
|
|
case 4: /* Ansi insert mode */
|
|
ClearInsertMode(ptrm);
|
|
break;
|
|
case 20: /* Ansi linefeed mode */
|
|
ClearLineMode(ptrm);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
ptrm->fEsc = 0;
|
|
break;
|
|
case 'i': /* VT102 MC Media Copy */
|
|
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 */
|
|
for (i=0; i<(DWORD)ptrm->cEscParams; ++i)
|
|
{
|
|
switch ( ptrm->dwEscCodes[i] )
|
|
{
|
|
case 7:
|
|
ptrm->fInverse = TRUE;
|
|
break;
|
|
default:
|
|
#if 0
|
|
wsprintf(rgchDbgBfr," m param %d\n",
|
|
ptrm->dwEscCodes[i]);
|
|
OutputDebugString(rgchDbgBfr);
|
|
break;
|
|
#endif
|
|
case 5: /* blink */
|
|
case 4: /* underline */
|
|
case 1: /* Bold */
|
|
case 0:
|
|
ptrm->fInverse = FALSE;
|
|
break;
|
|
}
|
|
|
|
}
|
|
ptrm->fEsc = 0;
|
|
break;
|
|
|
|
case 'n': /* VT102 DSR */
|
|
pchNBBuffer[0] = 0;
|
|
if (ptrm->dwEscCodes[0] == 5)
|
|
{
|
|
/* Terminal Status Report */
|
|
pchNBBuffer[0] = 0x1B;
|
|
pchNBBuffer[1] = '[';
|
|
pchNBBuffer[1] = '0';
|
|
pchNBBuffer[1] = 'n';
|
|
i = 4;
|
|
}
|
|
else if (ptrm->dwEscCodes[0] == 6)
|
|
{
|
|
i = wsprintf(pchNBBuffer, "%c[%d;%dR", (char)0x1B,
|
|
ptrm->dwCurLine+1, ptrm->dwCurChar+1);
|
|
}
|
|
|
|
if (pchNBBuffer[0] != 0)
|
|
{
|
|
pwi = (WI *)GetWindowLong(hwnd, WL_VTPWI);
|
|
NetBIOSWrite(pwi->nd.SessionNumber, (LPSTR)pchNBBuffer, i);
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
case 'q': /* Load LEDs */
|
|
ptrm->fEsc = 0;
|
|
break; /* (nothing) */
|
|
|
|
case 'r': /* VT102 DECSTBM */
|
|
if ((ptrm->cEscParams < 2) || (ptrm->dwEscCodes[1] == 0))
|
|
{
|
|
ptrm->dwEscCodes[1] = ui.dwMaxRow;
|
|
}
|
|
if (ptrm->dwEscCodes[0] == 0)
|
|
ptrm->dwEscCodes[0] = 1;
|
|
if ((ptrm->dwEscCodes[0] > 0) &&
|
|
(ptrm->dwEscCodes[0] < ptrm->dwEscCodes[1]) &&
|
|
(ptrm->dwEscCodes[1] <= ui.dwMaxCol))
|
|
{
|
|
SetMargins(ptrm, ptrm->dwEscCodes[0], ptrm->dwEscCodes[1]);
|
|
ptrm->dwCurChar = 0;
|
|
ptrm->dwCurLine = (ptrm->fRelCursor == TRUE)
|
|
? ptrm->dwScrollTop : 0;
|
|
}
|
|
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;
|
|
break;
|
|
|
|
default: /* unhandled */
|
|
#if 0
|
|
wsprintf(rgchDbgBfr,"Unhandled escape char %x\n",
|
|
pchTermOut[ich]);
|
|
OutputDebugString(rgchDbgBfr);
|
|
#endif
|
|
ptrm->fEsc = 0;
|
|
}
|
|
break;
|
|
case 3:
|
|
/* Handle VT102's Esc# */
|
|
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;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ptrm->fEsc = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
FlushBuffer(ptrm, hdc);
|
|
|
|
(void)SelectObject(hdc, hfontOld);
|
|
|
|
ReleaseDC(hwnd, hdc);
|
|
ptrm->fHideCursor = FALSE;
|
|
}
|
|
|
|
void
|
|
Paint(HWND hwnd, WI *pwi)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
DWORD dwRowFirst, dwRowLast, dwColFirst, dwColLast;
|
|
DWORD iCol;
|
|
UCHAR *pchInverse;
|
|
UCHAR *pch;
|
|
BOOL fIsInverse;
|
|
HFONT hfontOld;
|
|
HDC hdc;
|
|
DWORD i, j;
|
|
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
hfontOld = SelectObject(hdc, hfontDisplay);
|
|
|
|
dwRowFirst = (ps.rcPaint.top + vPos) / aiyPos[1];
|
|
dwRowLast = (ps.rcPaint.bottom + vPos) / aiyPos[1];
|
|
if (dwRowLast >= ui.dwMaxRow)
|
|
dwRowLast = ui.dwMaxRow-1;
|
|
|
|
dwColFirst = (ps.rcPaint.left + hPos) / aixPos[1];
|
|
dwColLast = (ps.rcPaint.right + hPos) / aixPos[1];
|
|
if (dwColLast >= ui.dwMaxCol)
|
|
dwColLast = ui.dwMaxCol-1;
|
|
|
|
// DbgPrint("rf = %d, rl = %d, cf = %d, cl = %d\n",
|
|
// dwRowFirst,dwRowLast,dwColFirst,dwColLast);
|
|
|
|
for (i=dwRowFirst; i<=dwRowLast; ++i)
|
|
{
|
|
pch = apcRows[i];
|
|
pchInverse = apcRows[i] + ui.dwMaxCol;
|
|
fIsInverse = FALSE;
|
|
|
|
iCol = j = dwColFirst;
|
|
SetTextColor(hdc, ui.clrText);
|
|
SetBkColor(hdc, ui.clrBk);
|
|
|
|
while (iCol <= dwColLast)
|
|
{
|
|
if ( !pch[iCol] )
|
|
{
|
|
fIsInverse = TRUE;
|
|
if (iCol > j)
|
|
{
|
|
// DbgPrint("TextOut at %d %d\n",aixPos[j],aiyPos[i]);
|
|
MyTextOut(hdc, j, i, pch+j, iCol-j);
|
|
}
|
|
j = ++iCol;
|
|
}
|
|
else
|
|
{
|
|
++iCol;
|
|
}
|
|
}
|
|
if (j < iCol)
|
|
MyTextOut(hdc, j, i, pch+j, iCol-j);
|
|
|
|
if ( fIsInverse )
|
|
{
|
|
SetTextColor(hdc, ui.clrBk);
|
|
SetBkColor(hdc, ui.clrText);
|
|
iCol = j = dwColFirst;
|
|
while (iCol <= dwColLast)
|
|
{
|
|
if ( !pchInverse[iCol] )
|
|
{
|
|
if (iCol > j)
|
|
{
|
|
MyTextOut(hdc, j, i,
|
|
pchInverse+j, iCol-j);
|
|
}
|
|
j = ++iCol;
|
|
}
|
|
else
|
|
{
|
|
++iCol;
|
|
}
|
|
}
|
|
if (j < iCol)
|
|
{
|
|
MyTextOut(hdc, j, i, pchInverse+j, iCol-j);
|
|
}
|
|
}
|
|
}
|
|
|
|
(void)SelectObject(hdc, hfontOld);
|
|
|
|
if ((pwi->trm.fHideCursor == FALSE) && !FInMarkMode(pwi->spb))
|
|
{
|
|
pwi->trm.fCursorOn = (pwi->trm.fCursorOn) ? FALSE : TRUE;
|
|
if (pwi->trm.fCursorOn == FALSE)
|
|
CursorOn( hwnd );
|
|
else
|
|
CursorOff( hwnd );
|
|
}
|
|
else if (FInMarkMode(pwi->spb) && FSelected(pwi->spb))
|
|
{
|
|
RECT rect;
|
|
RECT rect2;
|
|
|
|
rect2 = pwi->spb.rectSelect;
|
|
|
|
rect2.top = aiyPos[rect2.top]-vPos;
|
|
rect2.bottom = aiyPos[rect2.bottom]+iCursorHeight-vPos;
|
|
rect2.left = aixPos[rect2.left]-hPos;
|
|
rect2.right = aixPos[rect2.right]+iCursorWidth-hPos;
|
|
|
|
IntersectRect(&rect, &ps.rcPaint, &rect2);
|
|
InvertRect(hdc, &rect);
|
|
}
|
|
|
|
EndPaint(hwnd, &ps);
|
|
|
|
}
|
|
|
|
void
|
|
CursorOn(HWND hwnd)
|
|
{
|
|
WI *pwi = (WI *)GetWindowLong(hwnd, WL_VTPWI);
|
|
HDC hdc;
|
|
int yCursorHeight;
|
|
|
|
if (pwi->trm.fCursorOn == TRUE)
|
|
return;
|
|
|
|
hdc = GetDC( hwnd );
|
|
|
|
if (ui.fCursorEdit & fdwCursorUnderline)
|
|
{
|
|
yCursorHeight = iCursorHeight / 4;
|
|
if (yCursorHeight == 0)
|
|
yCursorHeight = 1;
|
|
PatBlt(hdc, aixPos[pwi->trm.dwCurChar]-hPos,
|
|
aiyPos[pwi->trm.dwCurLine] + iCursorHeight-yCursorHeight-vPos,
|
|
iCursorWidth, yCursorHeight, DSTINVERT);
|
|
}
|
|
else
|
|
{
|
|
PatBlt(hdc, aixPos[pwi->trm.dwCurChar]-hPos, aiyPos[pwi->trm.dwCurLine]-vPos,
|
|
iCursorWidth, iCursorHeight, DSTINVERT);
|
|
}
|
|
|
|
ReleaseDC(hwnd, hdc);
|
|
pwi->trm.fCursorOn = TRUE;
|
|
}
|
|
|
|
void
|
|
CursorOff(HWND hwnd)
|
|
{
|
|
WI *pwi = (WI *)GetWindowLong(hwnd, WL_VTPWI);
|
|
HDC hdc;
|
|
HFONT hfontOld;
|
|
|
|
if (pwi->trm.fCursorOn == FALSE)
|
|
return;
|
|
|
|
hdc = GetDC( hwnd );
|
|
|
|
/* suppress cursor on screen */
|
|
hfontOld = SelectObject(hdc, hfontDisplay);
|
|
|
|
if (apcRows[pwi->trm.dwCurLine][pwi->trm.dwCurChar] != 0)
|
|
{
|
|
SetTextColor(hdc, ui.clrText);
|
|
SetBkColor(hdc, ui.clrBk);
|
|
MyTextOut(hdc, pwi->trm.dwCurChar, pwi->trm.dwCurLine,
|
|
apcRows[pwi->trm.dwCurLine]+pwi->trm.dwCurChar, 1);
|
|
}
|
|
else if (apcRows[pwi->trm.dwCurLine][pwi->trm.dwCurChar+ui.dwMaxCol] != 0)
|
|
{
|
|
SetTextColor(hdc, ui.clrBk);
|
|
SetBkColor(hdc, ui.clrText);
|
|
MyTextOut(hdc, pwi->trm.dwCurChar, pwi->trm.dwCurLine,
|
|
apcRows[pwi->trm.dwCurLine]+pwi->trm.dwCurChar+ui.dwMaxCol, 1);
|
|
}
|
|
|
|
(void)SelectObject(hdc, hfontOld);
|
|
ReleaseDC(hwnd, hdc);
|
|
|
|
pwi->trm.fCursorOn = FALSE;
|
|
}
|
|
|
|
void
|
|
SetDisplaySize(HWND hwnd, DWORD dwSize, DWORD *pdwLine)
|
|
{
|
|
short idm;
|
|
short idmT;
|
|
HMENU hmenu;
|
|
DWORD i;
|
|
WI *pwi = (WI *)GetWindowLong(hwnd, WL_VTPWI);
|
|
|
|
if (dwSize == 50)
|
|
idm = IDM_50LINES;
|
|
else if (dwSize == 43)
|
|
idm = IDM_43LINES;
|
|
else if (dwSize == 25)
|
|
idm = IDM_25LINES;
|
|
else
|
|
idm = IDM_CUSTOMLINES;
|
|
|
|
/* Make the sure the right menu item is checked */
|
|
hmenu = GetMenu( hwnd );
|
|
for (idmT = IDM_25LINES; idmT <= IDM_CUSTOMLINES; ++idmT)
|
|
{
|
|
if (idm != idmT)
|
|
CheckMenuItem(hmenu, idmT, MF_UNCHECKED);
|
|
}
|
|
CheckMenuItem(hmenu, idm, MF_CHECKED);
|
|
DrawMenuBar( hwnd );
|
|
|
|
/* Adjust the data structures for the change in size */
|
|
if (ui.dwMaxRow != dwSize)
|
|
{
|
|
if (ui.dwMaxRow > dwSize)
|
|
{
|
|
for (i=dwSize; i<ui.dwMaxRow; ++i)
|
|
LocalFree( (HANDLE)apcRows[i] );
|
|
ui.dwMaxRow = dwSize;
|
|
}
|
|
|
|
aiyPos = LocalReAlloc(aiyPos, sizeof(DWORD)*(dwSize+1), LMEM_MOVEABLE);
|
|
|
|
apcRows = LocalReAlloc(apcRows, sizeof(CHAR *)*dwSize, LMEM_MOVEABLE);
|
|
|
|
for (i=ui.dwMaxRow; i<dwSize; ++i)
|
|
{
|
|
apcRows[i] = LocalAlloc(LPTR, 2*ui.dwMaxCol);
|
|
memcpy(apcRows[i], rgchRowEmpty, 2*ui.dwMaxCol);
|
|
}
|
|
|
|
ui.dwMaxRow = dwSize;
|
|
|
|
RecalcWindowSize( hwnd );
|
|
}
|
|
|
|
/* sanity checks */
|
|
if (ui.dwMaxRow != pwi->trm.dwScrollBottom)
|
|
{
|
|
pwi->trm.dwScrollBottom = ui.dwMaxRow;
|
|
|
|
if (pwi->trm.dwScrollTop >= pwi->trm.dwScrollBottom)
|
|
pwi->trm.dwScrollTop = pwi->trm.dwScrollBottom-1;
|
|
if (pwi->trm.dwScrollBottom <= pwi->trm.dwCurLine)
|
|
pwi->trm.dwCurLine = pwi->trm.dwScrollBottom-1;
|
|
if (pwi->trm.dwScrollBottom <= pwi->trm.dwSaveLine)
|
|
pwi->trm.dwSaveLine = pwi->trm.dwScrollBottom-1;
|
|
}
|
|
|
|
/* Reposition the cursor so it's on the screen */
|
|
if (dwSize < (*pdwLine))
|
|
*pdwLine = dwSize - 1;
|
|
}
|
|
|
|
void
|
|
HandleCharEvent(HWND hwnd, WI *pwi, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
DWORD i;
|
|
|
|
/* Map Alt-Control-C to Delete */
|
|
if ((LOWORD(wParam) == 3) && (lParam & 0x01000000))
|
|
wParam = 0x7F;
|
|
|
|
pchNBBuffer[0] = (UCHAR)wParam;
|
|
if (ui.fDebug & fdwLocalEcho)
|
|
{
|
|
i = 1;
|
|
if (pchNBBuffer[0] == 0x0D)
|
|
{
|
|
pchNBBuffer[i++] = 0x0A;
|
|
}
|
|
DoIBMANSIOutput(hwnd, &pwi->trm, i, pchNBBuffer);
|
|
}
|
|
NetBIOSWrite(pwi->nd.SessionNumber, (LPSTR)pchNBBuffer, 1);
|
|
}
|
|
|
|
BOOL
|
|
FHandleKeyDownEvent(HWND hwnd, WI *pwi, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (LOWORD(wParam) == VK_DELETE)
|
|
{
|
|
pchNBBuffer[0] = 0x7F;
|
|
NetBIOSWrite(pwi->nd.SessionNumber, (LPSTR)pchNBBuffer, 1);
|
|
return TRUE;
|
|
}
|
|
else if ( !(ui.fDebug & fdwNoVT100Keys) )
|
|
{
|
|
DWORD iPos = (FIsVT52(&pwi->trm)) ? 1 : 2;
|
|
DWORD cch = (FIsVT52(&pwi->trm)) ? 2 : 3;
|
|
WORD wKeyCode = LOWORD(wParam);
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
pchNBBuffer[0] = 0;
|
|
pchNBBuffer[1] = (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] = 'P'+(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)
|
|
{
|
|
NetBIOSWrite(pwi->nd.SessionNumber, (LPSTR)pchNBBuffer, cch);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|