From 228b0f1d54855e887c869831b35b378a99dc35e2 Mon Sep 17 00:00:00 2001 From: Mateusz Fibor Date: Sun, 5 Jan 2025 17:07:13 +0100 Subject: [PATCH] feat: Adapt to qt6 --- .github/workflows/macos.yml | 3 +- .github/workflows/ubuntu.yml | 5 +- .github/workflows/windows.yml | 8 +- QtScrcpy/CMakeLists.txt | 31 +++++--- QtScrcpy/QtScrcpyCore | 2 +- QtScrcpy/appversion | 2 +- QtScrcpy/audio/audiooutput.cpp | 84 +++++++++----------- QtScrcpy/audio/audiooutput.h | 2 + QtScrcpy/main.cpp | 8 +- QtScrcpy/ui/dialog.cpp | 6 +- QtScrcpy/ui/toolform.cpp | 4 +- QtScrcpy/ui/videoform.cpp | 111 +++++++++++---------------- QtScrcpy/util/config.cpp | 2 - QtScrcpy/util/mousetap/xmousetap.cpp | 90 ++++++++-------------- ci/generate-version.py | 25 +++--- 15 files changed, 168 insertions(+), 215 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index aaf52eda4..58f2fdbcb 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -16,7 +16,7 @@ jobs: runs-on: macos-14 strategy: matrix: - qt-ver: [5.15.2] + qt-ver: [6.5.3] qt-arch-install: [clang_64] clang-arch: [x64] env: @@ -34,6 +34,7 @@ jobs: uses: jurplel/install-qt-action@v4.1.1 with: version: ${{ matrix.qt-ver }} + modules: qtmultimedia cached: ${{ steps.cache-qt.outputs.cache-hit }} - uses: actions/checkout@v2 with: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0dd2b1c95..1f8755601 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -18,7 +18,7 @@ jobs: strategy: matrix: os: [ubuntu-22.04] - qt-ver: [5.15.2] + qt-ver: [6.5.3] qt-arch-install: [gcc_64] gcc-arch: [x64] env: @@ -30,6 +30,7 @@ jobs: uses: jurplel/install-qt-action@v4.1.1 with: version: ${{ matrix.qt-ver }} + modules: qtmultimedia cached: ${{ steps.cache-qt.outputs.cache-hit }} - name: Cache Qt id: cache-qt @@ -38,7 +39,7 @@ jobs: path: ${{ env.qt-install-path }}/${{ matrix.qt-arch-install }} key: ${{ runner.os }}/${{ matrix.qt-ver }}/${{ matrix.qt-arch-install }} - name: Install GL library - run: sudo apt-get install -y libglew-dev libglfw3-dev + run: sudo apt-get install -y libglew-dev libglfw3-dev libopengl-dev libx11-dev libxtst-dev - uses: actions/checkout@v2 with: fetch-depth: 0 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 105159845..37ba35f0f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -24,16 +24,13 @@ jobs: # 矩阵配置 https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix strategy: matrix: - qt-ver: [5.15.2] - qt-arch: [win64_msvc2019_64, win32_msvc2019] + qt-ver: [6.5.3] + qt-arch: [win64_msvc2019_64] # 配置qt-arch的额外设置msvc-arch,qt-arch-install include: - qt-arch: win64_msvc2019_64 msvc-arch: x64 qt-arch-install: msvc2019_64 - - qt-arch: win32_msvc2019 - msvc-arch: x86 - qt-arch-install: msvc2019 # job env,所有steps都可以访问 # 不同级别env详解 https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#env # 使用表达式语法${{}}访问上下文 https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions @@ -62,6 +59,7 @@ jobs: target: desktop # Architecture for Windows/Android arch: ${{ matrix.qt-arch }} + modules: qtmultimedia cached: ${{ steps.cache-qt.outputs.cache-hit }} # 拉取代码 - uses: actions/checkout@v2 diff --git a/QtScrcpy/CMakeLists.txt b/QtScrcpy/CMakeLists.txt index a9d1c645a..867320b8c 100755 --- a/QtScrcpy/CMakeLists.txt +++ b/QtScrcpy/CMakeLists.txt @@ -11,7 +11,9 @@ cmake_minimum_required(VERSION 3.19 FATAL_ERROR) # QC Custom config set(QC_PROJECT_NAME "QtScrcpy") # Read version numbers from file -file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/appversion QC_FILE_VERSION) +file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/appversion QC_FILE_VERSION_UNSTRIPPED) +string(STRIP "${QC_FILE_VERSION_UNSTRIPPED}" QC_FILE_VERSION) + set(QC_PROJECT_VERSION ${QC_FILE_VERSION}) # Project declare @@ -52,13 +54,13 @@ if (MSVC) add_compile_options(/W3 /WX /wd4566) # avoid warning C4819 - add_compile_options(-source-charset:utf-8) + #add_compile_options(-source-charset:utf-8) #add_compile_options(/utf-8) # ensure we use minimal "windows.h" lib without the crazy min max macros add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN) - - # disable SAFESEH - avoid "LNK2026: module unsafe"(Qt5.15&&vs2019) + + # disable SAFESEH - avoid "LNK2026: module unsafe"(Qt5.15&&vs2019) add_link_options(/SAFESEH:NO) endif() @@ -79,11 +81,10 @@ set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) -find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Network Multimedia REQUIRED) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network Multimedia REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Network Multimedia OpenGL OpenGLWidgets REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network Multimedia OpenGL OpenGLWidgets REQUIRED) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - find_package(QT NAMES Qt6 Qt5 COMPONENTS X11Extras REQUIRED) - find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED) + find_package(X11 REQUIRED) endif() message(STATUS "[${PROJECT_NAME}] Qt version is: ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}") @@ -146,7 +147,7 @@ set(QC_UTIL_SOURCES util/mousetap/mousetap.cpp ) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(QC_UTIL_SOURCES ${QC_UTIL_SOURCES} + set(QC_UTIL_SOURCES ${QC_UTIL_SOURCES} util/mousetap/winmousetap.h util/mousetap/winmousetap.cpp util/winutils.h @@ -154,13 +155,13 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") ) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - set(QC_UTIL_SOURCES ${QC_UTIL_SOURCES} + set(QC_UTIL_SOURCES ${QC_UTIL_SOURCES} util/mousetap/xmousetap.h util/mousetap/xmousetap.cpp ) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - set(QC_UTIL_SOURCES ${QC_UTIL_SOURCES} + set(QC_UTIL_SOURCES ${QC_UTIL_SOURCES} util/mousetap/cocoamousetap.h util/mousetap/cocoamousetap.mm util/path.h @@ -263,6 +264,8 @@ endif() # MacOS if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15") + # copy bundle file get_target_property(MACOS_BUNDLE_PATH ${PROJECT_NAME} RUNTIME_OUTPUT_DIRECTORY) set(MACOS_BUNDLE_PATH ${MACOS_BUNDLE_PATH}/${PROJECT_NAME}.app/Contents) @@ -310,13 +313,15 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) + include_directories(${X11_INCLUDE_DIR}) target_link_libraries(${PROJECT_NAME} PRIVATE # qx11 - Qt${QT_VERSION_MAJOR}::X11Extras + Qt${QT_VERSION_MAJOR}::CorePrivate # xcb https://doc.qt.io/qt-5/linux-requirements.html xcb # pthread + ${X11_LIBRARIES} Threads::Threads ) @@ -334,5 +339,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Multimedia + Qt${QT_VERSION_MAJOR}::OpenGL + Qt${QT_VERSION_MAJOR}::OpenGLWidgets QtScrcpyCore ) diff --git a/QtScrcpy/QtScrcpyCore b/QtScrcpy/QtScrcpyCore index cb9da00b4..4ca295f26 160000 --- a/QtScrcpy/QtScrcpyCore +++ b/QtScrcpy/QtScrcpyCore @@ -1 +1 @@ -Subproject commit cb9da00b4ac4e855b6cb8a9033fe45a1fabfd05b +Subproject commit 4ca295f2648cd41a0634d89c076908c63f3d5949 diff --git a/QtScrcpy/appversion b/QtScrcpy/appversion index 77d6f4ca2..bd52db81d 100644 --- a/QtScrcpy/appversion +++ b/QtScrcpy/appversion @@ -1 +1 @@ -0.0.0 +0.0.0 \ No newline at end of file diff --git a/QtScrcpy/audio/audiooutput.cpp b/QtScrcpy/audio/audiooutput.cpp index 34e00cd0c..5e7d952dd 100644 --- a/QtScrcpy/audio/audiooutput.cpp +++ b/QtScrcpy/audio/audiooutput.cpp @@ -1,31 +1,37 @@ #include #include -#include -#include +#include +#include #include - +#include +#include +#include +#include #include "audiooutput.h" AudioOutput::AudioOutput(QObject *parent) : QObject(parent) + , m_outputDevice(nullptr) + , m_running(false) + , m_audioSink(nullptr) { connect(&m_sndcpy, &QProcess::readyReadStandardOutput, this, [this]() { - qInfo() << QString("AudioOutput::") << QString(m_sndcpy.readAllStandardOutput()); + qInfo() << QString("AudioOutput::") << m_sndcpy.readAllStandardOutput(); }); connect(&m_sndcpy, &QProcess::readyReadStandardError, this, [this]() { - qInfo() << QString("AudioOutput::") << QString(m_sndcpy.readAllStandardError()); + qInfo() << QString("AudioOutput::") << m_sndcpy.readAllStandardError(); }); } AudioOutput::~AudioOutput() { - if (QProcess::NotRunning != m_sndcpy.state()) { + if (m_sndcpy.state() != QProcess::NotRunning) { m_sndcpy.kill(); } stop(); } -bool AudioOutput::start(const QString& serial, int port) +bool AudioOutput::start(const QString &serial, int port) { if (m_running) { stop(); @@ -36,7 +42,7 @@ bool AudioOutput::start(const QString& serial, int port) bool ret = runSndcpyProcess(serial, port); qInfo() << "AudioOutput::run sndcpy cost:" << timeConsumeCount.elapsed() << "milliseconds"; if (!ret) { - return ret; + return false; } startAudioOutput(); @@ -64,20 +70,15 @@ void AudioOutput::installonly(const QString &serial, int port) bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait) { - if (QProcess::NotRunning != m_sndcpy.state()) { + if (m_sndcpy.state() != QProcess::NotRunning) { m_sndcpy.kill(); } #ifdef Q_OS_WIN32 - QStringList params; - params << serial; - params << QString("%1").arg(port); + QStringList params{serial, QString::number(port)}; m_sndcpy.start("sndcpy.bat", params); #else - QStringList params; - params << "sndcpy.sh"; - params << serial; - params << QString("%1").arg(port); + QStringList params{"sndcpy.sh", serial, QString::number(port)}; m_sndcpy.start("bash", params); #endif @@ -86,11 +87,11 @@ bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait) } if (!m_sndcpy.waitForStarted()) { - qWarning() << "AudioOutput::start sndcpy.bat failed"; + qWarning() << "AudioOutput::start sndcpy process failed"; return false; } if (!m_sndcpy.waitForFinished()) { - qWarning() << "AudioOutput::sndcpy.bat crashed"; + qWarning() << "AudioOutput::sndcpy process crashed"; return false; } @@ -99,41 +100,39 @@ bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait) void AudioOutput::startAudioOutput() { - if (m_audioOutput) { + if (m_audioSink) { return; } QAudioFormat format; format.setSampleRate(48000); format.setChannelCount(2); - format.setSampleSize(16); - format.setCodec("audio/pcm"); - format.setByteOrder(QAudioFormat::LittleEndian); - format.setSampleType(QAudioFormat::SignedInt); + format.setSampleFormat(QAudioFormat::Int16); // 16-bit signed integer format - QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); - if (!info.isFormatSupported(format)) { + QAudioDevice defaultDevice = QMediaDevices::defaultAudioOutput(); + if (!defaultDevice.isFormatSupported(format)) { qWarning() << "AudioOutput::audio format not supported, cannot play audio."; return; } - m_audioOutput = new QAudioOutput(format, this); - connect(m_audioOutput, &QAudioOutput::stateChanged, this, [](QAudio::State state) { - qInfo() << "AudioOutput::audio state changed:" << state; - }); - m_audioOutput->setBufferSize(48000*2*15/1000 * 20); - m_outputDevice = m_audioOutput->start(); + m_audioSink = new QAudioSink(defaultDevice, format, this); + m_outputDevice = m_audioSink->start(); + if (!m_outputDevice) { + qWarning() << "AudioOutput::failed to start audio sink."; + delete m_audioSink; + m_audioSink = nullptr; + return; + } } void AudioOutput::stopAudioOutput() { - if (!m_audioOutput) { - return; + if (m_audioSink) { + m_audioSink->stop(); + delete m_audioSink; + m_audioSink = nullptr; } - - m_audioOutput->stop(); - delete m_audioOutput; - m_audioOutput = nullptr; + m_outputDevice = nullptr; } void AudioOutput::startRecvData(int port) @@ -156,7 +155,6 @@ void AudioOutput::startRecvData(int port) }); connect(audioSocket, &QIODevice::readyRead, audioSocket, [this, audioSocket]() { qint64 recv = audioSocket->bytesAvailable(); - //qDebug() << "AudioOutput::recv data:" << recv; if (!m_outputDevice) { return; @@ -165,22 +163,16 @@ void AudioOutput::startRecvData(int port) m_buffer.reserve(recv); } - qint64 count = audioSocket->read(m_buffer.data(), audioSocket->bytesAvailable()); + qint64 count = audioSocket->read(m_buffer.data(), recv); m_outputDevice->write(m_buffer.data(), count); }); connect(audioSocket, &QTcpSocket::stateChanged, audioSocket, [](QAbstractSocket::SocketState state) { qInfo() << "AudioOutput::audio socket state changed:" << state; - }); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + connect(audioSocket, &QTcpSocket::errorOccurred, audioSocket, [](QAbstractSocket::SocketError error) { qInfo() << "AudioOutput::audio socket error occurred:" << error; }); -#else - connect(audioSocket, QOverload::of(&QAbstractSocket::error), audioSocket, [](QAbstractSocket::SocketError error) { - qInfo() << "AudioOutput::audio socket error occurred:" << error; - }); -#endif m_workerThread.start(); emit connectTo(port); diff --git a/QtScrcpy/audio/audiooutput.h b/QtScrcpy/audio/audiooutput.h index 1690168b7..a969c7803 100644 --- a/QtScrcpy/audio/audiooutput.h +++ b/QtScrcpy/audio/audiooutput.h @@ -6,6 +6,7 @@ #include #include +class QAudioSink; class QAudioOutput; class QIODevice; class AudioOutput : public QObject @@ -36,6 +37,7 @@ class AudioOutput : public QObject QProcess m_sndcpy; QVector m_buffer; bool m_running = false; + QAudioSink *m_audioSink = nullptr; }; #endif // AUDIOOUTPUT_H diff --git a/QtScrcpy/main.cpp b/QtScrcpy/main.cpp index a24ba60b4..ab23e1862 100644 --- a/QtScrcpy/main.cpp +++ b/QtScrcpy/main.cpp @@ -8,7 +8,10 @@ #include "config.h" #include "dialog.h" -#include "mousetap/mousetap.h" + +#if defined(Q_OS_WIN32) || defined(Q_OS_OSX) + #include "mousetap/mousetap.h" +#endif static Dialog *g_mainDlg = Q_NULLPTR; static QtMessageHandler g_oldMessageHandler = Q_NULLPTR; @@ -55,7 +58,6 @@ int main(int argc, char *argv[]) QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); } - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); @@ -142,7 +144,7 @@ void installTranslator() break; } - translator.load(languagePath); + qInfo() << "Loading translation result =" << translator.load(languagePath); qApp->installTranslator(&translator); } diff --git a/QtScrcpy/ui/dialog.cpp b/QtScrcpy/ui/dialog.cpp index 493060c98..43f57f37e 100644 --- a/QtScrcpy/ui/dialog.cpp +++ b/QtScrcpy/ui/dialog.cpp @@ -618,9 +618,11 @@ void Dialog::on_usbConnectBtn_clicked() int Dialog::findDeviceFromeSerialBox(bool wifi) { - QRegExp regIP("\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\:([0-9]|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])\\b"); + QRegularExpression regIP(R"(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\:(?:[0-9]|[1-9]\d{1,4}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$)"); + for (int i = 0; i < ui->serialBox->count(); ++i) { - bool isWifi = regIP.exactMatch(ui->serialBox->itemText(i)); + QRegularExpressionMatch match = regIP.match(ui->serialBox->itemText(i)); + bool isWifi = match.hasMatch(); bool found = wifi ? isWifi : !isWifi; if (found) { return i; diff --git a/QtScrcpy/ui/toolform.cpp b/QtScrcpy/ui/toolform.cpp index 35614f704..262eada48 100644 --- a/QtScrcpy/ui/toolform.cpp +++ b/QtScrcpy/ui/toolform.cpp @@ -68,7 +68,7 @@ void ToolForm::updateGroupControl() void ToolForm::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { - m_dragPosition = event->globalPos() - frameGeometry().topLeft(); + m_dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft(); event->accept(); } } @@ -81,7 +81,7 @@ void ToolForm::mouseReleaseEvent(QMouseEvent *event) void ToolForm::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { - move(event->globalPos() - m_dragPosition); + move(event->globalPosition().toPoint() - m_dragPosition); event->accept(); } } diff --git a/QtScrcpy/ui/videoform.cpp b/QtScrcpy/ui/videoform.cpp index 5806f1d5d..6f0f99a6c 100644 --- a/QtScrcpy/ui/videoform.cpp +++ b/QtScrcpy/ui/videoform.cpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -363,21 +362,10 @@ void VideoForm::installShortcut() QRect VideoForm::getScreenRect() { QRect screenRect; - QWidget *win = window(); - if (!win) { - return screenRect; - } - - QWindow *winHandle = win->windowHandle(); QScreen *screen = QGuiApplication::primaryScreen(); - if (winHandle) { - screen = winHandle->screen(); - } - if (!screen) { - return screenRect; + if (screen) { + screenRect = screen->availableGeometry(); } - - screenRect = screen->availableGeometry(); return screenRect; } @@ -572,23 +560,25 @@ void VideoForm::mousePressEvent(QMouseEvent *event) } } - if (m_videoWidget->geometry().contains(event->pos())) { + if (m_videoWidget->geometry().contains(event->position().toPoint())) { if (!device) { return; } - event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); - emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size()); + QPointF mappedPos = m_videoWidget->mapFrom(this, event->position().toPoint()); + emit device->mouseEvent(new QMouseEvent( + event->type(), mappedPos, event->globalPosition(), + event->button(), event->buttons(), event->modifiers()), + m_videoWidget->frameSize(), m_videoWidget->size()); - // debug keymap pos if (event->button() == Qt::LeftButton) { - qreal x = event->localPos().x() / m_videoWidget->size().width(); - qreal y = event->localPos().y() / m_videoWidget->size().height(); + qreal x = mappedPos.x() / m_videoWidget->size().width(); + qreal y = mappedPos.y() / m_videoWidget->size().height(); QString posTip = QString(R"("pos": {"x": %1, "y": %2})").arg(x).arg(y); - qInfo() << posTip.toStdString().c_str(); + qInfo() << posTip; } } else { if (event->button() == Qt::LeftButton) { - m_dragPosition = event->globalPos() - frameGeometry().topLeft(); + m_dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft(); event->accept(); } } @@ -601,23 +591,18 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event) if (!device) { return; } - event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); - // local check - QPointF local = event->localPos(); - if (local.x() < 0) { - local.setX(0); - } - if (local.x() > m_videoWidget->width()) { - local.setX(m_videoWidget->width()); - } - if (local.y() < 0) { - local.setY(0); - } - if (local.y() > m_videoWidget->height()) { - local.setY(m_videoWidget->height()); - } - event->setLocalPos(local); - emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size()); + + QPointF mappedPos = m_videoWidget->mapFrom(this, event->position().toPoint()); + QPointF local = mappedPos; + if (local.x() < 0) local.setX(0); + if (local.x() > m_videoWidget->width()) local.setX(m_videoWidget->width()); + if (local.y() < 0) local.setY(0); + if (local.y() > m_videoWidget->height()) local.setY(m_videoWidget->height()); + + emit device->mouseEvent(new QMouseEvent( + event->type(), local, event->globalPosition(), + event->button(), event->buttons(), event->modifiers()), + m_videoWidget->frameSize(), m_videoWidget->size()); } else { m_dragPosition = QPoint(0, 0); } @@ -626,24 +611,25 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event) void VideoForm::mouseMoveEvent(QMouseEvent *event) { auto device = qsc::IDeviceManage::getInstance().getDevice(m_serial); - if (m_videoWidget->geometry().contains(event->pos())) { + if (m_videoWidget->geometry().contains(event->position().toPoint())) { if (!device) { return; } - event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); - emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size()); - } else if (!m_dragPosition.isNull()) { - if (event->buttons() & Qt::LeftButton) { - move(event->globalPos() - m_dragPosition); - event->accept(); - } + QPointF mappedPos = m_videoWidget->mapFrom(this, event->position().toPoint()); + emit device->mouseEvent(new QMouseEvent( + event->type(), mappedPos, event->globalPosition(), + event->button(), event->buttons(), event->modifiers()), + m_videoWidget->frameSize(), m_videoWidget->size()); + } else if (!m_dragPosition.isNull() && (event->buttons() & Qt::LeftButton)) { + move(event->globalPosition().toPoint() - m_dragPosition); + event->accept(); } } void VideoForm::mouseDoubleClickEvent(QMouseEvent *event) { auto device = qsc::IDeviceManage::getInstance().getDevice(m_serial); - if (event->button() == Qt::LeftButton && !m_videoWidget->geometry().contains(event->pos())) { + if (event->button() == Qt::LeftButton && !m_videoWidget->geometry().contains(event->position().toPoint())) { if (!isMaximized()) { removeBlackRect(); } @@ -653,38 +639,30 @@ void VideoForm::mouseDoubleClickEvent(QMouseEvent *event) emit device->postBackOrScreenOn(event->type() == QEvent::MouseButtonPress); } - if (m_videoWidget->geometry().contains(event->pos())) { + if (m_videoWidget->geometry().contains(event->position().toPoint())) { if (!device) { return; } - event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); - emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size()); + QPointF mappedPos = m_videoWidget->mapFrom(this, event->position().toPoint()); + emit device->mouseEvent(new QMouseEvent( + event->type(), mappedPos, event->globalPosition(), + event->button(), event->buttons(), event->modifiers()), + m_videoWidget->frameSize(), m_videoWidget->size()); } } void VideoForm::wheelEvent(QWheelEvent *event) { auto device = qsc::IDeviceManage::getInstance().getDevice(m_serial); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) if (m_videoWidget->geometry().contains(event->position().toPoint())) { if (!device) { return; } QPointF pos = m_videoWidget->mapFrom(this, event->position().toPoint()); - QWheelEvent wheelEvent( - pos, event->globalPosition(), event->pixelDelta(), event->angleDelta(), event->buttons(), event->modifiers(), event->phase(), event->inverted()); -#else - if (m_videoWidget->geometry().contains(event->pos())) { - if (!device) { - return; - } - QPointF pos = m_videoWidget->mapFrom(this, event->pos()); - - QWheelEvent wheelEvent( - pos, event->globalPosF(), event->pixelDelta(), event->angleDelta(), event->delta(), event->orientation(), - event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted()); -#endif - emit device->wheelEvent(&wheelEvent, m_videoWidget->frameSize(), m_videoWidget->size()); + QWheelEvent adjustedEvent( + pos, event->globalPosition(), event->pixelDelta(), event->angleDelta(), + event->buttons(), event->modifiers(), event->phase(), event->inverted()); + emit device->wheelEvent(&adjustedEvent, m_videoWidget->frameSize(), m_videoWidget->size()); } } @@ -714,7 +692,6 @@ void VideoForm::paintEvent(QPaintEvent *paint) { Q_UNUSED(paint) QStyleOption opt; - opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } diff --git a/QtScrcpy/util/config.cpp b/QtScrcpy/util/config.cpp index 5915cf29e..61eb86a8c 100644 --- a/QtScrcpy/util/config.cpp +++ b/QtScrcpy/util/config.cpp @@ -113,10 +113,8 @@ QString Config::s_configPath = ""; Config::Config(QObject *parent) : QObject(parent) { m_settings = new QSettings(getConfigPath() + "/config.ini", QSettings::IniFormat); - m_settings->setIniCodec("UTF-8"); m_userData = new QSettings(getConfigPath() + "/userdata.ini", QSettings::IniFormat); - m_userData->setIniCodec("UTF-8"); qDebug()<childGroups(); } diff --git a/QtScrcpy/util/mousetap/xmousetap.cpp b/QtScrcpy/util/mousetap/xmousetap.cpp index 18ba226eb..e6e6f1991 100644 --- a/QtScrcpy/util/mousetap/xmousetap.cpp +++ b/QtScrcpy/util/mousetap/xmousetap.cpp @@ -1,11 +1,19 @@ -#include - #include #include -#include + +#include +#include +#include +#include +#include #include "xmousetap.h" +#include +#include +#include +#include + XMouseTap::XMouseTap() {} XMouseTap::~XMouseTap() {} @@ -14,71 +22,37 @@ void XMouseTap::initMouseEventTap() {} void XMouseTap::quitMouseEventTap() {} -static void find_grab_window_recursive(xcb_connection_t *dpy, xcb_window_t window, - QRect rc, int16_t offset_x, int16_t offset_y, - xcb_window_t *grab_window, uint32_t *grab_window_size) { - xcb_query_tree_cookie_t tree_cookie; - xcb_query_tree_reply_t *tree; - tree_cookie = xcb_query_tree(dpy, window); - tree = xcb_query_tree_reply(dpy, tree_cookie, NULL); - - xcb_window_t *children = xcb_query_tree_children(tree); - for (int i = 0; i < xcb_query_tree_children_length(tree); i++) { - xcb_get_geometry_cookie_t gg_cookie; - xcb_get_geometry_reply_t *gg; - gg_cookie = xcb_get_geometry(dpy, children[i]); - gg = xcb_get_geometry_reply(dpy, gg_cookie, NULL); - - if (gg->x + offset_x <= rc.left() && gg->x + offset_x + gg->width >= rc.right() && - gg->y + offset_y <= rc.top() && gg->y + offset_y + gg->height >= rc.bottom()) { - if (!*grab_window || gg->width * gg->height <= *grab_window_size) { - *grab_window = children[i]; - *grab_window_size = gg->width * gg->height; - } - } - - find_grab_window_recursive(dpy, children[i], rc, - gg->x + offset_x, gg->y + offset_y, - grab_window, grab_window_size); - - free(gg); - } - - free(tree); -} - void XMouseTap::enableMouseEventTap(QRect rc, bool enabled) { if (enabled && rc.isEmpty()) { return; } - xcb_connection_t *dpy = QX11Info::connection(); + auto *x11Interface = qApp->nativeInterface(); + if (!x11Interface) { + qWarning() << "X11 interface is not available. Ensure the application is running on X11."; + return; + } - if (enabled) { - // We grab the top-most smallest window - xcb_window_t grab_window = 0; - uint32_t grab_window_size = 0; + Display *display = reinterpret_cast(x11Interface->display()); + if (!display) { + qWarning() << "Failed to get X Display."; + return; + } - find_grab_window_recursive(dpy, QX11Info::appRootWindow(QX11Info::appScreen()), - rc, 0, 0, &grab_window, &grab_window_size); + int screenNumber = DefaultScreen(display); - if (grab_window) { - xcb_grab_pointer_cookie_t grab_cookie; - xcb_grab_pointer_reply_t *grab; - grab_cookie = xcb_grab_pointer(dpy, /* owner_events = */ 1, - grab_window, /* event_mask = */ 0, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, - grab_window, XCB_NONE, XCB_CURRENT_TIME); - grab = xcb_grab_pointer_reply(dpy, grab_cookie, NULL); + Window rootWindow = RootWindow(display, screenNumber); - free(grab); + if (enabled) { + int result = XGrabPointer(display, rootWindow, True, + ButtonPressMask | ButtonReleaseMask | PointerMotionMask, + GrabModeAsync, GrabModeAsync, + None, None, CurrentTime); + if (result != GrabSuccess) { + qWarning() << "Failed to grab pointer."; } } else { - xcb_void_cookie_t ungrab_cookie; - xcb_generic_error_t *error; - ungrab_cookie = xcb_ungrab_pointer_checked(dpy, XCB_CURRENT_TIME); - error = xcb_request_check(dpy, ungrab_cookie); - - free(error); + XUngrabPointer(display, CurrentTime); } + XFlush(display); } diff --git a/ci/generate-version.py b/ci/generate-version.py index 74581cd8d..bc71ad9c0 100644 --- a/ci/generate-version.py +++ b/ci/generate-version.py @@ -2,19 +2,18 @@ import os if __name__ == '__main__': - p = os.popen('git rev-list --tags --max-count=1') - commit = p.read() - p.close() + commit = os.popen('git rev-list --tags --max-count=1').read().strip() + + if commit: + tag = os.popen('git describe --tags ' + commit).read().strip() + version = tag[1:] if tag else "0.0.0" + else: + version = "0.0.0" - p = os.popen('git describe --tags ' + commit) - tag = p.read() - p.close() - - # print('get tag:', tag) - - version = str(tag[1:]) + # Write version to file version_file = os.path.abspath(os.path.join(os.path.dirname(__file__), "../QtScrcpy/appversion")) - file=open(version_file, 'w') - file.write(version) - file.close() + with open(version_file, 'w') as file: + file.write(version) + + print(f"Version written: {version}") sys.exit(0) \ No newline at end of file