1 /*
2     This file is part of Konsole, an X terminal.
3 
4     Copyright 2007-2008 by Robert Knight <robert.knight@gmail.com>
5     Copyright 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20     02110-1301  USA.
21 */
22 
23 // Own
24 #include "Vt102Emulation.h"
25 
26 // XKB
27 //#include <config-konsole.h>
28 
29 // this allows konsole to be compiled without XKB and XTEST extensions
30 // even though it might be available on a particular system.
31 #if defined(AVOID_XKB)
32     #undef HAVE_XKB
33 #endif
34 
35 #if defined(HAVE_XKB)
36     void scrolllock_set_off();
37     void scrolllock_set_on();
38 #endif
39 
40 // Standard
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <assert.h>
44 
45 // Qt
46 #include <QEvent>
47 #include <QKeyEvent>
48 #include <QByteRef>
49 
50 // KDE
51 //#include <kdebug.h>
52 //#include <klocale.h>
53 
54 // Konsole
55 #include "KeyboardTranslator.h"
56 #include "Screen.h"
57 
58 
59 using namespace Konsole;
60 
Vt102Emulation()61 Vt102Emulation::Vt102Emulation()
62     : Emulation(),
63      _titleUpdateTimer(new QTimer(this))
64 {
65   _titleUpdateTimer->setSingleShot(true);
66   QObject::connect(_titleUpdateTimer , &QTimer::timeout , this , &Vt102Emulation::updateTitle);
67 
68   initTokenizer();
69   reset();
70 }
71 
~Vt102Emulation()72 Vt102Emulation::~Vt102Emulation()
73 {}
74 
clearEntireScreen()75 void Vt102Emulation::clearEntireScreen()
76 {
77   _currentScreen->clearEntireScreen();
78   bufferedUpdate();
79 }
80 
reset()81 void Vt102Emulation::reset()
82 {
83   resetTokenizer();
84   resetModes();
85   resetCharset(0);
86   _screen[0]->reset();
87   resetCharset(1);
88   _screen[1]->reset();
89   setCodec(LocaleCodec);
90 
91   bufferedUpdate();
92 }
93 
94 /* ------------------------------------------------------------------------- */
95 /*                                                                           */
96 /*                     Processing the incoming byte stream                   */
97 /*                                                                           */
98 /* ------------------------------------------------------------------------- */
99 
100 /* Incoming Bytes Event pipeline
101 
102    This section deals with decoding the incoming character stream.
103    Decoding means here, that the stream is first separated into `tokens'
104    which are then mapped to a `meaning' provided as operations by the
105    `Screen' class or by the emulation class itself.
106 
107    The pipeline proceeds as follows:
108 
109    - Tokenizing the ESC codes (onReceiveChar)
110    - VT100 code page translation of plain characters (applyCharset)
111    - Interpretation of ESC codes (processToken)
112 
113    The escape codes and their meaning are described in the
114    technical reference of this program.
115 */
116 
117 // Tokens ------------------------------------------------------------------ --
118 
119 /*
120    Since the tokens are the central notion if this section, we've put them
121    in front. They provide the syntactical elements used to represent the
122    terminals operations as byte sequences.
123 
124    They are encodes here into a single machine word, so that we can later
125    switch over them easily. Depending on the token itself, additional
126    argument variables are filled with parameter values.
127 
128    The tokens are defined below:
129 
130    - CHR        - Printable characters     (32..255 but DEL (=127))
131    - CTL        - Control characters       (0..31 but ESC (= 27), DEL)
132    - ESC        - Escape codes of the form <ESC><CHR but `[]()+*#'>
133    - ESC_DE     - Escape codes of the form <ESC><any of `()+*#%'> C
134    - CSI_PN     - Escape codes of the form <ESC>'['     {Pn} ';' {Pn} C
135    - CSI_PS     - Escape codes of the form <ESC>'['     {Pn} ';' ...  C
136    - CSI_PR     - Escape codes of the form <ESC>'[' '?' {Pn} ';' ...  C
137    - CSI_PE     - Escape codes of the form <ESC>'[' '!' {Pn} ';' ...  C
138    - VT52       - VT52 escape codes
139                   - <ESC><Chr>
140                   - <ESC>'Y'{Pc}{Pc}
141    - XTE_HA     - Xterm window/terminal attribute commands
142                   of the form <ESC>`]' {Pn} `;' {Text} <BEL>
143                   (Note that these are handled differently to the other formats)
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_CONSTRUCT(T,A,N) ( (((static_cast<int>(N)) & 0xffff) << 16) | (((static_cast<int>(A)) & 0xff) << 8) | ((static_cast<int>(T)) & 0xff) )
154 
155 #define TY_CHR(   )     TY_CONSTRUCT(0,0,0)
156 #define TY_CTL(A  )     TY_CONSTRUCT(1,A,0)
157 #define TY_ESC(A  )     TY_CONSTRUCT(2,A,0)
158 #define TY_ESC_CS(A,B)  TY_CONSTRUCT(3,A,B)
159 #define TY_ESC_DE(A  )  TY_CONSTRUCT(4,A,0)
160 #define TY_CSI_PS(A,N)  TY_CONSTRUCT(5,A,N)
161 #define TY_CSI_PN(A  )  TY_CONSTRUCT(6,A,0)
162 #define TY_CSI_PR(A,N)  TY_CONSTRUCT(7,A,N)
163 
164 #define TY_VT52(A)    TY_CONSTRUCT(8,A,0)
165 #define TY_CSI_PG(A)  TY_CONSTRUCT(9,A,0)
166 #define TY_CSI_PE(A)  TY_CONSTRUCT(10,A,0)
167 
168 #define MAX_ARGUMENT 4096
169 
170 // Tokenizer --------------------------------------------------------------- --
171 
172 /* The tokenizer's state
173 
174    The state is represented by the buffer (tokenBuffer, tokenBufferPos),
175    and accompanied by decoded arguments kept in (argv,argc).
176    Note that they are kept internal in the tokenizer.
177 */
178 
resetTokenizer()179 void Vt102Emulation::resetTokenizer()
180 {
181   tokenBufferPos = 0;
182   argc = 0;
183   argv[0] = 0;
184   argv[1] = 0;
185 }
186 
addDigit(int digit)187 void Vt102Emulation::addDigit(int digit)
188 {
189   if (argv[argc] < MAX_ARGUMENT)
190       argv[argc] = 10*argv[argc] + digit;
191 }
192 
addArgument()193 void Vt102Emulation::addArgument()
194 {
195   argc = std::min(argc+1,MAXARGS-1);
196   argv[argc] = 0;
197 }
198 
addToCurrentToken(int cc)199 void Vt102Emulation::addToCurrentToken(int cc)
200 {
201   tokenBuffer[tokenBufferPos] = cc;
202   tokenBufferPos = std::min(tokenBufferPos+1,MAX_TOKEN_LENGTH-1);
203 }
204 
205 // Character Class flags used while decoding
206 
207 #define CTL  1  // Control character
208 #define CHR  2  // Printable character
209 #define CPN  4  // TODO: Document me
210 #define DIG  8  // Digit
211 #define SCS 16  // TODO: Document me
212 #define GRP 32  // TODO: Document me
213 #define CPS 64  // Character which indicates end of window resize
214                 // escape sequence '\e[8;<row>;<col>t'
215 
initTokenizer()216 void Vt102Emulation::initTokenizer()
217 {
218   int i;
219   quint8* s;
220   for(i = 0;i < 256; ++i)
221     charClass[i] = 0;
222   for(i = 0;i < 32; ++i)
223     charClass[i] |= CTL;
224   for(i = 32;i < 256; ++i)
225     charClass[i] |= CHR;
226   for(s = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; ++s)
227     charClass[*s] |= CPN;
228   // resize = \e[8;<row>;<col>t
229   for(s = (quint8*)"t"; *s; ++s)
230     charClass[*s] |= CPS;
231   for(s = (quint8*)"0123456789"; *s; ++s)
232     charClass[*s] |= DIG;
233   for(s = (quint8*)"()+*%"; *s; ++s)
234     charClass[*s] |= SCS;
235   for(s = (quint8*)"()+*#[]%"; *s; ++s)
236     charClass[*s] |= GRP;
237 
238   resetTokenizer();
239 }
240 
241 /* OK, here comes the nasty part of the decoder.
242 
243    Instead of keeping an explicit state, we deduce it from the
244    token scanned so far. It is then immediately combined with
245    the current character to form a scanning decision.
246 
247    This is done by the following defines.
248 
249    - P is the length of the token scanned so far.
250    - L (often P-1) is the position on which contents we base a decision.
251    - C is a character or a group of characters (taken from 'charClass').
252 
253    - 'cc' is the current character
254    - 's' is a pointer to the start of the token buffer
255    - 'p' is the current position within the token buffer
256 
257    Note that they need to applied in proper order.
258 */
259 
260 #define lec(P,L,C) (p == (P) && s[(L)] == (C))
261 #define lun(     ) (p ==  1  && cc >= 32 )
262 #define les(P,L,C) (p == (P) && s[L] < 256 && (charClass[s[(L)]] & (C)) == (C))
263 #define eec(C)     (p >=  3  && cc == (C))
264 #define ees(C)     (p >=  3  && cc < 256 && (charClass[cc] & (C)) == (C))
265 #define eps(C)     (p >=  3  && s[2] != '?' && s[2] != '!' && s[2] != '>' && cc < 256 && (charClass[cc] & (C)) == (C))
266 #define epp()     (p >=  3  && s[2] == '?')
267 #define epe()     (p >=  3  && s[2] == '!')
268 #define egt()     (p >=  3  && s[2] == '>')
269 #define Xpe        (tokenBufferPos >= 2 && tokenBuffer[1] == ']')
270 #define Xte        (Xpe      && cc ==  7 )
271 #define ces(C)     (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte)
272 
273 #define ESC 27
274 #define CNTL(c) ((c)-'@')
275 
276 // process an incoming unicode character
receiveChar(int cc)277 void Vt102Emulation::receiveChar(int cc)
278 {
279   if (cc == 127)
280     return; //VT100: ignore.
281 
282   if (ces(CTL))
283   {
284     // DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100
285     // This means, they do neither a resetTokenizer() nor a pushToToken(). Some of them, do
286     // of course. Guess this originates from a weakly layered handling of the X-on
287     // X-off protocol, which comes really below this level.
288     if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC)
289         resetTokenizer(); //VT100: CAN or SUB
290     if (cc != ESC)
291     {
292         processToken(TY_CTL(cc+'@' ),0,0);
293         return;
294     }
295   }
296   // advance the state
297   addToCurrentToken(cc);
298 
299   int* s = tokenBuffer;
300   int  p = tokenBufferPos;
301 
302   if (getMode(MODE_Ansi))
303   {
304     if (lec(1,0,ESC)) { return; }
305     if (lec(1,0,ESC+128)) { s[0] = ESC; receiveChar('['); return; }
306     if (les(2,1,GRP)) { return; }
307     if (Xte         ) { processWindowAttributeChange(); resetTokenizer(); return; }
308     if (Xpe         ) { return; }
309     if (lec(3,2,'?')) { return; }
310     if (lec(3,2,'>')) { return; }
311     if (lec(3,2,'!')) { return; }
312     if (lun(       )) { processToken( TY_CHR(), applyCharset(cc), 0);   resetTokenizer(); return; }
313     if (lec(2,0,ESC)) { processToken( TY_ESC(s[1]), 0, 0);              resetTokenizer(); return; }
314     if (les(3,1,SCS)) { processToken( TY_ESC_CS(s[1],s[2]), 0, 0);      resetTokenizer(); return; }
315     if (lec(3,1,'#')) { processToken( TY_ESC_DE(s[2]), 0, 0);           resetTokenizer(); return; }
316     if (eps(    CPN)) { processToken( TY_CSI_PN(cc), argv[0],argv[1]);  resetTokenizer(); return; }
317 
318     // resize = \e[8;<row>;<col>t
319     if (eps(CPS))
320     {
321         processToken( TY_CSI_PS(cc, argv[0]), argv[1], argv[2]);
322         resetTokenizer();
323         return;
324     }
325 
326     if (epe(   )) { processToken( TY_CSI_PE(cc), 0, 0); resetTokenizer(); return; }
327     if (ees(DIG)) { addDigit(cc-'0'); return; }
328     if (eec(';')) { addArgument();    return; }
329     for (int i=0;i<=argc;i++)
330     {
331         if (epp())
332             processToken( TY_CSI_PR(cc,argv[i]), 0, 0);
333         else if (egt())
334             processToken( TY_CSI_PG(cc), 0, 0); // spec. case for ESC]>0c or ESC]>c
335         else if (cc == 'm' && argc - i >= 4 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 2)
336         {
337             // ESC[ ... 48;2;<red>;<green>;<blue> ... m -or- ESC[ ... 38;2;<red>;<green>;<blue> ... m
338             i += 2;
339             processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]);
340             i += 2;
341         }
342         else if (cc == 'm' && argc - i >= 2 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 5)
343         {
344             // ESC[ ... 48;5;<index> ... m -or- ESC[ ... 38;5;<index> ... m
345             i += 2;
346             processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]);
347         }
348         else
349             processToken( TY_CSI_PS(cc,argv[i]), 0, 0);
350     }
351     resetTokenizer();
352   }
353   else
354   {
355     // VT52 Mode
356     if (lec(1,0,ESC))
357         return;
358     if (les(1,0,CHR))
359     {
360         processToken( TY_CHR(), s[0], 0);
361         resetTokenizer();
362         return;
363     }
364     if (lec(2,1,'Y'))
365         return;
366     if (lec(3,1,'Y'))
367         return;
368     if (p < 4)
369     {
370         processToken( TY_VT52(s[1] ), 0, 0);
371         resetTokenizer();
372         return;
373     }
374     processToken( TY_VT52(s[1]), s[2], s[3]);
375     resetTokenizer();
376     return;
377   }
378 }
processWindowAttributeChange()379 void Vt102Emulation::processWindowAttributeChange()
380 {
381   // Describes the window or terminal session attribute to change
382   // See Session::UserTitleChange for possible values
383   int attributeToChange = 0;
384   int i;
385   for (i = 2; i < tokenBufferPos     &&
386               tokenBuffer[i] >= '0'  &&
387               tokenBuffer[i] <= '9'; i++)
388   {
389     attributeToChange = 10 * attributeToChange + (tokenBuffer[i]-'0');
390   }
391 
392   if (tokenBuffer[i] != ';')
393   {
394     reportDecodingError();
395     return;
396   }
397 
398   QString newValue;
399   newValue.reserve(tokenBufferPos-i-2);
400   for (int j = 0; j < tokenBufferPos-i-2; j++)
401     newValue[j] = tokenBuffer[i+1+j];
402 
403   _pendingTitleUpdates[attributeToChange] = newValue;
404   _titleUpdateTimer->start(20);
405 }
406 
updateTitle()407 void Vt102Emulation::updateTitle()
408 {
409     QListIterator<int> iter( _pendingTitleUpdates.keys() );
410     while (iter.hasNext()) {
411         int arg = iter.next();
412         emit titleChanged( arg , _pendingTitleUpdates[arg] );
413     }
414     _pendingTitleUpdates.clear();
415 }
416 
417 // Interpreting Codes ---------------------------------------------------------
418 
419 /*
420    Now that the incoming character stream is properly tokenized,
421    meaning is assigned to them. These are either operations of
422    the current _screen, or of the emulation class itself.
423 
424    The token to be interpreteted comes in as a machine word
425    possibly accompanied by two parameters.
426 
427    Likewise, the operations assigned to, come with up to two
428    arguments. One could consider to make up a proper table
429    from the function below.
430 
431    The technical reference manual provides more information
432    about this mapping.
433 */
434 
processToken(int token,int p,int q)435 void Vt102Emulation::processToken(int token, int p, int q)
436 {
437   switch (token)
438   {
439 
440     case TY_CHR(         ) : _currentScreen->displayCharacter     (p         ); break; //UTF16
441 
442     //             127 DEL    : ignored on input
443 
444     case TY_CTL('@'      ) : /* NUL: ignored                      */ break;
445     case TY_CTL('A'      ) : /* SOH: ignored                      */ break;
446     case TY_CTL('B'      ) : /* STX: ignored                      */ break;
447     case TY_CTL('C'      ) : /* ETX: ignored                      */ break;
448     case TY_CTL('D'      ) : /* EOT: ignored                      */ break;
449     case TY_CTL('E'      ) :      reportAnswerBack     (          ); break; //VT100
450     case TY_CTL('F'      ) : /* ACK: ignored                      */ break;
451     case TY_CTL('G'      ) : emit stateSet(NOTIFYBELL);
452                                 break; //VT100
453     case TY_CTL('H'      ) : _currentScreen->backspace            (          ); break; //VT100
454     case TY_CTL('I'      ) : _currentScreen->tab                  (          ); break; //VT100
455     case TY_CTL('J'      ) : _currentScreen->newLine              (          ); break; //VT100
456     case TY_CTL('K'      ) : _currentScreen->newLine              (          ); break; //VT100
457     case TY_CTL('L'      ) : _currentScreen->newLine              (          ); break; //VT100
458     case TY_CTL('M'      ) : _currentScreen->toStartOfLine        (          ); break; //VT100
459 
460     case TY_CTL('N'      ) :      useCharset           (         1); break; //VT100
461     case TY_CTL('O'      ) :      useCharset           (         0); break; //VT100
462 
463     case TY_CTL('P'      ) : /* DLE: ignored                      */ break;
464     case TY_CTL('Q'      ) : /* DC1: XON continue                 */ break; //VT100
465     case TY_CTL('R'      ) : /* DC2: ignored                      */ break;
466     case TY_CTL('S'      ) : /* DC3: XOFF halt                    */ break; //VT100
467     case TY_CTL('T'      ) : /* DC4: ignored                      */ break;
468     case TY_CTL('U'      ) : /* NAK: ignored                      */ break;
469     case TY_CTL('V'      ) : /* SYN: ignored                      */ break;
470     case TY_CTL('W'      ) : /* ETB: ignored                      */ break;
471     case TY_CTL('X'      ) : _currentScreen->displayCharacter     (    0x2592); break; //VT100
472     case TY_CTL('Y'      ) : /* EM : ignored                      */ break;
473     case TY_CTL('Z'      ) : _currentScreen->displayCharacter     (    0x2592); break; //VT100
474     case TY_CTL('['      ) : /* ESC: cannot be seen here.         */ break;
475     case TY_CTL('\\'     ) : /* FS : ignored                      */ break;
476     case TY_CTL(']'      ) : /* GS : ignored                      */ break;
477     case TY_CTL('^'      ) : /* RS : ignored                      */ break;
478     case TY_CTL('_'      ) : /* US : ignored                      */ break;
479 
480     case TY_ESC('D'      ) : _currentScreen->index                (          ); break; //VT100
481     case TY_ESC('E'      ) : _currentScreen->nextLine             (          ); break; //VT100
482     case TY_ESC('H'      ) : _currentScreen->changeTabStop        (true      ); break; //VT100
483     case TY_ESC('M'      ) : _currentScreen->reverseIndex         (          ); break; //VT100
484     case TY_ESC('Z'      ) :      reportTerminalType   (          ); break;
485     case TY_ESC('c'      ) :      reset                (          ); break;
486 
487     case TY_ESC('n'      ) :      useCharset           (         2); break;
488     case TY_ESC('o'      ) :      useCharset           (         3); break;
489     case TY_ESC('7'      ) :      saveCursor           (          ); break;
490     case TY_ESC('8'      ) :      restoreCursor        (          ); break;
491 
492     case TY_ESC('='      ) :          setMode      (MODE_AppKeyPad); break;
493     case TY_ESC('>'      ) :        resetMode      (MODE_AppKeyPad); break;
494     case TY_ESC('<'      ) :          setMode      (MODE_Ansi     ); break; //VT100
495 
496     case TY_ESC_CS('(', '0') :      setCharset           (0,    '0'); break; //VT100
497     case TY_ESC_CS('(', 'A') :      setCharset           (0,    'A'); break; //VT100
498     case TY_ESC_CS('(', 'B') :      setCharset           (0,    'B'); break; //VT100
499 
500     case TY_ESC_CS(')', '0') :      setCharset           (1,    '0'); break; //VT100
501     case TY_ESC_CS(')', 'A') :      setCharset           (1,    'A'); break; //VT100
502     case TY_ESC_CS(')', 'B') :      setCharset           (1,    'B'); break; //VT100
503 
504     case TY_ESC_CS('*', '0') :      setCharset           (2,    '0'); break; //VT100
505     case TY_ESC_CS('*', 'A') :      setCharset           (2,    'A'); break; //VT100
506     case TY_ESC_CS('*', 'B') :      setCharset           (2,    'B'); break; //VT100
507 
508     case TY_ESC_CS('+', '0') :      setCharset           (3,    '0'); break; //VT100
509     case TY_ESC_CS('+', 'A') :      setCharset           (3,    'A'); break; //VT100
510     case TY_ESC_CS('+', 'B') :      setCharset           (3,    'B'); break; //VT100
511 
512     case TY_ESC_CS('%', 'G') :      setCodec             (Utf8Codec   ); break; //LINUX
513     case TY_ESC_CS('%', '@') :      setCodec             (LocaleCodec ); break; //LINUX
514 
515     case TY_ESC_DE('3'      ) : /* Double height line, top half    */
516                                 _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true );
517                                 _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , true );
518                                     break;
519     case TY_ESC_DE('4'      ) : /* Double height line, bottom half */
520                                 _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true );
521                                 _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , true );
522                                     break;
523     case TY_ESC_DE('5'      ) : /* Single width, single height line*/
524                                 _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , false);
525                                 _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , false);
526                                 break;
527     case TY_ESC_DE('6'      ) : /* Double width, single height line*/
528                                 _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true);
529                                 _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , false);
530                                 break;
531     case TY_ESC_DE('8'      ) : _currentScreen->helpAlign            (          ); break;
532 
533 // resize = \e[8;<row>;<col>t
534     case TY_CSI_PS('t',   8) : setImageSize( q /* columns */, p /* lines */ );    break;
535 
536 // change tab text color : \e[28;<color>t  color: 0-16,777,215
537     case TY_CSI_PS('t',   28) : emit changeTabTextColorRequest      ( p        );          break;
538 
539     case TY_CSI_PS('K',   0) : _currentScreen->clearToEndOfLine     (          ); break;
540     case TY_CSI_PS('K',   1) : _currentScreen->clearToBeginOfLine   (          ); break;
541     case TY_CSI_PS('K',   2) : _currentScreen->clearEntireLine      (          ); break;
542     case TY_CSI_PS('J',   0) : _currentScreen->clearToEndOfScreen   (          ); break;
543     case TY_CSI_PS('J',   1) : _currentScreen->clearToBeginOfScreen (          ); break;
544     case TY_CSI_PS('J',   2) : _currentScreen->clearEntireScreen    (          ); break;
545     case TY_CSI_PS('J',      3) : clearHistory();                            break;
546     case TY_CSI_PS('g',   0) : _currentScreen->changeTabStop        (false     ); break; //VT100
547     case TY_CSI_PS('g',   3) : _currentScreen->clearTabStops        (          ); break; //VT100
548     case TY_CSI_PS('h',   4) : _currentScreen->    setMode      (MODE_Insert   ); break;
549     case TY_CSI_PS('h',  20) :          setMode      (MODE_NewLine  ); break;
550     case TY_CSI_PS('i',   0) : /* IGNORE: attached printer          */ break; //VT100
551     case TY_CSI_PS('l',   4) : _currentScreen->  resetMode      (MODE_Insert   ); break;
552     case TY_CSI_PS('l',  20) :        resetMode      (MODE_NewLine  ); break;
553     case TY_CSI_PS('s',   0) :      saveCursor           (          ); break;
554     case TY_CSI_PS('u',   0) :      restoreCursor        (          ); break;
555 
556     case TY_CSI_PS('m',   0) : _currentScreen->setDefaultRendition  (          ); break;
557     case TY_CSI_PS('m',   1) : _currentScreen->  setRendition     (RE_BOLD     ); break; //VT100
558     case TY_CSI_PS('m',   4) : _currentScreen->  setRendition     (RE_UNDERLINE); break; //VT100
559     case TY_CSI_PS('m',   5) : _currentScreen->  setRendition     (RE_BLINK    ); break; //VT100
560     case TY_CSI_PS('m',   7) : _currentScreen->  setRendition     (RE_REVERSE  ); break;
561     case TY_CSI_PS('m',  10) : /* IGNORED: mapping related          */ break; //LINUX
562     case TY_CSI_PS('m',  11) : /* IGNORED: mapping related          */ break; //LINUX
563     case TY_CSI_PS('m',  12) : /* IGNORED: mapping related          */ break; //LINUX
564     case TY_CSI_PS('m',  22) : _currentScreen->resetRendition     (RE_BOLD     ); break;
565     case TY_CSI_PS('m',  24) : _currentScreen->resetRendition     (RE_UNDERLINE); break;
566     case TY_CSI_PS('m',  25) : _currentScreen->resetRendition     (RE_BLINK    ); break;
567     case TY_CSI_PS('m',  27) : _currentScreen->resetRendition     (RE_REVERSE  ); break;
568 
569     case TY_CSI_PS('m',   30) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  0); break;
570     case TY_CSI_PS('m',   31) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  1); break;
571     case TY_CSI_PS('m',   32) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  2); break;
572     case TY_CSI_PS('m',   33) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  3); break;
573     case TY_CSI_PS('m',   34) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  4); break;
574     case TY_CSI_PS('m',   35) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  5); break;
575     case TY_CSI_PS('m',   36) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  6); break;
576     case TY_CSI_PS('m',   37) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  7); break;
577 
578     case TY_CSI_PS('m',   38) : _currentScreen->setForeColor         (p,       q); break;
579 
580     case TY_CSI_PS('m',   39) : _currentScreen->setForeColor         (COLOR_SPACE_DEFAULT,  0); break;
581 
582     case TY_CSI_PS('m',   40) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  0); break;
583     case TY_CSI_PS('m',   41) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  1); break;
584     case TY_CSI_PS('m',   42) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  2); break;
585     case TY_CSI_PS('m',   43) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  3); break;
586     case TY_CSI_PS('m',   44) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  4); break;
587     case TY_CSI_PS('m',   45) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  5); break;
588     case TY_CSI_PS('m',   46) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  6); break;
589     case TY_CSI_PS('m',   47) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  7); break;
590 
591     case TY_CSI_PS('m',   48) : _currentScreen->setBackColor         (p,       q); break;
592 
593     case TY_CSI_PS('m',   49) : _currentScreen->setBackColor         (COLOR_SPACE_DEFAULT,  1); break;
594 
595     case TY_CSI_PS('m',   90) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  8); break;
596     case TY_CSI_PS('m',   91) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM,  9); break;
597     case TY_CSI_PS('m',   92) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 10); break;
598     case TY_CSI_PS('m',   93) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 11); break;
599     case TY_CSI_PS('m',   94) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 12); break;
600     case TY_CSI_PS('m',   95) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 13); break;
601     case TY_CSI_PS('m',   96) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 14); break;
602     case TY_CSI_PS('m',   97) : _currentScreen->setForeColor         (COLOR_SPACE_SYSTEM, 15); break;
603 
604     case TY_CSI_PS('m',  100) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  8); break;
605     case TY_CSI_PS('m',  101) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM,  9); break;
606     case TY_CSI_PS('m',  102) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 10); break;
607     case TY_CSI_PS('m',  103) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 11); break;
608     case TY_CSI_PS('m',  104) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 12); break;
609     case TY_CSI_PS('m',  105) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 13); break;
610     case TY_CSI_PS('m',  106) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 14); break;
611     case TY_CSI_PS('m',  107) : _currentScreen->setBackColor         (COLOR_SPACE_SYSTEM, 15); break;
612 
613     case TY_CSI_PS('n',   5) :      reportStatus         (          ); break;
614     case TY_CSI_PS('n',   6) :      reportCursorPosition (          ); break;
615     case TY_CSI_PS('q',   0) : /* IGNORED: LEDs off                 */ break; //VT100
616     case TY_CSI_PS('q',   1) : /* IGNORED: LED1 on                  */ break; //VT100
617     case TY_CSI_PS('q',   2) : /* IGNORED: LED2 on                  */ break; //VT100
618     case TY_CSI_PS('q',   3) : /* IGNORED: LED3 on                  */ break; //VT100
619     case TY_CSI_PS('q',   4) : /* IGNORED: LED4 on                  */ break; //VT100
620     case TY_CSI_PS('x',   0) :      reportTerminalParms  (         2); break; //VT100
621     case TY_CSI_PS('x',   1) :      reportTerminalParms  (         3); break; //VT100
622 
623     case TY_CSI_PN('@'      ) : _currentScreen->insertChars          (p         ); break;
624     case TY_CSI_PN('A'      ) : _currentScreen->cursorUp             (p         ); break; //VT100
625     case TY_CSI_PN('B'      ) : _currentScreen->cursorDown           (p         ); break; //VT100
626     case TY_CSI_PN('C'      ) : _currentScreen->cursorRight          (p         ); break; //VT100
627     case TY_CSI_PN('D'      ) : _currentScreen->cursorLeft           (p         ); break; //VT100
628     case TY_CSI_PN('G'      ) : _currentScreen->setCursorX           (p         ); break; //LINUX
629     case TY_CSI_PN('H'      ) : _currentScreen->setCursorYX          (p,      q); break; //VT100
630     case TY_CSI_PN('I'      ) : _currentScreen->tab                  (p         ); break;
631     case TY_CSI_PN('L'      ) : _currentScreen->insertLines          (p         ); break;
632     case TY_CSI_PN('M'      ) : _currentScreen->deleteLines          (p         ); break;
633     case TY_CSI_PN('P'      ) : _currentScreen->deleteChars          (p         ); break;
634     case TY_CSI_PN('S'      ) : _currentScreen->scrollUp             (p         ); break;
635     case TY_CSI_PN('T'      ) : _currentScreen->scrollDown           (p         ); break;
636     case TY_CSI_PN('X'      ) : _currentScreen->eraseChars           (p         ); break;
637     case TY_CSI_PN('Z'      ) : _currentScreen->backtab              (p         ); break;
638     case TY_CSI_PN('c'      ) :      reportTerminalType   (          ); break; //VT100
639     case TY_CSI_PN('d'      ) : _currentScreen->setCursorY           (p         ); break; //LINUX
640     case TY_CSI_PN('f'      ) : _currentScreen->setCursorYX          (p,      q); break; //VT100
641     case TY_CSI_PN('r'      ) :      setMargins           (p,      q); break; //VT100
642     case TY_CSI_PN('y'      ) : /* IGNORED: Confidence test          */ break; //VT100
643 
644     case TY_CSI_PR('h',   1) :          setMode      (MODE_AppCuKeys); break; //VT100
645     case TY_CSI_PR('l',   1) :        resetMode      (MODE_AppCuKeys); break; //VT100
646     case TY_CSI_PR('s',   1) :         saveMode      (MODE_AppCuKeys); break; //FIXME
647     case TY_CSI_PR('r',   1) :      restoreMode      (MODE_AppCuKeys); break; //FIXME
648 
649     case TY_CSI_PR('l',   2) :        resetMode      (MODE_Ansi     ); break; //VT100
650 
651     case TY_CSI_PR('h',   3) :          setMode      (MODE_132Columns);break; //VT100
652     case TY_CSI_PR('l',   3) :        resetMode      (MODE_132Columns);break; //VT100
653 
654     case TY_CSI_PR('h',   4) : /* IGNORED: soft scrolling           */ break; //VT100
655     case TY_CSI_PR('l',   4) : /* IGNORED: soft scrolling           */ break; //VT100
656 
657     case TY_CSI_PR('h',   5) : _currentScreen->    setMode      (MODE_Screen   ); break; //VT100
658     case TY_CSI_PR('l',   5) : _currentScreen->  resetMode      (MODE_Screen   ); break; //VT100
659 
660     case TY_CSI_PR('h',   6) : _currentScreen->    setMode      (MODE_Origin   ); break; //VT100
661     case TY_CSI_PR('l',   6) : _currentScreen->  resetMode      (MODE_Origin   ); break; //VT100
662     case TY_CSI_PR('s',   6) : _currentScreen->   saveMode      (MODE_Origin   ); break; //FIXME
663     case TY_CSI_PR('r',   6) : _currentScreen->restoreMode      (MODE_Origin   ); break; //FIXME
664 
665     case TY_CSI_PR('h',   7) : _currentScreen->    setMode      (MODE_Wrap     ); break; //VT100
666     case TY_CSI_PR('l',   7) : _currentScreen->  resetMode      (MODE_Wrap     ); break; //VT100
667     case TY_CSI_PR('s',   7) : _currentScreen->   saveMode      (MODE_Wrap     ); break; //FIXME
668     case TY_CSI_PR('r',   7) : _currentScreen->restoreMode      (MODE_Wrap     ); break; //FIXME
669 
670     case TY_CSI_PR('h',   8) : /* IGNORED: autorepeat on            */ break; //VT100
671     case TY_CSI_PR('l',   8) : /* IGNORED: autorepeat off           */ break; //VT100
672     case TY_CSI_PR('s',   8) : /* IGNORED: autorepeat on            */ break; //VT100
673     case TY_CSI_PR('r',   8) : /* IGNORED: autorepeat off           */ break; //VT100
674 
675     case TY_CSI_PR('h',   9) : /* IGNORED: interlace                */ break; //VT100
676     case TY_CSI_PR('l',   9) : /* IGNORED: interlace                */ break; //VT100
677     case TY_CSI_PR('s',   9) : /* IGNORED: interlace                */ break; //VT100
678     case TY_CSI_PR('r',   9) : /* IGNORED: interlace                */ break; //VT100
679 
680     case TY_CSI_PR('h',  12) : /* IGNORED: Cursor blink             */ break; //att610
681     case TY_CSI_PR('l',  12) : /* IGNORED: Cursor blink             */ break; //att610
682     case TY_CSI_PR('s',  12) : /* IGNORED: Cursor blink             */ break; //att610
683     case TY_CSI_PR('r',  12) : /* IGNORED: Cursor blink             */ break; //att610
684 
685     case TY_CSI_PR('h',  25) :          setMode      (MODE_Cursor   ); break; //VT100
686     case TY_CSI_PR('l',  25) :        resetMode      (MODE_Cursor   ); break; //VT100
687     case TY_CSI_PR('s',  25) :         saveMode      (MODE_Cursor   ); break; //VT100
688     case TY_CSI_PR('r',  25) :      restoreMode      (MODE_Cursor   ); break; //VT100
689 
690     case TY_CSI_PR('h',  40) :         setMode(MODE_Allow132Columns ); break; // XTERM
691     case TY_CSI_PR('l',  40) :       resetMode(MODE_Allow132Columns ); break; // XTERM
692 
693     case TY_CSI_PR('h',  41) : /* IGNORED: obsolete more(1) fix     */ break; //XTERM
694     case TY_CSI_PR('l',  41) : /* IGNORED: obsolete more(1) fix     */ break; //XTERM
695     case TY_CSI_PR('s',  41) : /* IGNORED: obsolete more(1) fix     */ break; //XTERM
696     case TY_CSI_PR('r',  41) : /* IGNORED: obsolete more(1) fix     */ break; //XTERM
697 
698     case TY_CSI_PR('h',  47) :          setMode      (MODE_AppScreen); break; //VT100
699     case TY_CSI_PR('l',  47) :        resetMode      (MODE_AppScreen); break; //VT100
700     case TY_CSI_PR('s',  47) :         saveMode      (MODE_AppScreen); break; //XTERM
701     case TY_CSI_PR('r',  47) :      restoreMode      (MODE_AppScreen); break; //XTERM
702 
703     case TY_CSI_PR('h',  67) : /* IGNORED: DECBKM                   */ break; //XTERM
704     case TY_CSI_PR('l',  67) : /* IGNORED: DECBKM                   */ break; //XTERM
705     case TY_CSI_PR('s',  67) : /* IGNORED: DECBKM                   */ break; //XTERM
706     case TY_CSI_PR('r',  67) : /* IGNORED: DECBKM                   */ break; //XTERM
707 
708     // XTerm defines the following modes:
709     // SET_VT200_MOUSE             1000
710     // SET_VT200_HIGHLIGHT_MOUSE   1001
711     // SET_BTN_EVENT_MOUSE         1002
712     // SET_ANY_EVENT_MOUSE         1003
713     //
714 
715     //Note about mouse modes:
716     //There are four mouse modes which xterm-compatible terminals can support - 1000,1001,1002,1003
717     //Konsole currently supports mode 1000 (basic mouse press and release) and mode 1002 (dragging the mouse).
718     //TODO:  Implementation of mouse modes 1001 (something called hilight tracking) and
719     //1003 (a slight variation on dragging the mouse)
720     //
721 
722     case TY_CSI_PR('h', 1000) :          setMode      (MODE_Mouse1000); break; //XTERM
723     case TY_CSI_PR('l', 1000) :        resetMode      (MODE_Mouse1000); break; //XTERM
724     case TY_CSI_PR('s', 1000) :         saveMode      (MODE_Mouse1000); break; //XTERM
725     case TY_CSI_PR('r', 1000) :      restoreMode      (MODE_Mouse1000); break; //XTERM
726 
727     case TY_CSI_PR('h', 1001) : /* IGNORED: hilite mouse tracking    */ break; //XTERM
728     case TY_CSI_PR('l', 1001) :        resetMode      (MODE_Mouse1001); break; //XTERM
729     case TY_CSI_PR('s', 1001) : /* IGNORED: hilite mouse tracking    */ break; //XTERM
730     case TY_CSI_PR('r', 1001) : /* IGNORED: hilite mouse tracking    */ break; //XTERM
731 
732     case TY_CSI_PR('h', 1002) :          setMode      (MODE_Mouse1002); break; //XTERM
733     case TY_CSI_PR('l', 1002) :        resetMode      (MODE_Mouse1002); break; //XTERM
734     case TY_CSI_PR('s', 1002) :         saveMode      (MODE_Mouse1002); break; //XTERM
735     case TY_CSI_PR('r', 1002) :      restoreMode      (MODE_Mouse1002); break; //XTERM
736 
737     case TY_CSI_PR('h', 1003) :          setMode      (MODE_Mouse1003); break; //XTERM
738     case TY_CSI_PR('l', 1003) :        resetMode      (MODE_Mouse1003); break; //XTERM
739     case TY_CSI_PR('s', 1003) :         saveMode      (MODE_Mouse1003); break; //XTERM
740     case TY_CSI_PR('r', 1003) :      restoreMode      (MODE_Mouse1003); break; //XTERM
741 
742     case TY_CSI_PR('h', 1034) : /* IGNORED: 8bitinput activation     */ break; //XTERM
743 
744     case TY_CSI_PR('h', 1047) :          setMode      (MODE_AppScreen); break; //XTERM
745     case TY_CSI_PR('l', 1047) : _screen[1]->clearEntireScreen(); resetMode(MODE_AppScreen); break; //XTERM
746     case TY_CSI_PR('s', 1047) :         saveMode      (MODE_AppScreen); break; //XTERM
747     case TY_CSI_PR('r', 1047) :      restoreMode      (MODE_AppScreen); break; //XTERM
748 
749     //FIXME: Unitoken: save translations
750     case TY_CSI_PR('h', 1048) :      saveCursor           (          ); break; //XTERM
751     case TY_CSI_PR('l', 1048) :      restoreCursor        (          ); break; //XTERM
752     case TY_CSI_PR('s', 1048) :      saveCursor           (          ); break; //XTERM
753     case TY_CSI_PR('r', 1048) :      restoreCursor        (          ); break; //XTERM
754 
755     //FIXME: every once new sequences like this pop up in xterm.
756     //       Here's a guess of what they could mean.
757     case TY_CSI_PR('h', 1049) : saveCursor(); _screen[1]->clearEntireScreen(); setMode(MODE_AppScreen); break; //XTERM
758     case TY_CSI_PR('l', 1049) : resetMode(MODE_AppScreen); restoreCursor(); break; //XTERM
759 
760     //FIXME: weird DEC reset sequence
761     case TY_CSI_PE('p'      ) : /* IGNORED: reset         (        ) */ break;
762 
763     //FIXME: when changing between vt52 and ansi mode evtl do some resetting.
764     case TY_VT52('A'      ) : _currentScreen->cursorUp             (         1); break; //VT52
765     case TY_VT52('B'      ) : _currentScreen->cursorDown           (         1); break; //VT52
766     case TY_VT52('C'      ) : _currentScreen->cursorRight          (         1); break; //VT52
767     case TY_VT52('D'      ) : _currentScreen->cursorLeft           (         1); break; //VT52
768 
769     case TY_VT52('F'      ) :      setAndUseCharset     (0,    '0'); break; //VT52
770     case TY_VT52('G'      ) :      setAndUseCharset     (0,    'B'); break; //VT52
771 
772     case TY_VT52('H'      ) : _currentScreen->setCursorYX          (1,1       ); break; //VT52
773     case TY_VT52('I'      ) : _currentScreen->reverseIndex         (          ); break; //VT52
774     case TY_VT52('J'      ) : _currentScreen->clearToEndOfScreen   (          ); break; //VT52
775     case TY_VT52('K'      ) : _currentScreen->clearToEndOfLine     (          ); break; //VT52
776     case TY_VT52('Y'      ) : _currentScreen->setCursorYX          (p-31,q-31 ); break; //VT52
777     case TY_VT52('Z'      ) :      reportTerminalType   (           ); break; //VT52
778     case TY_VT52('<'      ) :          setMode      (MODE_Ansi     ); break; //VT52
779     case TY_VT52('='      ) :          setMode      (MODE_AppKeyPad); break; //VT52
780     case TY_VT52('>'      ) :        resetMode      (MODE_AppKeyPad); break; //VT52
781 
782     case TY_CSI_PG('c'      ) :  reportSecondaryAttributes(          ); break; //VT100
783 
784     default:
785         reportDecodingError();
786         break;
787   };
788 }
789 
clearScreenAndSetColumns(int columnCount)790 void Vt102Emulation::clearScreenAndSetColumns(int columnCount)
791 {
792     setImageSize(_currentScreen->getLines(),columnCount);
793     clearEntireScreen();
794     setDefaultMargins();
795     _currentScreen->setCursorYX(0,0);
796 }
797 
sendString(const char * s,int length)798 void Vt102Emulation::sendString(const char* s , int length)
799 {
800   if ( length >= 0 )
801     emit sendData(s,length);
802   else
803     emit sendData(s,strlen(s));
804 }
805 
reportCursorPosition()806 void Vt102Emulation::reportCursorPosition()
807 {
808   char tmp[20];
809   sprintf(tmp,"\033[%d;%dR",_currentScreen->getCursorY()+1,_currentScreen->getCursorX()+1);
810   sendString(tmp);
811 }
812 
reportTerminalType()813 void Vt102Emulation::reportTerminalType()
814 {
815   // Primary device attribute response (Request was: ^[[0c or ^[[c (from TT321 Users Guide))
816   // VT220:  ^[[?63;1;2;3;6;7;8c   (list deps on emul. capabilities)
817   // VT100:  ^[[?1;2c
818   // VT101:  ^[[?1;0c
819   // VT102:  ^[[?6v
820   if (getMode(MODE_Ansi))
821     sendString("\033[?1;2c"); // I'm a VT100
822   else
823     sendString("\033/Z"); // I'm a VT52
824 }
825 
reportSecondaryAttributes()826 void Vt102Emulation::reportSecondaryAttributes()
827 {
828   // Seconday device attribute response (Request was: ^[[>0c or ^[[>c)
829   if (getMode(MODE_Ansi))
830     sendString("\033[>0;115;0c"); // Why 115?  ;)
831   else
832     sendString("\033/Z");         // FIXME I don't think VT52 knows about it but kept for
833                                   // konsoles backward compatibility.
834 }
835 
reportTerminalParms(int p)836 void Vt102Emulation::reportTerminalParms(int p)
837 // DECREPTPARM
838 {
839   char tmp[100];
840   sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true.
841   sendString(tmp);
842 }
843 
reportStatus()844 void Vt102Emulation::reportStatus()
845 {
846   sendString("\033[0n"); //VT100. Device status report. 0 = Ready.
847 }
848 
reportAnswerBack()849 void Vt102Emulation::reportAnswerBack()
850 {
851   // FIXME - Test this with VTTEST
852   // This is really obsolete VT100 stuff.
853   const char* ANSWER_BACK = "";
854   sendString(ANSWER_BACK);
855 }
856 
857 /*!
858     `cx',`cy' are 1-based.
859     `eventType' indicates the button pressed (0-2)
860                 or a general mouse release (3).
861 
862     eventType represents the kind of mouse action that occurred:
863         0 = Mouse button press or release
864         1 = Mouse drag
865 */
866 
sendMouseEvent(int cb,int cx,int cy,int eventType)867 void Vt102Emulation::sendMouseEvent( int cb, int cx, int cy , int eventType )
868 {
869   if (cx < 1 || cy < 1)
870     return;
871 
872   // normal buttons are passed as 0x20 + button,
873   // mouse wheel (buttons 4,5) as 0x5c + button
874   if (cb >= 4)
875     cb += 0x3c;
876 
877   //Mouse motion handling
878   if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1)
879       cb += 0x20; //add 32 to signify motion event
880 
881   char command[20];
882   sprintf(command,"\033[M%c%c%c",cb+0x20,cx+0x20,cy+0x20);
883   sendString(command);
884 }
885 
sendText(const QString & text)886 void Vt102Emulation::sendText( const QString& text )
887 {
888   if (!text.isEmpty())
889   {
890     QKeyEvent event(QEvent::KeyPress,
891                     0,
892                     Qt::NoModifier,
893                     text);
894     sendKeyEvent(&event); // expose as a big fat keypress event
895   }
896 }
sendKeyEvent(QKeyEvent * event)897 void Vt102Emulation::sendKeyEvent( QKeyEvent* event )
898 {
899     Qt::KeyboardModifiers modifiers = event->modifiers();
900     KeyboardTranslator::States states = KeyboardTranslator::NoState;
901 
902     // get current states
903     if (getMode(MODE_NewLine)  ) states |= KeyboardTranslator::NewLineState;
904     if (getMode(MODE_Ansi)     ) states |= KeyboardTranslator::AnsiState;
905     if (getMode(MODE_AppCuKeys)) states |= KeyboardTranslator::CursorKeysState;
906     if (getMode(MODE_AppScreen)) states |= KeyboardTranslator::AlternateScreenState;
907     if (getMode(MODE_AppKeyPad) && (modifiers & Qt::KeypadModifier))
908         states |= KeyboardTranslator::ApplicationKeypadState;
909 
910     // check flow control state
911     if (modifiers & Qt::ControlModifier)
912     {
913         if (event->key() == Qt::Key_S)
914             emit flowControlKeyPressed(true);
915         else if (event->key() == Qt::Key_Q)
916             emit flowControlKeyPressed(false);
917     }
918 
919     // lookup key binding
920     if ( _keyTranslator )
921     {
922     KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
923                                                 event->key() ,
924                                                 modifiers,
925                                                 states );
926 
927         // send result to terminal
928         QByteArray textToSend;
929 
930         // special handling for the Alt (aka. Meta) modifier.  pressing
931         // Alt+[Character] results in Esc+[Character] being sent
932         // (unless there is an entry defined for this particular combination
933         //  in the keyboard modifier)
934         bool wantsAltModifier = entry.modifiers() & entry.modifierMask() & Qt::AltModifier;
935         bool wantsAnyModifier = entry.state() &
936                                 entry.stateMask() & KeyboardTranslator::AnyModifierState;
937 
938         if ( modifiers & Qt::AltModifier && !(wantsAltModifier || wantsAnyModifier)
939              && !event->text().isEmpty() )
940         {
941             textToSend.prepend("\033");
942         }
943 
944         if ( entry.command() != KeyboardTranslator::NoCommand )
945         {
946             if (entry.command() & KeyboardTranslator::EraseCommand)
947                 textToSend += eraseChar();
948 
949             // TODO command handling
950         }
951         else if ( !entry.text().isEmpty() )
952         {
953             textToSend += _codec->fromUnicode(entry.text(true,modifiers));
954         }
955         else if((modifiers & Qt::ControlModifier) && event->key() >= 0x40 && event->key() < 0x5f) {
956             textToSend += (event->key() & 0x1f);
957         }
958         else if(event->key() == Qt::Key_Tab) {
959             textToSend += 0x09;
960         }
961         else if (event->key() == Qt::Key_PageUp) {
962             textToSend += "\033[5~";
963         }
964         else if (event->key() == Qt::Key_PageDown) {
965             textToSend += "\033[6~";
966         }
967         else {
968             textToSend += _codec->fromUnicode(event->text());
969         }
970 
971         sendData( textToSend.constData() , textToSend.length() );
972     }
973     else
974     {
975         // print an error message to the terminal if no key translator has been
976         // set
977         QString translatorError =  tr("No keyboard translator available.  "
978                                          "The information needed to convert key presses "
979                                          "into characters to send to the terminal "
980                                          "is missing.");
981         reset();
982         receiveData( translatorError.toUtf8().constData() , translatorError.count() );
983     }
984 }
985 
986 /* ------------------------------------------------------------------------- */
987 /*                                                                           */
988 /*                                VT100 Charsets                             */
989 /*                                                                           */
990 /* ------------------------------------------------------------------------- */
991 
992 // Character Set Conversion ------------------------------------------------ --
993 
994 /*
995    The processing contains a VT100 specific code translation layer.
996    It's still in use and mainly responsible for the line drawing graphics.
997 
998    These and some other glyphs are assigned to codes (0x5f-0xfe)
999    normally occupied by the latin letters. Since this codes also
1000    appear within control sequences, the extra code conversion
1001    does not permute with the tokenizer and is placed behind it
1002    in the pipeline. It only applies to tokens, which represent
1003    plain characters.
1004 
1005    This conversion it eventually continued in TerminalDisplay.C, since
1006    it might involve VT100 enhanced fonts, which have these
1007    particular glyphs allocated in (0x00-0x1f) in their code page.
1008 */
1009 
1010 #define CHARSET _charset[_currentScreen==_screen[1]]
1011 
1012 // Apply current character map.
1013 
applyCharset(unsigned short c)1014 unsigned short Vt102Emulation::applyCharset(unsigned short c)
1015 {
1016   if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f];
1017   if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete
1018   return c;
1019 }
1020 
1021 /*
1022    "Charset" related part of the emulation state.
1023    This configures the VT100 charset filter.
1024 
1025    While most operation work on the current _screen,
1026    the following two are different.
1027 */
1028 
resetCharset(int scrno)1029 void Vt102Emulation::resetCharset(int scrno)
1030 {
1031   _charset[scrno].cu_cs = 0;
1032   strncpy(_charset[scrno].charset,"BBBB",4);
1033   _charset[scrno].sa_graphic = false;
1034   _charset[scrno].sa_pound = false;
1035   _charset[scrno].graphic = false;
1036   _charset[scrno].pound = false;
1037 }
1038 
setCharset(int n,int cs)1039 void Vt102Emulation::setCharset(int n, int cs) // on both screens.
1040 {
1041   _charset[0].charset[n&3] = cs; useCharset(_charset[0].cu_cs);
1042   _charset[1].charset[n&3] = cs; useCharset(_charset[1].cu_cs);
1043 }
1044 
setAndUseCharset(int n,int cs)1045 void Vt102Emulation::setAndUseCharset(int n, int cs)
1046 {
1047   CHARSET.charset[n&3] = cs;
1048   useCharset(n&3);
1049 }
1050 
useCharset(int n)1051 void Vt102Emulation::useCharset(int n)
1052 {
1053   CHARSET.cu_cs   = n&3;
1054   CHARSET.graphic = (CHARSET.charset[n&3] == '0');
1055   CHARSET.pound   = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete
1056 }
1057 
setDefaultMargins()1058 void Vt102Emulation::setDefaultMargins()
1059 {
1060     _screen[0]->setDefaultMargins();
1061     _screen[1]->setDefaultMargins();
1062 }
1063 
setMargins(int t,int b)1064 void Vt102Emulation::setMargins(int t, int b)
1065 {
1066   _screen[0]->setMargins(t, b);
1067   _screen[1]->setMargins(t, b);
1068 }
1069 
saveCursor()1070 void Vt102Emulation::saveCursor()
1071 {
1072   CHARSET.sa_graphic = CHARSET.graphic;
1073   CHARSET.sa_pound   = CHARSET.pound; //This mode is obsolete
1074   // we are not clear about these
1075   //sa_charset = charsets[cScreen->_charset];
1076   //sa_charset_num = cScreen->_charset;
1077   _currentScreen->saveCursor();
1078 }
1079 
restoreCursor()1080 void Vt102Emulation::restoreCursor()
1081 {
1082   CHARSET.graphic = CHARSET.sa_graphic;
1083   CHARSET.pound   = CHARSET.sa_pound; //This mode is obsolete
1084   _currentScreen->restoreCursor();
1085 }
1086 
1087 /* ------------------------------------------------------------------------- */
1088 /*                                                                           */
1089 /*                                Mode Operations                            */
1090 /*                                                                           */
1091 /* ------------------------------------------------------------------------- */
1092 
1093 /*
1094    Some of the emulations state is either added to the state of the screens.
1095 
1096    This causes some scoping problems, since different emulations choose to
1097    located the mode either to the current _screen or to both.
1098 
1099    For strange reasons, the extend of the rendition attributes ranges over
1100    all screens and not over the actual _screen.
1101 
1102    We decided on the precise precise extend, somehow.
1103 */
1104 
1105 // "Mode" related part of the state. These are all booleans.
1106 
resetModes()1107 void Vt102Emulation::resetModes()
1108 {
1109   // MODE_Allow132Columns is not reset here
1110   // to match Xterm's behaviour (see Xterm's VTReset() function)
1111 
1112   resetMode(MODE_132Columns); saveMode(MODE_132Columns);
1113   resetMode(MODE_Mouse1000);  saveMode(MODE_Mouse1000);
1114   resetMode(MODE_Mouse1001);  saveMode(MODE_Mouse1001);
1115   resetMode(MODE_Mouse1002);  saveMode(MODE_Mouse1002);
1116   resetMode(MODE_Mouse1003);  saveMode(MODE_Mouse1003);
1117 
1118   resetMode(MODE_AppScreen);  saveMode(MODE_AppScreen);
1119   resetMode(MODE_AppCuKeys);  saveMode(MODE_AppCuKeys);
1120   resetMode(MODE_AppKeyPad);  saveMode(MODE_AppKeyPad);
1121   resetMode(MODE_NewLine);
1122   setMode(MODE_Ansi);
1123 }
1124 
setMode(int m)1125 void Vt102Emulation::setMode(int m)
1126 {
1127   _currentModes.mode[m] = true;
1128   switch (m)
1129   {
1130     case MODE_132Columns:
1131         if (getMode(MODE_Allow132Columns))
1132             clearScreenAndSetColumns(132);
1133         else
1134             _currentModes.mode[m] = false;
1135         break;
1136     case MODE_Mouse1000:
1137     case MODE_Mouse1001:
1138     case MODE_Mouse1002:
1139     case MODE_Mouse1003:
1140          emit programUsesMouseChanged(false);
1141     break;
1142 
1143     case MODE_AppScreen : _screen[1]->clearSelection();
1144                           setScreen(1);
1145     break;
1146   }
1147   if (m < MODES_SCREEN || m == MODE_NewLine)
1148   {
1149     _screen[0]->setMode(m);
1150     _screen[1]->setMode(m);
1151   }
1152 }
1153 
resetMode(int m)1154 void Vt102Emulation::resetMode(int m)
1155 {
1156   _currentModes.mode[m] = false;
1157   switch (m)
1158   {
1159     case MODE_132Columns:
1160         if (getMode(MODE_Allow132Columns))
1161             clearScreenAndSetColumns(80);
1162         break;
1163     case MODE_Mouse1000 :
1164     case MODE_Mouse1001 :
1165     case MODE_Mouse1002 :
1166     case MODE_Mouse1003 :
1167         emit programUsesMouseChanged(true);
1168     break;
1169 
1170     case MODE_AppScreen :
1171         _screen[0]->clearSelection();
1172         setScreen(0);
1173     break;
1174   }
1175   if (m < MODES_SCREEN || m == MODE_NewLine)
1176   {
1177     _screen[0]->resetMode(m);
1178     _screen[1]->resetMode(m);
1179   }
1180 }
1181 
saveMode(int m)1182 void Vt102Emulation::saveMode(int m)
1183 {
1184   _savedModes.mode[m] = _currentModes.mode[m];
1185 }
1186 
restoreMode(int m)1187 void Vt102Emulation::restoreMode(int m)
1188 {
1189   if (_savedModes.mode[m])
1190       setMode(m);
1191   else
1192       resetMode(m);
1193 }
1194 
getMode(int m)1195 bool Vt102Emulation::getMode(int m)
1196 {
1197   return _currentModes.mode[m];
1198 }
1199 
eraseChar() const1200 char Vt102Emulation::eraseChar() const
1201 {
1202   KeyboardTranslator::Entry entry = _keyTranslator->findEntry(
1203                                             Qt::Key_Backspace,
1204                                             0,
1205                                             0);
1206   if ( entry.text().count() > 0 )
1207       return entry.text()[0];
1208   else
1209       return '\b';
1210 }
1211 
1212 // print contents of the scan buffer
hexdump(int * s,int len)1213 static void hexdump(int* s, int len)
1214 { int i;
1215   for (i = 0; i < len; i++)
1216   {
1217     if (s[i] == '\\')
1218       printf("\\\\");
1219     else
1220     if ((s[i]) > 32 && s[i] < 127)
1221       printf("%c",s[i]);
1222     else
1223       printf("\\%04x(hex)",s[i]);
1224   }
1225 }
1226 
reportDecodingError()1227 void Vt102Emulation::reportDecodingError()
1228 {
1229   if (tokenBufferPos == 0 || ( tokenBufferPos == 1 && (tokenBuffer[0] & 0xff) >= 32) )
1230     return;
1231   printf("Undecodable sequence: ");
1232   hexdump(tokenBuffer,tokenBufferPos);
1233   printf("\n");
1234 }
1235 
1236 //#include "Vt102Emulation.moc"
1237 
1238