📄 vt102em.cpp
字号:
// vt102em.cpp - vt102 emulator methods
// $Id: vt102em.cpp 2.3 1995/10/31 02:26:20 tsurace Beta $
// $Log: vt102em.cpp $// Revision 2.3 1995/10/31 02:26:20 tsurace// Fixed ret_val uninitialized in _SysMenuCommand.//
// Revision 2.2 1995/10/30 18:28:46 tsurace
// Added debug toggle and console mode switch to system menu.
//
// Revision 2.1 1995/10/24 15:52:51 tsurace
// Roll.
//
// Revision 1.8 1995/10/19 00:58:27 tsurace
// Changed title.
//
// Revision 1.7 1995/10/18 22:58:01 tsurace
// Made MY_SOCKET_LONG message globally accessible.
//
// Revision 1.6 1995/10/15 23:33:25 tsurace
// Added one line comment.
//
// Revision 1.5 1995/10/15 23:23:39 tsurace
// Fixed bug that caused all windows to resize on SIZE_MINIMIZE.
//
// Revision 1.4 1995/10/11 21:40:43 tsurace
// Modified the "select event" handling code.
// Modified resize functionality.
// Reflects changes to the scream_and_die function.
//
// Revision 1.3 1995/10/08 23:29:29 tsurace
// Modified code to update more quickly when scrolling. It kind
// of sucks if you have a slow display card right now.
//
// Revision 1.2 1995/10/07 00:33:48 tsurace
// Added some cursor colors and the _Size function. Scrolling
// optimization.
//
// (End of log)
// This is a simple VT102 emulator library for 32-bit
// programs only, but supportive of win32s. This is intended to
// support the subset of vt102 required by VaporTalk, the best MUD
// client in the world. It may also support ANSI color, someday.
#define STRICT
#include <windows.h>
#pragma hdrstop
#include <stdlib.h>
#include <string.h>
#include "debug.hpp"
#include "esc_seq.hpp"
#include "global.hpp"
#include "keyev.hpp"
#include "vt102em.hpp"
extern "C" {
// Functions from VT -- these define entry points into the
// vt code to send keyboard events, check for remote input, and
// so on.
//
// Be sure to check the type of these when updating
// to a new version of VT! I wanted to put these in a shared header
// file, but it was getting to be a lot of trouble. <frown>
extern int io_check(long sec, long usec); /* remote.c */
extern int io_cycle(); /* main.c */
extern void process_incoming (char * str); /* keyboard input routine */
extern void resize_screen(int new_rows, int new_cols);
extern void curs_input(); /* window.c */
extern void console(); /* console.c */
extern int console_mode; /* console.c */
extern int debug; /* vtc.c */
};
#define TEXT_FORE RGB(160,160,160)
#define TEXT_BACK RGB(0,0,0)
#define TEXT_BOLD RGB(40,255,100)
#define CURSOR_FORE RGB(255,255,255)
#define CURSOR_BACK RGB(128,0,128)
//
// >>>>> VT102Emulator class <<<<< //
//
char VT102Emulator::_szClassName[] = "VT102 Emulator Window";
static const char _TITLE[] = "VT-Win 1.1 $State: Beta $";
// ------------------------------------------------------------------------
// VT102Emulator constructor
// Do not create unless previously registered.
//
VT102Emulator::VT102Emulator(int nCmdShow)
: _screen(80,35,
TEXT_FORE, // Normal foreground
TEXT_BOLD, // Bold foreground
&VT102Emulator::InvalidateStaticCB,
this,
&VT102Emulator::ScrollAreaStaticCB,
this),
_font(0),
_cursorColor(CURSOR_FORE),
_cursorBackground(CURSOR_BACK),
_cursorPen(0),
_backgroundColor(TEXT_BACK),
_fontSize(8,16),
_lastPaintTickCount(0),
_forceUpdateSoon(0),
_initialized(0)
{
// A Windows class should be registered with Windows before any windows
// of that type are created.
if (! Global::PrevInstance()) // Not already registered?
_Register(); // Register!
// Create a window, and Pass 'this' pointer in lpParam of CreateWindow()
_hWnd = CreateWindow(_szClassName,
_TITLE,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
0,
CW_USEDEFAULT,
0,
NULL,
NULL,
Global::Instance(),
(LPSTR) this );
// Could not create window, might as well exit
if (!_hWnd)
scream_and_die(EC_FatalError, ERR_CreateWindow);
// Load the monospace font, and initialize the "screen"
_InitScreen();
Show(nCmdShow); // Show the window the correct/official way
Update();
_initialized = 1; // Call after construction
};
VT102Emulator::~VT102Emulator()
{
// _cursorPen is a stock object
// _font is a stock object, maybe
}
// ------------------------------------------------------------------------
// ScrollAreaStaticCB - callback function, calls ScrollArea
//
int VT102Emulator::ScrollAreaStaticCB(int target,
int source,
int size,
void * this_ptr)
{
return ((VT102Emulator *)this_ptr)->ScrollArea(target, source, size);
}
// ------------------------------------------------------------------------
// ScrollArea - Scrolls the specified area of the screen
//
// Parameters:
// top - first line to scroll (zero-indexed)
// bottom - last line to scroll (also zero-indexed)
// amount - amount to scroll, may be negative
//
// Returns:
// nonzero if the row was successfully copied
//
int VT102Emulator::ScrollArea(int top, int bottom, int amount)
{
ASSERT(bottom >= top, "No area to scroll");
ASSERT(top >= 0, "Top is off screen");
ASSERT(bottom < _screen.Height(), "Bottom is off screen");
if (amount != 0)
{
RECT area;
area.top = top * _fontSize.Height();
area.bottom = ((bottom + 1) * _fontSize.Height()) - 1;
area.left = 0;
area.right = (_screen.Width() * _fontSize.Width());
ScrollWindow(Handle(),
0, // No scroll of x
- (amount * _fontSize.Height()),
NULL, // Must be null so that exposed regions scroll
&area); // Clip area
_forceUpdateSoon = 1;
};
return 1; // Successful scroll
}
// ------------------------------------------------------------------------
// _InvalidateStaticCB - invalidate rect - static callback calls builtin
void VT102Emulator::InvalidateStaticCB(const Pos & pos,
const Size & size,
void * this_ptr)
{
((VT102Emulator *)this_ptr)->Invalidate(pos, size);
}
void VT102Emulator::Invalidate(const Pos & pos, const Size & size)
{
RECT area;
area.left = pos.X() * _fontSize.Width();
area.top = pos.Y() * _fontSize.Height();
area.right = (pos.X() + size.Width()) * _fontSize.Width();
area.bottom = (pos.Y() + size.Height()) * _fontSize.Height();
// Don't clear, because it causes an annoying flicker, and the
// textbackmode is opaque anyway
InvalidateRect(Handle(), &area, TRUE);
}
// ------------------------------------------------------------------------
// NewSocket - tell windows about this new socket.
//
// Returns:
// NULL on success or an error string on failure.
const char * VT102Emulator::NewSocket (SOCKET s, long events)
{
// Select soctet messages
if (SOCKET_ERROR == WSAAsyncSelect (s, Handle(), VT_SOCKET_MSG, events))
{
switch (WSAGetLastError())
{
case WSAENETDOWN: // Net is dead!
return "The network is dead";
case WSAEINPROGRESS:
return "Blocking WinSock operation in progress";
default:
return "A horrible unknown WinSock error occurred";
};
};
return NULL; // No problem
};
// ------------------------------------------------------------------------
void VT102Emulator::Output(char * str, int len)
{
for (int i=0; i < len; i++)
{
_screen.Put(str[i]); // Output the next character
// Update screen at LEAST every quarter of a second, which is
// generally accepted as the minimum acceptable delay.
if (_forceUpdateSoon
|| ((GetTickCount() - _lastPaintTickCount) > 200))
{
Update();
};
};
}
// >>>>> PRIVATE and PROTECTED functions <<<<< //
// ------------------------------------------------------------------------
// This is the expose function, the critical heart of any graphic
// program! :>
//
// Only call this in response to a WM_PAINT event!
//
void VT102Emulator::_Paint()
{
_lastPaintTickCount = GetTickCount(); // Now
_forceUpdateSoon = 0; // We are updating now.
PAINTSTRUCT ps; // Begin paint, get info
BeginPaint(Handle(), &ps);
RECT clip_rect;
GetClipBox(ps.hdc, &clip_rect);
HRGN clip_reg = CreateRectRgnIndirect(&clip_rect);
SelectClipRgn(ps.hdc, clip_reg);
_PutText(ps.hdc, clip_reg);
_PutCursor(ps.hdc);
DeleteObject(clip_reg); // Don't need this region any more
EndPaint(Handle(), &ps ); // Done, yay!
}
// ------------------------------------------------------------------------
// _PutTextOneLine - puts just this line of text on the screen
//
void VT102Emulator::_PutTextOneLine(HDC hdc, int row)
{
ASSERT(_screen.Width() > 0, "Assuming the screen has width");
// TextOut is very slow...count characters that are all the
// same color and put them all at once.
int y_pixel_location = row * _fontSize.Height();
int x_text_location = 0;
int start = _screen.IndexOf(0,row); // Start of string to put
int row_end_marker = start + _screen.Width();
int width = 0; // Width of current segment
COLORREF thisColor = _screen.ForegroundElement(start);
while(1) // Loop forever
{
++width;
int end = start + width; // End of string
if ((end >= row_end_marker)
|| (_screen.ForegroundElement(end) != thisColor))
{
// New color, flush text.
SetTextColor(hdc, thisColor);
TextOut(hdc,
x_text_location * _fontSize.Width(),
y_pixel_location,
&_screen.TextElement(start),
width);
if (end >= row_end_marker) // Done with this line
break;
start += width; // Increment array offset
x_text_location += width; // Increment column offset
width = 0;
thisColor = _screen.ForegroundElement(end); // Save new color
};
};
}
// ------------------------------------------------------------------------
// _PutText - _Paint helper function that updates all modified text areas
//
// Parameters:
// hdc - dc to paint to
// clip_reg - current exposed region
//
void VT102Emulator::_PutText(HDC hdc, HRGN clip_reg)
{
RECT exposeRect;
GetRgnBox(clip_reg, &exposeRect); // What area of the screen to paint?
int firstRow = (exposeRect.top+1) / _fontSize.Height();
if (firstRow < 0) // Off top of screen?
firstRow = 0;
else if (firstRow >= _screen.Height()) // Or bottom?
firstRow = _screen.Height();
int lastRow = (exposeRect.bottom) / _fontSize.Height();
if (lastRow < 0) // Off top of screen
lastRow = 0;
else if (lastRow >= _screen.Height()) // Off bottom of screen?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -