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