📄 ansiterm.cpp
字号:
// ***************** START OF ANSITERM.CPP *****************
//
//
// This file contains all the code to support the AnsiTerm
// class, which is a terminal emulation class that supports
// the IBM PC ANSI.SYS control sequences.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "terminal.h"
#include "ansiterm.h"
// These two defines can be used to help debug the terminal
// emulation class. DEBUG is used to split the screen and
// provide a bottom window that displays escape sequences as
// they are parsed. KEYBOARD_FAKE lets you input escape
// sequences from the keyboard.
//#define KEYBOARD_FAKE
#define DEBUG
//
// The debug macro in this file is only meant to be used
// when debugging in MS-DOS. A bit of additional code would
// need to be written under Windows to create a debug window.
// So we turn off the debug macro if we are building a
// Windows program.
//
#if defined( _WINDOWS ) && defined( DEBUG )
#undef DEBUG
#endif
#if defined( DEBUG )
#include "textwind.h"
BaseWindow *debug_window;
#endif
// This is a list of keyboard mappings that are defined when the
// emulator first starts. These key mappings can be remapped
// dynamically, although this class does not support the feature.
// These values are loaded into the mapping arrays when the
// constructor executes.
struct key_strings {
int key_value;
char *translation;
} initial_key_translations[] = { { LEFT, "\x1b[D" },
{ RIGHT, "\x1b[C" },
{ UP, "\x1b[A" },
{ DOWN, "\x1b[B" },
{ HOME, "\x1b[H" },
{ END, "\x1b[F" },
{ PGUP, "\x1b[I" },
{ PGDN, "\x1b[G" },
{ INSERT, "\x1b[L" },
{ F1, "\x1b[M" },
{ F2, "\x1b[N" },
{ F3, "\x1b[O" },
{ F4, "\x1b[P" },
{ F5, "\x1b[Q" },
{ F6, "\x1b[R" },
{ F7, "\x1b[S" },
{ F8, "\x1b[T" },
{ F9, "\x1b[U" },
{ F10, "\x1b[V" },
{ SHIFT_F1, "\x1b[Y" },
{ SHIFT_F2, "\x1b[Z" },
{ SHIFT_F3, "\x1b[a" },
{ SHIFT_F4, "\x1b[b" },
{ SHIFT_F5, "\x1b[c" },
{ SHIFT_F6, "\x1b[d" },
{ SHIFT_F7, "\x1b[e" },
{ SHIFT_F8, "\x1b[f" },
{ SHIFT_F9, "\x1b[g" },
{ SHIFT_F10, "\x1b[h" },
{ CONTROL_F1, "\x1b[k" },
{ CONTROL_F2, "\x1b[l" },
{ CONTROL_F3, "\x1b[m" },
{ CONTROL_F4, "\x1b[n" },
{ CONTROL_F5, "\x1b[o" },
{ CONTROL_F6, "\x1b[p" },
{ CONTROL_F7, "\x1b[q" },
{ CONTROL_F8, "\x1b[r" },
{ CONTROL_F9, "\x1b[s" },
{ CONTROL_F10, "\x1b[t" },
{ ALT_F1, "\x1b[w" },
{ ALT_F2, "\x1b[x" },
{ ALT_F3, "\x1b[y" },
{ ALT_F4, "\x1b[z" },
{ ALT_F5, "\x1b[@" },
{ ALT_F6, "\x1b[[" },
{ ALT_F7, "\x1b[\\" },
{ ALT_F8, "\x1b[]" },
{ ALT_F9, "\x1b[^" },
{ ALT_F10, "\x1b[_" },
{ 0, 0 }
};
//
// The constructor sets up the pointers to the port and the
// TextWindow objects. It puts the window in a predefined
// state, allocates the memory for the ansi string parsing
// storage, then initializes the key maps. If the DEBUG macro
// is turned on, the screen is split and a second debug text
// window is opened.
//
AnsiTerminal::AnsiTerminal( RS232 &p, BaseWindow &w )
: Terminal( p, w )
{
int key;
char *translation;
window->Clear();
window->Goto();
window->SetWrap( 1 );
saved_row = 0;
saved_col = 0;
for ( int i = 0 ; i < 15 ; i++ )
ansi_parms[ i ] = new char[ 81 ];
ansi_parms[ 15 ] = 0;
keys = new char *[ 256 ];
extended_keys = new char *[ 256 ];
for ( i = 0 ; i < 256 ; i++ ) {
if ( keys )
keys[ i ] = 0;
if ( extended_keys )
extended_keys[ i ] = 0;
}
for ( i = 0;
initial_key_translations[ i ].translation != 0;
i++ )
{
key = initial_key_translations[ i ].key_value;
translation = initial_key_translations[ i ].translation;
if ( extended_keys && key > 256 )
extended_keys[ ( key >> 8 ) & 0xff ] = translation;
else if ( keys )
keys[ key ] = translation;
}
#if defined( DEBUG )
Set43LineMode( 1 );
debug_window = new TextWindow( 25, 0, 80, 18 );
debug_window->SetWrap( 1 );
#endif
}
//
// ReadPort filters port input for the end application. If
// it sees the first character of an escape sequence, it gets
// parsed, and the application never sees it. Normal characters
// get passed straight back to the application. Note that if
// the KEYBOARD_FAKE macro is defined, input comes from the
// keyboard instead of the port.
//
int AnsiTerminal::ReadPort( void )
{
int c;
#ifdef KEYBOARD_FAKE
while ( ( c = window->ReadKey() ) == 0 )
;
if ( c == F10 )
return RS232_ERROR;
#else
c = port->Read();
#endif
if ( c == ESC ) {
parse();
return RS232_TIMEOUT;
}
return c;
}
//
// The destructor for an AnsiTerminal objects just has to free
// up the memory allocated for the ANSI parser. If DEBUG is
// turned on, the screen is restored to 25 line mode.
AnsiTerminal::~AnsiTerminal( void )
{
for ( int i = 0 ; i < 15 ; i++ )
delete[] ansi_parms[ i ];
delete[] keys;
delete[] extended_keys;
#if defined( DEBUG ) && !defined( _WINDOWS )
Set43LineMode( 0 );
#endif
}
// This is the actual parser that reads in ANSI strings. It
// is just a fairly simple state machine, that sits in a loop
// reading in characters until it detects the end of an ANSI
// sequence. When it is done, the ansi_parms[] array holds a
// list of numeric and quoted strings, and parm_count is the
// index to the last valid string. Error handling is
// non-existent, if anything odd happens the routine just returns
// with a failure.
int AnsiTerminal::parse_ansi_string( void )
{
int index;
enum { READY_TO_READ,
READING_DIGITS,
READING_STRING,
DONE_WITH_STRING } scan_state;
int c;
parm_count = 0;
index = 0;
for ( int i = 0 ; i < 15 ; i++ )
if ( ansi_parms[ i ] != 0 )
memset( ansi_parms[ i ], 0, 81 );
#ifdef KEYBOARD_FAKE
while ( ( c = window->ReadKey() ) == 0 )
;
#else
c = port->Read( 200 );
#endif
if ( c != '[' )
return 0;
scan_state = READY_TO_READ;
for ( ; ; ) {
if ( index >= 80 || ansi_parms[ parm_count ] == 0 )
return 0;
#ifdef KEYBOARD_FAKE
while ( ( c = window->ReadKey() ) == 0 )
;
#else
c = port->Read( 1000 );
#endif
if ( c < 0 )
return 0;
switch ( scan_state ) {
case READY_TO_READ:
if ( parm_count == 0 && ( c == '=' || c == '?' ) )
ansi_parms[ parm_count++ ][ 0 ] = (char) c;
else if ( c == '"' ) {
scan_state = READING_STRING;
ansi_parms[ parm_count ][ index++ ] = (char) c;
} else if ( c >= '0' && c <= '9' ) {
ansi_parms[ parm_count ][ index++ ] = (char) c;
scan_state = READING_DIGITS;
} else if ( c == ';' ) {
parm_count++;
index = 0;
} else {
ansi_parms[ parm_count ][ index ] = (char) c;
return 1;
}
break;
case READING_DIGITS :
if ( c == ';' ) {
parm_count++;
index = 0;
scan_state = READY_TO_READ;
} else if ( c >= '0' && c <='9' )
ansi_parms[ parm_count ][ index++ ] = (char) c;
else {
ansi_parms[ ++parm_count ][ 0 ] = (char) c;
return 1;
}
break;
case READING_STRING :
if ( c == '"' )
scan_state = DONE_WITH_STRING;
ansi_parms[ parm_count ][ index++ ] = (char) c;
break;
case DONE_WITH_STRING :
if ( c == ';' ) {
parm_count++;
index = 0;
scan_state = READY_TO_READ;
} else {
ansi_parms[ ++parm_count ][ 0 ] = (char) c;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -