You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
803 lines
35 KiB
803 lines
35 KiB
/* ------------------------------------------------------------------------- */ |
|
/* */ |
|
/* [vt102emu.cpp] VT102 Terminal Emulation */ |
|
/* */ |
|
/* ------------------------------------------------------------------------- */ |
|
/* */ |
|
/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ |
|
/* */ |
|
/* This file is part of Konsole - an X terminal for KDE */ |
|
/* */ |
|
/* ------------------------------------------------------------------------- */ |
|
|
|
/* \class |
|
|
|
This class is responsible to scan the escapes sequences of the terminal |
|
emulation and to map it to their corresponding semantic complements. |
|
Thus this module knows mainly about decoding escapes sequences and |
|
is a stateless device w.r.t. the semantics. |
|
|
|
It is also responsible to refresh the TEWidget by certain rules. |
|
|
|
\sa TEWidget \sa TEScreen |
|
*/ |
|
|
|
/* FIXME |
|
- For strange reasons, the extend of the rendition attributes ranges over |
|
all screens and not over the actual screen. We have to find out the |
|
precise extend. |
|
*/ |
|
//NOTE: search for 'NotImplemented' and IGNORED to find unimplemented features. |
|
//TODO: we have no means yet, to change the emulation on the fly. |
|
|
|
#include "TEmuVt102.h" |
|
#include "TEWidget.h" |
|
#include "TEScreen.h" |
|
|
|
#include <stdio.h> |
|
#include <unistd.h> |
|
#include <qkeycode.h> |
|
|
|
#include <assert.h> |
|
|
|
#include "TEmuVt102.moc" |
|
|
|
#define ESC 27 |
|
#define MIN(a,b) ((a)<(b)?(a):(b)) |
|
#define MAX(a,b) ((a)>(b)?(a):(b)) |
|
|
|
#define HERE printf("%s(%d): here\n",__FILE__,__LINE__) |
|
|
|
/* ------------------------------------------------------------------------- */ |
|
/* */ |
|
/* Emulation */ |
|
/* */ |
|
/* ------------------------------------------------------------------------- */ |
|
|
|
#define CNTL(c) ((c)-'@') |
|
|
|
/*! |
|
*/ |
|
|
|
int maxHistLines = 100; |
|
//#define MAXHISTLINES 100 // natural constant for now. |
|
|
|
VT102Emulation::VT102Emulation(TEWidget* gui, const char* term) : Emulation(gui) |
|
{ |
|
screen[0] = scr; |
|
screen[0]->setHistMaxLines(maxHistLines); |
|
screen[1] = new TEScreen(gui->Lines(),gui->Columns()); |
|
// note that the application screen has not history buffer. |
|
|
|
QObject::connect(gui,SIGNAL(mouseSignal(int,int,int)), |
|
this,SLOT(onMouse(int,int,int))); |
|
|
|
tableInit(); |
|
resetTerminal(); |
|
setMode(MODE_BsHack); |
|
emulation = term; |
|
} |
|
|
|
void VT102Emulation::resetTerminal() |
|
{ |
|
|
|
reset(); |
|
|
|
resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000); |
|
resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys); |
|
resetMode(MODE_AppScreen); saveMode(MODE_AppScreen); |
|
resetMode(MODE_NewLine); |
|
setMode(MODE_Ansi); |
|
|
|
screen[0]->reset(); |
|
screen[1]->reset(); |
|
} |
|
|
|
/*! |
|
*/ |
|
|
|
VT102Emulation::~VT102Emulation() |
|
{ |
|
scr = screen[0]; |
|
delete screen[1]; |
|
} |
|
|
|
|
|
void VT102Emulation::onImageSizeChange(int lines, int columns) |
|
{ |
|
if (scr != screen[0]) screen[0]->resizeImage(lines,columns); |
|
if (scr != screen[1]) screen[1]->resizeImage(lines,columns); |
|
Emulation::onImageSizeChange(lines,columns); |
|
} |
|
|
|
void VT102Emulation::NewLine() |
|
{ |
|
scr->NewLine(); bulkNewline(); |
|
} |
|
|
|
void VT102Emulation::setColumns(int columns) |
|
{ |
|
emit changeColumns(columns); // this goes strange ways |
|
} |
|
|
|
// Interpreting Codes --------------------------------------------------------- |
|
/* |
|
This section deals with decoding the incoming character stream. |
|
Decoding means here, that the stream is first seperated into `tokens' |
|
which are then mapped to a `meaning' provided as operations by the |
|
`Screen' class. |
|
|
|
The tokens are defined below. They are: |
|
|
|
- CHR - Printable characters (32..255 but DEL (=127)) |
|
- CTL - Control characters (0..31 but ESC (= 27), DEL) |
|
- ESC - Escape codes of the form <ESC><CHR but `[]()+*#'> |
|
- ESC_DE - Escape codes of the form <ESC><any of `()+*#'> C |
|
- CSI_PN - Escape codes of the form <ESC>'[' {Pn} ';' {Pn} C |
|
- CSI_PS - Escape codes of the form <ESC>'[' {Pn} ';' ... C |
|
- CSI_PR - Escape codes of the form <ESC>'[' '?' {Pn} ';' ... C |
|
- VT52 - VT52 escape codes |
|
- <ESC><Chr> |
|
- <ESC>'Y'{Pc}{Pc} |
|
- XTE_HA - Xterm hacks <ESC>`]' {Pn} `;' {Text} <BEL> |
|
note that this is handled differently |
|
|
|
The last two forms allow list of arguments. Since the elements of |
|
the lists are treated individually the same way, they are passed |
|
as individual tokens to the interpretation. Further, because the |
|
meaning of the parameters are names (althought represented as numbers), |
|
they are includes within the token ('N'). |
|
|
|
*/ |
|
|
|
#define TY_CONSTR(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) ) |
|
|
|
#define TY_CHR___( ) TY_CONSTR(0,0,0) |
|
#define TY_CTL___(A ) TY_CONSTR(1,A,0) |
|
#define TY_ESC___(A ) TY_CONSTR(2,A,0) |
|
#define TY_ESC_CS( ) TY_CONSTR(3,0,0) |
|
#define TY_ESC_DE(A ) TY_CONSTR(4,A,0) |
|
#define TY_CSI_PS(A,N) TY_CONSTR(5,A,N) |
|
#define TY_CSI_PN(A ) TY_CONSTR(6,A,0) |
|
#define TY_CSI_PR(A,N) TY_CONSTR(7,A,N) |
|
|
|
#define TY_VT52__(A ) TY_CONSTR(8,A,0) |
|
|
|
//FIXME: include recognition of remaining VT100 codes. |
|
// this are printing modes, ESC[{ps}i (printing) and VT52 printing. |
|
|
|
void VT102Emulation::tau( int code, int p, int q ) |
|
{ |
|
//scan_buffer_report(); |
|
//if (code == TY_CHR___()) printf("%c",p); else |
|
//printf("tau(%d,%d,%d, %d,%d)\n",(code>>0)&0xff,(code>>8)&0xff,(code>>16)&0xffff,p,q); |
|
switch (code) |
|
{ |
|
case TY_CHR___( ) : scr->ShowCharacter (p ); break; //VT100 |
|
|
|
//FIXME: 127 DEL : ignored on input? |
|
|
|
case TY_CTL___(CNTL('@')) : /* NUL: ignored */ break; |
|
case TY_CTL___(CNTL('A')) : /* SOH: ignored */ break; |
|
case TY_CTL___(CNTL('B')) : /* STX: ignored */ break; |
|
case TY_CTL___(CNTL('C')) : /* ETX: ignored */ break; |
|
case TY_CTL___(CNTL('D')) : /* EOT: ignored */ break; |
|
case TY_CTL___(CNTL('E')) : reportAnswerBack ( ); break; //VT100 |
|
case TY_CTL___(CNTL('F')) : /* ACK: ignored */ break; |
|
case TY_CTL___(CNTL('G')) : gui->Bell ( ); break; //VT100 |
|
case TY_CTL___(CNTL('H')) : scr->BackSpace ( ); break; //VT100 |
|
case TY_CTL___(CNTL('I')) : scr->Tabulate ( ); break; //VT100 |
|
case TY_CTL___(CNTL('J')) : NewLine ( ); break; //VT100 |
|
case TY_CTL___(CNTL('K')) : NewLine ( ); break; //VT100 |
|
case TY_CTL___(CNTL('L')) : NewLine ( ); break; //VT100 |
|
case TY_CTL___(CNTL('M')) : scr->Return ( ); break; //VT100 |
|
case TY_CTL___(CNTL('N')) : scr->useCharset ( 1); break; //VT100 |
|
case TY_CTL___(CNTL('O')) : scr->useCharset ( 0); break; //VT100 |
|
case TY_CTL___(CNTL('P')) : /* DLE: ignored */ break; |
|
case TY_CTL___(CNTL('Q')) : /* DC1: FIXME: XON continue */ break; //VT100 |
|
case TY_CTL___(CNTL('R')) : /* DC2: ignored */ break; |
|
case TY_CTL___(CNTL('S')) : /* DC3: XOFF halt */ break; //VT100 |
|
case TY_CTL___(CNTL('T')) : /* DC4: ignored */ break; |
|
case TY_CTL___(CNTL('U')) : /* NAK: ignored */ break; |
|
case TY_CTL___(CNTL('V')) : /* SYN: ignored */ break; |
|
case TY_CTL___(CNTL('W')) : /* ETB: ignored */ break; |
|
case TY_CTL___(CNTL('X')) : scr->ShowCharacter ( 2); break; //VT100 |
|
case TY_CTL___(CNTL('Y')) : /* EM : ignored */ break; |
|
case TY_CTL___(CNTL('Z')) : scr->ShowCharacter ( 2); break; //VT100 |
|
case TY_CTL___(CNTL('[')) : /* ESC: cannot be seen here. */ break; |
|
case TY_CTL___(CNTL('\\')): /* FS : ignored */ break; |
|
case TY_CTL___(CNTL(']')) : /* GS : ignored */ break; |
|
case TY_CTL___(CNTL('^')) : /* RS : ignored */ break; |
|
case TY_CTL___(CNTL('_')) : /* US : ignored */ break; |
|
|
|
case TY_ESC___('D' ) : scr->index ( ); break; //VT100 |
|
case TY_ESC___('E' ) : scr->NextLine ( ); break; //VT100 |
|
case TY_ESC___('H' ) : scr->changeTabStop (TRUE ); break; //VT100 |
|
case TY_ESC___('M' ) : scr->reverseIndex ( ); break; //VT100 |
|
case TY_ESC___('Z' ) : reportTerminalType ( ); break; |
|
case TY_ESC___('c' ) : resetTerminal ( ); break; |
|
case TY_ESC___('n' ) : scr->useCharset ( 2); break; |
|
case TY_ESC___('o' ) : scr->useCharset ( 3); break; |
|
case TY_ESC___('7' ) : scr->saveCursor ( ); break; |
|
case TY_ESC___('8' ) : scr->restoreCursor ( ); break; |
|
case TY_ESC___('=' ) : setMode (MODE_AppKeyPad); break; |
|
case TY_ESC___('>' ) : resetMode (MODE_AppKeyPad); break; |
|
case TY_ESC___('<' ) : setMode (MODE_Ansi ); break; //VT100 |
|
|
|
case TY_ESC_CS( ) : setCharset (p-'(', q); break; //VT100 |
|
|
|
case TY_ESC_DE('3' ) : /* IGNORED: double high, top half */ break; |
|
case TY_ESC_DE('4' ) : /* IGNORED: double high, bottom half */ break; |
|
case TY_ESC_DE('5' ) : /* IGNORED: single width, single high*/ break; |
|
case TY_ESC_DE('6' ) : /* IGNORED: double width, single high*/ break; |
|
case TY_ESC_DE('8' ) : scr->helpAlign ( ); break; |
|
|
|
case TY_CSI_PS('K', 0) : scr->clearToEndOfLine ( ); break; |
|
case TY_CSI_PS('K', 1) : scr->clearToBeginOfLine ( ); break; |
|
case TY_CSI_PS('K', 2) : scr->clearEntireLine ( ); break; |
|
case TY_CSI_PS('J', 0) : scr->clearToEndOfScreen ( ); break; |
|
case TY_CSI_PS('J', 1) : scr->clearToBeginOfScreen ( ); break; |
|
case TY_CSI_PS('J', 2) : scr->clearEntireScreen ( ); break; |
|
case TY_CSI_PS('g', 0) : scr->changeTabStop (FALSE ); break; //VT100 |
|
case TY_CSI_PS('g', 3) : scr->clearTabStops ( ); break; //VT100 |
|
case TY_CSI_PS('h', 4) : scr-> setMode (MODE_Insert ); break; |
|
case TY_CSI_PS('h', 20) : setMode (MODE_NewLine ); break; |
|
case TY_CSI_PS('i', 0) : /* */ break; //VT100 |
|
case TY_CSI_PS('l', 4) : scr-> resetMode (MODE_Insert ); break; |
|
case TY_CSI_PS('l', 20) : resetMode (MODE_NewLine ); break; |
|
|
|
case TY_CSI_PS('m', 0) : scr->setDefaultRendition ( ); break; |
|
case TY_CSI_PS('m', 1) : scr-> setRendition (RE_BOLD ); break; //VT100 |
|
case TY_CSI_PS('m', 4) : scr-> setRendition (RE_UNDERLINE); break; //VT100 |
|
case TY_CSI_PS('m', 5) : scr-> setRendition (RE_BLINK ); break; //VT100 |
|
case TY_CSI_PS('m', 7) : scr-> setRendition (RE_REVERSE ); break; |
|
case TY_CSI_PS('m', 10) : /* IGNORED: mapping related */ break; //LINUX |
|
case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX |
|
case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX |
|
case TY_CSI_PS('m', 22) : scr->resetRendition (RE_BOLD ); break; |
|
case TY_CSI_PS('m', 24) : scr->resetRendition (RE_UNDERLINE); break; |
|
case TY_CSI_PS('m', 25) : scr->resetRendition (RE_BLINK ); break; |
|
case TY_CSI_PS('m', 27) : scr->resetRendition (RE_REVERSE ); break; |
|
|
|
case TY_CSI_PS('m', 30) : scr->setForeColor ( 0); break; |
|
case TY_CSI_PS('m', 31) : scr->setForeColor ( 1); break; |
|
case TY_CSI_PS('m', 32) : scr->setForeColor ( 2); break; |
|
case TY_CSI_PS('m', 33) : scr->setForeColor ( 3); break; |
|
case TY_CSI_PS('m', 34) : scr->setForeColor ( 4); break; |
|
case TY_CSI_PS('m', 35) : scr->setForeColor ( 5); break; |
|
case TY_CSI_PS('m', 36) : scr->setForeColor ( 6); break; |
|
case TY_CSI_PS('m', 37) : scr->setForeColor ( 7); break; |
|
case TY_CSI_PS('m', 39) : scr->setForeColorToDefault( ); break; |
|
|
|
case TY_CSI_PS('m', 40) : scr->setBackColor ( 0); break; |
|
case TY_CSI_PS('m', 41) : scr->setBackColor ( 1); break; |
|
case TY_CSI_PS('m', 42) : scr->setBackColor ( 2); break; |
|
case TY_CSI_PS('m', 43) : scr->setBackColor ( 3); break; |
|
case TY_CSI_PS('m', 44) : scr->setBackColor ( 4); break; |
|
case TY_CSI_PS('m', 45) : scr->setBackColor ( 5); break; |
|
case TY_CSI_PS('m', 46) : scr->setBackColor ( 6); break; |
|
case TY_CSI_PS('m', 47) : scr->setBackColor ( 7); break; |
|
case TY_CSI_PS('m', 49) : scr->setBackColorToDefault( ); break; |
|
|
|
case TY_CSI_PS('m', 90) : scr->setForeColor ( 8); break; |
|
case TY_CSI_PS('m', 91) : scr->setForeColor ( 9); break; |
|
case TY_CSI_PS('m', 92) : scr->setForeColor ( 10); break; |
|
case TY_CSI_PS('m', 93) : scr->setForeColor ( 11); break; |
|
case TY_CSI_PS('m', 94) : scr->setForeColor ( 12); break; |
|
case TY_CSI_PS('m', 95) : scr->setForeColor ( 13); break; |
|
case TY_CSI_PS('m', 96) : scr->setForeColor ( 14); break; |
|
case TY_CSI_PS('m', 97) : scr->setForeColor ( 15); break; |
|
|
|
case TY_CSI_PS('m', 100) : scr->setBackColor ( 8); break; |
|
case TY_CSI_PS('m', 101) : scr->setBackColor ( 9); break; |
|
case TY_CSI_PS('m', 102) : scr->setBackColor ( 10); break; |
|
case TY_CSI_PS('m', 103) : scr->setBackColor ( 11); break; |
|
case TY_CSI_PS('m', 104) : scr->setBackColor ( 12); break; |
|
case TY_CSI_PS('m', 105) : scr->setBackColor ( 13); break; |
|
case TY_CSI_PS('m', 106) : scr->setBackColor ( 14); break; |
|
case TY_CSI_PS('m', 107) : scr->setBackColor ( 15); break; |
|
|
|
case TY_CSI_PS('n', 5) : reportStatus ( ); break; |
|
case TY_CSI_PS('n', 6) : reportCursorPosition ( ); break; |
|
case TY_CSI_PS('q', 0) : /* IGNORED: LEDs off */ break; //VT100 |
|
case TY_CSI_PS('q', 1) : /* IGNORED: LED1 on */ break; //VT100 |
|
case TY_CSI_PS('q', 2) : /* IGNORED: LED2 on */ break; //VT100 |
|
case TY_CSI_PS('q', 3) : /* IGNORED: LED3 on */ break; //VT100 |
|
case TY_CSI_PS('q', 4) : /* IGNORED: LED4 on */ break; //VT100 |
|
case TY_CSI_PS('x', 0) : reportTerminalParms ( 2); break; //VT100 |
|
case TY_CSI_PS('x', 1) : reportTerminalParms ( 3); break; //VT100 |
|
|
|
case TY_CSI_PN('@' ) : scr->insertChars (p ); break; |
|
case TY_CSI_PN('A' ) : scr->cursorUp (p ); break; //VT100 |
|
case TY_CSI_PN('B' ) : scr->cursorDown (p ); break; //VT100 |
|
case TY_CSI_PN('C' ) : scr->cursorRight (p ); break; //VT100 |
|
case TY_CSI_PN('D' ) : scr->cursorLeft (p ); break; //VT100 |
|
case TY_CSI_PN('G' ) : scr->setCursorX (p ); break; //LINUX |
|
case TY_CSI_PN('H' ) : scr->setCursorYX (p, q); break; //VT100 |
|
case TY_CSI_PN('L' ) : scr->insertLines (p ); break; |
|
case TY_CSI_PN('M' ) : scr->deleteLines (p ); break; |
|
case TY_CSI_PN('P' ) : scr->deleteChars (p ); break; |
|
case TY_CSI_PN('X' ) : scr->eraseChars (p ); break; |
|
case TY_CSI_PN('c' ) : reportTerminalType ( ); break; //VT100 |
|
case TY_CSI_PN('d' ) : scr->setCursorY (p ); break; //LINUX |
|
case TY_CSI_PN('f' ) : scr->setCursorYX (p, q); break; //VT100 |
|
case TY_CSI_PN('r' ) : scr->setMargins (p, q); break; //VT100 |
|
case TY_CSI_PN('y' ) : /* IGNORED: Confidence test */ break; //VT100 |
|
|
|
//FIXME: experimental, evtl. we can shrink this a little. (hlsr as parm?) |
|
case TY_CSI_PR('h', 1) : setMode (MODE_AppCuKeys); break; //VT100 |
|
case TY_CSI_PR('l', 1) : resetMode (MODE_AppCuKeys); break; //VT100 |
|
case TY_CSI_PR('s', 1) : saveMode (MODE_AppCuKeys); break; //FIXME |
|
case TY_CSI_PR('r', 1) : restoreMode (MODE_AppCuKeys); break; //FIXME |
|
case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100 |
|
case TY_CSI_PR('h', 3) : setColumns ( 132); break; //VT100 |
|
case TY_CSI_PR('l', 3) : setColumns ( 80); break; //VT100 |
|
case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100 |
|
case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100 |
|
case TY_CSI_PR('h', 5) : scr-> setMode (MODE_Screen ); break; //VT100 |
|
case TY_CSI_PR('l', 5) : scr-> resetMode (MODE_Screen ); break; //VT100 |
|
case TY_CSI_PR('h', 6) : scr-> setMode (MODE_Origin ); break; //VT100 |
|
case TY_CSI_PR('l', 6) : scr-> resetMode (MODE_Origin ); break; //VT100 |
|
case TY_CSI_PR('s', 6) : scr-> saveMode (MODE_Origin ); break; //FIXME |
|
case TY_CSI_PR('r', 6) : scr->restoreMode (MODE_Origin ); break; //FIXME |
|
case TY_CSI_PR('h', 7) : scr-> setMode (MODE_Wrap ); break; //VT100 |
|
case TY_CSI_PR('l', 7) : scr-> resetMode (MODE_Wrap ); break; //VT100 |
|
case TY_CSI_PR('s', 7) : scr-> saveMode (MODE_Wrap ); break; //FIXME |
|
case TY_CSI_PR('r', 7) : scr->restoreMode (MODE_Wrap ); break; //FIXME |
|
case TY_CSI_PR('h', 8) : /* IGNORED: autorepeat on */ break; //VT100 |
|
case TY_CSI_PR('l', 8) : /* IGNORED: autorepeat off */ break; //VT100 |
|
case TY_CSI_PR('h', 9) : /* IGNORED: interlace */ break; //VT100 |
|
case TY_CSI_PR('l', 9) : /* IGNORED: interlace */ break; //VT100 |
|
case TY_CSI_PR('h', 25) : setMode (MODE_Cursor ); break; //VT100 |
|
case TY_CSI_PR('l', 25) : resetMode (MODE_Cursor ); break; //VT100 |
|
case TY_CSI_PR('h', 47) : setMode (MODE_AppScreen); break; //VT100 |
|
case TY_CSI_PR('l', 47) : resetMode (MODE_AppScreen); break; //VT100 |
|
case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM |
|
case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM |
|
case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM |
|
case TY_CSI_PR('r', 1000) : restoreMode (MODE_Mouse1000); break; //XTERM |
|
case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM |
|
case TY_CSI_PR('l', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM |
|
case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM |
|
case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM |
|
case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM |
|
case TY_CSI_PR('l', 1047) : resetMode (MODE_AppScreen); break; //XTERM |
|
case TY_CSI_PR('h', 1048) : scr->saveCursor ( ); break; //XTERM |
|
case TY_CSI_PR('l', 1048) : scr->restoreCursor ( ); break; //XTERM |
|
|
|
//FIXME: when changing between vt52 and ansi mode evtl do some resetting. |
|
case TY_VT52__('A' ) : scr->cursorUp ( 1); break; //VT52 |
|
case TY_VT52__('B' ) : scr->cursorDown ( 1); break; //VT52 |
|
case TY_VT52__('C' ) : scr->cursorRight ( 1); break; //VT52 |
|
case TY_VT52__('D' ) : scr->cursorLeft ( 1); break; //VT52 |
|
case TY_VT52__('F' ) : scr->setAndUseCharset (0, '0'); break; //VT52 |
|
case TY_VT52__('G' ) : scr->setAndUseCharset (0, 'B'); break; //VT52 |
|
case TY_VT52__('H' ) : scr->setCursorYX (1,1 ); break; //VT52 |
|
case TY_VT52__('I' ) : scr->reverseIndex ( ); break; //VT52 |
|
case TY_VT52__('J' ) : scr->clearToEndOfScreen ( ); break; //VT52 |
|
case TY_VT52__('K' ) : scr->clearToEndOfLine ( ); break; //VT52 |
|
case TY_VT52__('Y' ) : scr->setCursorYX (p-31,q-31 ); break; //VT52 |
|
case TY_VT52__('Z' ) : reportTerminalType ( ); break; //VT52 |
|
case TY_VT52__('<' ) : setMode (MODE_Ansi ); break; //VT52 |
|
case TY_VT52__('=' ) : setMode (MODE_AppKeyPad); break; //VT52 |
|
case TY_VT52__('>' ) : resetMode (MODE_AppKeyPad); break; //VT52 |
|
|
|
default : ReportErrorToken(); break; |
|
}; |
|
} |
|
|
|
// ----------------------------------------------------------------------------- |
|
// |
|
// Scanner / Transducer |
|
// |
|
// ----------------------------------------------------------------------------- |
|
|
|
//FIXME: evtl. we have to straiten the scanner a bit. |
|
|
|
// Scanning ------------------------------------------------------------------- |
|
|
|
void VT102Emulation::reset() |
|
{ |
|
ppos = 0; argc = 0; argv[0] = 0; argv[1] = 0; |
|
} |
|
|
|
#define CTL 1 |
|
#define CHR 2 |
|
#define CPN 4 |
|
#define DIG 8 |
|
#define SCS 16 |
|
#define GRP 32 |
|
|
|
void VT102Emulation::tableInit() |
|
{ int i; UINT8* s; |
|
for(i = 0; i < 256; i++) tbl[ i] = 0; |
|
for(i = 0; i < 32; i++) tbl[ i] |= CTL; |
|
for(i = 32; i < 256; i++) tbl[ i] |= CHR; |
|
for(s = (UINT8*)"@ABCDGHLMPXcdfry"; *s; s++) tbl[*s] |= CPN; |
|
for(s = (UINT8*)"0123456789" ; *s; s++) tbl[*s] |= DIG; |
|
for(s = (UINT8*)"()+*" ; *s; s++) tbl[*s] |= SCS; |
|
for(s = (UINT8*)"()+*#[]" ; *s; s++) tbl[*s] |= GRP; |
|
} |
|
|
|
/* Ok, here comes the nasty part of the decoder. |
|
|
|
The following defines do not abstract nor explain anything, |
|
they are only introduced to shorten the lines in the following |
|
routine, which is their only application. |
|
|
|
- P is the length of the token scanned so far. |
|
- L (often P-1) is the position on which contents we base a decision. |
|
- C is a character or a group of characters (taken from 'tbl'). |
|
*/ |
|
|
|
#define lec(P,L,C) (p == (P) && s[(L)] == (C)) |
|
#define les(P,L,C) (p == (P) && (tbl[s[(L)]] & (C)) == (C)) |
|
#define eec(C) (p >= 3 && cc == (C)) |
|
#define ees(C) (p >= 3 && (tbl[ cc ] & (C)) == (C)) |
|
#define eps(C) (p >= 3 && s[2] != '?' && (tbl[ cc ] & (C)) == (C)) |
|
#define epp( ) (p >= 3 && s[2] == '?' ) |
|
#define Xpe (ppos>=2 && pbuf[1] == ']' ) |
|
#define Xte (Xpe && cc == 7 ) |
|
#define ces(C) ( (tbl[ cc ] & (C)) == (C) && !Xte) |
|
#define Dig a[n] = 10*a[n] + cc - '0'; |
|
#define Arg argc = MIN(argc+1,MAXARGS-1); argv[argc] = 0; |
|
|
|
//FIXME: introduce real states. |
|
// |
|
// |
|
|
|
void VT102Emulation::onRcvByte(int c) |
|
{ unsigned char cc = c; int i; |
|
if (cc == 127) return; //VT100: ignore. |
|
|
|
if (ces( CTL)) |
|
{ |
|
if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) reset(); //VT100: CAN or SUB |
|
if (cc != ESC) { tau( TY_CTL___(cc ), 0, 0); return; } |
|
} |
|
pbuf[ppos] = cc; ppos = MIN(ppos+1,MAXPBUF-1); |
|
unsigned char* s = pbuf; |
|
int p = ppos; |
|
int * a = argv; |
|
int n = argc; |
|
if (getMode(MODE_Ansi)) |
|
{ |
|
if (lec(1,0,ESC)) { return; } |
|
if (les(2,1,GRP)) { return; } |
|
if (Xte ) { XtermHack(); reset(); return; } |
|
if (Xpe ) { return; } |
|
if (lec(3,2,'?')) { return; } |
|
if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); reset(); return; } |
|
if (lec(2,0,ESC)) { tau( TY_ESC___(s[1] ), 0, 0); reset(); return; } |
|
if (les(3,1,SCS)) { tau( TY_ESC_CS( ), s[1],s[2]); reset(); return; } |
|
if (lec(3,1,'#')) { tau( TY_ESC_DE(s[2] ), 0, 0); reset(); return; } |
|
if (eps( CPN)) { tau( TY_CSI_PN(cc ), a[0],a[1]); reset(); return; } |
|
if (ees( DIG)) { Dig return; } |
|
if (eec( ';')) { Arg return; } |
|
for (i=0;i<=n;i++) |
|
if (epp( )) tau( TY_CSI_PR(cc,a[i]), 0, 0); else |
|
tau( TY_CSI_PS(cc,a[i]), 0, 0); |
|
reset(); |
|
} |
|
else // mode VT52 |
|
{ |
|
if (lec(1,0,ESC)) return; |
|
if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); reset(); return; } |
|
if (lec(2,1,'Y')) return; |
|
if (lec(3,1,'Y')) return; |
|
if (p < 4) { tau( TY_VT52__(s[1] ), 0, 0); reset(); return; } |
|
tau( TY_VT52__(s[1] ), s[2],s[3]); reset(); return; |
|
} |
|
} |
|
|
|
void VT102Emulation::XtermHack() |
|
{ int i,arg = 0; |
|
for (i = 2; i < ppos && '0'<=pbuf[i] && pbuf[i]<'9' ; i++) |
|
arg = 10*arg + (pbuf[i]-'0'); |
|
if (pbuf[i] != ';') { ReportErrorToken(); return; } |
|
char str[ppos-i-1]; |
|
strncpy(str,(char*)pbuf+i+1,ppos-i-2); |
|
str[ppos-i-2]='\0'; |
|
if (arg <= 2) emit changeTitle(arg,str); |
|
} |
|
|
|
/* ------------------------------------------------------------------------- */ |
|
/* */ |
|
/* Reporting */ |
|
/* */ |
|
/* ------------------------------------------------------------------------- */ |
|
|
|
/*! shows the contents of the scan buffer. |
|
|
|
This functions is used for diagnostics. It is called by \e ReportErrorToken |
|
to inform about strings that cannot be decoded or handled by the emulation. |
|
|
|
\sa ReportErrorToken |
|
*/ |
|
|
|
/*! |
|
*/ |
|
|
|
static void hexdump(char* s, int len) |
|
{ int i; |
|
for (i = 0; i < len; i++) |
|
{ |
|
if (s[i] == '\\') |
|
printf("\\\\"); |
|
else |
|
if ((s[i]&0xff) > 32) |
|
printf("%c",s[i]); |
|
else |
|
printf("\\%02x",s[i]&0xff); |
|
} |
|
} |
|
|
|
void VT102Emulation::scan_buffer_report() |
|
{ |
|
if (ppos == 0 || ppos == 1 && (pbuf[0] & 0xff) >= 32) return; |
|
printf("token: "); hexdump((char*)pbuf,ppos); printf("\n"); |
|
} |
|
|
|
/*! |
|
*/ |
|
|
|
void VT102Emulation::ReportErrorToken() |
|
{ |
|
printf("undecodable "); scan_buffer_report(); |
|
} |
|
|
|
void VT102Emulation::NotImplemented(char* text) |
|
{ |
|
printf("not implemented: %s.",text); scan_buffer_report(); |
|
} |
|
|
|
/*! |
|
*/ |
|
|
|
void VT102Emulation::sendString(const char* s) |
|
{ |
|
emit sndBlock(s,strlen(s)); |
|
} |
|
|
|
/*! |
|
*/ |
|
|
|
void VT102Emulation::reportTerminalType() |
|
{ |
|
//FIXME: should change? |
|
if (getMode(MODE_Ansi)) |
|
sendString("\033[?1;2c"); // I'm a VT100 with AP0 |
|
else |
|
sendString("\033/Z"); // I'm a VT52 |
|
} |
|
|
|
/*! |
|
*/ |
|
|
|
void VT102Emulation::reportStatus() |
|
{ |
|
sendString("\033[0n"); //VT100. Device status report. 0 = Ready. |
|
} |
|
|
|
/*! |
|
*/ |
|
|
|
void VT102Emulation::reportAnswerBack() |
|
{ |
|
sendString("konsole"); //FIXME? make configurable? |
|
} |
|
|
|
/*! |
|
*/ |
|
|
|
void VT102Emulation::reportCursorPosition() |
|
{ char tmp[20]; |
|
sprintf(tmp,"\033[%d;%dR",scr->getCursorY()+1,scr->getCursorX()+1); |
|
sendString(tmp); |
|
} |
|
|
|
/*! |
|
`x',`y' are 1-based. |
|
`ev' (event) indicates the button pressed (0-2) |
|
or a general mouse release (3). |
|
*/ |
|
|
|
void VT102Emulation::reportMouseEvent(int ev, int x, int y) |
|
{ char tmp[20]; |
|
sprintf(tmp,"\033[M%c%c%c",ev+040,x+040,y+040); |
|
sendString(tmp); |
|
} |
|
|
|
void VT102Emulation::reportTerminalParms(int p) |
|
// DECREPTPARM |
|
{ char tmp[100]; |
|
sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true. |
|
sendString(tmp); |
|
} |
|
|
|
/* ------------------------------------------------------------------------- */ |
|
/* */ |
|
/* Mode Operations */ |
|
/* */ |
|
/* ------------------------------------------------------------------------- */ |
|
|
|
// NOTE: experimental section. |
|
// This is due to the fact that modes have to be handled both on |
|
// emulation and screen level. Dought that we can clean this up. |
|
|
|
void VT102Emulation::setMode(int m) |
|
{ |
|
currParm.mode[m] = TRUE; |
|
switch (m) |
|
{ |
|
case MODE_Mouse1000 : gui->setMouseMarks(FALSE); |
|
break; |
|
case MODE_AppScreen : screen[1]->clearSelection(); |
|
screen[1]->clearEntireScreen(); |
|
setScreen(1); |
|
break; |
|
} |
|
if (m < MODES_SCREEN || m == MODE_NewLine) |
|
{ |
|
screen[0]->setMode(m); |
|
screen[1]->setMode(m); |
|
} |
|
} |
|
|
|
void VT102Emulation::resetMode(int m) |
|
{ |
|
currParm.mode[m] = FALSE; |
|
switch (m) |
|
{ |
|
case MODE_Mouse1000 : gui->setMouseMarks(TRUE); |
|
break; |
|
case MODE_AppScreen : screen[0]->clearSelection(); |
|
setScreen(0); |
|
break; |
|
} |
|
if (m < MODES_SCREEN || m == MODE_NewLine) |
|
{ |
|
screen[0]->resetMode(m); |
|
screen[1]->resetMode(m); |
|
} |
|
} |
|
|
|
void VT102Emulation::saveMode(int m) |
|
{ |
|
saveParm.mode[m] = currParm.mode[m]; |
|
} |
|
|
|
void VT102Emulation::restoreMode(int m) |
|
{ |
|
if(saveParm.mode[m]) setMode(m); else resetMode(m); |
|
} |
|
|
|
//NOTE: this is a helper function |
|
BOOL VT102Emulation::getMode(int m) |
|
{ |
|
return currParm.mode[m]; |
|
} |
|
|
|
void VT102Emulation::setConnect(bool c) |
|
{ |
|
Emulation::setConnect(c); |
|
if (c) |
|
{ // refresh mouse mode |
|
if (getMode(MODE_Mouse1000)) |
|
setMode(MODE_Mouse1000); |
|
else |
|
resetMode(MODE_Mouse1000); |
|
} |
|
} |
|
|
|
void VT102Emulation::setCharset(int n, int cs) |
|
{ |
|
screen[0]->setCharset(n, cs); |
|
screen[1]->setCharset(n, cs); |
|
} |
|
|
|
/* ------------------------------------------------------------------------- */ |
|
/* */ |
|
/* Miscelaneous */ |
|
/* */ |
|
/* ------------------------------------------------------------------------- */ |
|
|
|
/*! change between primary and alternate screen |
|
*/ |
|
|
|
void VT102Emulation::setScreen(int n) |
|
{ |
|
scr = screen[n&1]; |
|
} |
|
|
|
/* ------------------------------------------------------------------------- */ |
|
/* */ |
|
/* Mouse Handling */ |
|
/* */ |
|
/* ------------------------------------------------------------------------- */ |
|
|
|
void VT102Emulation::onMouse( int cb, int cx, int cy ) |
|
{ |
|
if (!connected) return; |
|
reportMouseEvent(cb,cx,cy); |
|
} |
|
|
|
/* ------------------------------------------------------------------------- */ |
|
/* */ |
|
/* Keyboard Handling */ |
|
/* */ |
|
/* ------------------------------------------------------------------------- */ |
|
|
|
#define KeyComb(B,K) ((ev->state() & (B)) == (B) && ev->key() == (K)) |
|
|
|
#define Xterm (!strcmp(emulation.data(),"xterm")) |
|
/*! |
|
*/ |
|
|
|
void VT102Emulation::onKeyPress( QKeyEvent* ev ) |
|
{ int key; |
|
|
|
if (!connected) return; // someone else gets the keys |
|
|
|
// revert to non-history when typing |
|
if (scr->getHistCursor() != scr->getHistLines()); |
|
scr->setHistCursor(scr->getHistLines()); |
|
|
|
// Note: there 3 ways in rxvt to handle the Meta (Alt) key |
|
// 1) ignore it |
|
// 2) preceed the keycode by ESC (what we do here) |
|
// 3) set the 8th bit of each char in string |
|
// (which may fail for 8bit (european) characters. |
|
if (ev->state() & AltButton) sendString("\033"); // ESC |
|
|
|
//printf("State/Key: 0x%04x 0x%04x\n",ev->state(),ev->key()); |
|
|
|
key = ev->key(); |
|
switch (key) |
|
{ |
|
case Key_Return : sendString(getMode(MODE_NewLine)?"\r\n" :"\r" ); return; |
|
case Key_Backspace : sendString(getMode(MODE_BsHack )?"\x7f" :"\x08"); return; |
|
case Key_Delete : sendString(getMode(MODE_BsHack )?"\033[3~":"\x7f"); return; |
|
|
|
case Key_Up : sendString(!getMode(MODE_Ansi)?"\033A":getMode(MODE_AppCuKeys)?"\033OA":"\033[A"); return; |
|
case Key_Down : sendString(!getMode(MODE_Ansi)?"\033B":getMode(MODE_AppCuKeys)?"\033OB":"\033[B"); return; |
|
case Key_Right : sendString(!getMode(MODE_Ansi)?"\033C":getMode(MODE_AppCuKeys)?"\033OC":"\033[C"); return; |
|
case Key_Left : sendString(!getMode(MODE_Ansi)?"\033D":getMode(MODE_AppCuKeys)?"\033OD":"\033[D"); return; |
|
|
|
// XTERM LINUX |
|
case Key_F1 : sendString(Xterm? "\033[11~": "\033[[A" ); return; |
|
case Key_F2 : sendString(Xterm? "\033[12~": "\033[[B" ); return; |
|
case Key_F3 : sendString(Xterm? "\033[13~": "\033[[C" ); return; |
|
case Key_F4 : sendString(Xterm? "\033[14~": "\033[[D" ); return; |
|
case Key_F5 : sendString(Xterm? "\033[15~": "\033[[E" ); return; |
|
case Key_F6 : sendString("\033[17~" ); return; |
|
case Key_F7 : sendString("\033[18~" ); return; |
|
case Key_F8 : sendString("\033[19~" ); return; |
|
case Key_F9 : sendString("\033[20~" ); return; |
|
case Key_F10 : sendString("\033[21~" ); return; |
|
case Key_F11 : sendString("\033[23~" ); return; |
|
case Key_F12 : sendString("\033[24~" ); return; |
|
|
|
case Key_Home : sendString("\033[H" ); return; |
|
case Key_End : sendString("\033[F" ); return; |
|
case Key_Prior : sendString("\033[5~" ); return; |
|
case Key_Next : sendString("\033[6~" ); return; |
|
case Key_Insert : sendString("\033[2~" ); return; |
|
//FIXME: get keypad somehow |
|
} |
|
if (KeyComb(ControlButton,Key_Space)) // ctrl-Space == ctrl-@ |
|
{ |
|
sndBlock("\x00",1); return; |
|
} |
|
if (KeyComb(ControlButton,Key_Print)) // ctrl-print == sys-req |
|
{ |
|
reportAnswerBack(); return; |
|
} |
|
if (ev->ascii()>0) |
|
{ unsigned char c[1]; |
|
c[0] = ev->ascii(); |
|
//printf("ansi key: "); hexdump(c,1); printf("\n"); |
|
emit sndBlock((char*)c,1); |
|
return; |
|
} |
|
}
|
|
|