summaryrefslogtreecommitdiff
path: root/core/apps/embeddedkonsole/TEmuVt102.cpp
Unidiff
Diffstat (limited to 'core/apps/embeddedkonsole/TEmuVt102.cpp') (more/less context) (show whitespace changes)
-rw-r--r--core/apps/embeddedkonsole/TEmuVt102.cpp991
1 files changed, 991 insertions, 0 deletions
diff --git a/core/apps/embeddedkonsole/TEmuVt102.cpp b/core/apps/embeddedkonsole/TEmuVt102.cpp
new file mode 100644
index 0000000..752c49f
--- a/dev/null
+++ b/core/apps/embeddedkonsole/TEmuVt102.cpp
@@ -0,0 +1,991 @@
1/* ------------------------------------------------------------------------- */
2/* */
3/* [TEmuVt102.C] VT102 Terminal Emulation */
4/* */
5/* ------------------------------------------------------------------------- */
6/* */
7/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */
8/* */
9/* This file is part of Konsole - an X terminal for KDE */
10/* */
11/* ------------------------------------------------------------------------- */
12 /* */
13/* Ported Konsole to Qt/Embedded */
14 /* */
15/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */
16 /* */
17/* -------------------------------------------------------------------------- */
18
19/*! \class TEmuVt102
20
21 \brief Actual Emulation for Konsole
22
23 \sa TEWidget \sa TEScreen
24*/
25
26#include "TEmuVt102.h"
27#include "TEWidget.h"
28#include "TEScreen.h"
29#include "keytrans.h"
30
31#include <stdio.h>
32#include <unistd.h>
33#include <qkeycode.h>
34#include <qtextcodec.h>
35
36
37/* VT102 Terminal Emulation
38
39 This class puts together the screens, the pty and the widget to a
40 complete terminal emulation. Beside combining it's componentes, it
41 handles the emulations's protocol.
42
43 This module consists of the following sections:
44
45 - Constructor/Destructor
46 - Incoming Bytes Event pipeline
47 - Outgoing Bytes
48 - Mouse Events
49 - Keyboard Events
50 - Modes and Charset State
51 - Diagnostics
52*/
53
54
55/* ------------------------------------------------------------------------- */
56/* */
57/* Constructor / Destructor */
58/* */
59/* ------------------------------------------------------------------------- */
60
61/*
62 Nothing really intesting happens here.
63*/
64
65/*!
66*/
67
68TEmuVt102::TEmuVt102(TEWidget* gui) : TEmulation(gui)
69{
70 QObject::connect(gui,SIGNAL(mouseSignal(int,int,int)),
71 this,SLOT(onMouse(int,int,int)));
72 initTokenizer();
73 reset();
74}
75
76/*!
77*/
78
79TEmuVt102::~TEmuVt102()
80{
81}
82
83/*!
84*/
85
86void TEmuVt102::reset()
87{
88 resetToken();
89 resetModes();
90 resetCharset(0); screen[0]->reset();
91 resetCharset(1); screen[0]->reset();
92 setCodec(0);
93 setKeytrans("linux.keytab");
94}
95
96/* ------------------------------------------------------------------------- */
97/* */
98/* Processing the incoming byte stream */
99/* */
100/* ------------------------------------------------------------------------- */
101
102/* Incoming Bytes Event pipeline
103
104 This section deals with decoding the incoming character stream.
105 Decoding means here, that the stream is first seperated into `tokens'
106 which are then mapped to a `meaning' provided as operations by the
107 `TEScreen' class or by the emulation class itself.
108
109 The pipeline proceeds as follows:
110
111 - Tokenizing the ESC codes (onRcvChar)
112 - VT100 code page translation of plain characters (applyCharset)
113 - Interpretation of ESC codes (tau)
114
115 The escape codes and their meaning are described in the
116 technical reference of this program.
117*/
118
119// Tokens ------------------------------------------------------------------ --
120
121/*
122 Since the tokens are the central notion if this section, we've put them
123 in front. They provide the syntactical elements used to represent the
124 terminals operations as byte sequences.
125
126 They are encodes here into a single machine word, so that we can later
127 switch over them easily. Depending on the token itself, additional
128 argument variables are filled with parameter values.
129
130 The tokens are defined below:
131
132 - CHR - Printable characters (32..255 but DEL (=127))
133 - CTL - Control characters (0..31 but ESC (= 27), DEL)
134 - ESC - Escape codes of the form <ESC><CHR but `[]()+*#'>
135 - ESC_DE - Escape codes of the form <ESC><any of `()+*#%'> C
136 - CSI_PN - Escape codes of the form <ESC>'[' {Pn} ';' {Pn} C
137 - CSI_PS - Escape codes of the form <ESC>'[' {Pn} ';' ... C
138 - CSI_PR - Escape codes of the form <ESC>'[' '?' {Pn} ';' ... C
139 - VT52 - VT52 escape codes
140 - <ESC><Chr>
141 - <ESC>'Y'{Pc}{Pc}
142 - XTE_HA - Xterm hacks <ESC>`]' {Pn} `;' {Text} <BEL>
143 note that this is handled differently
144
145 The last two forms allow list of arguments. Since the elements of
146 the lists are treated individually the same way, they are passed
147 as individual tokens to the interpretation. Further, because the
148 meaning of the parameters are names (althought represented as numbers),
149 they are includes within the token ('N').
150
151*/
152
153#define TY_CONSTR(T,A,N) ( ((((int)N) & 0xffff) << 16) | ((((int)A) & 0xff) << 8) | (((int)T) & 0xff) )
154
155#define TY_CHR___( ) TY_CONSTR(0,0,0)
156#define TY_CTL___(A ) TY_CONSTR(1,A,0)
157#define TY_ESC___(A ) TY_CONSTR(2,A,0)
158#define TY_ESC_CS(A,B) TY_CONSTR(3,A,B)
159#define TY_ESC_DE(A ) TY_CONSTR(4,A,0)
160#define TY_CSI_PS(A,N) TY_CONSTR(5,A,N)
161#define TY_CSI_PN(A ) TY_CONSTR(6,A,0)
162#define TY_CSI_PR(A,N) TY_CONSTR(7,A,N)
163
164#define TY_VT52__(A ) TY_CONSTR(8,A,0)
165
166// Tokenizer --------------------------------------------------------------- --
167
168/* The tokenizers state
169
170 The state is represented by the buffer (pbuf, ppos),
171 and accompanied by decoded arguments kept in (argv,argc).
172 Note that they are kept internal in the tokenizer.
173*/
174
175void TEmuVt102::resetToken()
176{
177 ppos = 0; argc = 0; argv[0] = 0; argv[1] = 0;
178}
179
180void TEmuVt102::addDigit(int dig)
181{
182 argv[argc] = 10*argv[argc] + dig;
183}
184
185void TEmuVt102::addArgument()
186{
187 argc = QMIN(argc+1,MAXARGS-1);
188 argv[argc] = 0;
189}
190
191void TEmuVt102::pushToToken(int cc)
192{
193 pbuf[ppos] = cc;
194 ppos = QMIN(ppos+1,MAXPBUF-1);
195}
196
197// Character Classes used while decoding
198
199#define CTL 1
200#define CHR 2
201#define CPN 4
202#define DIG 8
203#define SCS 16
204#define GRP 32
205
206void TEmuVt102::initTokenizer()
207{ int i; UINT8* s;
208 for(i = 0; i < 256; i++) tbl[ i] = 0;
209 for(i = 0; i < 32; i++) tbl[ i] |= CTL;
210 for(i = 32; i < 256; i++) tbl[ i] |= CHR;
211 for(s = (UINT8*)"@ABCDGHLMPXcdfry"; *s; s++) tbl[*s] |= CPN;
212 for(s = (UINT8*)"0123456789" ; *s; s++) tbl[*s] |= DIG;
213 for(s = (UINT8*)"()+*%" ; *s; s++) tbl[*s] |= SCS;
214 for(s = (UINT8*)"()+*#[]%" ; *s; s++) tbl[*s] |= GRP;
215 resetToken();
216}
217
218/* Ok, here comes the nasty part of the decoder.
219
220 Instead of keeping an explicit state, we deduce it from the
221 token scanned so far. It is then immediately combined with
222 the current character to form a scanning decision.
223
224 This is done by the following defines.
225
226 - P is the length of the token scanned so far.
227 - L (often P-1) is the position on which contents we base a decision.
228 - C is a character or a group of characters (taken from 'tbl').
229
230 Note that they need to applied in proper order.
231*/
232
233#define lec(P,L,C) (p == (P) && s[(L)] == (C))
234#define lun( ) (p == 1 && cc >= 32 )
235#define les(P,L,C) (p == (P) && s[L] < 256 && (tbl[s[(L)]] & (C)) == (C))
236#define eec(C) (p >= 3 && cc == (C))
237#define ees(C) (p >= 3 && cc < 256 && (tbl[ cc ] & (C)) == (C))
238#define eps(C) (p >= 3 && s[2] != '?' && cc < 256 && (tbl[ cc ] & (C)) == (C))
239#define epp( ) (p >= 3 && s[2] == '?' )
240#define egt( ) (p == 3 && s[2] == '>' )
241#define Xpe (ppos>=2 && pbuf[1] == ']' )
242#define Xte (Xpe && cc == 7 )
243#define ces(C) ( cc < 256 && (tbl[ cc ] & (C)) == (C) && !Xte)
244
245#define ESC 27
246#define CNTL(c) ((c)-'@')
247
248// process an incoming unicode character
249
250void TEmuVt102::onRcvChar(int cc)
251{ int i;
252
253 if (cc == 127) return; //VT100: ignore.
254
255 if (ces( CTL))
256 { // DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100
257 // This means, they do neither a resetToken nor a pushToToken. Some of them, do
258 // of course. Guess this originates from a weakly layered handling of the X-on
259 // X-off protocol, which comes really below this level.
260 if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) resetToken(); //VT100: CAN or SUB
261 if (cc != ESC) { tau( TY_CTL___(cc+'@' ), 0, 0); return; }
262 }
263
264 pushToToken(cc); // advance the state
265
266 int* s = pbuf;
267 int p = ppos;
268
269 if (getMode(MODE_Ansi)) // decide on proper action
270 {
271 if (lec(1,0,ESC)) { return; }
272 if (les(2,1,GRP)) { return; }
273 if (Xte ) { XtermHack(); resetToken(); return; }
274 if (Xpe ) { return; }
275 if (lec(3,2,'?')) { return; }
276 if (lec(3,2,'>')) { return; }
277 if (lun( )) { tau( TY_CHR___(), applyCharset(cc), 0); resetToken(); return; }
278 if (lec(2,0,ESC)) { tau( TY_ESC___(s[1]), 0, 0); resetToken(); return; }
279 if (les(3,1,SCS)) { tau( TY_ESC_CS(s[1],s[2]), 0, 0); resetToken(); return; }
280 if (lec(3,1,'#')) { tau( TY_ESC_DE(s[2]), 0, 0); resetToken(); return; }
281// if (egt( )) { tau( TY_CSI_PG(cc ), '>', 0); resetToken(); return; }
282 if (eps( CPN)) { tau( TY_CSI_PN(cc), argv[0],argv[1]); resetToken(); return; }
283 if (ees( DIG)) { addDigit(cc-'0'); return; }
284 if (eec( ';')) { addArgument(); return; }
285 for (i=0;i<=argc;i++)
286 if (epp( )) tau( TY_CSI_PR(cc,argv[i]), 0, 0); else
287 tau( TY_CSI_PS(cc,argv[i]), 0, 0);
288 resetToken();
289 }
290 else // mode VT52
291 {
292 if (lec(1,0,ESC)) return;
293 if (les(1,0,CHR)) { tau( TY_CHR___( ), s[0], 0); resetToken(); return; }
294 if (lec(2,1,'Y')) return;
295 if (lec(3,1,'Y')) return;
296 if (p < 4) { tau( TY_VT52__(s[1] ), 0, 0); resetToken(); return; }
297 tau( TY_VT52__(s[1] ), s[2],s[3]); resetToken(); return;
298 }
299}
300
301void TEmuVt102::XtermHack()
302{ int i,arg = 0;
303 for (i = 2; i < ppos && '0'<=pbuf[i] && pbuf[i]<'9' ; i++)
304 arg = 10*arg + (pbuf[i]-'0');
305 if (pbuf[i] != ';') { ReportErrorToken(); return; }
306 QChar *str = new QChar[ppos-i-2];
307 for (int j = 0; j < ppos-i-2; j++) str[j] = pbuf[i+1+j];
308 QString unistr(str,ppos-i-2);
309 // arg == 1 doesn't change the title. In XTerm it only changes the icon name
310 // (btw: arg=0 changes title and icon, arg=1 only icon, arg=2 only title
311 if (arg == 0 || arg == 2) emit changeTitle(arg,unistr);
312 delete [] str;
313}
314
315// Interpreting Codes ---------------------------------------------------------
316
317/*
318 Now that the incoming character stream is properly tokenized,
319 meaning is assigned to them. These are either operations of
320 the current screen, or of the emulation class itself.
321
322 The token to be interpreteted comes in as a machine word
323 possibly accompanied by two parameters.
324
325 Likewise, the operations assigned to, come with up to two
326 arguments. One could consider to make up a proper table
327 from the function below.
328
329 The technical reference manual provides more informations
330 about this mapping.
331*/
332
333void TEmuVt102::tau( int token, int p, int q )
334{
335//scan_buffer_report();
336//if (token == TY_CHR___()) printf("%c",p); else
337//printf("tau(%d,%d,%d, %d,%d)\n",(token>>0)&0xff,(token>>8)&0xff,(token>>16)&0xffff,p,q);
338 switch (token)
339 {
340
341 case TY_CHR___( ) : scr->ShowCharacter (p ); break; //UTF16
342
343 // 127 DEL : ignored on input
344
345 case TY_CTL___('@' ) : /* NUL: ignored */ break;
346 case TY_CTL___('A' ) : /* SOH: ignored */ break;
347 case TY_CTL___('B' ) : /* STX: ignored */ break;
348 case TY_CTL___('C' ) : /* ETX: ignored */ break;
349 case TY_CTL___('D' ) : /* EOT: ignored */ break;
350 case TY_CTL___('E' ) : reportAnswerBack ( ); break; //VT100
351 case TY_CTL___('F' ) : /* ACK: ignored */ break;
352 case TY_CTL___('G' ) : gui->Bell ( ); break; //VT100
353 case TY_CTL___('H' ) : scr->BackSpace ( ); break; //VT100
354 case TY_CTL___('I' ) : scr->Tabulate ( ); break; //VT100
355 case TY_CTL___('J' ) : scr->NewLine ( ); break; //VT100
356 case TY_CTL___('K' ) : scr->NewLine ( ); break; //VT100
357 case TY_CTL___('L' ) : scr->NewLine ( ); break; //VT100
358 case TY_CTL___('M' ) : scr->Return ( ); break; //VT100
359
360 case TY_CTL___('N' ) : useCharset ( 1); break; //VT100
361 case TY_CTL___('O' ) : useCharset ( 0); break; //VT100
362
363 case TY_CTL___('P' ) : /* DLE: ignored */ break;
364 case TY_CTL___('Q' ) : /* DC1: XON continue */ break; //VT100
365 case TY_CTL___('R' ) : /* DC2: ignored */ break;
366 case TY_CTL___('S' ) : /* DC3: XOFF halt */ break; //VT100
367 case TY_CTL___('T' ) : /* DC4: ignored */ break;
368 case TY_CTL___('U' ) : /* NAK: ignored */ break;
369 case TY_CTL___('V' ) : /* SYN: ignored */ break;
370 case TY_CTL___('W' ) : /* ETB: ignored */ break;
371 case TY_CTL___('X' ) : scr->ShowCharacter ( 0x2592); break; //VT100
372 case TY_CTL___('Y' ) : /* EM : ignored */ break;
373 case TY_CTL___('Z' ) : scr->ShowCharacter ( 0x2592); break; //VT100
374 case TY_CTL___('[' ) : /* ESC: cannot be seen here. */ break;
375 case TY_CTL___('\\' ) : /* FS : ignored */ break;
376 case TY_CTL___(']' ) : /* GS : ignored */ break;
377 case TY_CTL___('^' ) : /* RS : ignored */ break;
378 case TY_CTL___('_' ) : /* US : ignored */ break;
379
380 case TY_ESC___('D' ) : scr->index ( ); break; //VT100
381 case TY_ESC___('E' ) : scr->NextLine ( ); break; //VT100
382 case TY_ESC___('H' ) : scr->changeTabStop (TRUE ); break; //VT100
383 case TY_ESC___('M' ) : scr->reverseIndex ( ); break; //VT100
384 case TY_ESC___('Z' ) : reportTerminalType ( ); break;
385 case TY_ESC___('c' ) : reset ( ); break;
386
387 case TY_ESC___('n' ) : useCharset ( 2); break;
388 case TY_ESC___('o' ) : useCharset ( 3); break;
389 case TY_ESC___('7' ) : saveCursor ( ); break;
390 case TY_ESC___('8' ) : restoreCursor ( ); break;
391
392 case TY_ESC___('=' ) : setMode (MODE_AppKeyPad); break;
393 case TY_ESC___('>' ) : resetMode (MODE_AppKeyPad); break;
394 case TY_ESC___('<' ) : setMode (MODE_Ansi ); break; //VT100
395
396 case TY_ESC_CS('(', '0') : setCharset (0, '0'); break; //VT100
397 case TY_ESC_CS('(', 'A') : setCharset (0, 'A'); break; //VT100
398 case TY_ESC_CS('(', 'B') : setCharset (0, 'B'); break; //VT100
399
400 case TY_ESC_CS(')', '0') : setCharset (1, '0'); break; //VT100
401 case TY_ESC_CS(')', 'A') : setCharset (1, 'A'); break; //VT100
402 case TY_ESC_CS(')', 'B') : setCharset (1, 'B'); break; //VT100
403
404 case TY_ESC_CS('*', '0') : setCharset (2, '0'); break; //VT100
405 case TY_ESC_CS('*', 'A') : setCharset (2, 'A'); break; //VT100
406 case TY_ESC_CS('*', 'B') : setCharset (2, 'B'); break; //VT100
407
408 case TY_ESC_CS('+', '0') : setCharset (3, '0'); break; //VT100
409 case TY_ESC_CS('+', 'A') : setCharset (3, 'A'); break; //VT100
410 case TY_ESC_CS('+', 'B') : setCharset (3, 'B'); break; //VT100
411
412 case TY_ESC_CS('%', 'G') : setCodec (1 ); break; //LINUX
413 case TY_ESC_CS('%', '@') : setCodec (0 ); break; //LINUX
414
415 case TY_ESC_DE('3' ) : /* IGNORED: double high, top half */ break;
416 case TY_ESC_DE('4' ) : /* IGNORED: double high, bottom half */ break;
417 case TY_ESC_DE('5' ) : /* IGNORED: single width, single high*/ break;
418 case TY_ESC_DE('6' ) : /* IGNORED: double width, single high*/ break;
419 case TY_ESC_DE('8' ) : scr->helpAlign ( ); break;
420
421 case TY_CSI_PS('K', 0) : scr->clearToEndOfLine ( ); break;
422 case TY_CSI_PS('K', 1) : scr->clearToBeginOfLine ( ); break;
423 case TY_CSI_PS('K', 2) : scr->clearEntireLine ( ); break;
424 case TY_CSI_PS('J', 0) : scr->clearToEndOfScreen ( ); break;
425 case TY_CSI_PS('J', 1) : scr->clearToBeginOfScreen ( ); break;
426 case TY_CSI_PS('J', 2) : scr->clearEntireScreen ( ); break;
427 case TY_CSI_PS('g', 0) : scr->changeTabStop (FALSE ); break; //VT100
428 case TY_CSI_PS('g', 3) : scr->clearTabStops ( ); break; //VT100
429 case TY_CSI_PS('h', 4) : scr-> setMode (MODE_Insert ); break;
430 case TY_CSI_PS('h', 20) : setMode (MODE_NewLine ); break;
431 case TY_CSI_PS('i', 0) : /* IGNORE: attached printer */ break; //VT100
432 case TY_CSI_PS('l', 4) : scr-> resetMode (MODE_Insert ); break;
433 case TY_CSI_PS('l', 20) : resetMode (MODE_NewLine ); break;
434
435 case TY_CSI_PS('m', 0) : scr->setDefaultRendition ( ); break;
436 case TY_CSI_PS('m', 1) : scr-> setRendition (RE_BOLD ); break; //VT100
437 case TY_CSI_PS('m', 4) : scr-> setRendition (RE_UNDERLINE); break; //VT100
438 case TY_CSI_PS('m', 5) : scr-> setRendition (RE_BLINK ); break; //VT100
439 case TY_CSI_PS('m', 7) : scr-> setRendition (RE_REVERSE ); break;
440 case TY_CSI_PS('m', 10) : /* IGNORED: mapping related */ break; //LINUX
441 case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX
442 case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX
443 case TY_CSI_PS('m', 22) : scr->resetRendition (RE_BOLD ); break;
444 case TY_CSI_PS('m', 24) : scr->resetRendition (RE_UNDERLINE); break;
445 case TY_CSI_PS('m', 25) : scr->resetRendition (RE_BLINK ); break;
446 case TY_CSI_PS('m', 27) : scr->resetRendition (RE_REVERSE ); break;
447
448 case TY_CSI_PS('m', 30) : scr->setForeColor ( 0); break;
449 case TY_CSI_PS('m', 31) : scr->setForeColor ( 1); break;
450 case TY_CSI_PS('m', 32) : scr->setForeColor ( 2); break;
451 case TY_CSI_PS('m', 33) : scr->setForeColor ( 3); break;
452 case TY_CSI_PS('m', 34) : scr->setForeColor ( 4); break;
453 case TY_CSI_PS('m', 35) : scr->setForeColor ( 5); break;
454 case TY_CSI_PS('m', 36) : scr->setForeColor ( 6); break;
455 case TY_CSI_PS('m', 37) : scr->setForeColor ( 7); break;
456 case TY_CSI_PS('m', 39) : scr->setForeColorToDefault( ); break;
457
458 case TY_CSI_PS('m', 40) : scr->setBackColor ( 0); break;
459 case TY_CSI_PS('m', 41) : scr->setBackColor ( 1); break;
460 case TY_CSI_PS('m', 42) : scr->setBackColor ( 2); break;
461 case TY_CSI_PS('m', 43) : scr->setBackColor ( 3); break;
462 case TY_CSI_PS('m', 44) : scr->setBackColor ( 4); break;
463 case TY_CSI_PS('m', 45) : scr->setBackColor ( 5); break;
464 case TY_CSI_PS('m', 46) : scr->setBackColor ( 6); break;
465 case TY_CSI_PS('m', 47) : scr->setBackColor ( 7); break;
466 case TY_CSI_PS('m', 49) : scr->setBackColorToDefault( ); break;
467
468 case TY_CSI_PS('m', 90) : scr->setForeColor ( 8); break;
469 case TY_CSI_PS('m', 91) : scr->setForeColor ( 9); break;
470 case TY_CSI_PS('m', 92) : scr->setForeColor ( 10); break;
471 case TY_CSI_PS('m', 93) : scr->setForeColor ( 11); break;
472 case TY_CSI_PS('m', 94) : scr->setForeColor ( 12); break;
473 case TY_CSI_PS('m', 95) : scr->setForeColor ( 13); break;
474 case TY_CSI_PS('m', 96) : scr->setForeColor ( 14); break;
475 case TY_CSI_PS('m', 97) : scr->setForeColor ( 15); break;
476
477 case TY_CSI_PS('m', 100) : scr->setBackColor ( 8); break;
478 case TY_CSI_PS('m', 101) : scr->setBackColor ( 9); break;
479 case TY_CSI_PS('m', 102) : scr->setBackColor ( 10); break;
480 case TY_CSI_PS('m', 103) : scr->setBackColor ( 11); break;
481 case TY_CSI_PS('m', 104) : scr->setBackColor ( 12); break;
482 case TY_CSI_PS('m', 105) : scr->setBackColor ( 13); break;
483 case TY_CSI_PS('m', 106) : scr->setBackColor ( 14); break;
484 case TY_CSI_PS('m', 107) : scr->setBackColor ( 15); break;
485
486 case TY_CSI_PS('n', 5) : reportStatus ( ); break;
487 case TY_CSI_PS('n', 6) : reportCursorPosition ( ); break;
488 case TY_CSI_PS('q', 0) : /* IGNORED: LEDs off */ break; //VT100
489 case TY_CSI_PS('q', 1) : /* IGNORED: LED1 on */ break; //VT100
490 case TY_CSI_PS('q', 2) : /* IGNORED: LED2 on */ break; //VT100
491 case TY_CSI_PS('q', 3) : /* IGNORED: LED3 on */ break; //VT100
492 case TY_CSI_PS('q', 4) : /* IGNORED: LED4 on */ break; //VT100
493 case TY_CSI_PS('x', 0) : reportTerminalParms ( 2); break; //VT100
494 case TY_CSI_PS('x', 1) : reportTerminalParms ( 3); break; //VT100
495
496 case TY_CSI_PN('@' ) : scr->insertChars (p ); break;
497 case TY_CSI_PN('A' ) : scr->cursorUp (p ); break; //VT100
498 case TY_CSI_PN('B' ) : scr->cursorDown (p ); break; //VT100
499 case TY_CSI_PN('C' ) : scr->cursorRight (p ); break; //VT100
500 case TY_CSI_PN('D' ) : scr->cursorLeft (p ); break; //VT100
501 case TY_CSI_PN('G' ) : scr->setCursorX (p ); break; //LINUX
502 case TY_CSI_PN('H' ) : scr->setCursorYX (p, q); break; //VT100
503 case TY_CSI_PN('L' ) : scr->insertLines (p ); break;
504 case TY_CSI_PN('M' ) : scr->deleteLines (p ); break;
505 case TY_CSI_PN('P' ) : scr->deleteChars (p ); break;
506 case TY_CSI_PN('X' ) : scr->eraseChars (p ); break;
507 case TY_CSI_PN('c' ) : reportTerminalType ( ); break; //VT100
508 case TY_CSI_PN('d' ) : scr->setCursorY (p ); break; //LINUX
509 case TY_CSI_PN('f' ) : scr->setCursorYX (p, q); break; //VT100
510 case TY_CSI_PN('r' ) : scr->setMargins (p, q); break; //VT100
511 case TY_CSI_PN('y' ) : /* IGNORED: Confidence test */ break; //VT100
512
513 case TY_CSI_PR('h', 1) : setMode (MODE_AppCuKeys); break; //VT100
514 case TY_CSI_PR('l', 1) : resetMode (MODE_AppCuKeys); break; //VT100
515 case TY_CSI_PR('s', 1) : saveMode (MODE_AppCuKeys); break; //FIXME
516 case TY_CSI_PR('r', 1) : restoreMode (MODE_AppCuKeys); break; //FIXME
517
518 case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100
519
520 case TY_CSI_PR('h', 3) : setColumns ( 132); break; //VT100
521 case TY_CSI_PR('l', 3) : setColumns ( 80); break; //VT100
522
523 case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100
524 case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100
525
526 case TY_CSI_PR('h', 5) : scr-> setMode (MODE_Screen ); break; //VT100
527 case TY_CSI_PR('l', 5) : scr-> resetMode (MODE_Screen ); break; //VT100
528
529 case TY_CSI_PR('h', 6) : scr-> setMode (MODE_Origin ); break; //VT100
530 case TY_CSI_PR('l', 6) : scr-> resetMode (MODE_Origin ); break; //VT100
531 case TY_CSI_PR('s', 6) : scr-> saveMode (MODE_Origin ); break; //FIXME
532 case TY_CSI_PR('r', 6) : scr->restoreMode (MODE_Origin ); break; //FIXME
533
534 case TY_CSI_PR('h', 7) : scr-> setMode (MODE_Wrap ); break; //VT100
535 case TY_CSI_PR('l', 7) : scr-> resetMode (MODE_Wrap ); break; //VT100
536 case TY_CSI_PR('s', 7) : scr-> saveMode (MODE_Wrap ); break; //FIXME
537 case TY_CSI_PR('r', 7) : scr->restoreMode (MODE_Wrap ); break; //FIXME
538
539 case TY_CSI_PR('h', 8) : /* IGNORED: autorepeat on */ break; //VT100
540 case TY_CSI_PR('l', 8) : /* IGNORED: autorepeat off */ break; //VT100
541
542 case TY_CSI_PR('h', 9) : /* IGNORED: interlace */ break; //VT100
543 case TY_CSI_PR('l', 9) : /* IGNORED: interlace */ break; //VT100
544
545 case TY_CSI_PR('h', 25) : setMode (MODE_Cursor ); break; //VT100
546 case TY_CSI_PR('l', 25) : resetMode (MODE_Cursor ); break; //VT100
547
548 case TY_CSI_PR('h', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM
549 case TY_CSI_PR('l', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM
550 case TY_CSI_PR('s', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM
551 case TY_CSI_PR('r', 41) : /* IGNORED: obsolete more(1) fix */ break; //XTERM
552
553 case TY_CSI_PR('h', 47) : setMode (MODE_AppScreen); break; //VT100
554 case TY_CSI_PR('l', 47) : resetMode (MODE_AppScreen); break; //VT100
555
556 case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM
557 case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM
558 case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM
559 case TY_CSI_PR('r', 1000) : restoreMode (MODE_Mouse1000); break; //XTERM
560
561 case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM
562 case TY_CSI_PR('l', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM
563 case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM
564 case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking */ break; //XTERM
565
566 case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM
567 case TY_CSI_PR('l', 1047) : resetMode (MODE_AppScreen); break; //XTERM
568
569 //FIXME: Unitoken: save translations
570 case TY_CSI_PR('h', 1048) : saveCursor ( ); break; //XTERM
571 case TY_CSI_PR('l', 1048) : restoreCursor ( ); break; //XTERM
572
573 //FIXME: every once new sequences like this pop up in xterm.
574 // Here's a guess of what they could mean.
575 case TY_CSI_PR('h', 1049) : setMode (MODE_AppScreen); break; //XTERM
576 case TY_CSI_PR('l', 1049) : resetMode (MODE_AppScreen); break; //XTERM
577
578 //FIXME: when changing between vt52 and ansi mode evtl do some resetting.
579 case TY_VT52__('A' ) : scr->cursorUp ( 1); break; //VT52
580 case TY_VT52__('B' ) : scr->cursorDown ( 1); break; //VT52
581 case TY_VT52__('C' ) : scr->cursorRight ( 1); break; //VT52
582 case TY_VT52__('D' ) : scr->cursorLeft ( 1); break; //VT52
583
584 case TY_VT52__('F' ) : setAndUseCharset (0, '0'); break; //VT52
585 case TY_VT52__('G' ) : setAndUseCharset (0, 'B'); break; //VT52
586
587 case TY_VT52__('H' ) : scr->setCursorYX (1,1 ); break; //VT52
588 case TY_VT52__('I' ) : scr->reverseIndex ( ); break; //VT52
589 case TY_VT52__('J' ) : scr->clearToEndOfScreen ( ); break; //VT52
590 case TY_VT52__('K' ) : scr->clearToEndOfLine ( ); break; //VT52
591 case TY_VT52__('Y' ) : scr->setCursorYX (p-31,q-31 ); break; //VT52
592 case TY_VT52__('Z' ) : reportTerminalType ( ); break; //VT52
593 case TY_VT52__('<' ) : setMode (MODE_Ansi ); break; //VT52
594 case TY_VT52__('=' ) : setMode (MODE_AppKeyPad); break; //VT52
595 case TY_VT52__('>' ) : resetMode (MODE_AppKeyPad); break; //VT52
596
597 default : ReportErrorToken(); break;
598 };
599}
600
601/* ------------------------------------------------------------------------- */
602/* */
603/* Terminal to Host protocol */
604/* */
605/* ------------------------------------------------------------------------- */
606
607/*
608 Outgoing bytes originate from several sources:
609
610 - Replies to Enquieries.
611 - Mouse Events
612 - Keyboard Events
613*/
614
615/*!
616*/
617
618void TEmuVt102::sendString(const char* s)
619{
620 emit sndBlock(s,strlen(s));
621}
622
623// Replies ----------------------------------------------------------------- --
624
625// This section copes with replies send as response to an enquiery control code.
626
627/*!
628*/
629
630void TEmuVt102::reportCursorPosition()
631{ char tmp[20];
632 sprintf(tmp,"\033[%d;%dR",scr->getCursorY()+1,scr->getCursorX()+1);
633 sendString(tmp);
634}
635
636/*
637 What follows here is rather obsolete and faked stuff.
638 The correspondent enquieries are neverthenless issued.
639*/
640
641/*!
642*/
643
644void TEmuVt102::reportTerminalType()
645{
646//FIXME: should change?
647 if (getMode(MODE_Ansi))
648// sendString("\033[?1;2c"); // I'm a VT100 with AP0 //FIXME: send only in response to ^[[0c
649 sendString("\033[>0;115;0c"); // I'm a VT220 //FIXME: send only in response to ^[[>c
650 else
651 sendString("\033/Z"); // I'm a VT52
652}
653
654void TEmuVt102::reportTerminalParms(int p)
655// DECREPTPARM
656{ char tmp[100];
657 sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true.
658 sendString(tmp);
659}
660
661/*!
662*/
663
664void TEmuVt102::reportStatus()
665{
666 sendString("\033[0n"); //VT100. Device status report. 0 = Ready.
667}
668
669/*!
670*/
671
672#define ANSWER_BACK "" // This is really obsolete VT100 stuff.
673
674void TEmuVt102::reportAnswerBack()
675{
676 sendString(ANSWER_BACK);
677}
678
679// Mouse Handling ---------------------------------------------------------- --
680
681/*!
682 Mouse clicks are possibly reported to the client
683 application if it has issued interest in them.
684 They are normally consumed by the widget for copy
685 and paste, but may be propagated from the widget
686 when gui->setMouseMarks is set via setMode(MODE_Mouse1000).
687
688 `x',`y' are 1-based.
689 `ev' (event) indicates the button pressed (0-2)
690 or a general mouse release (3).
691*/
692
693void TEmuVt102::onMouse( int cb, int cx, int cy )
694{ char tmp[20];
695 if (!connected) return;
696 sprintf(tmp,"\033[M%c%c%c",cb+040,cx+040,cy+040);
697 sendString(tmp);
698}
699
700// Keyboard Handling ------------------------------------------------------- --
701
702#define encodeMode(M,B) BITS(B,getMode(M))
703#define encodeStat(M,B) BITS(B,((ev->state() & (M)) == (M)))
704
705/*
706 Keyboard event handling has been simplified somewhat by pushing
707 the complications towards a configuration file [see KeyTrans class].
708*/
709
710void TEmuVt102::onKeyPress( QKeyEvent* ev )
711{
712 if (!connected) return; // someone else gets the keys
713
714//printf("State/Key: 0x%04x 0x%04x (%d,%d)\n",ev->state(),ev->key(),ev->text().length(),ev->text().length()?ev->text().ascii()[0]:0);
715
716 // revert to non-history when typing
717 if (scr->getHistCursor() != scr->getHistLines());
718 scr->setHistCursor(scr->getHistLines());
719
720 // lookup in keyboard translation table ...
721 int cmd; const char* txt; int len;
722 if (keytrans->findEntry(ev->key(), encodeMode(MODE_NewLine , BITS_NewLine ) + // OLD,
723 encodeMode(MODE_Ansi , BITS_Ansi ) + // OBSOLETE,
724 encodeMode(MODE_AppCuKeys, BITS_AppCuKeys ) + // VT100 stuff
725 encodeStat(ControlButton , BITS_Control ) +
726 encodeStat(ShiftButton , BITS_Shift ) +
727 encodeStat(AltButton , BITS_Alt ),
728 &cmd, &txt, &len ))
729//printf("cmd: %d, %s, %d\n",cmd,txt,len);
730 switch(cmd) // ... and execute if found.
731 {
732 case CMD_emitSelection : gui->emitSelection(); return;
733 case CMD_scrollPageUp : gui->doScroll(-gui->Lines()/2); return;
734 case CMD_scrollPageDown : gui->doScroll(+gui->Lines()/2); return;
735 case CMD_scrollLineUp : gui->doScroll(-1 ); return;
736 case CMD_scrollLineDown : gui->doScroll(+1 ); return;
737 case CMD_send : emit sndBlock(txt,len); return;
738 case CMD_prevSession : emit prevSession(); return;
739 case CMD_nextSession : emit nextSession(); return;
740 }
741
742 // fall back handling
743 if (!ev->text().isEmpty())
744 {
745 if (ev->state() & AltButton) sendString("\033"); // ESC, this is the ALT prefix
746 QCString s = codec->fromUnicode(ev->text()); // encode for application
747 emit sndBlock(s.data(),s.length()); // we may well have s.length() > 1
748 return;
749 }
750}
751
752/* ------------------------------------------------------------------------- */
753/* */
754/* VT100 Charsets */
755/* */
756/* ------------------------------------------------------------------------- */
757
758// Character Set Conversion ------------------------------------------------ --
759
760/*
761 The processing contains a VT100 specific code translation layer.
762 It's still in use and mainly responsible for the line drawing graphics.
763
764 These and some other glyphs are assigned to codes (0x5f-0xfe)
765 normally occupied by the latin letters. Since this codes also
766 appear within control sequences, the extra code conversion
767 does not permute with the tokenizer and is placed behind it
768 in the pipeline. It only applies to tokens, which represent
769 plain characters.
770
771 This conversion it eventually continued in TEWidget.C, since
772 it might involve VT100 enhanced fonts, which have these
773 particular glyphs allocated in (0x00-0x1f) in their code page.
774*/
775
776#define CHARSET charset[scr==screen[1]]
777
778// Apply current character map.
779
780unsigned short TEmuVt102::applyCharset(unsigned short c)
781{
782 if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f];
783 if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete
784 return c;
785}
786
787/*
788 "Charset" related part of the emulation state.
789 This configures the VT100 charset filter.
790
791 While most operation work on the current screen,
792 the following two are different.
793*/
794
795void TEmuVt102::resetCharset(int scrno)
796{
797 charset[scrno].cu_cs = 0;
798 strncpy(charset[scrno].charset,"BBBB",4);
799 charset[scrno].sa_graphic = FALSE;
800 charset[scrno].sa_pound = FALSE;
801 charset[scrno].graphic = FALSE;
802 charset[scrno].pound = FALSE;
803}
804
805/*!
806*/
807
808void TEmuVt102::setCharset(int n, int cs) // on both screens.
809{
810 charset[0].charset[n&3] = cs; useCharset(charset[0].cu_cs);
811 charset[1].charset[n&3] = cs; useCharset(charset[1].cu_cs);
812}
813
814/*!
815*/
816
817void TEmuVt102::setAndUseCharset(int n, int cs)
818{
819 CHARSET.charset[n&3] = cs;
820 useCharset(n&3);
821}
822
823/*!
824*/
825
826void TEmuVt102::useCharset(int n)
827{
828 CHARSET.cu_cs = n&3;
829 CHARSET.graphic = (CHARSET.charset[n&3] == '0');
830 CHARSET.pound = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete
831}
832
833/*! Save the cursor position and the rendition attribute settings. */
834
835void TEmuVt102::saveCursor()
836{
837 CHARSET.sa_graphic = CHARSET.graphic;
838 CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete
839 // we are not clear about these
840 //sa_charset = charsets[cScreen->charset];
841 //sa_charset_num = cScreen->charset;
842 scr->saveCursor();
843}
844
845/*! Restore the cursor position and the rendition attribute settings. */
846
847void TEmuVt102::restoreCursor()
848{
849 CHARSET.graphic = CHARSET.sa_graphic;
850 CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete
851 scr->restoreCursor();
852}
853
854/* ------------------------------------------------------------------------- */
855/* */
856/* Mode Operations */
857/* */
858/* ------------------------------------------------------------------------- */
859
860/*
861 Some of the emulations state is either added to the state of the screens.
862
863 This causes some scoping problems, since different emulations choose to
864 located the mode either to the current screen or to both.
865
866 For strange reasons, the extend of the rendition attributes ranges over
867 all screens and not over the actual screen.
868
869 We decided on the precise precise extend, somehow.
870*/
871
872// "Mode" related part of the state. These are all booleans.
873
874void TEmuVt102::resetModes()
875{
876 resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000);
877 resetMode(MODE_AppScreen); saveMode(MODE_AppScreen);
878 // here come obsolete modes
879 resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys);
880 resetMode(MODE_NewLine );
881 setMode(MODE_Ansi );
882}
883
884void TEmuVt102::setMode(int m)
885{
886 currParm.mode[m] = TRUE;
887 switch (m)
888 {
889 case MODE_Mouse1000 : gui->setMouseMarks(FALSE);
890 break;
891 case MODE_AppScreen : screen[1]->clearSelection();
892 screen[1]->clearEntireScreen();
893 setScreen(1);
894 break;
895 }
896 if (m < MODES_SCREEN || m == MODE_NewLine)
897 {
898 screen[0]->setMode(m);
899 screen[1]->setMode(m);
900 }
901}
902
903void TEmuVt102::resetMode(int m)
904{
905 currParm.mode[m] = FALSE;
906 switch (m)
907 {
908 case MODE_Mouse1000 : gui->setMouseMarks(TRUE);
909 break;
910 case MODE_AppScreen : screen[0]->clearSelection();
911 setScreen(0);
912 break;
913 }
914 if (m < MODES_SCREEN || m == MODE_NewLine)
915 {
916 screen[0]->resetMode(m);
917 screen[1]->resetMode(m);
918 }
919}
920
921void TEmuVt102::saveMode(int m)
922{
923 saveParm.mode[m] = currParm.mode[m];
924}
925
926void TEmuVt102::restoreMode(int m)
927{
928 if(saveParm.mode[m]) setMode(m); else resetMode(m);
929}
930
931BOOL TEmuVt102::getMode(int m)
932{
933 return currParm.mode[m];
934}
935
936void TEmuVt102::setConnect(bool c)
937{
938 TEmulation::setConnect(c);
939 if (c)
940 { // refresh mouse mode
941 if (getMode(MODE_Mouse1000))
942 setMode(MODE_Mouse1000);
943 else
944 resetMode(MODE_Mouse1000);
945 }
946}
947
948/* ------------------------------------------------------------------------- */
949/* */
950/* Diagnostic */
951/* */
952/* ------------------------------------------------------------------------- */
953
954/*! shows the contents of the scan buffer.
955
956 This functions is used for diagnostics. It is called by \e ReportErrorToken
957 to inform about strings that cannot be decoded or handled by the emulation.
958
959 \sa ReportErrorToken
960*/
961
962/*!
963*/
964
965static void hexdump(int* s, int len)
966{ int i;
967 for (i = 0; i < len; i++)
968 {
969 if (s[i] == '\\')
970 printf("\\\\");
971 else
972 if ((s[i]) > 32 && s[i] < 127)
973 printf("%c",s[i]);
974 else
975 printf("\\%04x(hex)",s[i]);
976 }
977}
978
979void TEmuVt102::scan_buffer_report()
980{
981 if (ppos == 0 || ppos == 1 && (pbuf[0] & 0xff) >= 32) return;
982 printf("token: "); hexdump(pbuf,ppos); printf("\n");
983}
984
985/*!
986*/
987
988void TEmuVt102::ReportErrorToken()
989{
990 printf("undecodable "); scan_buffer_report();
991}