diff --git a/src/Emulation.h b/src/Emulation.h --- a/src/Emulation.h +++ b/src/Emulation.h @@ -29,6 +29,7 @@ #include // Konsole +#include "Enumeration.h" #include "konsoleprivate_export.h" class QKeyEvent; @@ -429,6 +430,19 @@ */ void sessionAttributeRequest(int id); + /** + * Emitted when Set Cursor Style (DECSCUSR) escape sequences are sent + * to the terminal. + * @p shape cursor shape + * @p isBlinking if true, the cursor will be set to blink + */ + void setCursorStyleRequest(Enum::CursorShapeEnum shape = Enum::BlockCursor, bool isBlinking = false); + /** + * Emitted when reset() is called to reset the cursor style to the + * current profile cursor shape and blinking settings. + */ + void resetCursorStyleRequest(); + protected: virtual void setMode(int mode) = 0; virtual void resetMode(int mode) = 0; diff --git a/src/Session.cpp b/src/Session.cpp --- a/src/Session.cpp +++ b/src/Session.cpp @@ -325,6 +325,9 @@ connect(widget, &Konsole::TerminalDisplay::focusLost, _emulation, &Konsole::Emulation::focusLost); connect(widget, &Konsole::TerminalDisplay::focusGained, _emulation, &Konsole::Emulation::focusGained); + + connect(_emulation, &Konsole::Emulation::setCursorStyleRequest, widget, &Konsole::TerminalDisplay::setCursorStyle); + connect(_emulation, &Konsole::Emulation::resetCursorStyleRequest, widget, &Konsole::TerminalDisplay::resetCursorStyle); } void Session::viewDestroyed(QObject* view) diff --git a/src/TerminalDisplay.h b/src/TerminalDisplay.h --- a/src/TerminalDisplay.h +++ b/src/TerminalDisplay.h @@ -263,6 +263,18 @@ */ Enum::CursorShapeEnum keyboardCursorShape() const; + /** + * Sets the Cursor Style (DECSCUSR) via escape sequences + * @p shape cursor shape + * @p isBlinking if true, the cursor will be set to blink + */ + void setCursorStyle(Enum::CursorShapeEnum shape, bool isBlinking); + /** + * Resets the cursor style to the current profile cursor shape and + * blinking settings + */ + void resetCursorStyle(); + /** * Sets the color used to draw the keyboard cursor. * diff --git a/src/TerminalDisplay.cpp b/src/TerminalDisplay.cpp --- a/src/TerminalDisplay.cpp +++ b/src/TerminalDisplay.cpp @@ -768,6 +768,36 @@ { return _cursorShape; } + +void TerminalDisplay::setCursorStyle(Enum::CursorShapeEnum shape, bool isBlinking) +{ + setKeyboardCursorShape(shape); + + setBlinkingCursorEnabled(isBlinking); + + // when the cursor shape and blinking state are changed via the + // Set Cursor Style (DECSCUSR) escape sequences in vim, and if the + // cursor isn't set to blink, the cursor shape doesn't actually + // change until the cursor is moved by the user; calling update() + // makes the cursor shape get updated sooner. + if (!isBlinking) { + update(); + } +} +void TerminalDisplay::resetCursorStyle() +{ + if (sessionController() != nullptr) { + Profile::Ptr currentProfile = SessionManager::instance()->sessionProfile(sessionController()->session()); + + if (currentProfile != nullptr) { + Enum::CursorShapeEnum shape = static_cast(currentProfile->property(Profile::CursorShape)); + + setKeyboardCursorShape(shape); + setBlinkingCursorEnabled(currentProfile->blinkingCursorEnabled()); + } + } +} + void TerminalDisplay::setKeyboardCursorColor(const QColor& color) { _cursorColor = color; diff --git a/src/Vt102Emulation.cpp b/src/Vt102Emulation.cpp --- a/src/Vt102Emulation.cpp +++ b/src/Vt102Emulation.cpp @@ -107,6 +107,8 @@ setCodec(LocaleCodec); } + emit resetCursorStyleRequest(); + bufferedUpdate(); } @@ -154,6 +156,10 @@ - CSI_PS - Escape codes of the form '[' {Pn} ';' ... C - CSI_PR - Escape codes of the form '[' '?' {Pn} ';' ... C - CSI_PE - Escape codes of the form '[' '!' {Pn} ';' ... C + - CSI_SP - Escape codes of the form '[' ' ' C + (3rd field is a space) + - CSI_PSP - Escape codes of the form '[' '{Pn}' ' ' C + (4th field is a space) - VT52 - VT52 escape codes - - 'Y'{Pc}{Pc} @@ -216,6 +222,14 @@ { return token_construct(10, a, 0); } +constexpr int token_csi_sp(int a) +{ + return token_construct(11, a, 0); +} +constexpr int token_csi_psp(int a, int n) +{ + return token_construct(12, a, n); +} const int MAX_ARGUMENT = 4096; @@ -325,14 +339,17 @@ #define epp( ) (p >= 3 && s[2] == '?') #define epe( ) (p >= 3 && s[2] == '!') #define egt( ) (p >= 3 && s[2] == '>') +#define esp( ) (p >= 4 && s[2] == SP ) +#define epsp( ) (p >= 5 && s[3] == SP ) #define Xpe (tokenBufferPos >= 2 && tokenBuffer[1] == ']') #define Xte (Xpe && (cc == 7 || cc == 27)) #define ces(C) (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte) #define dcs (p >= 2 && s[0] == ESC && s[1] == 'P') #define CNTL(c) ((c)-'@') const int ESC = 27; const int DEL = 127; +const int SP = 32; // process an incoming unicode character void Vt102Emulation::receiveChar(int cc) @@ -372,6 +389,8 @@ if (lec(3,2,'?')) { return; } if (lec(3,2,'>')) { return; } if (lec(3,2,'!')) { return; } + if (lec(3,2,SP )) { return; } + if (lec(4,3,SP )) { return; } if (lun( )) { processToken(token_chr(), applyCharset(cc), 0); resetTokenizer(); return; } if (dcs ) { return; /* TODO We don't xterm DCS, so we just eat it */ } if (lec(2,0,ESC)) { processToken(token_esc(s[1]), 0, 0); resetTokenizer(); return; } @@ -388,6 +407,10 @@ } if (epe( )) { processToken(token_csi_pe(cc), 0, 0); resetTokenizer(); return; } + + if (esp ( )) { processToken(token_csi_sp(cc), 0, 0); resetTokenizer(); return; } + if (epsp( )) { processToken(token_csi_psp(cc, argv[0]), 0, 0); resetTokenizer(); return; } + if (ees(DIG)) { addDigit(cc-'0'); return; } if (eec(';')) { addArgument(); return; } for (int i = 0; i <= argc; i++) @@ -872,6 +895,17 @@ case token_csi_pr('s', 2004) : saveMode (MODE_BracketedPaste); break; //XTERM case token_csi_pr('r', 2004) : restoreMode (MODE_BracketedPaste); break; //XTERM + // Set Cursor Style (DECSCUSR), VT520, with the extra xterm sequences + // the first one is a special case, 'ESC[ q', which mimics 'ESC[1 q' + case token_csi_sp ('q' ) : emit setCursorStyleRequest(Enum::BlockCursor, true); break; + case token_csi_psp('q', 0) : emit setCursorStyleRequest(Enum::BlockCursor, true); break; + case token_csi_psp('q', 1) : emit setCursorStyleRequest(Enum::BlockCursor, true); break; + case token_csi_psp('q', 2) : emit setCursorStyleRequest(Enum::BlockCursor, false); break; + case token_csi_psp('q', 3) : emit setCursorStyleRequest(Enum::UnderlineCursor, true); break; + case token_csi_psp('q', 4) : emit setCursorStyleRequest(Enum::UnderlineCursor, false); break; + case token_csi_psp('q', 5) : emit setCursorStyleRequest(Enum::IBeamCursor, true); break; + case token_csi_psp('q', 6) : emit setCursorStyleRequest(Enum::IBeamCursor, false); break; + //FIXME: weird DEC reset sequence case token_csi_pe('p' ) : /* IGNORED: reset ( ) */ break;