File indexing completed on 2024-04-21 05:51:30

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 VT102EMULATION_H
0009 #define VT102EMULATION_H
0010 
0011 // Qt
0012 #include <QHash>
0013 #include <QMap>
0014 #include <QMediaPlayer>
0015 #include <QPair>
0016 #include <QVector>
0017 
0018 // Konsole
0019 #include "Emulation.h"
0020 #include "Screen.h"
0021 #include "keyboardtranslator/KeyboardTranslator.h"
0022 
0023 class QTimer;
0024 class QKeyEvent;
0025 
0026 #define MODE_AppCuKeys (MODES_SCREEN + 0) // Application cursor keys (DECCKM)
0027 #define MODE_AppKeyPad (MODES_SCREEN + 1) //
0028 #define MODE_Mouse1000 (MODES_SCREEN + 2) // Send mouse X,Y position on press and release
0029 #define MODE_Mouse1001 (MODES_SCREEN + 3) // Use Highlight mouse tracking
0030 #define MODE_Mouse1002 (MODES_SCREEN + 4) // Use cell motion mouse tracking
0031 #define MODE_Mouse1003 (MODES_SCREEN + 5) // Use all motion mouse tracking
0032 #define MODE_Mouse1005 (MODES_SCREEN + 6) // Xterm-style extended coordinates
0033 #define MODE_Mouse1006 (MODES_SCREEN + 7) // 2nd Xterm-style extended coordinates
0034 #define MODE_Mouse1007 (MODES_SCREEN + 8) // XTerm Alternate Scroll mode; also check AlternateScrolling profile property
0035 #define MODE_Mouse1015 (MODES_SCREEN + 9) // Urxvt-style extended coordinates
0036 #define MODE_Ansi (MODES_SCREEN + 10) // Use US Ascii for character sets G0-G3 (DECANM)
0037 #define MODE_132Columns (MODES_SCREEN + 11) // 80 <-> 132 column mode switch (DECCOLM)
0038 #define MODE_Allow132Columns (MODES_SCREEN + 12) // Allow DECCOLM mode
0039 #define MODE_BracketedPaste (MODES_SCREEN + 13) // Xterm-style bracketed paste mode
0040 #define MODE_Sixel (MODES_SCREEN + 14) // Xterm-style bracketed paste mode
0041 #define MODE_total (MODES_SCREEN + 15)
0042 
0043 namespace Konsole
0044 {
0045 extern unsigned short vt100_graphics[32];
0046 
0047 struct CharCodes {
0048     // coding info
0049     char charset[4]; //
0050     int cu_cs; // actual charset.
0051     bool graphic; // Some VT100 tricks
0052     bool pound; // Some VT100 tricks
0053     bool sa_graphic; // saved graphic
0054     bool sa_pound; // saved pound
0055 };
0056 
0057 /**
0058  * Provides an xterm compatible terminal emulation based on the DEC VT102 terminal.
0059  * A full description of this terminal can be found at https://vt100.net/docs/vt102-ug/
0060  *
0061  * In addition, various additional xterm escape sequences are supported to provide
0062  * features such as mouse input handling.
0063  * See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html for a description of xterm's escape
0064  * sequences.
0065  *
0066  */
0067 class KONSOLEPRIVATE_EXPORT Vt102Emulation : public Emulation
0068 {
0069     Q_OBJECT
0070 
0071 public:
0072     /** Constructs a new emulation */
0073     Vt102Emulation();
0074     ~Vt102Emulation() override;
0075 
0076     // reimplemented from Emulation
0077     void clearEntireScreen() override;
0078     void reset(bool softReset = false, bool preservePrompt = false) override;
0079     char eraseChar() const override;
0080 
0081 public Q_SLOTS:
0082     // reimplemented from Emulation
0083     void sendString(const QByteArray &string) override;
0084     void sendText(const QString &text) override;
0085     void sendKeyEvent(QKeyEvent *) override;
0086     void sendMouseEvent(int buttons, int column, int line, int eventType) override;
0087     void focusChanged(bool focused) override;
0088     void clearHistory() override;
0089 
0090 protected:
0091     // reimplemented from Emulation
0092     void setMode(int mode) override;
0093     void resetMode(int mode) override;
0094     void receiveChars(const QVector<uint> &chars) override;
0095 
0096 private Q_SLOTS:
0097     // Causes sessionAttributeChanged() to be emitted for each (int,QString)
0098     // pair in _pendingSessionAttributesUpdates.
0099     // Used to buffer multiple attribute updates in the current session
0100     void updateSessionAttributes();
0101     void deletePlayer(QMediaPlayer::MediaStatus);
0102 
0103 private:
0104     unsigned int applyCharset(uint c);
0105     void setCharset(int n, int cs);
0106     void useCharset(int n);
0107     void setAndUseCharset(int n, int cs);
0108     void saveCursor();
0109     void restoreCursor();
0110     void resetCharset(int scrno);
0111 
0112     void setMargins(int top, int bottom);
0113     // set margins for all screens back to their defaults
0114     void setDefaultMargins();
0115 
0116     // returns true if 'mode' is set or false otherwise
0117     bool getMode(int mode);
0118     // saves the current boolean value of 'mode'
0119     void saveMode(int mode);
0120     // restores the boolean value of 'mode'
0121     void restoreMode(int mode);
0122     // resets all modes
0123     // (except MODE_Allow132Columns)
0124     void resetModes();
0125 
0126     void resetTokenizer();
0127 #define MAX_TOKEN_LENGTH 256 // Max length of tokens (e.g. window title)
0128     void addToCurrentToken(uint cc);
0129     int tokenBufferPos;
0130 
0131 protected:
0132     char32_t tokenBuffer[MAX_TOKEN_LENGTH]; // FIXME: overflow?
0133 
0134 private:
0135 #define MAXARGS 16
0136     void addDigit(int dig);
0137     void addArgument();
0138     void addSub();
0139 
0140     struct subParam {
0141         int value[MAXARGS]; // value[0] unused, it would correspond to the containing param value
0142         int count;
0143     };
0144 
0145     struct {
0146         int value[MAXARGS];
0147         struct subParam sub[MAXARGS];
0148         int count;
0149         bool hasSubParams;
0150     } params = {};
0151 
0152     void initTokenizer();
0153 
0154     enum ParserStates {
0155         Ground,
0156         Escape,
0157         EscapeIntermediate,
0158         CsiEntry,
0159         CsiParam,
0160         CsiIntermediate,
0161         CsiIgnore,
0162         DcsEntry,
0163         DcsParam,
0164         DcsIntermediate,
0165         DcsPassthrough,
0166         DcsIgnore,
0167         OscString,
0168         SosPmApcString,
0169 
0170         Vt52Escape,
0171         Vt52CupRow,
0172         Vt52CupColumn,
0173     };
0174 
0175     enum {
0176         Sos,
0177         Pm,
0178         Apc,
0179     } _sosPmApc;
0180 
0181     enum osc {
0182         // https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-Operating-System-Commands
0183         ReportColors = 4,
0184         ResetColors = 104,
0185         // https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md
0186         SemanticPrompts = 133,
0187         // https://chromium.googlesource.com/apps/libapps/+/master/hterm/doc/ControlSequences.md#OSC
0188         Notification = 777,
0189         Image = 1337,
0190     };
0191 
0192     ParserStates _state = Ground;
0193     bool _ignore = false;
0194     int _nIntermediate = 0;
0195     unsigned char _intermediate[1];
0196 
0197     void switchState(const ParserStates newState, const uint cc);
0198     void esc_dispatch(const uint cc);
0199     void clear();
0200     void collect(const uint cc);
0201     void param(const uint cc);
0202     void csi_dispatch(const uint cc);
0203     void osc_start();
0204     void osc_put(const uint cc);
0205     void osc_end(const uint cc);
0206     void hook(const uint cc);
0207     void unhook();
0208     void put(const uint cc);
0209     void apc_start(const uint cc);
0210     void apc_put(const uint cc);
0211     void apc_end();
0212 
0213     // State machine for escape sequences containing large amount of data
0214     int tokenState;
0215     const char *tokenStateChange;
0216     int tokenPos;
0217     QByteArray tokenData;
0218 
0219     // Set of flags for each of the ASCII characters which indicates
0220     // what category they fall into (printable character, control, digit etc.)
0221     // for the purposes of decoding terminal output
0222     int charClass[256];
0223 
0224     QByteArray imageData;
0225     quint32 imageId;
0226     QMap<char, qint64> savedKeys;
0227 
0228 protected:
0229     virtual void reportDecodingError(int token);
0230 
0231     virtual void processToken(int code, int p, int q);
0232     virtual void processSessionAttributeRequest(const int tokenSize, const uint terminator);
0233     virtual void processChecksumRequest(int argc, int argv[]);
0234 
0235 private:
0236     void processGraphicsToken(int tokenSize);
0237 
0238     void sendGraphicsReply(const QString &params, const QString &error);
0239     void reportTerminalType();
0240     void reportTertiaryAttributes();
0241     void reportSecondaryAttributes();
0242     void reportVersion();
0243     void reportStatus();
0244     void reportAnswerBack();
0245     void reportCursorPosition();
0246     void reportPixelSize();
0247     void reportCellSize();
0248     void iTermReportCellSize();
0249     void reportSize();
0250     void reportColor(int c, QColor color);
0251     void reportTerminalParms(int p);
0252 
0253     void emulateUpDown(bool up, KeyboardTranslator::Entry entry, QByteArray &textToSend, int toCol = -1);
0254 
0255     // clears the screen and resizes it to the specified
0256     // number of columns
0257     void clearScreenAndSetColumns(int columnCount);
0258 
0259     CharCodes _charset[2];
0260 
0261     class TerminalState
0262     {
0263     public:
0264         // Initializes all modes to false
0265         TerminalState()
0266         {
0267             memset(&mode, 0, MODE_total * sizeof(bool));
0268         }
0269 
0270         bool mode[MODE_total];
0271     };
0272 
0273     TerminalState _currentModes;
0274     TerminalState _savedModes;
0275 
0276     // Hash table and timer for buffering calls to update certain session
0277     // attributes (e.g. the name of the session, window title).
0278     // These calls occur when certain escape sequences are detected in the
0279     // output from the terminal. See Emulation::sessionAttributeChanged()
0280     QHash<int, QString> _pendingSessionAttributesUpdates;
0281     QTimer *_sessionAttributesUpdateTimer;
0282 
0283     bool _reportFocusEvents;
0284 
0285     QColor colorTable[256];
0286 
0287     // Sixel:
0288 #define MAX_SIXEL_COLORS 256
0289 #define MAX_IMAGE_DIM 16384
0290     void sixelQuery(int query);
0291     bool processSixel(uint cc);
0292     void SixelModeEnable(int width, int height /*, bool preserveBackground*/);
0293     void SixelModeAbort();
0294     void SixelModeDisable();
0295     void SixelColorChangeRGB(const int index, int red, int green, int blue);
0296     void SixelColorChangeHSL(const int index, int hue, int saturation, int value);
0297     void SixelCharacterAdd(uint8_t character, int repeat = 1);
0298     bool m_SixelPictureDefinition = false;
0299     bool m_SixelStarted = false;
0300     QImage m_currentImage;
0301     int m_currentX = 0;
0302     int m_verticalPosition = 0;
0303     uint8_t m_currentColor = 0;
0304     bool m_preserveBackground = true;
0305     QPair<int, int> m_aspect = qMakePair(1, 1);
0306     bool m_SixelScrolling = true;
0307     QSize m_actualSize; // For efficiency reasons, we keep the image in memory larger than what the end result is
0308 
0309     // Kitty
0310     QHash<int, QPixmap> _graphicsImages;
0311     // For kitty graphics protocol - image cache
0312     int getFreeGraphicsImageId();
0313 
0314     QMediaPlayer *player;
0315 };
0316 
0317 }
0318 
0319 #endif // VT102EMULATION_H