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