File indexing completed on 2024-04-21 09:42:21
0001 /* 0002 SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com> 0003 SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef EMULATION_H 0009 #define EMULATION_H 0010 0011 // Qt 0012 #include <QSize> 0013 #include <QTextCodec> 0014 #include <QTimer> 0015 0016 // Konsole 0017 #include "Enumeration.h" 0018 #include "konsoleprivate_export.h" 0019 #include "terminalDisplay/TerminalDisplay.h" 0020 0021 #include <memory> 0022 0023 class QKeyEvent; 0024 0025 namespace Konsole 0026 { 0027 class KeyboardTranslator; 0028 class HistoryType; 0029 class Screen; 0030 class ScreenWindow; 0031 class TerminalCharacterDecoder; 0032 0033 /** 0034 * Base class for terminal emulation back-ends. 0035 * 0036 * The back-end is responsible for decoding an incoming character stream and 0037 * producing an output image of characters. 0038 * 0039 * When input from the terminal is received, the receiveData() slot should be called with 0040 * the data which has arrived. The emulation will process the data and update the 0041 * screen image accordingly. The codec used to decode the incoming character stream 0042 * into the unicode characters used internally can be specified using setCodec() 0043 * 0044 * The size of the screen image can be specified by calling setImageSize() with the 0045 * desired number of lines and columns. When new lines are added, old content 0046 * is moved into a history store, which can be set by calling setHistory(). 0047 * 0048 * The screen image can be accessed by creating a ScreenWindow onto this emulation 0049 * by calling createWindow(). Screen windows provide access to a section of the 0050 * output. Each screen window covers the same number of lines and columns as the 0051 * image size returned by imageSize(). The screen window can be moved up and down 0052 * and provides transparent access to both the current on-screen image and the 0053 * previous output. The screen windows emit an outputChanged signal 0054 * when the section of the image they are looking at changes. 0055 * Graphical views can then render the contents of a screen window, listening for notifications 0056 * of output changes from the screen window which they are associated with and updating 0057 * accordingly. 0058 * 0059 * The emulation also is also responsible for converting input from the connected views such 0060 * as keypresses and mouse activity into a character string which can be sent 0061 * to the terminal program. Key presses can be processed by calling the sendKeyEvent() slot, 0062 * while mouse events can be processed using the sendMouseEvent() slot. When the character 0063 * stream has been produced, the emulation will emit a sendData() signal with a pointer 0064 * to the character buffer. This data should be fed to the standard input of the terminal 0065 * process. The translation of key presses into an output character stream is performed 0066 * using a lookup in a set of key bindings which map key sequences to output 0067 * character sequences. The name of the key bindings set used can be specified using 0068 * setKeyBindings() 0069 * 0070 * The emulation maintains certain state information which changes depending on the 0071 * input received. The emulation can be reset back to its starting state by calling 0072 * reset(). 0073 * 0074 * The emulation also maintains an activity state, which specifies whether 0075 * terminal is currently active ( when data is received ), normal 0076 * ( when the terminal is idle or receiving user input ) or trying 0077 * to alert the user ( also known as a "Bell" event ). The stateSet() signal 0078 * is emitted whenever the activity state is set. This can be used to determine 0079 * how long the emulation has been active/idle for and also respond to 0080 * a 'bell' event in different ways. 0081 */ 0082 class KONSOLEPRIVATE_EXPORT Emulation : public QObject 0083 { 0084 Q_OBJECT 0085 0086 public: 0087 /** Constructs a new terminal emulation */ 0088 Emulation(); 0089 ~Emulation() override; 0090 0091 /** 0092 * Creates a new window onto the output from this emulation. The contents 0093 * of the window are then rendered by views which are set to use this window using the 0094 * TerminalDisplay::setScreenWindow() method. 0095 */ 0096 ScreenWindow *createWindow(); 0097 0098 /** 0099 * Associates a TerminalDisplay with this emulation. 0100 */ 0101 void setCurrentTerminalDisplay(TerminalDisplay *display); 0102 0103 /** Returns the size of the screen image which the emulation produces */ 0104 QSize imageSize() const; 0105 0106 /** 0107 * Returns the total number of lines, including those stored in the history. 0108 */ 0109 int lineCount() const; 0110 0111 /** 0112 * Sets the history store used by this emulation. When new lines 0113 * are added to the output, older lines at the top of the screen are transferred to a history 0114 * store. 0115 * 0116 * The number of lines which are kept and the storage location depend on the 0117 * type of store. 0118 */ 0119 void setHistory(const HistoryType &); 0120 /** Returns the history store used by this emulation. See setHistory() */ 0121 const HistoryType &history() const; 0122 /** Clears the history scroll. */ 0123 virtual void clearHistory(); 0124 0125 /** 0126 * Copies the output history from @p startLine to @p endLine 0127 * into @p stream, using @p decoder to convert the terminal 0128 * characters into text. 0129 * 0130 * @param decoder A decoder which converts lines of terminal characters with 0131 * appearance attributes into output text. PlainTextDecoder is the most commonly 0132 * used decoder. 0133 * @param startLine Index of first line to copy 0134 * @param endLine Index of last line to copy 0135 */ 0136 virtual void writeToStream(TerminalCharacterDecoder *decoder, int startLine, int endLine); 0137 0138 /** Returns the codec used to decode incoming characters. See setCodec() */ 0139 const QTextCodec *codec() const 0140 { 0141 return _codec; 0142 } 0143 0144 /** Sets the codec used to decode incoming characters. */ 0145 void setCodec(const QTextCodec *); 0146 0147 /** 0148 * Convenience method. 0149 * Returns true if the current codec used to decode incoming 0150 * characters is UTF-8 0151 */ 0152 bool utf8() const 0153 { 0154 Q_ASSERT(_codec); 0155 return _codec->mibEnum() == 106; 0156 } 0157 0158 /** Returns the special character used for erasing character. */ 0159 virtual char eraseChar() const; 0160 0161 /** 0162 * Sets the key bindings used to key events 0163 * ( received through sendKeyEvent() ) into character 0164 * streams to send to the terminal. 0165 */ 0166 void setKeyBindings(const QString &name); 0167 /** 0168 * Returns the name of the emulation's current key bindings. 0169 * See setKeyBindings() 0170 */ 0171 QString keyBindings() const; 0172 0173 /** 0174 * Copies the current image into the history and clears the screen. 0175 */ 0176 virtual void clearEntireScreen() = 0; 0177 0178 /** Resets the state of the terminal. 0179 * 0180 * @param softReset The reset was initiated by DECSTR 0181 * @param preservePrompt Try to preserve the command prompt */ 0182 virtual void reset(bool softReset = false, bool preservePrompt = false) = 0; 0183 0184 /** 0185 * Returns true if the active terminal program is interested in Mouse 0186 * Tracking events. 0187 * 0188 * The programRequestsMouseTracking() signal is emitted when a program 0189 * indicates it's interested in Mouse Tracking events. 0190 * 0191 * See MODE_Mouse100{0,1,2,3} in Vt102Emulation. 0192 */ 0193 bool programUsesMouseTracking() const; 0194 0195 bool programBracketedPasteMode() const; 0196 0197 public Q_SLOTS: 0198 0199 /** Change the size of the emulation's image */ 0200 virtual void setImageSize(int lines, int columns); 0201 0202 /** 0203 * Interprets a sequence of characters and sends the result to the terminal. 0204 * This is equivalent to calling sendKeyEvent() for each character in @p text in succession. 0205 */ 0206 virtual void sendText(const QString &text) = 0; 0207 0208 /** 0209 * Interprets a key press event and emits the sendData() signal with 0210 * the resulting character stream. 0211 */ 0212 virtual void sendKeyEvent(QKeyEvent *); 0213 0214 /** 0215 * Converts information about a mouse event into an xterm-compatible escape 0216 * sequence and emits the character sequence via sendData() 0217 */ 0218 virtual void sendMouseEvent(int buttons, int column, int line, int eventType) = 0; 0219 0220 /** 0221 * Sends a string of characters to the foreground terminal process. 0222 * 0223 * @param string The characters to send. 0224 */ 0225 virtual void sendString(const QByteArray &string) = 0; 0226 0227 /** 0228 * Processes an incoming stream of characters. receiveData() decodes the incoming 0229 * character buffer using the current codec(), and then calls receiveChar() for 0230 * each unicode character in the resulting buffer. 0231 * 0232 * receiveData() also starts a timer which causes the outputChanged() signal 0233 * to be emitted when it expires. The timer allows multiple updates in quick 0234 * succession to be buffered into a single outputChanged() signal emission. 0235 * 0236 * @param text A string of characters received from the terminal program. 0237 * @param length The length of @p text 0238 */ 0239 void receiveData(const char *text, int length); 0240 0241 /** 0242 * Sends information about the focus event to the terminal. 0243 */ 0244 virtual void focusChanged(bool focused) = 0; 0245 0246 void setPeekPrimary(const bool doPeek); 0247 0248 Q_SIGNALS: 0249 0250 /** 0251 * Emitted when a buffer of data is ready to send to the 0252 * standard input of the terminal. 0253 * 0254 * @param data The buffer of data ready to be sent 0255 */ 0256 void sendData(const QByteArray &data); 0257 0258 /** 0259 * Requests that the pty used by the terminal process 0260 * be set to UTF 8 mode. 0261 * 0262 * Refer to the IUTF8 entry in termios(3) for more information. 0263 */ 0264 void useUtf8Request(bool); 0265 0266 /** 0267 * Emitted when bell appeared 0268 */ 0269 void bell(); 0270 0271 /** 0272 * Emitted when the special sequence indicating the request for data 0273 * transmission through ZModem protocol is detected. 0274 */ 0275 void zmodemDownloadDetected(); 0276 void zmodemUploadDetected(); 0277 0278 /** 0279 * This is emitted when the program (typically editors and other full-screen 0280 * applications, ones that take up the whole terminal display), running in 0281 * the terminal indicates whether or not it is interested in Mouse Tracking 0282 * events. This is an XTerm extension, for more information have a look at: 0283 * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Mouse-Tracking 0284 * 0285 * @param usesMouseTracking This will be true if the program is interested 0286 * in Mouse Tracking events or false otherwise. 0287 */ 0288 void programRequestsMouseTracking(bool usesMouseTracking); 0289 0290 void enableAlternateScrolling(bool enable); 0291 0292 void programBracketedPasteModeChanged(bool bracketedPasteMode); 0293 0294 /** 0295 * Emitted when the contents of the screen image change. 0296 * The emulation buffers the updates from successive image changes, 0297 * and only emits outputChanged() at sensible intervals when 0298 * there is a lot of terminal activity. 0299 * 0300 * Normally there is no need for objects other than the screen windows 0301 * created with createWindow() to listen for this signal. 0302 * 0303 * ScreenWindow objects created using createWindow() will emit their 0304 * own outputChanged() signal in response to this signal. 0305 */ 0306 void outputChanged(); 0307 0308 /** 0309 * Emitted when the program running in the terminal wishes to update 0310 * certain session attributes. This allows terminal programs to customize 0311 * certain aspects of the terminal emulation display. 0312 * 0313 * This signal is emitted when the escape sequence "\033]ARG;VALUE\007" 0314 * is received in an input string, where ARG is a number specifying 0315 * what should be changed and VALUE is a string specifying the new value. 0316 * 0317 * @param attribute Specifies which session attribute to change: 0318 * <ul> 0319 * <li> 0 - Set window icon text and session title to @p newValue</li> 0320 * <li> 1 - Set window icon text to @p newValue</li> 0321 * <li> 2 - Set session title to @p newValue</li> 0322 * <li> 11 - Set the session's default background color to @p newValue, 0323 * where @p newValue can be an HTML-style string ("#RRGGBB") or a 0324 * named color (e.g. 'red', 'blue'). For more details see: 0325 * https://doc.qt.io/qt-5/qcolor.html#setNamedColor 0326 * </li> 0327 * <li> 31 - Supposedly treats @p newValue as a URL and opens it (NOT 0328 * IMPLEMENTED) 0329 * </li> 0330 * <li> 32 - Sets the icon associated with the session. @p newValue 0331 * is the name of the icon to use, which can be the name of any 0332 * icon in the current KDE icon theme (eg: 'konsole', 'kate', 0333 * 'folder_home') 0334 * </li> 0335 * </ul> 0336 * @param newValue Specifies the new value of the session attribute 0337 */ 0338 void sessionAttributeChanged(int attribute, const QString &newValue); 0339 0340 /** 0341 * Emitted when the terminal emulator's size has changed 0342 */ 0343 void imageSizeChanged(int lineCount, int columnCount); 0344 0345 /** 0346 * Emitted when the setImageSize() is called on this emulation for 0347 * the first time. 0348 */ 0349 void imageSizeInitialized(); 0350 0351 /** 0352 * Emitted after receiving the escape sequence which asks to change 0353 * the terminal emulator's size 0354 */ 0355 void imageResizeRequest(const QSize &sizz); 0356 0357 /** 0358 * Emitted when the terminal program requests to change various properties 0359 * of the terminal display. 0360 * 0361 * A profile change command occurs when a special escape sequence, followed 0362 * by a string containing a series of name and value pairs is received. 0363 * This string can be parsed using a ProfileCommandParser instance. 0364 * 0365 * @param text A string expected to contain a series of key and value pairs in 0366 * the form: name=value;name2=value2 ... 0367 */ 0368 void profileChangeCommandReceived(const QString &text); 0369 0370 /** 0371 * Emitted when a flow control key combination ( Ctrl+S or Ctrl+Q ) is pressed. 0372 * @param suspendKeyPressed True if Ctrl+S was pressed to suspend output or Ctrl+Q to 0373 * resume output. 0374 */ 0375 void flowControlKeyPressed(bool suspendKeyPressed); 0376 0377 /** 0378 * Emitted when the active screen is switched, to indicate whether the primary 0379 * screen is in use. 0380 */ 0381 void primaryScreenInUse(bool use); 0382 0383 /** 0384 * Emitted when the text selection is changed 0385 */ 0386 void selectionChanged(const bool selectionEmpty); 0387 0388 /** 0389 * Emitted when terminal code requiring terminal's response received. 0390 */ 0391 void sessionAttributeRequest(int id, uint terminator); 0392 0393 /** 0394 * Emitted when Set Cursor Style (DECSCUSR) escape sequences are sent 0395 * to the terminal. 0396 * @p shape cursor shape 0397 * @p isBlinking if true, the cursor will be set to blink 0398 * @p customColor custom cursor color 0399 */ 0400 void setCursorStyleRequest(Enum::CursorShapeEnum shape = Enum::BlockCursor, bool isBlinking = false, const QColor &customColor = {}); 0401 0402 /** 0403 * Emitted when reset() is called to reset the cursor style to the 0404 * current profile cursor shape and blinking settings. 0405 */ 0406 void resetCursorStyleRequest(); 0407 0408 void toggleUrlExtractionRequest(); 0409 0410 protected: 0411 virtual void setMode(int mode) = 0; 0412 virtual void resetMode(int mode) = 0; 0413 0414 /** 0415 * Processes an incoming character. See receiveData() 0416 * @p c A unicode character code. 0417 */ 0418 virtual void receiveChars(const QVector<uint> &c); 0419 0420 /** 0421 * Sets the active screen. The terminal has two screens, primary and alternate. 0422 * The primary screen is used by default. When certain interactive programs such 0423 * as Vim are run, they trigger a switch to the alternate screen. 0424 * 0425 * @param index 0 to switch to the primary screen, or 1 to switch to the alternate screen 0426 */ 0427 void setScreen(int index); 0428 0429 enum EmulationCodec { 0430 LocaleCodec = 0, 0431 Utf8Codec = 1, 0432 }; 0433 0434 void setCodec(EmulationCodec codec); 0435 0436 QList<ScreenWindow *> _windows; 0437 0438 Screen *_currentScreen = nullptr; // pointer to the screen which is currently active, 0439 // this is one of the elements in the screen[] array 0440 0441 Screen *_screen[2]; // 0 = primary screen ( used by most programs, including the shell 0442 // scrollbars are enabled in this mode ) 0443 // 1 = alternate ( used by vi , emacs etc. 0444 // scrollbars are not enabled in this mode ) 0445 0446 // decodes an incoming C-style character stream into a unicode QString using 0447 // the current text codec. (this allows for rendering of non-ASCII characters in text files etc.) 0448 const QTextCodec *_codec = nullptr; 0449 std::unique_ptr<QTextDecoder> _decoder; 0450 const KeyboardTranslator *_keyTranslator = nullptr; // the keyboard layout 0451 0452 protected Q_SLOTS: 0453 /** 0454 * Schedules an update of attached views. 0455 * Repeated calls to bufferedUpdate() in close succession will result in only a single update, 0456 * much like the Qt buffered update of widgets. 0457 */ 0458 void bufferedUpdate(); 0459 0460 // used to emit the primaryScreenInUse(bool) signal 0461 void checkScreenInUse(); 0462 0463 // used to emit the selectionChanged(QString) signal 0464 void checkSelectedText(); 0465 0466 private Q_SLOTS: 0467 // triggered by timer, causes the emulation to send an updated screen image to each 0468 // view 0469 void showBulk(); 0470 0471 void setUsesMouseTracking(bool usesMouseTracking); 0472 0473 void bracketedPasteModeChanged(bool bracketedPasteMode); 0474 0475 private: 0476 void setScreenInternal(int index); 0477 Q_DISABLE_COPY(Emulation) 0478 0479 bool _usesMouseTracking = false; 0480 bool _bracketedPasteMode = false; 0481 QTimer _bulkTimer1{this}; 0482 QTimer _bulkTimer2{this}; 0483 bool _imageSizeInitialized = false; 0484 bool _peekingPrimary = false; 0485 int _activeScreenIndex = 0; 0486 }; 0487 } 0488 0489 #endif // ifndef EMULATION_H