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