feat: Adapt to qt6

This commit is contained in:
Mateusz Fibor 2025-01-05 17:07:13 +01:00
commit 228b0f1d54
15 changed files with 170 additions and 217 deletions

View file

@ -16,7 +16,7 @@ jobs:
runs-on: macos-14 runs-on: macos-14
strategy: strategy:
matrix: matrix:
qt-ver: [5.15.2] qt-ver: [6.5.3]
qt-arch-install: [clang_64] qt-arch-install: [clang_64]
clang-arch: [x64] clang-arch: [x64]
env: env:
@ -34,6 +34,7 @@ jobs:
uses: jurplel/install-qt-action@v4.1.1 uses: jurplel/install-qt-action@v4.1.1
with: with:
version: ${{ matrix.qt-ver }} version: ${{ matrix.qt-ver }}
modules: qtmultimedia
cached: ${{ steps.cache-qt.outputs.cache-hit }} cached: ${{ steps.cache-qt.outputs.cache-hit }}
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:

View file

@ -18,7 +18,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [ubuntu-22.04] os: [ubuntu-22.04]
qt-ver: [5.15.2] qt-ver: [6.5.3]
qt-arch-install: [gcc_64] qt-arch-install: [gcc_64]
gcc-arch: [x64] gcc-arch: [x64]
env: env:
@ -30,6 +30,7 @@ jobs:
uses: jurplel/install-qt-action@v4.1.1 uses: jurplel/install-qt-action@v4.1.1
with: with:
version: ${{ matrix.qt-ver }} version: ${{ matrix.qt-ver }}
modules: qtmultimedia
cached: ${{ steps.cache-qt.outputs.cache-hit }} cached: ${{ steps.cache-qt.outputs.cache-hit }}
- name: Cache Qt - name: Cache Qt
id: cache-qt id: cache-qt
@ -38,7 +39,7 @@ jobs:
path: ${{ env.qt-install-path }}/${{ matrix.qt-arch-install }} path: ${{ env.qt-install-path }}/${{ matrix.qt-arch-install }}
key: ${{ runner.os }}/${{ matrix.qt-ver }}/${{ matrix.qt-arch-install }} key: ${{ runner.os }}/${{ matrix.qt-ver }}/${{ matrix.qt-arch-install }}
- name: Install GL library - 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 - uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch-depth: 0

View file

@ -24,16 +24,13 @@ jobs:
# 矩阵配置 https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix # 矩阵配置 https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix
strategy: strategy:
matrix: matrix:
qt-ver: [5.15.2] qt-ver: [6.5.3]
qt-arch: [win64_msvc2019_64, win32_msvc2019] qt-arch: [win64_msvc2019_64]
# 配置qt-arch的额外设置msvc-archqt-arch-install # 配置qt-arch的额外设置msvc-archqt-arch-install
include: include:
- qt-arch: win64_msvc2019_64 - qt-arch: win64_msvc2019_64
msvc-arch: x64 msvc-arch: x64
qt-arch-install: msvc2019_64 qt-arch-install: msvc2019_64
- qt-arch: win32_msvc2019
msvc-arch: x86
qt-arch-install: msvc2019
# job env,所有steps都可以访问 # job env,所有steps都可以访问
# 不同级别env详解 https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#env # 不同级别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 # 使用表达式语法${{}}访问上下文 https://help.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions
@ -62,6 +59,7 @@ jobs:
target: desktop target: desktop
# Architecture for Windows/Android # Architecture for Windows/Android
arch: ${{ matrix.qt-arch }} arch: ${{ matrix.qt-arch }}
modules: qtmultimedia
cached: ${{ steps.cache-qt.outputs.cache-hit }} cached: ${{ steps.cache-qt.outputs.cache-hit }}
# 拉取代码 # 拉取代码
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View file

@ -11,7 +11,9 @@ cmake_minimum_required(VERSION 3.19 FATAL_ERROR)
# QC Custom config # QC Custom config
set(QC_PROJECT_NAME "QtScrcpy") set(QC_PROJECT_NAME "QtScrcpy")
# Read version numbers from file # 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}) set(QC_PROJECT_VERSION ${QC_FILE_VERSION})
# Project declare # Project declare
@ -52,13 +54,13 @@ if (MSVC)
add_compile_options(/W3 /WX /wd4566) add_compile_options(/W3 /WX /wd4566)
# avoid warning C4819 # avoid warning C4819
add_compile_options(-source-charset:utf-8) #add_compile_options(-source-charset:utf-8)
#add_compile_options(/utf-8) #add_compile_options(/utf-8)
# ensure we use minimal "windows.h" lib without the crazy min max macros # ensure we use minimal "windows.h" lib without the crazy min max macros
add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN) 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) add_link_options(/SAFESEH:NO)
endif() endif()
@ -79,11 +81,10 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
find_package(QT NAMES Qt6 Qt5 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 REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network Multimedia OpenGL OpenGLWidgets REQUIRED)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux") if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(QT NAMES Qt6 Qt5 COMPONENTS X11Extras REQUIRED) find_package(X11 REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED)
endif() endif()
message(STATUS "[${PROJECT_NAME}] Qt version is: ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}") 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 util/mousetap/mousetap.cpp
) )
if(CMAKE_SYSTEM_NAME STREQUAL "Windows") 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.h
util/mousetap/winmousetap.cpp util/mousetap/winmousetap.cpp
util/winutils.h util/winutils.h
@ -154,13 +155,13 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
) )
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 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.h
util/mousetap/xmousetap.cpp util/mousetap/xmousetap.cpp
) )
endif() endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") 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.h
util/mousetap/cocoamousetap.mm util/mousetap/cocoamousetap.mm
util/path.h util/path.h
@ -263,6 +264,8 @@ endif()
# MacOS # MacOS
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15")
# copy bundle file # copy bundle file
get_target_property(MACOS_BUNDLE_PATH ${PROJECT_NAME} RUNTIME_OUTPUT_DIRECTORY) get_target_property(MACOS_BUNDLE_PATH ${PROJECT_NAME} RUNTIME_OUTPUT_DIRECTORY)
set(MACOS_BUNDLE_PATH ${MACOS_BUNDLE_PATH}/${PROJECT_NAME}.app/Contents) 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) set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
include_directories(${X11_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
# qx11 # qx11
Qt${QT_VERSION_MAJOR}::X11Extras Qt${QT_VERSION_MAJOR}::CorePrivate
# xcb https://doc.qt.io/qt-5/linux-requirements.html # xcb https://doc.qt.io/qt-5/linux-requirements.html
xcb xcb
# pthread # pthread
${X11_LIBRARIES}
Threads::Threads Threads::Threads
) )
@ -334,5 +339,7 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Multimedia Qt${QT_VERSION_MAJOR}::Multimedia
Qt${QT_VERSION_MAJOR}::OpenGL
Qt${QT_VERSION_MAJOR}::OpenGLWidgets
QtScrcpyCore QtScrcpyCore
) )

@ -1 +1 @@
Subproject commit cb9da00b4ac4e855b6cb8a9033fe45a1fabfd05b Subproject commit 4ca295f2648cd41a0634d89c076908c63f3d5949

View file

@ -1 +1 @@
0.0.0 0.0.0

View file

@ -1,31 +1,37 @@
#include <QTcpSocket> #include <QTcpSocket>
#include <QHostAddress> #include <QHostAddress>
#include <QAudioOutput> #include <QAudioSink>
#include <QTime> #include <QMediaDevices>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QProcess>
#include <QThread>
#include <QDebug>
#include <QByteArray>
#include "audiooutput.h" #include "audiooutput.h"
AudioOutput::AudioOutput(QObject *parent) AudioOutput::AudioOutput(QObject *parent)
: QObject(parent) : QObject(parent)
, m_outputDevice(nullptr)
, m_running(false)
, m_audioSink(nullptr)
{ {
connect(&m_sndcpy, &QProcess::readyReadStandardOutput, this, [this]() { 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]() { connect(&m_sndcpy, &QProcess::readyReadStandardError, this, [this]() {
qInfo() << QString("AudioOutput::") << QString(m_sndcpy.readAllStandardError()); qInfo() << QString("AudioOutput::") << m_sndcpy.readAllStandardError();
}); });
} }
AudioOutput::~AudioOutput() AudioOutput::~AudioOutput()
{ {
if (QProcess::NotRunning != m_sndcpy.state()) { if (m_sndcpy.state() != QProcess::NotRunning) {
m_sndcpy.kill(); m_sndcpy.kill();
} }
stop(); stop();
} }
bool AudioOutput::start(const QString& serial, int port) bool AudioOutput::start(const QString &serial, int port)
{ {
if (m_running) { if (m_running) {
stop(); stop();
@ -36,7 +42,7 @@ bool AudioOutput::start(const QString& serial, int port)
bool ret = runSndcpyProcess(serial, port); bool ret = runSndcpyProcess(serial, port);
qInfo() << "AudioOutput::run sndcpy cost:" << timeConsumeCount.elapsed() << "milliseconds"; qInfo() << "AudioOutput::run sndcpy cost:" << timeConsumeCount.elapsed() << "milliseconds";
if (!ret) { if (!ret) {
return ret; return false;
} }
startAudioOutput(); startAudioOutput();
@ -64,20 +70,15 @@ void AudioOutput::installonly(const QString &serial, int port)
bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait) 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(); m_sndcpy.kill();
} }
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
QStringList params; QStringList params{serial, QString::number(port)};
params << serial;
params << QString("%1").arg(port);
m_sndcpy.start("sndcpy.bat", params); m_sndcpy.start("sndcpy.bat", params);
#else #else
QStringList params; QStringList params{"sndcpy.sh", serial, QString::number(port)};
params << "sndcpy.sh";
params << serial;
params << QString("%1").arg(port);
m_sndcpy.start("bash", params); m_sndcpy.start("bash", params);
#endif #endif
@ -86,11 +87,11 @@ bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait)
} }
if (!m_sndcpy.waitForStarted()) { if (!m_sndcpy.waitForStarted()) {
qWarning() << "AudioOutput::start sndcpy.bat failed"; qWarning() << "AudioOutput::start sndcpy process failed";
return false; return false;
} }
if (!m_sndcpy.waitForFinished()) { if (!m_sndcpy.waitForFinished()) {
qWarning() << "AudioOutput::sndcpy.bat crashed"; qWarning() << "AudioOutput::sndcpy process crashed";
return false; return false;
} }
@ -99,41 +100,39 @@ bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait)
void AudioOutput::startAudioOutput() void AudioOutput::startAudioOutput()
{ {
if (m_audioOutput) { if (m_audioSink) {
return; return;
} }
QAudioFormat format; QAudioFormat format;
format.setSampleRate(48000); format.setSampleRate(48000);
format.setChannelCount(2); format.setChannelCount(2);
format.setSampleSize(16); format.setSampleFormat(QAudioFormat::Int16); // 16-bit signed integer format
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); QAudioDevice defaultDevice = QMediaDevices::defaultAudioOutput();
if (!info.isFormatSupported(format)) { if (!defaultDevice.isFormatSupported(format)) {
qWarning() << "AudioOutput::audio format not supported, cannot play audio."; qWarning() << "AudioOutput::audio format not supported, cannot play audio.";
return; return;
} }
m_audioOutput = new QAudioOutput(format, this); m_audioSink = new QAudioSink(defaultDevice, format, this);
connect(m_audioOutput, &QAudioOutput::stateChanged, this, [](QAudio::State state) { m_outputDevice = m_audioSink->start();
qInfo() << "AudioOutput::audio state changed:" << state; if (!m_outputDevice) {
}); qWarning() << "AudioOutput::failed to start audio sink.";
m_audioOutput->setBufferSize(48000*2*15/1000 * 20); delete m_audioSink;
m_outputDevice = m_audioOutput->start(); m_audioSink = nullptr;
return;
}
} }
void AudioOutput::stopAudioOutput() void AudioOutput::stopAudioOutput()
{ {
if (!m_audioOutput) { if (m_audioSink) {
return; m_audioSink->stop();
delete m_audioSink;
m_audioSink = nullptr;
} }
m_outputDevice = nullptr;
m_audioOutput->stop();
delete m_audioOutput;
m_audioOutput = nullptr;
} }
void AudioOutput::startRecvData(int port) void AudioOutput::startRecvData(int port)
@ -156,7 +155,6 @@ void AudioOutput::startRecvData(int port)
}); });
connect(audioSocket, &QIODevice::readyRead, audioSocket, [this, audioSocket]() { connect(audioSocket, &QIODevice::readyRead, audioSocket, [this, audioSocket]() {
qint64 recv = audioSocket->bytesAvailable(); qint64 recv = audioSocket->bytesAvailable();
//qDebug() << "AudioOutput::recv data:" << recv;
if (!m_outputDevice) { if (!m_outputDevice) {
return; return;
@ -165,22 +163,16 @@ void AudioOutput::startRecvData(int port)
m_buffer.reserve(recv); 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); m_outputDevice->write(m_buffer.data(), count);
}); });
connect(audioSocket, &QTcpSocket::stateChanged, audioSocket, [](QAbstractSocket::SocketState state) { connect(audioSocket, &QTcpSocket::stateChanged, audioSocket, [](QAbstractSocket::SocketState state) {
qInfo() << "AudioOutput::audio socket state changed:" << 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) { connect(audioSocket, &QTcpSocket::errorOccurred, audioSocket, [](QAbstractSocket::SocketError error) {
qInfo() << "AudioOutput::audio socket error occurred:" << error; qInfo() << "AudioOutput::audio socket error occurred:" << error;
}); });
#else
connect(audioSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), audioSocket, [](QAbstractSocket::SocketError error) {
qInfo() << "AudioOutput::audio socket error occurred:" << error;
});
#endif
m_workerThread.start(); m_workerThread.start();
emit connectTo(port); emit connectTo(port);

View file

@ -6,6 +6,7 @@
#include <QPointer> #include <QPointer>
#include <QVector> #include <QVector>
class QAudioSink;
class QAudioOutput; class QAudioOutput;
class QIODevice; class QIODevice;
class AudioOutput : public QObject class AudioOutput : public QObject
@ -36,6 +37,7 @@ private:
QProcess m_sndcpy; QProcess m_sndcpy;
QVector<char> m_buffer; QVector<char> m_buffer;
bool m_running = false; bool m_running = false;
QAudioSink *m_audioSink = nullptr;
}; };
#endif // AUDIOOUTPUT_H #endif // AUDIOOUTPUT_H

View file

@ -8,7 +8,10 @@
#include "config.h" #include "config.h"
#include "dialog.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 Dialog *g_mainDlg = Q_NULLPTR;
static QtMessageHandler g_oldMessageHandler = Q_NULLPTR; static QtMessageHandler g_oldMessageHandler = Q_NULLPTR;
@ -55,7 +58,6 @@ int main(int argc, char *argv[])
QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); QApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
} }
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) #if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
@ -142,7 +144,7 @@ void installTranslator()
break; break;
} }
translator.load(languagePath); qInfo() << "Loading translation result =" << translator.load(languagePath);
qApp->installTranslator(&translator); qApp->installTranslator(&translator);
} }

View file

@ -618,9 +618,11 @@ void Dialog::on_usbConnectBtn_clicked()
int Dialog::findDeviceFromeSerialBox(bool wifi) 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) { 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; bool found = wifi ? isWifi : !isWifi;
if (found) { if (found) {
return i; return i;

View file

@ -68,7 +68,7 @@ void ToolForm::updateGroupControl()
void ToolForm::mousePressEvent(QMouseEvent *event) void ToolForm::mousePressEvent(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
m_dragPosition = event->globalPos() - frameGeometry().topLeft(); m_dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft();
event->accept(); event->accept();
} }
} }
@ -81,7 +81,7 @@ void ToolForm::mouseReleaseEvent(QMouseEvent *event)
void ToolForm::mouseMoveEvent(QMouseEvent *event) void ToolForm::mouseMoveEvent(QMouseEvent *event)
{ {
if (event->buttons() & Qt::LeftButton) { if (event->buttons() & Qt::LeftButton) {
move(event->globalPos() - m_dragPosition); move(event->globalPosition().toPoint() - m_dragPosition);
event->accept(); event->accept();
} }
} }

View file

@ -1,4 +1,3 @@
#include <QDesktopWidget>
#include <QFileInfo> #include <QFileInfo>
#include <QLabel> #include <QLabel>
#include <QMessageBox> #include <QMessageBox>
@ -363,21 +362,10 @@ void VideoForm::installShortcut()
QRect VideoForm::getScreenRect() QRect VideoForm::getScreenRect()
{ {
QRect screenRect; QRect screenRect;
QWidget *win = window();
if (!win) {
return screenRect;
}
QWindow *winHandle = win->windowHandle();
QScreen *screen = QGuiApplication::primaryScreen(); QScreen *screen = QGuiApplication::primaryScreen();
if (winHandle) { if (screen) {
screen = winHandle->screen(); screenRect = screen->availableGeometry();
} }
if (!screen) {
return screenRect;
}
screenRect = screen->availableGeometry();
return screenRect; 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) { if (!device) {
return; return;
} }
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); QPointF mappedPos = m_videoWidget->mapFrom(this, event->position().toPoint());
emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size()); 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) { if (event->button() == Qt::LeftButton) {
qreal x = event->localPos().x() / m_videoWidget->size().width(); qreal x = mappedPos.x() / m_videoWidget->size().width();
qreal y = event->localPos().y() / m_videoWidget->size().height(); qreal y = mappedPos.y() / m_videoWidget->size().height();
QString posTip = QString(R"("pos": {"x": %1, "y": %2})").arg(x).arg(y); QString posTip = QString(R"("pos": {"x": %1, "y": %2})").arg(x).arg(y);
qInfo() << posTip.toStdString().c_str(); qInfo() << posTip;
} }
} else { } else {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
m_dragPosition = event->globalPos() - frameGeometry().topLeft(); m_dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft();
event->accept(); event->accept();
} }
} }
@ -601,23 +591,18 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
if (!device) { if (!device) {
return; return;
} }
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
// local check QPointF mappedPos = m_videoWidget->mapFrom(this, event->position().toPoint());
QPointF local = event->localPos(); QPointF local = mappedPos;
if (local.x() < 0) { if (local.x() < 0) local.setX(0);
local.setX(0); if (local.x() > m_videoWidget->width()) local.setX(m_videoWidget->width());
} if (local.y() < 0) local.setY(0);
if (local.x() > m_videoWidget->width()) { if (local.y() > m_videoWidget->height()) local.setY(m_videoWidget->height());
local.setX(m_videoWidget->width());
} emit device->mouseEvent(new QMouseEvent(
if (local.y() < 0) { event->type(), local, event->globalPosition(),
local.setY(0); event->button(), event->buttons(), event->modifiers()),
} m_videoWidget->frameSize(), m_videoWidget->size());
if (local.y() > m_videoWidget->height()) {
local.setY(m_videoWidget->height());
}
event->setLocalPos(local);
emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
} else { } else {
m_dragPosition = QPoint(0, 0); m_dragPosition = QPoint(0, 0);
} }
@ -626,24 +611,25 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
void VideoForm::mouseMoveEvent(QMouseEvent *event) void VideoForm::mouseMoveEvent(QMouseEvent *event)
{ {
auto device = qsc::IDeviceManage::getInstance().getDevice(m_serial); 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) { if (!device) {
return; return;
} }
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); QPointF mappedPos = m_videoWidget->mapFrom(this, event->position().toPoint());
emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size()); emit device->mouseEvent(new QMouseEvent(
} else if (!m_dragPosition.isNull()) { event->type(), mappedPos, event->globalPosition(),
if (event->buttons() & Qt::LeftButton) { event->button(), event->buttons(), event->modifiers()),
move(event->globalPos() - m_dragPosition); m_videoWidget->frameSize(), m_videoWidget->size());
event->accept(); } else if (!m_dragPosition.isNull() && (event->buttons() & Qt::LeftButton)) {
} move(event->globalPosition().toPoint() - m_dragPosition);
event->accept();
} }
} }
void VideoForm::mouseDoubleClickEvent(QMouseEvent *event) void VideoForm::mouseDoubleClickEvent(QMouseEvent *event)
{ {
auto device = qsc::IDeviceManage::getInstance().getDevice(m_serial); 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()) { if (!isMaximized()) {
removeBlackRect(); removeBlackRect();
} }
@ -653,38 +639,30 @@ void VideoForm::mouseDoubleClickEvent(QMouseEvent *event)
emit device->postBackOrScreenOn(event->type() == QEvent::MouseButtonPress); emit device->postBackOrScreenOn(event->type() == QEvent::MouseButtonPress);
} }
if (m_videoWidget->geometry().contains(event->pos())) { if (m_videoWidget->geometry().contains(event->position().toPoint())) {
if (!device) { if (!device) {
return; return;
} }
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); QPointF mappedPos = m_videoWidget->mapFrom(this, event->position().toPoint());
emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size()); 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) void VideoForm::wheelEvent(QWheelEvent *event)
{ {
auto device = qsc::IDeviceManage::getInstance().getDevice(m_serial); 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 (m_videoWidget->geometry().contains(event->position().toPoint())) {
if (!device) { if (!device) {
return; return;
} }
QPointF pos = m_videoWidget->mapFrom(this, event->position().toPoint()); QPointF pos = m_videoWidget->mapFrom(this, event->position().toPoint());
QWheelEvent wheelEvent( QWheelEvent adjustedEvent(
pos, event->globalPosition(), event->pixelDelta(), event->angleDelta(), event->buttons(), event->modifiers(), event->phase(), event->inverted()); pos, event->globalPosition(), event->pixelDelta(), event->angleDelta(),
#else event->buttons(), event->modifiers(), event->phase(), event->inverted());
if (m_videoWidget->geometry().contains(event->pos())) { emit device->wheelEvent(&adjustedEvent, m_videoWidget->frameSize(), m_videoWidget->size());
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());
} }
} }
@ -714,7 +692,6 @@ void VideoForm::paintEvent(QPaintEvent *paint)
{ {
Q_UNUSED(paint) Q_UNUSED(paint)
QStyleOption opt; QStyleOption opt;
opt.init(this);
QPainter p(this); QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
} }

View file

@ -113,10 +113,8 @@ QString Config::s_configPath = "";
Config::Config(QObject *parent) : QObject(parent) Config::Config(QObject *parent) : QObject(parent)
{ {
m_settings = new QSettings(getConfigPath() + "/config.ini", QSettings::IniFormat); 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 = new QSettings(getConfigPath() + "/userdata.ini", QSettings::IniFormat);
m_userData->setIniCodec("UTF-8");
qDebug()<<m_userData->childGroups(); qDebug()<<m_userData->childGroups();
} }

View file

@ -1,11 +1,19 @@
#include <QX11Info>
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <QDebug>
#include <QRect>
#include <xcb/xproto.h>
#include <QGuiApplication>
#include <QRect>
#include "xmousetap.h" #include "xmousetap.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XTest.h>
#include <xcb/xcb.h>
XMouseTap::XMouseTap() {} XMouseTap::XMouseTap() {}
XMouseTap::~XMouseTap() {} XMouseTap::~XMouseTap() {}
@ -14,71 +22,37 @@ void XMouseTap::initMouseEventTap() {}
void XMouseTap::quitMouseEventTap() {} 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) { void XMouseTap::enableMouseEventTap(QRect rc, bool enabled) {
if (enabled && rc.isEmpty()) { if (enabled && rc.isEmpty()) {
return; return;
} }
xcb_connection_t *dpy = QX11Info::connection(); auto *x11Interface = qApp->nativeInterface<QNativeInterface::QX11Application>();
if (!x11Interface) {
qWarning() << "X11 interface is not available. Ensure the application is running on X11.";
return;
}
Display *display = reinterpret_cast<Display*>(x11Interface->display());
if (!display) {
qWarning() << "Failed to get X Display.";
return;
}
int screenNumber = DefaultScreen(display);
Window rootWindow = RootWindow(display, screenNumber);
if (enabled) { if (enabled) {
// We grab the top-most smallest window int result = XGrabPointer(display, rootWindow, True,
xcb_window_t grab_window = 0; ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
uint32_t grab_window_size = 0; GrabModeAsync, GrabModeAsync,
None, None, CurrentTime);
find_grab_window_recursive(dpy, QX11Info::appRootWindow(QX11Info::appScreen()), if (result != GrabSuccess) {
rc, 0, 0, &grab_window, &grab_window_size); qWarning() << "Failed to grab pointer.";
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);
free(grab);
} }
} else { } else {
xcb_void_cookie_t ungrab_cookie; XUngrabPointer(display, CurrentTime);
xcb_generic_error_t *error;
ungrab_cookie = xcb_ungrab_pointer_checked(dpy, XCB_CURRENT_TIME);
error = xcb_request_check(dpy, ungrab_cookie);
free(error);
} }
XFlush(display);
} }

View file

@ -2,19 +2,18 @@ import sys
import os import os
if __name__ == '__main__': if __name__ == '__main__':
p = os.popen('git rev-list --tags --max-count=1') commit = os.popen('git rev-list --tags --max-count=1').read().strip()
commit = p.read()
p.close() 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) # Write version to file
tag = p.read()
p.close()
# print('get tag:', tag)
version = str(tag[1:])
version_file = os.path.abspath(os.path.join(os.path.dirname(__file__), "../QtScrcpy/appversion")) version_file = os.path.abspath(os.path.join(os.path.dirname(__file__), "../QtScrcpy/appversion"))
file=open(version_file, 'w') with open(version_file, 'w') as file:
file.write(version) file.write(version)
file.close()
print(f"Version written: {version}")
sys.exit(0) sys.exit(0)