From d69a767588f9bfbbb8ea873212f255c8faa82c06 Mon Sep 17 00:00:00 2001 From: xiaoming <2014500726@smail.xtu.edu.cn> Date: Sun, 12 Nov 2023 23:27:21 +0800 Subject: [PATCH] src:Add enhancements and fix issues in quardCRT The commit includes enhancements to the Windows terminal, such as the ability to use the Tab key for command completion, and fixes an issue with macOS shortcut keys. Additionally, the commit includes updates to various files related to child process information. Signed-off-by: xiaoming <2014500726@smail.xtu.edu.cn> --- CHANGELOG.md | 2 ++ lib/ptyqt/conptyprocess.cpp | 36 +++++++++++++++++++++++ lib/ptyqt/conptyprocess.h | 1 + lib/ptyqt/iptyprocess.h | 1 + lib/ptyqt/ptyqt.pri | 2 +- lib/ptyqt/unixptyprocess.cpp | 56 ++++++++++++++++++++++++++++++++---- lib/ptyqt/unixptyprocess.h | 1 + lib/ptyqt/winptyprocess.cpp | 36 +++++++++++++++++++++++ lib/ptyqt/winptyprocess.h | 1 + scripts/Profile.ps1 | 4 +++ src/mainwindow.cpp | 8 +++--- src/sessionswindow.cpp | 27 +++++++++++++++++ src/sessionswindow.h | 1 + 13 files changed, 166 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb251887..c8adf9c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ## [[Unrelease](https://github.com/QQxiaoming/quardCRT)] - 增加标签卡悬浮预览功能 +- windows终端增强,现在可以像linux一样使用Tab键选择补全命令 +- 修复macOS错误绑定了复制粘贴快捷键导致无法kill终端内进程问题 ## [[V0.2.5](https://github.com/QQxiaoming/quardCRT/releases/tag/V0.2.5)] - 2023-11-09 diff --git a/lib/ptyqt/conptyprocess.cpp b/lib/ptyqt/conptyprocess.cpp index 44158add..d99f30a1 100644 --- a/lib/ptyqt/conptyprocess.cpp +++ b/lib/ptyqt/conptyprocess.cpp @@ -1,6 +1,7 @@ #include "conptyprocess.h" #include #include +#include #include #include #include @@ -326,6 +327,41 @@ bool ConPtyProcess::hasChildProcess() return false; } +QList> ConPtyProcess::childProcessInfoList() +{ + QList> result; + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + if (snapshot == INVALID_HANDLE_VALUE) + return result; + + PROCESSENTRY32 pe; + pe.dwSize = sizeof(PROCESSENTRY32); + + if (Process32First(snapshot, &pe)) { + do { + if (pe.th32ParentProcessID == m_pid) { + // get full path + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe.th32ProcessID); + if (hProcess != NULL) + { + TCHAR szProcessName[MAX_PATH] = TEXT(""); + if (GetModuleFileNameExW(hProcess, NULL, szProcessName, MAX_PATH) != 0) + { + QPair pair = QPair(pe.th32ProcessID, QString::fromWCharArray(szProcessName)); + result.append(pair); + } + CloseHandle(hProcess); + } + } + } while (Process32Next(snapshot, &pe)); + } + + CloseHandle(snapshot); + return result; +} + bool ConPtyProcess::isAvailable() { #ifdef TOO_OLD_WINSDK diff --git a/lib/ptyqt/conptyprocess.h b/lib/ptyqt/conptyprocess.h index d8f590ee..2668eed2 100644 --- a/lib/ptyqt/conptyprocess.h +++ b/lib/ptyqt/conptyprocess.h @@ -141,6 +141,7 @@ class ConPtyProcess : public IPtyProcess virtual qint64 write(const QByteArray &byteArray); virtual QString currentDir(); virtual bool hasChildProcess(); + virtual QList> childProcessInfoList(); bool isAvailable(); void moveToThread(QThread *targetThread); diff --git a/lib/ptyqt/iptyprocess.h b/lib/ptyqt/iptyprocess.h index a3b4db4f..8a65e5a8 100644 --- a/lib/ptyqt/iptyprocess.h +++ b/lib/ptyqt/iptyprocess.h @@ -41,6 +41,7 @@ class IPtyProcess virtual bool isAvailable() = 0; virtual void moveToThread(QThread *targetThread) = 0; virtual bool hasChildProcess() = 0; + virtual QList> childProcessInfoList() = 0; qint64 pid() { return m_pid; } QPair size() { return m_size; } const QString lastError() { return m_lastError; } diff --git a/lib/ptyqt/ptyqt.pri b/lib/ptyqt/ptyqt.pri index 3eb95991..312f4eba 100644 --- a/lib/ptyqt/ptyqt.pri +++ b/lib/ptyqt/ptyqt.pri @@ -17,7 +17,7 @@ win32:{ $$PWD/conptyprocess.cpp \ $$PWD/winptyprocess.cpp - WINPTY_DIR=D:\quardCRT\depend\winpty + WINPTY_DIR=D:\\winpty INCLUDEPATH += $${WINPTY_DIR}\include\winpty LIBS += $${WINPTY_DIR}\lib\winpty.lib diff --git a/lib/ptyqt/unixptyprocess.cpp b/lib/ptyqt/unixptyprocess.cpp index f6f8b783..aad13f68 100644 --- a/lib/ptyqt/unixptyprocess.cpp +++ b/lib/ptyqt/unixptyprocess.cpp @@ -319,13 +319,59 @@ QString UnixPtyProcess::currentDir() bool UnixPtyProcess::hasChildProcess() { - int pid = tcgetpgrp(m_shellProcess.m_handleMaster); - if ( pid != -1 ) { - if(m_pid != pid) { - return true; + QList> childList = childProcessInfoList(); + return (childList.size() > 0); +} + +QList> UnixPtyProcess::childProcessInfoList() +{ + QList> result; + QString cmd = QString("ps"); + QStringList args = { "-o", "pid,ppid,pgid,command", "-ax" }; + QProcess ps; + ps.start(cmd, args); + ps.waitForFinished(-1); + QString psResult = ps.readAllStandardOutput(); + QStringList psLines = psResult.split("\n"); + foreach (QString line, psLines) + { + if (line.contains("PID")) + continue; + + QStringList lineParts = line.split(" "); + QStringList linePartsFiltered; + foreach (QString part, lineParts) + { + if (!part.isEmpty()) + linePartsFiltered.append(part); + } + if (linePartsFiltered.size() < 4) + continue; + + QString pid = linePartsFiltered.at(0); + QString ppid = linePartsFiltered.at(1); + QString pgid = linePartsFiltered.at(2); + QString command = linePartsFiltered.at(3); + QStringList arg = linePartsFiltered.mid(4); + + if (pid == QString::number(m_pid)) + continue; + + if (ppid == QString::number(m_pid)) + { + QPair pair = QPair(pid.toInt(), command+" "+arg.join(" ")); + result.push_back(pair); + continue; + } + + if (pgid == QString::number(m_pid)) + { + QPair pair = QPair(pid.toInt(), command+" "+arg.join(" ")); + result.push_back(pair); + continue; } } - return false; + return result; } bool UnixPtyProcess::isAvailable() diff --git a/lib/ptyqt/unixptyprocess.h b/lib/ptyqt/unixptyprocess.h index 2ad819ce..a653ae25 100644 --- a/lib/ptyqt/unixptyprocess.h +++ b/lib/ptyqt/unixptyprocess.h @@ -107,6 +107,7 @@ class UnixPtyProcess : public IPtyProcess virtual qint64 write(const QByteArray &byteArray); virtual QString currentDir(); virtual bool hasChildProcess(); + virtual QList> childProcessInfoList(); virtual bool isAvailable(); void moveToThread(QThread *targetThread); diff --git a/lib/ptyqt/winptyprocess.cpp b/lib/ptyqt/winptyprocess.cpp index afcf5220..51c751f5 100644 --- a/lib/ptyqt/winptyprocess.cpp +++ b/lib/ptyqt/winptyprocess.cpp @@ -1,6 +1,7 @@ #include "winptyprocess.h" #include #include +#include #include #include #include @@ -264,6 +265,41 @@ bool WinPtyProcess::hasChildProcess() return false; } +QList> WinPtyProcess::childProcessInfoList() +{ + QList> result; + + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + if (snapshot == INVALID_HANDLE_VALUE) + return result; + + PROCESSENTRY32 pe; + pe.dwSize = sizeof(PROCESSENTRY32); + + if (Process32First(snapshot, &pe)) { + do { + if (pe.th32ParentProcessID == m_pid) { + // get full path + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe.th32ProcessID); + if (hProcess != NULL) + { + TCHAR szProcessName[MAX_PATH] = TEXT(""); + if (GetModuleFileNameExW(hProcess, NULL, szProcessName, MAX_PATH) != 0) + { + QPair pair = QPair(pe.th32ProcessID, QString::fromWCharArray(szProcessName)); + result.append(pair); + } + CloseHandle(hProcess); + } + } + } while (Process32Next(snapshot, &pe)); + } + + CloseHandle(snapshot); + return result; +} + bool WinPtyProcess::isAvailable() { return QFile::exists(QCoreApplication::applicationDirPath() + "/" + WINPTY_AGENT_NAME) diff --git a/lib/ptyqt/winptyprocess.h b/lib/ptyqt/winptyprocess.h index 960269f5..c762518c 100644 --- a/lib/ptyqt/winptyprocess.h +++ b/lib/ptyqt/winptyprocess.h @@ -21,6 +21,7 @@ class WinPtyProcess : public IPtyProcess qint64 write(const QByteArray &byteArray); QString currentDir(); virtual bool hasChildProcess(); + virtual QList> childProcessInfoList(); bool isAvailable(); void moveToThread(QThread *targetThread); diff --git a/scripts/Profile.ps1 b/scripts/Profile.ps1 index f54104ca..bc6b5cdf 100644 --- a/scripts/Profile.ps1 +++ b/scripts/Profile.ps1 @@ -62,3 +62,7 @@ function prompt { return $out } + +Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete +Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward +Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3190040b..e990a231 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -748,8 +748,8 @@ void MainWindow::menuAndToolBarRetranslateUi(void) { copyAction->setText(tr("Copy")); copyAction->setIcon(QFontIcon::icon(QChar(0xf0c5))); #if defined(Q_OS_MACOS) - copyAction->setStatusTip(tr("Copy the selected text to the clipboard ")); - copyAction->setShortcut(QKeySequence(Qt::META|Qt::Key_C)); + copyAction->setStatusTip(tr("Copy the selected text to the clipboard ")); + copyAction->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_C)); #else copyAction->setStatusTip(tr("Copy the selected text to the clipboard ")); copyAction->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_Insert)); @@ -757,8 +757,8 @@ void MainWindow::menuAndToolBarRetranslateUi(void) { pasteAction->setText(tr("Paste")); pasteAction->setIcon(QFontIcon::icon(QChar(0xf0ea))); #if defined(Q_OS_MACOS) - pasteAction->setStatusTip(tr("Paste the clipboard text to the current session ")); - pasteAction->setShortcut(QKeySequence(Qt::META|Qt::Key_V)); + pasteAction->setStatusTip(tr("Paste the clipboard text to the current session ")); + pasteAction->setShortcut(QKeySequence(Qt::CTRL|Qt::Key_V)); #else pasteAction->setStatusTip(tr("Paste the clipboard text to the current session ")); pasteAction->setShortcut(QKeySequence(Qt::SHIFT|Qt::Key_Insert)); diff --git a/src/sessionswindow.cpp b/src/sessionswindow.cpp index 8d164a4c..fd501707 100644 --- a/src/sessionswindow.cpp +++ b/src/sessionswindow.cpp @@ -542,3 +542,30 @@ bool SessionsWindow::hasChildProcess() { } } +QString SessionsWindow::getStateInfo() { + switch(type) { + case LocalShell:{ + QList> list = localShell->childProcessInfoList(); + if(list.isEmpty()) return tr("No child process."); + QString ret = ""; + ret += ""; + foreach(auto info, list) { + ret += ""; + } + ret += "
PIDCommand
" + + QString::number(info.first) + + "" + + info.second + + "
"; + return ret; + } + case Telnet: + return tr("Telnet %1:%2").arg(m_hostname).arg(m_port); + case Serial: + return tr("Serial %1 %2 %3 %4 %5 %6 %7").arg(m_portName).arg(m_baudRate).arg(m_dataBits).arg(m_parity).arg(m_stopBits).arg(m_flowControl).arg(m_xEnable); + case RawSocket: + return tr("Raw Socket %1:%2").arg(m_hostname).arg(m_port); + case NamePipe: + return tr("Name Pipe %1").arg(m_pipeName); + } +} diff --git a/src/sessionswindow.h b/src/sessionswindow.h index fa462b2d..c61ca14f 100644 --- a/src/sessionswindow.h +++ b/src/sessionswindow.h @@ -83,6 +83,7 @@ class SessionsWindow : public QObject bool isLocked() const { return locked; } SessionsState getState() const { return state; } bool hasChildProcess(); + QString getStateInfo(); QString getHostname() const { return m_hostname; } quint16 getPort() const { return m_port; }