From a0bfe0f77ffb21058f78c58d25ec63052bdf41ea Mon Sep 17 00:00:00 2001 From: Filippo Scognamiglio Date: Wed, 27 Aug 2014 21:53:15 +0200 Subject: [PATCH] Much improved mouse emulation. --- konsole-qml-plugin/src/Character.h | 46 +- konsole-qml-plugin/src/Emulation.h | 6 + konsole-qml-plugin/src/Session.cpp | 3 +- konsole-qml-plugin/src/Vt102Emulation.cpp | 767 +++++++++++++--------- konsole-qml-plugin/src/Vt102Emulation.h | 239 +++---- 5 files changed, 599 insertions(+), 462 deletions(-) diff --git a/konsole-qml-plugin/src/Character.h b/konsole-qml-plugin/src/Character.h index 30fb0b8..f29470e 100644 --- a/konsole-qml-plugin/src/Character.h +++ b/konsole-qml-plugin/src/Character.h @@ -1,6 +1,6 @@ /* This file is part of Konsole, KDE's terminal. - + Copyright 2007-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle @@ -53,7 +53,7 @@ static const int LINE_DOUBLEHEIGHT = (1 << 2); class Character { public: - /** + /** * Constructs a new character. * * @param _c The unicode character value of this character. @@ -71,25 +71,25 @@ public: { /** The unicode character value for this character. */ quint16 character; - /** + /** * Experimental addition which allows a single Character instance to contain more than * one unicode character. * * charSequence is a hash code which can be used to look up the unicode * character sequence in the ExtendedCharTable used to create the sequence. */ - quint16 charSequence; + quint16 charSequence; }; /** A combination of RENDITION flags which specify options for drawing the character. */ quint8 rendition; /** The foreground color used to draw this character. */ - CharacterColor foregroundColor; + CharacterColor foregroundColor; /** The color used to draw this character's background. */ CharacterColor backgroundColor; - /** + /** * Returns true if this character has a transparent background when * it is drawn with the specified @p palette. */ @@ -97,16 +97,16 @@ public: /** * Returns true if this character should always be drawn in bold when * it is drawn with the specified @p palette, independent of whether - * or not the character has the RE_BOLD rendition flag. + * or not the character has the RE_BOLD rendition flag. */ ColorEntry::FontWeight fontWeight(const ColorEntry* base) const; - - /** + + /** * returns true if the format (color, rendition flag) of the compared characters is equal */ bool equalsFormat(const Character &other) const; - /** + /** * Compares two characters and returns true if they have the same unicode character value, * rendition and colors. */ @@ -119,36 +119,36 @@ public: }; inline bool operator == (const Character& a, const Character& b) -{ - return a.character == b.character && - a.rendition == b.rendition && - a.foregroundColor == b.foregroundColor && +{ + return a.character == b.character && + a.rendition == b.rendition && + a.foregroundColor == b.foregroundColor && a.backgroundColor == b.backgroundColor; } inline bool operator != (const Character& a, const Character& b) { - return a.character != b.character || - a.rendition != b.rendition || - a.foregroundColor != b.foregroundColor || + return a.character != b.character || + a.rendition != b.rendition || + a.foregroundColor != b.foregroundColor || a.backgroundColor != b.backgroundColor; } inline bool Character::isTransparent(const ColorEntry* base) const { - return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) && + return ((backgroundColor._colorSpace == COLOR_SPACE_DEFAULT) && base[backgroundColor._u+0+(backgroundColor._v?BASE_COLORS:0)].transparent) - || ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) && + || ((backgroundColor._colorSpace == COLOR_SPACE_SYSTEM) && base[backgroundColor._u+2+(backgroundColor._v?BASE_COLORS:0)].transparent); } inline bool Character::equalsFormat(const Character& other) const { - return + return backgroundColor==other.backgroundColor && foregroundColor==other.foregroundColor && rendition==other.rendition; -} +} inline ColorEntry::FontWeight Character::fontWeight(const ColorEntry* base) const { @@ -193,7 +193,7 @@ public: * which was added to the table using createExtendedChar(). * * @param hash The hash key returned by createExtendedChar() - * @param length This variable is set to the length of the + * @param length This variable is set to the length of the * character sequence. * * @return A unicode character sequence of size @p length. @@ -205,7 +205,7 @@ public: private: // calculates the hash key of a sequence of unicode points of size 'length' ushort extendedCharHash(ushort* unicodePoints , ushort length) const; - // tests whether the entry in the table specified by 'hash' matches the + // tests whether the entry in the table specified by 'hash' matches the // character sequence 'unicodePoints' of size 'length' bool extendedCharMatch(ushort hash , ushort* unicodePoints , ushort length) const; // internal, maps hash keys to character sequence buffers. The first ushort diff --git a/konsole-qml-plugin/src/Emulation.h b/konsole-qml-plugin/src/Emulation.h index 49f707d..a01d63e 100644 --- a/konsole-qml-plugin/src/Emulation.h +++ b/konsole-qml-plugin/src/Emulation.h @@ -376,6 +376,12 @@ signals: */ void imageSizeChanged(int lineCount , int columnCount); + /** + * Emitted after receiving the escape sequence which asks to change + * the terminal emulator's size + */ + void imageResizeRequest(const QSize& sizz); + /** * Emitted when the terminal program requests to change various properties * of the terminal display. diff --git a/konsole-qml-plugin/src/Session.cpp b/konsole-qml-plugin/src/Session.cpp index 41b9738..1e499ea 100644 --- a/konsole-qml-plugin/src/Session.cpp +++ b/konsole-qml-plugin/src/Session.cpp @@ -48,9 +48,10 @@ #include "ShellCommand.h" // REUSE THIS #include "Vt102Emulation.h" // REUSE THIS - int Session::lastSessionId = 0; +using namespace Konsole; + Session::Session() : _shellProcess(0) , _emulation(0) diff --git a/konsole-qml-plugin/src/Vt102Emulation.cpp b/konsole-qml-plugin/src/Vt102Emulation.cpp index f38787a..4663b41 100644 --- a/konsole-qml-plugin/src/Vt102Emulation.cpp +++ b/konsole-qml-plugin/src/Vt102Emulation.cpp @@ -1,6 +1,6 @@ /* This file is part of Konsole, an X terminal. - + Copyright 2007-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle @@ -23,47 +23,57 @@ // Own #include "Vt102Emulation.h" -// XKB -//#include - -// this allows konsole to be compiled without XKB and XTEST extensions -// even though it might be available on a particular system. -#if defined(AVOID_XKB) - #undef HAVE_XKB -#endif - -#if defined(HAVE_XKB) - void scrolllock_set_off(); - void scrolllock_set_on(); -#endif - -// Standard +// Standard #include #include -#include // Qt #include +#include #include -#include // KDE -//#include -//#include +//#include +//#include // Konsole #include "KeyboardTranslator.h" #include "Screen.h" +#include "TerminalDisplay.h" -Vt102Emulation::Vt102Emulation() +using Konsole::Vt102Emulation; + +/* + The VT100 has 32 special graphical characters. The usual vt100 extended + xterm fonts have these at 0x00..0x1f. + + QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals + come in here as proper unicode characters. + + We treat non-iso10646 fonts as VT100 extended and do the required mapping + from unicode to 0x00..0x1f. The remaining translation is then left to the + QCodec. +*/ + +// assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. + +unsigned short Konsole::vt100_graphics[32] = { + // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15 + 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, + 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, + 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534, + 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7 +}; + +Vt102Emulation::Vt102Emulation() : Emulation(), - _titleUpdateTimer(new QTimer(this)) + _titleUpdateTimer(new QTimer(this)) { - _titleUpdateTimer->setSingleShot(true); - QObject::connect(_titleUpdateTimer , SIGNAL(timeout()) , this , SLOT(updateTitle())); + _titleUpdateTimer->setSingleShot(true); + QObject::connect(_titleUpdateTimer , SIGNAL(timeout()) , this , SLOT(updateTitle())); - initTokenizer(); - reset(); + initTokenizer(); + reset(); } Vt102Emulation::~Vt102Emulation() @@ -71,21 +81,29 @@ Vt102Emulation::~Vt102Emulation() void Vt102Emulation::clearEntireScreen() { - _currentScreen->clearEntireScreen(); - bufferedUpdate(); + _currentScreen->clearEntireScreen(); + bufferedUpdate(); } void Vt102Emulation::reset() { - resetTokenizer(); - resetModes(); - resetCharset(0); - _screen[0]->reset(); - resetCharset(1); - _screen[1]->reset(); - setCodec(LocaleCodec); - - bufferedUpdate(); + // Save the current codec so we can set it later. + // Ideally we would want to use the profile setting + const QTextCodec* currentCodec = codec(); + + resetTokenizer(); + resetModes(); + resetCharset(0); + _screen[0]->reset(); + resetCharset(1); + _screen[1]->reset(); + + if (currentCodec) + setCodec(currentCodec); + else + setCodec(LocaleCodec); + + bufferedUpdate(); } /* ------------------------------------------------------------------------- */ @@ -135,14 +153,14 @@ void Vt102Emulation::reset() - VT52 - VT52 escape codes - - 'Y'{Pc}{Pc} - - XTE_HA - Xterm window/terminal attribute commands + - XTE_HA - Xterm window/terminal attribute commands of the form `]' {Pn} `;' {Text} (Note that these are handled differently to the other formats) The last two forms allow list of arguments. Since the elements of the lists are treated individually the same way, they are passed as individual tokens to the interpretation. Further, because the - meaning of the parameters are names (althought represented as numbers), + meaning of the parameters are names (although represented as numbers), they are includes within the token ('N'). */ @@ -162,7 +180,7 @@ void Vt102Emulation::reset() #define TY_CSI_PG(A) TY_CONSTRUCT(9,A,0) #define TY_CSI_PE(A) TY_CONSTRUCT(10,A,0) -#define MAX_ARGUMENT 4096 +const int MAX_ARGUMENT = 4096; // Tokenizer --------------------------------------------------------------- -- @@ -175,64 +193,62 @@ void Vt102Emulation::reset() void Vt102Emulation::resetTokenizer() { - tokenBufferPos = 0; - argc = 0; - argv[0] = 0; - argv[1] = 0; + tokenBufferPos = 0; + argc = 0; + argv[0] = 0; + argv[1] = 0; } void Vt102Emulation::addDigit(int digit) { - if (argv[argc] < MAX_ARGUMENT) - argv[argc] = 10*argv[argc] + digit; + if (argv[argc] < MAX_ARGUMENT) + argv[argc] = 10 * argv[argc] + digit; } void Vt102Emulation::addArgument() { - argc = qMin(argc+1,MAXARGS-1); - argv[argc] = 0; + argc = qMin(argc + 1, MAXARGS - 1); + argv[argc] = 0; } void Vt102Emulation::addToCurrentToken(int cc) { - tokenBuffer[tokenBufferPos] = cc; - tokenBufferPos = qMin(tokenBufferPos+1,MAX_TOKEN_LENGTH-1); + tokenBuffer[tokenBufferPos] = cc; + tokenBufferPos = qMin(tokenBufferPos + 1, MAX_TOKEN_LENGTH - 1); } // Character Class flags used while decoding - -#define CTL 1 // Control character -#define CHR 2 // Printable character -#define CPN 4 // TODO: Document me -#define DIG 8 // Digit -#define SCS 16 // TODO: Document me -#define GRP 32 // TODO: Document me -#define CPS 64 // Character which indicates end of window resize - // escape sequence '\e[8;;t' +const int CTL = 1; // Control character +const int CHR = 2; // Printable character +const int CPN = 4; // TODO: Document me +const int DIG = 8; // Digit +const int SCS = 16; // Select Character Set +const int GRP = 32; // TODO: Document me +const int CPS = 64; // Character which indicates end of window resize void Vt102Emulation::initTokenizer() -{ - int i; - quint8* s; - for(i = 0;i < 256; ++i) - charClass[i] = 0; - for(i = 0;i < 32; ++i) - charClass[i] |= CTL; - for(i = 32;i < 256; ++i) - charClass[i] |= CHR; - for(s = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; ++s) - charClass[*s] |= CPN; - // resize = \e[8;;t - for(s = (quint8*)"t"; *s; ++s) - charClass[*s] |= CPS; - for(s = (quint8*)"0123456789"; *s; ++s) - charClass[*s] |= DIG; - for(s = (quint8*)"()+*%"; *s; ++s) - charClass[*s] |= SCS; - for(s = (quint8*)"()+*#[]%"; *s; ++s) - charClass[*s] |= GRP; +{ + int i; + quint8* s; + for (i = 0; i < 256; ++i) + charClass[i] = 0; + for (i = 0; i < 32; ++i) + charClass[i] |= CTL; + for (i = 32; i < 256; ++i) + charClass[i] |= CHR; + for (s = (quint8*)"@ABCDGHILMPSTXZcdfry"; *s; ++s) + charClass[*s] |= CPN; + // resize = \e[8;;t + for (s = (quint8*)"t"; *s; ++s) + charClass[*s] |= CPS; + for (s = (quint8*)"0123456789"; *s; ++s) + charClass[*s] |= DIG; + for (s = (quint8*)"()+*%"; *s; ++s) + charClass[*s] |= SCS; + for (s = (quint8*)"()+*#[]%"; *s; ++s) + charClass[*s] |= GRP; - resetTokenizer(); + resetTokenizer(); } /* Ok, here comes the nasty part of the decoder. @@ -246,10 +262,10 @@ void Vt102Emulation::initTokenizer() - P is the length of the token scanned so far. - L (often P-1) is the position on which contents we base a decision. - C is a character or a group of characters (taken from 'charClass'). - + - 'cc' is the current character - 's' is a pointer to the start of the token buffer - - 'p' is the current position within the token buffer + - 'p' is the current position within the token buffer Note that they need to applied in proper order. */ @@ -267,36 +283,37 @@ void Vt102Emulation::initTokenizer() #define Xte (Xpe && cc == 7 ) #define ces(C) (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte) -#define ESC 27 #define CNTL(c) ((c)-'@') +const int ESC = 27; +const int DEL = 127; // process an incoming unicode character void Vt102Emulation::receiveChar(int cc) -{ - if (cc == 127) +{ + if (cc == DEL) return; //VT100: ignore. if (ces(CTL)) - { + { // DEC HACK ALERT! Control Characters are allowed *within* esc sequences in VT100 // This means, they do neither a resetTokenizer() nor a pushToToken(). Some of them, do // of course. Guess this originates from a weakly layered handling of the X-on // X-off protocol, which comes really below this level. - if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) + if (cc == CNTL('X') || cc == CNTL('Z') || cc == ESC) resetTokenizer(); //VT100: CAN or SUB - if (cc != ESC) - { - processToken(TY_CTL(cc+'@' ),0,0); - return; + if (cc != ESC) + { + processToken(TY_CTL(cc+'@' ),0,0); + return; } } // advance the state - addToCurrentToken(cc); + addToCurrentToken(cc); int* s = tokenBuffer; - int p = tokenBufferPos; + const int p = tokenBufferPos; - if (getMode(MODE_Ansi)) + if (getMode(MODE_Ansi)) { if (lec(1,0,ESC)) { return; } if (lec(1,0,ESC+128)) { s[0] = ESC; receiveChar('['); return; } @@ -313,63 +330,63 @@ void Vt102Emulation::receiveChar(int cc) if (eps( CPN)) { processToken( TY_CSI_PN(cc), argv[0],argv[1]); resetTokenizer(); return; } // resize = \e[8;;t - if (eps(CPS)) - { - processToken( TY_CSI_PS(cc, argv[0]), argv[1], argv[2]); - resetTokenizer(); - return; + if (eps(CPS)) + { + processToken( TY_CSI_PS(cc, argv[0]), argv[1], argv[2]); + resetTokenizer(); + return; } if (epe( )) { processToken( TY_CSI_PE(cc), 0, 0); resetTokenizer(); return; } if (ees(DIG)) { addDigit(cc-'0'); return; } if (eec(';')) { addArgument(); return; } - for (int i=0;i<=argc;i++) + for (int i = 0; i <= argc; i++) { - if (epp()) - processToken( TY_CSI_PR(cc,argv[i]), 0, 0); - else if (egt()) - processToken( TY_CSI_PG(cc), 0, 0); // spec. case for ESC]>0c or ESC]>c + if (epp()) + processToken(TY_CSI_PR(cc,argv[i]), 0, 0); + else if (egt()) + processToken(TY_CSI_PG(cc), 0, 0); // spec. case for ESC]>0c or ESC]>c else if (cc == 'm' && argc - i >= 4 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 2) - { + { // ESC[ ... 48;2;;; ... m -or- ESC[ ... 38;2;;; ... m i += 2; - processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]); + processToken(TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_RGB, (argv[i] << 16) | (argv[i+1] << 8) | argv[i+2]); i += 2; } else if (cc == 'm' && argc - i >= 2 && (argv[i] == 38 || argv[i] == 48) && argv[i+1] == 5) - { + { // ESC[ ... 48;5; ... m -or- ESC[ ... 38;5; ... m i += 2; - processToken( TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]); + processToken(TY_CSI_PS(cc, argv[i-2]), COLOR_SPACE_256, argv[i]); } else - processToken( TY_CSI_PS(cc,argv[i]), 0, 0); + processToken(TY_CSI_PS(cc,argv[i]), 0, 0); } resetTokenizer(); } - else + else { // VT52 Mode - if (lec(1,0,ESC)) + if (lec(1,0,ESC)) + return; + if (les(1,0,CHR)) + { + processToken( TY_CHR(), s[0], 0); + resetTokenizer(); return; - if (les(1,0,CHR)) - { - processToken( TY_CHR(), s[0], 0); - resetTokenizer(); - return; } - if (lec(2,1,'Y')) + if (lec(2,1,'Y')) return; - if (lec(3,1,'Y')) + if (lec(3,1,'Y')) + return; + if (p < 4) + { + processToken(TY_VT52(s[1] ), 0, 0); + resetTokenizer(); return; - if (p < 4) - { - processToken( TY_VT52(s[1] ), 0, 0); - resetTokenizer(); - return; } - processToken( TY_VT52(s[1]), s[2], s[3]); - resetTokenizer(); + processToken(TY_VT52(s[1]), s[2], s[3]); + resetTokenizer(); return; } } @@ -379,24 +396,24 @@ void Vt102Emulation::processWindowAttributeChange() // See Session::UserTitleChange for possible values int attributeToChange = 0; int i; - for (i = 2; i < tokenBufferPos && - tokenBuffer[i] >= '0' && + for (i = 2; i < tokenBufferPos && + tokenBuffer[i] >= '0' && tokenBuffer[i] <= '9'; i++) { attributeToChange = 10 * attributeToChange + (tokenBuffer[i]-'0'); } - if (tokenBuffer[i] != ';') - { - reportDecodingError(); - return; + if (tokenBuffer[i] != ';') + { + reportDecodingError(); + return; } - + QString newValue; newValue.reserve(tokenBufferPos-i-2); for (int j = 0; j < tokenBufferPos-i-2; j++) newValue[j] = tokenBuffer[i+1+j]; - + _pendingTitleUpdates[attributeToChange] = newValue; _titleUpdateTimer->start(20); } @@ -406,9 +423,9 @@ void Vt102Emulation::updateTitle() QListIterator iter( _pendingTitleUpdates.keys() ); while (iter.hasNext()) { int arg = iter.next(); - emit titleChanged( arg , _pendingTitleUpdates[arg] ); + emit titleChanged( arg , _pendingTitleUpdates[arg] ); } - _pendingTitleUpdates.clear(); + _pendingTitleUpdates.clear(); } // Interpreting Codes --------------------------------------------------------- @@ -418,7 +435,7 @@ void Vt102Emulation::updateTitle() meaning is assigned to them. These are either operations of the current _screen, or of the emulation class itself. - The token to be interpreteted comes in as a machine word + The token to be interpreted comes in as a machine word possibly accompanied by two parameters. Likewise, the operations assigned to, come with up to two @@ -433,7 +450,6 @@ void Vt102Emulation::processToken(int token, int p, int q) { switch (token) { - case TY_CHR( ) : _currentScreen->displayCharacter (p ); break; //UTF16 // 127 DEL : ignored on input @@ -509,11 +525,11 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_ESC_CS('%', 'G') : setCodec (Utf8Codec ); break; //LINUX case TY_ESC_CS('%', '@') : setCodec (LocaleCodec ); break; //LINUX - case TY_ESC_DE('3' ) : /* Double height line, top half */ + case TY_ESC_DE('3' ) : /* Double height line, top half */ _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true ); _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , true ); break; - case TY_ESC_DE('4' ) : /* Double height line, bottom half */ + case TY_ESC_DE('4' ) : /* Double height line, bottom half */ _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true ); _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , true ); break; @@ -521,14 +537,16 @@ void Vt102Emulation::processToken(int token, int p, int q) _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , false); _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , false); break; - case TY_ESC_DE('6' ) : /* Double width, single height line*/ - _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true); + case TY_ESC_DE('6' ) : /* Double width, single height line*/ + _currentScreen->setLineProperty( LINE_DOUBLEWIDTH , true); _currentScreen->setLineProperty( LINE_DOUBLEHEIGHT , false); break; case TY_ESC_DE('8' ) : _currentScreen->helpAlign ( ); break; // resize = \e[8;;t - case TY_CSI_PS('t', 8) : setImageSize( q /* columns */, p /* lines */ ); break; + case TY_CSI_PS('t', 8) : setImageSize( p /*lines */, q /* columns */ ); + emit imageResizeRequest(QSize(q, p)); + break; // change tab text color : \e[28;t color: 0-16,777,215 case TY_CSI_PS('t', 28) : emit changeTabTextColorRequest ( p ); break; @@ -552,6 +570,7 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PS('m', 0) : _currentScreen->setDefaultRendition ( ); break; case TY_CSI_PS('m', 1) : _currentScreen-> setRendition (RE_BOLD ); break; //VT100 + //case TY_CSI_PS('m', 3) : _currentScreen-> setRendition (RE_ITALIC ); break; //VT100 case TY_CSI_PS('m', 4) : _currentScreen-> setRendition (RE_UNDERLINE); break; //VT100 case TY_CSI_PS('m', 5) : _currentScreen-> setRendition (RE_BLINK ); break; //VT100 case TY_CSI_PS('m', 7) : _currentScreen-> setRendition (RE_REVERSE ); break; @@ -559,6 +578,7 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PS('m', 11) : /* IGNORED: mapping related */ break; //LINUX case TY_CSI_PS('m', 12) : /* IGNORED: mapping related */ break; //LINUX case TY_CSI_PS('m', 22) : _currentScreen->resetRendition (RE_BOLD ); break; + //case TY_CSI_PS('m', 23) : _currentScreen->resetRendition (RE_ITALIC ); break; //VT100 case TY_CSI_PS('m', 24) : _currentScreen->resetRendition (RE_UNDERLINE); break; case TY_CSI_PS('m', 25) : _currentScreen->resetRendition (RE_BLINK ); break; case TY_CSI_PS('m', 27) : _currentScreen->resetRendition (RE_REVERSE ); break; @@ -622,6 +642,8 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PN('B' ) : _currentScreen->cursorDown (p ); break; //VT100 case TY_CSI_PN('C' ) : _currentScreen->cursorRight (p ); break; //VT100 case TY_CSI_PN('D' ) : _currentScreen->cursorLeft (p ); break; //VT100 + case TY_CSI_PN('E' ) : /* Not implemented: cursor next p lines */ break; //VT100 + case TY_CSI_PN('F' ) : /* Not implemented: cursor preceding p lines */ break; //VT100 case TY_CSI_PN('G' ) : _currentScreen->setCursorX (p ); break; //LINUX case TY_CSI_PN('H' ) : _currentScreen->setCursorYX (p, q); break; //VT100 case TY_CSI_PN('I' ) : _currentScreen->tab (p ); break; @@ -645,8 +667,8 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PR('l', 2) : resetMode (MODE_Ansi ); break; //VT100 - case TY_CSI_PR('h', 3) : setMode (MODE_132Columns);break; //VT100 - case TY_CSI_PR('l', 3) : resetMode (MODE_132Columns);break; //VT100 + case TY_CSI_PR('h', 3) : setMode (MODE_132Columns); break; //VT100 + case TY_CSI_PR('l', 3) : resetMode (MODE_132Columns); break; //VT100 case TY_CSI_PR('h', 4) : /* IGNORED: soft scrolling */ break; //VT100 case TY_CSI_PR('l', 4) : /* IGNORED: soft scrolling */ break; //VT100 @@ -708,14 +730,14 @@ void Vt102Emulation::processToken(int token, int p, int q) // SET_BTN_EVENT_MOUSE 1002 // SET_ANY_EVENT_MOUSE 1003 // - + //Note about mouse modes: //There are four mouse modes which xterm-compatible terminals can support - 1000,1001,1002,1003 //Konsole currently supports mode 1000 (basic mouse press and release) and mode 1002 (dragging the mouse). - //TODO: Implementation of mouse modes 1001 (something called hilight tracking) and + //TODO: Implementation of mouse modes 1001 (something called hilight tracking) and //1003 (a slight variation on dragging the mouse) // - + case TY_CSI_PR('h', 1000) : setMode (MODE_Mouse1000); break; //XTERM case TY_CSI_PR('l', 1000) : resetMode (MODE_Mouse1000); break; //XTERM case TY_CSI_PR('s', 1000) : saveMode (MODE_Mouse1000); break; //XTERM @@ -736,6 +758,21 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PR('s', 1003) : saveMode (MODE_Mouse1003); break; //XTERM case TY_CSI_PR('r', 1003) : restoreMode (MODE_Mouse1003); break; //XTERM + case TY_CSI_PR('h', 1005) : setMode (MODE_Mouse1005); break; //XTERM + case TY_CSI_PR('l', 1005) : resetMode (MODE_Mouse1005); break; //XTERM + case TY_CSI_PR('s', 1005) : saveMode (MODE_Mouse1005); break; //XTERM + case TY_CSI_PR('r', 1005) : restoreMode (MODE_Mouse1005); break; //XTERM + + case TY_CSI_PR('h', 1006) : setMode (MODE_Mouse1006); break; //XTERM + case TY_CSI_PR('l', 1006) : resetMode (MODE_Mouse1006); break; //XTERM + case TY_CSI_PR('s', 1006) : saveMode (MODE_Mouse1006); break; //XTERM + case TY_CSI_PR('r', 1006) : restoreMode (MODE_Mouse1006); break; //XTERM + + case TY_CSI_PR('h', 1015) : setMode (MODE_Mouse1015); break; //URXVT + case TY_CSI_PR('l', 1015) : resetMode (MODE_Mouse1015); break; //URXVT + case TY_CSI_PR('s', 1015) : saveMode (MODE_Mouse1015); break; //URXVT + case TY_CSI_PR('r', 1015) : restoreMode (MODE_Mouse1015); break; //URXVT + case TY_CSI_PR('h', 1034) : /* IGNORED: 8bitinput activation */ break; //XTERM case TY_CSI_PR('h', 1047) : setMode (MODE_AppScreen); break; //XTERM @@ -754,6 +791,11 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PR('h', 1049) : saveCursor(); _screen[1]->clearEntireScreen(); setMode(MODE_AppScreen); break; //XTERM case TY_CSI_PR('l', 1049) : resetMode(MODE_AppScreen); restoreCursor(); break; //XTERM + case TY_CSI_PR('h', 2004) : setMode (MODE_BracketedPaste); break; //XTERM + case TY_CSI_PR('l', 2004) : resetMode (MODE_BracketedPaste); break; //XTERM + case TY_CSI_PR('s', 2004) : saveMode (MODE_BracketedPaste); break; //XTERM + case TY_CSI_PR('r', 2004) : restoreMode (MODE_BracketedPaste); break; //XTERM + //FIXME: weird DEC reset sequence case TY_CSI_PE('p' ) : /* IGNORED: reset ( ) */ break; @@ -778,17 +820,17 @@ void Vt102Emulation::processToken(int token, int p, int q) case TY_CSI_PG('c' ) : reportSecondaryAttributes( ); break; //VT100 - default: - reportDecodingError(); + default: + reportDecodingError(); break; }; } void Vt102Emulation::clearScreenAndSetColumns(int columnCount) { - setImageSize(_currentScreen->getLines(),columnCount); + setImageSize(_currentScreen->getLines(),columnCount); clearEntireScreen(); - setDefaultMargins(); + setDefaultMargins(); _currentScreen->setCursorYX(0,0); } @@ -797,13 +839,13 @@ void Vt102Emulation::sendString(const char* s , int length) if ( length >= 0 ) emit sendData(s,length); else - emit sendData(s,strlen(s)); + emit sendData(s,qstrlen(s)); } void Vt102Emulation::reportCursorPosition() -{ +{ char tmp[20]; - sprintf(tmp,"\033[%d;%dR",_currentScreen->getCursorY()+1,_currentScreen->getCursorX()+1); + snprintf(tmp, sizeof(tmp), "\033[%d;%dR", _currentScreen->getCursorY()+1, _currentScreen->getCursorX()+1); sendString(tmp); } @@ -822,7 +864,7 @@ void Vt102Emulation::reportTerminalType() void Vt102Emulation::reportSecondaryAttributes() { - // Seconday device attribute response (Request was: ^[[>0c or ^[[>c) + // Secondary device attribute response (Request was: ^[[>0c or ^[[>c) if (getMode(MODE_Ansi)) sendString("\033[>0;115;0c"); // Why 115? ;) else @@ -830,96 +872,137 @@ void Vt102Emulation::reportSecondaryAttributes() // konsoles backward compatibility. } +/* DECREPTPARM – Report Terminal Parameters + ESC [ ; ; ; ; ; ; x + + http://vt100.net/docs/vt100-ug/chapter3.html +*/ void Vt102Emulation::reportTerminalParms(int p) -// DECREPTPARM -{ +{ char tmp[100]; - sprintf(tmp,"\033[%d;1;1;112;112;1;0x",p); // not really true. +/* + sol=1: This message is a request; report in response to a request. + par=1: No parity set + nbits=1: 8 bits per character + xspeed=112: 9600 + rspeed=112: 9600 + clkmul=1: The bit rate multiplier is 16. + flags=0: None +*/ + snprintf(tmp, sizeof(tmp), "\033[%d;1;1;112;112;1;0x", p); // not really true. sendString(tmp); } void Vt102Emulation::reportStatus() { - sendString("\033[0n"); //VT100. Device status report. 0 = Ready. + sendString("\033[0n"); //VT100. Device status report. 0 = Ready. } void Vt102Emulation::reportAnswerBack() { - // FIXME - Test this with VTTEST - // This is really obsolete VT100 stuff. - const char* ANSWER_BACK = ""; - sendString(ANSWER_BACK); + // FIXME - Test this with VTTEST + // This is really obsolete VT100 stuff. + const char* ANSWER_BACK = ""; + sendString(ANSWER_BACK); } /*! `cx',`cy' are 1-based. - `eventType' indicates the button pressed (0-2) - or a general mouse release (3). + `cb' indicates the button pressed or released (0-2) or scroll event (4-5). eventType represents the kind of mouse action that occurred: - 0 = Mouse button press or release + 0 = Mouse button press 1 = Mouse drag + 2 = Mouse button release */ -void Vt102Emulation::sendMouseEvent( int cb, int cx, int cy , int eventType ) +void Vt102Emulation::sendMouseEvent(int cb, int cx, int cy , int eventType) { - if (cx < 1 || cy < 1) - return; + if (cx < 1 || cy < 1) + return; - // normal buttons are passed as 0x20 + button, - // mouse wheel (buttons 4,5) as 0x5c + button - if (cb >= 4) - cb += 0x3c; + // With the exception of the 1006 mode, button release is encoded in cb. + // Note that if multiple extensions are enabled, the 1006 is used, so it's okay to check for only that. + if (eventType == 2 && !getMode(MODE_Mouse1006)) + cb = 3; - //Mouse motion handling - if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1) - cb += 0x20; //add 32 to signify motion event + // normal buttons are passed as 0x20 + button, + // mouse wheel (buttons 4,5) as 0x5c + button + if (cb >= 4) + cb += 0x3c; - char command[20]; - sprintf(command,"\033[M%c%c%c",cb+0x20,cx+0x20,cy+0x20); - sendString(command); + //Mouse motion handling + if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1) + cb += 0x20; //add 32 to signify motion event + + char command[32]; + command[0] = '\0'; + // Check the extensions in decreasing order of preference. Encoding the release event above assumes that 1006 comes first. + if (getMode(MODE_Mouse1006)) { + snprintf(command, sizeof(command), "\033[<%d;%d;%d%c", cb, cx, cy, eventType == 2 ? 'm' : 'M'); + } else if (getMode(MODE_Mouse1015)) { + snprintf(command, sizeof(command), "\033[%d;%d;%dM", cb + 0x20, cx, cy); + } else if (getMode(MODE_Mouse1005)) { + if (cx <= 2015 && cy <= 2015) { + // The xterm extension uses UTF-8 (up to 2 bytes) to encode + // coordinate+32, no matter what the locale is. We could easily + // convert manually, but QString can also do it for us. + QChar coords[2]; + coords[0] = cx + 0x20; + coords[1] = cy + 0x20; + QString coordsStr = QString(coords, 2); + QByteArray utf8 = coordsStr.toUtf8(); + snprintf(command, sizeof(command), "\033[M%c%s", cb + 0x20, (const char *)utf8); + } + } else if (cx <= 223 && cy <= 223) { + snprintf(command, sizeof(command), "\033[M%c%c%c", cb + 0x20, cx + 0x20, cy + 0x20); + } + + sendString(command); } -void Vt102Emulation::sendText( const QString& text ) +void Vt102Emulation::sendText(const QString& text) { - if (!text.isEmpty()) - { - QKeyEvent event(QEvent::KeyPress, - 0, - Qt::NoModifier, - text); - sendKeyEvent(&event); // expose as a big fat keypress event - } + if (!text.isEmpty()) { + QKeyEvent event(QEvent::KeyPress, + 0, + Qt::NoModifier, + text); + sendKeyEvent(&event); // expose as a big fat keypress event + } } -void Vt102Emulation::sendKeyEvent( QKeyEvent* event ) +void Vt102Emulation::sendKeyEvent(QKeyEvent* event) { - Qt::KeyboardModifiers modifiers = event->modifiers(); + const Qt::KeyboardModifiers modifiers = event->modifiers(); KeyboardTranslator::States states = KeyboardTranslator::NoState; // get current states - if (getMode(MODE_NewLine) ) states |= KeyboardTranslator::NewLineState; - if (getMode(MODE_Ansi) ) states |= KeyboardTranslator::AnsiState; + if (getMode(MODE_NewLine)) states |= KeyboardTranslator::NewLineState; + if (getMode(MODE_Ansi)) states |= KeyboardTranslator::AnsiState; if (getMode(MODE_AppCuKeys)) states |= KeyboardTranslator::CursorKeysState; if (getMode(MODE_AppScreen)) states |= KeyboardTranslator::AlternateScreenState; - if (getMode(MODE_AppKeyPad) && (modifiers & Qt::KeypadModifier)) + if (getMode(MODE_AppKeyPad) && (modifiers & Qt::KeypadModifier)) states |= KeyboardTranslator::ApplicationKeypadState; // check flow control state - if (modifiers & Qt::ControlModifier) - { - if (event->key() == Qt::Key_S) + if (modifiers & Qt::ControlModifier) { + switch (event->key()) { + case Qt::Key_S: emit flowControlKeyPressed(true); - else if (event->key() == Qt::Key_Q) + break; + case Qt::Key_Q: + case Qt::Key_C: // cancel flow control emit flowControlKeyPressed(false); + break; + } } - // lookup key binding - if ( _keyTranslator ) - { - KeyboardTranslator::Entry entry = _keyTranslator->findEntry( - event->key() , - modifiers, - states ); + // look up key binding + if (_keyTranslator) { + KeyboardTranslator::Entry entry = _keyTranslator->findEntry( + event->key() , + modifiers, + states); // send result to terminal QByteArray textToSend; @@ -928,22 +1011,28 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event ) // Alt+[Character] results in Esc+[Character] being sent // (unless there is an entry defined for this particular combination // in the keyboard modifier) - bool wantsAltModifier = entry.modifiers() & entry.modifierMask() & Qt::AltModifier; - bool wantsAnyModifier = entry.state() & + const bool wantsAltModifier = entry.modifiers() & entry.modifierMask() & Qt::AltModifier; + const bool wantsMetaModifier = entry.modifiers() & entry.modifierMask() & Qt::MetaModifier; + const bool wantsAnyModifier = entry.state() & entry.stateMask() & KeyboardTranslator::AnyModifierState; - if ( modifiers & Qt::AltModifier && !(wantsAltModifier || wantsAnyModifier) + if ( modifiers & Qt::AltModifier && !(wantsAltModifier || wantsAnyModifier) && !event->text().isEmpty() ) { textToSend.prepend("\033"); } + if ( modifiers & Qt::MetaModifier && !(wantsMetaModifier || wantsAnyModifier) + && !event->text().isEmpty() ) + { + textToSend.prepend("\030@s"); + } if ( entry.command() != KeyboardTranslator::NoCommand ) { - KTerminalDisplay* currentView = _currentScreen->currentTerminalDisplay(); - if (entry.command() & KeyboardTranslator::EraseCommand) + KTerminalDisplay * currentView = _currentScreen->currentTerminalDisplay(); + if (entry.command() & KeyboardTranslator::EraseCommand) { textToSend += eraseChar(); - else if (entry.command() & KeyboardTranslator::ScrollPageUpCommand) + } else if (entry.command() & KeyboardTranslator::ScrollPageUpCommand) currentView->scrollScreenWindow(ScreenWindow::ScrollPages, -1); else if (entry.command() & KeyboardTranslator::ScrollPageDownCommand) currentView->scrollScreenWindow(ScreenWindow::ScrollPages, 1); @@ -951,28 +1040,31 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event ) currentView->scrollScreenWindow(ScreenWindow::ScrollLines, -1); else if (entry.command() & KeyboardTranslator::ScrollLineDownCommand) currentView->scrollScreenWindow(ScreenWindow::ScrollLines, 1); - - // TODO command handling +// else if (entry.command() & KeyboardTranslator::ScrollUpToTopCommand) +// currentView->scrollScreenWindow(ScreenWindow::ScrollLines, +// - currentView->screenWindow()->currentLine()); +// else if (entry.command() & KeyboardTranslator::ScrollDownToBottomCommand) +// currentView->scrollScreenWindow(ScreenWindow::ScrollLines, lineCount()); } - else if ( !entry.text().isEmpty() ) + else if (!entry.text().isEmpty()) { textToSend += _codec->fromUnicode(entry.text(true,modifiers)); } else textToSend += _codec->fromUnicode(event->text()); - sendData( textToSend.constData() , textToSend.length() ); + sendData(textToSend.constData(), textToSend.length()); } else { // print an error message to the terminal if no key translator has been // set - QString translatorError = tr("No keyboard translator available. " - "The information needed to convert key presses " - "into characters to send to the terminal " - "is missing."); +// QString translatorError = i18n("No keyboard translator available. " +// "The information needed to convert key presses " +// "into characters to send to the terminal " +// "is missing."); reset(); - receiveData( translatorError.toLatin1().constData() , translatorError.count() ); +// receiveData(translatorError.toAscii().constData(), translatorError.count()); } } @@ -984,7 +1076,7 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event ) // Character Set Conversion ------------------------------------------------ -- -/* +/* The processing contains a VT100 specific code translation layer. It's still in use and mainly responsible for the line drawing graphics. @@ -995,7 +1087,7 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event ) in the pipeline. It only applies to tokens, which represent plain characters. - This conversion it eventually continued in TerminalDisplay.C, since + This conversion it eventually continued in TerminalDisplay.C, since it might involve VT100 enhanced fonts, which have these particular glyphs allocated in (0x00-0x1f) in their code page. */ @@ -1006,9 +1098,9 @@ void Vt102Emulation::sendKeyEvent( QKeyEvent* event ) unsigned short Vt102Emulation::applyCharset(unsigned short c) { - if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c-0x5f]; - if (CHARSET.pound && c == '#' ) return 0xa3; //This mode is obsolete - return c; + if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c - 0x5f]; + if (CHARSET.pound && c == '#') return 0xa3; //This mode is obsolete + return c; } /* @@ -1021,31 +1113,31 @@ unsigned short Vt102Emulation::applyCharset(unsigned short c) void Vt102Emulation::resetCharset(int scrno) { - _charset[scrno].cu_cs = 0; - strncpy(_charset[scrno].charset,"BBBB",4); - _charset[scrno].sa_graphic = false; - _charset[scrno].sa_pound = false; - _charset[scrno].graphic = false; - _charset[scrno].pound = false; + _charset[scrno].cu_cs = 0; + qstrncpy(_charset[scrno].charset, "BBBB", 4); + _charset[scrno].sa_graphic = false; + _charset[scrno].sa_pound = false; + _charset[scrno].graphic = false; + _charset[scrno].pound = false; } void Vt102Emulation::setCharset(int n, int cs) // on both screens. { - _charset[0].charset[n&3] = cs; useCharset(_charset[0].cu_cs); - _charset[1].charset[n&3] = cs; useCharset(_charset[1].cu_cs); + _charset[0].charset[n & 3] = cs; useCharset(_charset[0].cu_cs); + _charset[1].charset[n & 3] = cs; useCharset(_charset[1].cu_cs); } void Vt102Emulation::setAndUseCharset(int n, int cs) { - CHARSET.charset[n&3] = cs; - useCharset(n&3); + CHARSET.charset[n & 3] = cs; + useCharset(n & 3); } void Vt102Emulation::useCharset(int n) { - CHARSET.cu_cs = n&3; - CHARSET.graphic = (CHARSET.charset[n&3] == '0'); - CHARSET.pound = (CHARSET.charset[n&3] == 'A'); //This mode is obsolete + CHARSET.cu_cs = n & 3; + CHARSET.graphic = (CHARSET.charset[n & 3] == '0'); + CHARSET.pound = (CHARSET.charset[n & 3] == 'A'); //This mode is obsolete } void Vt102Emulation::setDefaultMargins() @@ -1056,25 +1148,25 @@ void Vt102Emulation::setDefaultMargins() void Vt102Emulation::setMargins(int t, int b) { - _screen[0]->setMargins(t, b); - _screen[1]->setMargins(t, b); + _screen[0]->setMargins(t, b); + _screen[1]->setMargins(t, b); } void Vt102Emulation::saveCursor() { - CHARSET.sa_graphic = CHARSET.graphic; - CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete - // we are not clear about these - //sa_charset = charsets[cScreen->_charset]; - //sa_charset_num = cScreen->_charset; - _currentScreen->saveCursor(); + CHARSET.sa_graphic = CHARSET.graphic; + CHARSET.sa_pound = CHARSET.pound; //This mode is obsolete + // we are not clear about these + //sa_charset = charsets[cScreen->_charset]; + //sa_charset_num = cScreen->_charset; + _currentScreen->saveCursor(); } void Vt102Emulation::restoreCursor() { - CHARSET.graphic = CHARSET.sa_graphic; - CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete - _currentScreen->restoreCursor(); + CHARSET.graphic = CHARSET.sa_graphic; + CHARSET.pound = CHARSET.sa_pound; //This mode is obsolete + _currentScreen->restoreCursor(); } /* ------------------------------------------------------------------------- */ @@ -1099,27 +1191,30 @@ void Vt102Emulation::restoreCursor() void Vt102Emulation::resetModes() { - // MODE_Allow132Columns is not reset here - // to match Xterm's behaviour (see Xterm's VTReset() function) + // MODE_Allow132Columns is not reset here + // to match Xterm's behavior (see Xterm's VTReset() function) - resetMode(MODE_132Columns); saveMode(MODE_132Columns); - resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000); - resetMode(MODE_Mouse1001); saveMode(MODE_Mouse1001); - resetMode(MODE_Mouse1002); saveMode(MODE_Mouse1002); - resetMode(MODE_Mouse1003); saveMode(MODE_Mouse1003); + resetMode(MODE_132Columns); saveMode(MODE_132Columns); + resetMode(MODE_Mouse1000); saveMode(MODE_Mouse1000); + resetMode(MODE_Mouse1001); saveMode(MODE_Mouse1001); + resetMode(MODE_Mouse1002); saveMode(MODE_Mouse1002); + resetMode(MODE_Mouse1003); saveMode(MODE_Mouse1003); + resetMode(MODE_Mouse1005); saveMode(MODE_Mouse1005); + resetMode(MODE_Mouse1006); saveMode(MODE_Mouse1006); + resetMode(MODE_Mouse1015); saveMode(MODE_Mouse1015); + resetMode(MODE_BracketedPaste); saveMode(MODE_BracketedPaste); - resetMode(MODE_AppScreen); saveMode(MODE_AppScreen); - resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys); - resetMode(MODE_AppKeyPad); saveMode(MODE_AppKeyPad); - resetMode(MODE_NewLine); - setMode(MODE_Ansi); + resetMode(MODE_AppScreen); saveMode(MODE_AppScreen); + resetMode(MODE_AppCuKeys); saveMode(MODE_AppCuKeys); + resetMode(MODE_AppKeyPad); saveMode(MODE_AppKeyPad); + resetMode(MODE_NewLine); + setMode(MODE_Ansi); } void Vt102Emulation::setMode(int m) { - _currentModes.mode[m] = true; - switch (m) - { + _currentModes.mode[m] = true; + switch (m) { case MODE_132Columns: if (getMode(MODE_Allow132Columns)) clearScreenAndSetColumns(132); @@ -1130,101 +1225,135 @@ void Vt102Emulation::setMode(int m) case MODE_Mouse1001: case MODE_Mouse1002: case MODE_Mouse1003: - emit programUsesMouseChanged(false); - break; + emit programUsesMouseChanged(false); + break; - case MODE_AppScreen : _screen[1]->clearSelection(); - setScreen(1); - break; - } - if (m < MODES_SCREEN || m == MODE_NewLine) - { - _screen[0]->setMode(m); - _screen[1]->setMode(m); - } + case MODE_BracketedPaste: + //emit programBracketedPasteModeChanged(true); + break; + + case MODE_AppScreen : + _screen[1]->clearSelection(); + setScreen(1); + break; + } + // FIXME: Currently this has a redundant condition as MODES_SCREEN is 6 + // and MODE_NewLine is 5 + if (m < MODES_SCREEN || m == MODE_NewLine) { + _screen[0]->setMode(m); + _screen[1]->setMode(m); + } } void Vt102Emulation::resetMode(int m) { - _currentModes.mode[m] = false; - switch (m) - { + _currentModes.mode[m] = false; + switch (m) { case MODE_132Columns: if (getMode(MODE_Allow132Columns)) clearScreenAndSetColumns(80); break; - case MODE_Mouse1000 : + case MODE_Mouse1000 : case MODE_Mouse1001 : case MODE_Mouse1002 : case MODE_Mouse1003 : - emit programUsesMouseChanged(true); - break; + emit programUsesMouseChanged(true); + break; - case MODE_AppScreen : + case MODE_BracketedPaste: + //emit programBracketedPasteModeChanged(false); + break; + + case MODE_AppScreen : _screen[0]->clearSelection(); setScreen(0); - break; - } - if (m < MODES_SCREEN || m == MODE_NewLine) - { - _screen[0]->resetMode(m); - _screen[1]->resetMode(m); - } + break; + } + // FIXME: Currently this has a redundant condition as MODES_SCREEN is 6 + // and MODE_NewLine is 5 + if (m < MODES_SCREEN || m == MODE_NewLine) { + _screen[0]->resetMode(m); + _screen[1]->resetMode(m); + } } void Vt102Emulation::saveMode(int m) { - _savedModes.mode[m] = _currentModes.mode[m]; + _savedModes.mode[m] = _currentModes.mode[m]; } void Vt102Emulation::restoreMode(int m) { - if (_savedModes.mode[m]) - setMode(m); - else - resetMode(m); + if (_savedModes.mode[m]) + setMode(m); + else + resetMode(m); } bool Vt102Emulation::getMode(int m) { - return _currentModes.mode[m]; + return _currentModes.mode[m]; } char Vt102Emulation::eraseChar() const { - KeyboardTranslator::Entry entry = _keyTranslator->findEntry( - Qt::Key_Backspace, - 0, - 0); - if ( entry.text().count() > 0 ) - return entry.text()[0]; - else - return '\b'; + KeyboardTranslator::Entry entry = _keyTranslator->findEntry( + Qt::Key_Backspace, + 0, + 0); + if (entry.text().count() > 0) + return entry.text()[0]; + else + return '\b'; } +#if 0 // print contents of the scan buffer static void hexdump(int* s, int len) -{ int i; - for (i = 0; i < len; i++) - { - if (s[i] == '\\') - printf("\\\\"); - else - if ((s[i]) > 32 && s[i] < 127) - printf("%c",s[i]); - else - printf("\\%04x(hex)",s[i]); - } +{ + int i; + for (i = 0; i < len; i++) { + if (s[i] == '\\') + printf("\\\\"); + else if ((s[i]) > 32 && s[i] < 127) + printf("%c", s[i]); + else + printf("\\%04x(hex)", s[i]); + } +} +#endif + +// return contents of the scan buffer +static QString hexdump2(int* s, int len) +{ + int i; + char dump[128]; + QString returnDump; + + for (i = 0; i < len; i++) { + if (s[i] == '\\') + snprintf(dump, sizeof(dump), "%s", "\\\\"); + else if ((s[i]) > 32 && s[i] < 127) + snprintf(dump, sizeof(dump), "%c", s[i]); + else + snprintf(dump, sizeof(dump), "\\%04x(hex)", s[i]); + returnDump.append(QString(dump)); + } + return returnDump; } void Vt102Emulation::reportDecodingError() { - if (tokenBufferPos == 0 || ( tokenBufferPos == 1 && (tokenBuffer[0] & 0xff) >= 32) ) - return; - printf("Undecodable sequence: "); - hexdump(tokenBuffer,tokenBufferPos); - printf("\n"); + if (tokenBufferPos == 0 || (tokenBufferPos == 1 && (tokenBuffer[0] & 0xff) >= 32)) + return; + +// printf("Undecodable sequence: "); +// hexdump(tokenBuffer, tokenBufferPos); +// printf("\n"); + + QString outputError = QString("Undecodable sequence: "); + outputError.append(hexdump2(tokenBuffer, tokenBufferPos)); + //kDebug() << outputError; } //#include "Vt102Emulation.moc" - diff --git a/konsole-qml-plugin/src/Vt102Emulation.h b/konsole-qml-plugin/src/Vt102Emulation.h index 9dc6f6e..070672f 100644 --- a/konsole-qml-plugin/src/Vt102Emulation.h +++ b/konsole-qml-plugin/src/Vt102Emulation.h @@ -1,6 +1,6 @@ /* This file is part of Konsole, an X terminal. - + Copyright 2007-2008 by Robert Knight Copyright 1997,1998 by Lars Doelle @@ -23,168 +23,169 @@ #ifndef VT102EMULATION_H #define VT102EMULATION_H -// Standard Library -#include -// Qt -#include +// Qt #include -#include // Konsole #include "Emulation.h" #include "Screen.h" -#include "ScreenWindow.h" -#include "TerminalDisplay.h" + +class QTimer; +class QKeyEvent; #define MODE_AppScreen (MODES_SCREEN+0) // Mode #1 #define MODE_AppCuKeys (MODES_SCREEN+1) // Application cursor keys (DECCKM) -#define MODE_AppKeyPad (MODES_SCREEN+2) // +#define MODE_AppKeyPad (MODES_SCREEN+2) // #define MODE_Mouse1000 (MODES_SCREEN+3) // Send mouse X,Y position on press and release #define MODE_Mouse1001 (MODES_SCREEN+4) // Use Hilight mouse tracking #define MODE_Mouse1002 (MODES_SCREEN+5) // Use cell motion mouse tracking -#define MODE_Mouse1003 (MODES_SCREEN+6) // Use all motion mouse tracking -#define MODE_Ansi (MODES_SCREEN+7) // Use US Ascii for character sets G0-G3 (DECANM) -#define MODE_132Columns (MODES_SCREEN+8) // 80 <-> 132 column mode switch (DECCOLM) -#define MODE_Allow132Columns (MODES_SCREEN+9) // Allow DECCOLM mode -#define MODE_total (MODES_SCREEN+10) +#define MODE_Mouse1003 (MODES_SCREEN+6) // Use all motion mouse tracking +#define MODE_Mouse1005 (MODES_SCREEN+7) // Xterm-style extended coordinates +#define MODE_Mouse1006 (MODES_SCREEN+8) // 2nd Xterm-style extended coordinates +#define MODE_Mouse1015 (MODES_SCREEN+9) // Urxvt-style extended coordinates +#define MODE_Ansi (MODES_SCREEN+10) // Use US Ascii for character sets G0-G3 (DECANM) +#define MODE_132Columns (MODES_SCREEN+11) // 80 <-> 132 column mode switch (DECCOLM) +#define MODE_Allow132Columns (MODES_SCREEN+12) // Allow DECCOLM mode +#define MODE_BracketedPaste (MODES_SCREEN+13) // Xterm-style bracketed paste mode +#define MODE_total (MODES_SCREEN+14) - -struct CharCodes +namespace Konsole { - // coding info - char charset[4]; // - int cu_cs; // actual charset. - bool graphic; // Some VT100 tricks - bool pound ; // Some VT100 tricks - bool sa_graphic; // saved graphic - bool sa_pound; // saved pound +extern unsigned short vt100_graphics[32]; + +struct CharCodes { + // coding info + char charset[4]; // + int cu_cs; // actual charset. + bool graphic; // Some VT100 tricks + bool pound; // Some VT100 tricks + bool sa_graphic; // saved graphic + bool sa_pound; // saved pound }; /** * Provides an xterm compatible terminal emulation based on the DEC VT102 terminal. * A full description of this terminal can be found at http://vt100.net/docs/vt102-ug/ - * - * In addition, various additional xterm escape sequences are supported to provide + * + * In addition, various additional xterm escape sequences are supported to provide * features such as mouse input handling. * See http://rtfm.etla.org/xterm/ctlseq.html for a description of xterm's escape - * sequences. + * sequences. * */ class Vt102Emulation : public Emulation -{ -Q_OBJECT +{ + Q_OBJECT public: - /** Constructs a new emulation */ - Vt102Emulation(); - ~Vt102Emulation(); - - // reimplemented from Emulation - virtual void clearEntireScreen(); - virtual void reset(); - virtual char eraseChar() const; - -public slots: - // reimplemented from Emulation - virtual void sendString(const char*,int length = -1); - virtual void sendText(const QString& text); - virtual void sendKeyEvent(QKeyEvent*); - virtual void sendMouseEvent(int buttons, int column, int line, int eventType); - + /** Constructs a new emulation */ + Vt102Emulation(); + ~Vt102Emulation(); + + // reimplemented from Emulation + virtual void clearEntireScreen(); + virtual void reset(); + virtual char eraseChar() const; + +public slots: + // reimplemented from Emulation + virtual void sendString(const char*, int length = -1); + virtual void sendText(const QString& text); + virtual void sendKeyEvent(QKeyEvent*); + virtual void sendMouseEvent(int buttons, int column, int line, int eventType); + protected: - // reimplemented from Emulation - virtual void setMode(int mode); - virtual void resetMode(int mode); - virtual void receiveChar(int cc); - + // reimplemented from Emulation + virtual void setMode(int mode); + virtual void resetMode(int mode); + virtual void receiveChar(int cc); + private slots: - //causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates - //used to buffer multiple title updates - void updateTitle(); + //causes changeTitle() to be emitted for each (int,QString) pair in pendingTitleUpdates + //used to buffer multiple title updates + void updateTitle(); private: - unsigned short applyCharset(unsigned short c); - void setCharset(int n, int cs); - void useCharset(int n); - void setAndUseCharset(int n, int cs); - void saveCursor(); - void restoreCursor(); - void resetCharset(int scrno); + unsigned short applyCharset(unsigned short c); + void setCharset(int n, int cs); + void useCharset(int n); + void setAndUseCharset(int n, int cs); + void saveCursor(); + void restoreCursor(); + void resetCharset(int scrno); - void setMargins(int top, int bottom); - //set margins for all screens back to their defaults - void setDefaultMargins(); + void setMargins(int top, int bottom); + //set margins for all screens back to their defaults + void setDefaultMargins(); - // returns true if 'mode' is set or false otherwise - bool getMode (int mode); - // saves the current boolean value of 'mode' - void saveMode (int mode); - // restores the boolean value of 'mode' - void restoreMode(int mode); - // resets all modes - // (except MODE_Allow132Columns) - void resetModes(); + // returns true if 'mode' is set or false otherwise + bool getMode(int mode); + // saves the current boolean value of 'mode' + void saveMode(int mode); + // restores the boolean value of 'mode' + void restoreMode(int mode); + // resets all modes + // (except MODE_Allow132Columns) + void resetModes(); - void resetTokenizer(); - #define MAX_TOKEN_LENGTH 80 - void addToCurrentToken(int cc); - int tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow? - int tokenBufferPos; + void resetTokenizer(); +#define MAX_TOKEN_LENGTH 256 // Max length of tokens (e.g. window title) + void addToCurrentToken(int cc); + int tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow? + int tokenBufferPos; #define MAXARGS 15 - void addDigit(int dig); - void addArgument(); - int argv[MAXARGS]; - int argc; - void initTokenizer(); + void addDigit(int dig); + void addArgument(); + int argv[MAXARGS]; + int argc; + void initTokenizer(); - // Set of flags for each of the ASCII characters which indicates - // what category they fall into (printable character, control, digit etc.) - // for the purposes of decoding terminal output - int charClass[256]; + // Set of flags for each of the ASCII characters which indicates + // what category they fall into (printable character, control, digit etc.) + // for the purposes of decoding terminal output + int charClass[256]; - void reportDecodingError(); + void reportDecodingError(); - void processToken(int code, int p, int q); - void processWindowAttributeChange(); + void processToken(int code, int p, int q); + void processWindowAttributeChange(); - void reportTerminalType(); - void reportSecondaryAttributes(); - void reportStatus(); - void reportAnswerBack(); - void reportCursorPosition(); - void reportTerminalParms(int p); + void reportTerminalType(); + void reportSecondaryAttributes(); + void reportStatus(); + void reportAnswerBack(); + void reportCursorPosition(); + void reportTerminalParms(int p); - void onScrollLock(); - void scrollLock(const bool lock); + // clears the screen and resizes it to the specified + // number of columns + void clearScreenAndSetColumns(int columnCount); - // clears the screen and resizes it to the specified - // number of columns - void clearScreenAndSetColumns(int columnCount); + CharCodes _charset[2]; - CharCodes _charset[2]; + class TerminalState + { + public: + // Initializes all modes to false + TerminalState() { + memset(&mode, false, MODE_total * sizeof(bool)); + } - class TerminalState - { - public: - // Initializes all modes to false - TerminalState() - { memset(&mode,false,MODE_total * sizeof(bool)); } + bool mode[MODE_total]; + }; - bool mode[MODE_total]; - }; + TerminalState _currentModes; + TerminalState _savedModes; - TerminalState _currentModes; - TerminalState _savedModes; - - //hash table and timer for buffering calls to the session instance - //to update the name of the session - //or window title. - //these calls occur when certain escape sequences are seen in the - //output from the terminal - QHash _pendingTitleUpdates; - QTimer* _titleUpdateTimer; + //hash table and timer for buffering calls to the session instance + //to update the name of the session + //or window title. + //these calls occur when certain escape sequences are seen in the + //output from the terminal + QHash _pendingTitleUpdates; + QTimer* _titleUpdateTimer; }; - +} #endif // VT102EMULATION_H