Compare commits

..

No commits in common. "dev" and "v3.1.0" have entirely different histories.

36 changed files with 135 additions and 1018 deletions

View file

@ -13,23 +13,12 @@ on:
jobs: jobs:
build: build:
name: Build name: Build
# install-qt-action在arm上执行macdeployqt会报parse otool错误所以在intel mac上执行: runs-on: macos-14
# 用qt6时在arm mac上编译arm和intel都没有问题
# qt5+intel mac编译intel没问题
# qt5+arm mac编译intel会报错
# https://github.com/actions/runner-images?tab=readme-ov-file#available-images
runs-on: macos-13
strategy: strategy:
matrix: matrix:
qt-ver: [5.15.2, 6.5.3] qt-ver: [5.15.2]
# 配置qt-ver的额外设置qt-arch-installbuild-arch qt-arch-install: [clang_64]
include: clang-arch: [x64]
- qt-ver: 5.15.2
qt-arch-install: clang_64
build-arch: x64
- qt-ver: 6.5.3
qt-arch-install: arm64
build-arch: arm64
env: env:
target-name: QtScrcpy target-name: QtScrcpy
qt-install-path: ${{ github.workspace }}/${{ matrix.qt-ver }} qt-install-path: ${{ github.workspace }}/${{ matrix.qt-ver }}
@ -41,19 +30,11 @@ jobs:
with: with:
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 Qt5 - name: Install Qt
if: startsWith(matrix.qt-ver, '5.')
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 }}
cached: ${{ steps.cache-qt.outputs.cache-hit }} cached: ${{ steps.cache-qt.outputs.cache-hit }}
- name: Install Qt6
if: startsWith(matrix.qt-ver, '6.')
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 - uses: actions/checkout@v2
with: with:
fetch-depth: 0 fetch-depth: 0
@ -65,7 +46,7 @@ jobs:
ENV_QT_PATH: ${{ env.qt-install-path }} ENV_QT_PATH: ${{ env.qt-install-path }}
run: | run: |
python ci/generate-version.py python ci/generate-version.py
ci/mac/build_for_mac.sh RelWithDebInfo ${{ matrix.build-arch }} ci/mac/build_for_mac.sh RelWithDebInfo
# 获取ref最后一个/后的内容 # 获取ref最后一个/后的内容
- name: Get the version - name: Get the version
shell: bash shell: bash
@ -77,9 +58,9 @@ jobs:
id: package id: package
env: env:
ENV_QT_PATH: ${{ env.qt-install-path }} ENV_QT_PATH: ${{ env.qt-install-path }}
publish_name: ${{ env.target-name }}-${{ env.plantform-des }}-${{ matrix.build-arch }}-Qt${{matrix.qt-ver}}-${{ steps.get-version.outputs.version }} publish_name: ${{ env.target-name }}-${{ env.plantform-des }}-${{ matrix.clang-arch }}-${{ steps.get-version.outputs.version }}
run: | run: |
ci/mac/publish_for_mac.sh ../build ${{ matrix.build-arch }} ci/mac/publish_for_mac.sh ../build
ci/mac/package_for_mac.sh ci/mac/package_for_mac.sh
mv ci/build/QtScrcpy.app ci/build/${{ env.publish_name }}.app mv ci/build/QtScrcpy.app ci/build/${{ env.publish_name }}.app
mv ci/build/QtScrcpy.dmg ci/build/${{ env.publish_name }}.dmg mv ci/build/QtScrcpy.dmg ci/build/${{ env.publish_name }}.dmg

View file

@ -16,10 +16,10 @@ on:
jobs: jobs:
build: build:
name: Build name: Build
# windows-latest目前是windows server 2022 # windows-latest目前是windows server 2019
# windows server 2019安装的是vs2019windows server 2016安装的是vs2017 # windows server 2019安装的是vs2019windows server 2016安装的是vs2017
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
runs-on: windows-latest runs-on: windows-2019
# 矩阵配置 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:
@ -39,8 +39,8 @@ jobs:
# 使用表达式语法${{}}访问上下文 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
env: env:
target-name: QtScrcpy target-name: QtScrcpy
vcvarsall-path: 'C:\Program Files (x86)\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat' vcvarsall-path: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat'
vcinstall-path: 'C:\Program Files (x86)\Microsoft Visual Studio\2022\Enterprise\VC' vcinstall-path: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC'
qt-install-path: ${{ github.workspace }}/${{ matrix.qt-ver }} qt-install-path: ${{ github.workspace }}/${{ matrix.qt-ver }}
plantform-des: win plantform-des: win
# 步骤 # 步骤

View file

@ -26,19 +26,6 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
else() else()
set(QC_CPU_ARCH x86) set(QC_CPU_ARCH x86)
endif() endif()
# MacOS
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# mac default arch arm64
if(NOT CMAKE_OSX_ARCHITECTURES)
set(CMAKE_OSX_ARCHITECTURES arm64)
endif()
if (CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
set(QC_CPU_ARCH arm64)
endif()
endif()
message(STATUS "[${PROJECT_NAME}] CPU_ARCH:${QC_CPU_ARCH}") message(STATUS "[${PROJECT_NAME}] CPU_ARCH:${QC_CPU_ARCH}")
# CMake set # CMake set
@ -65,9 +52,8 @@ 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)
# /utf-8 will set source charset and execution charset to utf-8, so we don't need to set 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)
@ -89,49 +75,18 @@ endif()
# Qt # Qt
# #
# Find Qt version
if (NOT QT_DESIRED_VERSION)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
message(" >>> Found Qt version: ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}.${QT_VERSION_PATCH}")
set(QT_DESIRED_VERSION ${QT_VERSION_MAJOR})
endif()
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
set(qt_required_components Widgets Network Multimedia) find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Network Multimedia REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network Multimedia REQUIRED)
if (QT_DESIRED_VERSION MATCHES 6) if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
# list(APPEND qt_required_components Core5Compat) find_package(QT NAMES Qt6 Qt5 COMPONENTS X11Extras REQUIRED)
list(APPEND qt_required_components OpenGL) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED)
list(APPEND qt_required_components OpenGLWidgets)
else()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND qt_required_components X11Extras )
endif()
endif() endif()
find_package(Qt${QT_DESIRED_VERSION} REQUIRED COMPONENTS ${qt_required_components}) message(STATUS "[${PROJECT_NAME}] Qt version is: ${QT_VERSION_MAJOR}.${QT_VERSION_MINOR}")
set(LINK_LIBS
Qt${QT_DESIRED_VERSION}::Widgets
Qt${QT_DESIRED_VERSION}::Network
Qt${QT_DESIRED_VERSION}::Multimedia
)
if (QT_DESIRED_VERSION MATCHES 6)
# list(APPEND LINK_LIBS Qt${QT_DESIRED_VERSION}::Core5Compat)
list(APPEND LINK_LIBS Qt${QT_DESIRED_VERSION}::GuiPrivate)
list(APPEND LINK_LIBS Qt${QT_DESIRED_VERSION}::OpenGL)
list(APPEND LINK_LIBS Qt${QT_DESIRED_VERSION}::OpenGLWidgets)
else()
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
list(APPEND LINK_LIBS Qt${QT_DESIRED_VERSION}::X11Extras)
endif()
endif()
message(STATUS "[${PROJECT_NAME}] Qt version is: ${QT_DESIRED_VERSION}")
# #
# Sources # Sources
@ -308,9 +263,6 @@ endif()
# MacOS # MacOS
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# qt6 need 10.15 or later
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)
@ -360,6 +312,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
# qx11
Qt${QT_VERSION_MAJOR}::X11Extras
# xcb https://doc.qt.io/qt-5/linux-requirements.html # xcb https://doc.qt.io/qt-5/linux-requirements.html
xcb xcb
# pthread # pthread
@ -377,6 +331,8 @@ add_subdirectory(QtScrcpyCore)
# Qt # Qt
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
${LINK_LIBS} Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Network
Qt${QT_VERSION_MAJOR}::Multimedia
QtScrcpyCore QtScrcpyCore
) )

@ -1 +1 @@
Subproject commit fd3cfa521b3e9c407f7afe9117089b51e5e07dd8 Subproject commit 6beab5c967f7f77ddcfabe79757dc01202653ab7

View file

@ -1,27 +1,14 @@
#include <QAudioOutput>
#include <QCoreApplication>
#include <QElapsedTimer>
#include <QHostAddress>
#include <QTcpSocket> #include <QTcpSocket>
#include <QHostAddress>
#include <QAudioOutput>
#include <QTime> #include <QTime>
#include <QElapsedTimer>
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#include <QAudioSink>
#include <QAudioDevice>
#include <QMediaDevices>
#endif
#include "audiooutput.h" #include "audiooutput.h"
AudioOutput::AudioOutput(QObject *parent) AudioOutput::AudioOutput(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
m_running = false;
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
m_audioOutput = nullptr;
#else
m_audioSink = nullptr;
#endif
connect(&m_sndcpy, &QProcess::readyReadStandardOutput, this, [this]() { connect(&m_sndcpy, &QProcess::readyReadStandardOutput, this, [this]() {
qInfo() << QString("AudioOutput::") << QString(m_sndcpy.readAllStandardOutput()); qInfo() << QString("AudioOutput::") << QString(m_sndcpy.readAllStandardOutput());
}); });
@ -82,11 +69,15 @@ bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait)
} }
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
QStringList params{serial, QString::number(port)}; QStringList params;
params << serial;
params << QString("%1").arg(port);
m_sndcpy.start("sndcpy.bat", params); m_sndcpy.start("sndcpy.bat", params);
#else #else
QStringList params{"sndcpy.sh", serial, QString::number(port)}; QStringList params;
m_sndcpy.setWorkingDirectory(QCoreApplication::applicationDirPath()); params << "sndcpy.sh";
params << serial;
params << QString("%1").arg(port);
m_sndcpy.start("bash", params); m_sndcpy.start("bash", params);
#endif #endif
@ -95,11 +86,11 @@ bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait)
} }
if (!m_sndcpy.waitForStarted()) { if (!m_sndcpy.waitForStarted()) {
qWarning() << "AudioOutput::start sndcpy process failed"; qWarning() << "AudioOutput::start sndcpy.bat failed";
return false; return false;
} }
if (!m_sndcpy.waitForFinished()) { if (!m_sndcpy.waitForFinished()) {
qWarning() << "AudioOutput::sndcpy process crashed"; qWarning() << "AudioOutput::sndcpy.bat crashed";
return false; return false;
} }
@ -108,7 +99,6 @@ bool AudioOutput::runSndcpyProcess(const QString &serial, int port, bool wait)
void AudioOutput::startAudioOutput() void AudioOutput::startAudioOutput()
{ {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
if (m_audioOutput) { if (m_audioOutput) {
return; return;
} }
@ -120,8 +110,8 @@ void AudioOutput::startAudioOutput()
format.setCodec("audio/pcm"); format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian); format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt); format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(format)) { if (!info.isFormatSupported(format)) {
qWarning() << "AudioOutput::audio format not supported, cannot play audio."; qWarning() << "AudioOutput::audio format not supported, cannot play audio.";
return; return;
@ -133,47 +123,17 @@ void AudioOutput::startAudioOutput()
}); });
m_audioOutput->setBufferSize(48000*2*15/1000 * 20); m_audioOutput->setBufferSize(48000*2*15/1000 * 20);
m_outputDevice = m_audioOutput->start(); m_outputDevice = m_audioOutput->start();
#else
if (m_audioSink) {
return;
}
QAudioFormat format;
format.setSampleRate(48000);
format.setChannelCount(2);
format.setSampleFormat(QAudioFormat::Int16);
QAudioDevice defaultDevice = QMediaDevices::defaultAudioOutput();
if (!defaultDevice.isFormatSupported(format)) {
qWarning() << "AudioOutput::audio format not supported, cannot play audio.";
return;
}
m_audioSink = new QAudioSink(defaultDevice, format, this);
m_outputDevice = m_audioSink->start();
if (!m_outputDevice) {
qWarning() << "AudioOutput::audio output device not available, cannot play audio.";
delete m_audioSink;
m_audioSink = nullptr;
return;
}
#endif
} }
void AudioOutput::stopAudioOutput() void AudioOutput::stopAudioOutput()
{ {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) if (!m_audioOutput) {
if (m_audioOutput) { return;
m_audioOutput->stop();
delete m_audioOutput;
m_audioOutput = nullptr;
} }
#else
if (m_audioSink) { m_audioOutput->stop();
m_audioSink->stop(); delete m_audioOutput;
delete m_audioSink; m_audioOutput = nullptr;
m_audioSink = nullptr;
}
#endif
m_outputDevice = nullptr;
} }
void AudioOutput::startRecvData(int port) void AudioOutput::startRecvData(int port)
@ -205,7 +165,7 @@ void AudioOutput::startRecvData(int port)
m_buffer.reserve(recv); m_buffer.reserve(recv);
} }
qint64 count = audioSocket->read(m_buffer.data(), recv); qint64 count = audioSocket->read(m_buffer.data(), audioSocket->bytesAvailable());
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) {

View file

@ -6,7 +6,6 @@
#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
@ -31,16 +30,12 @@ signals:
void connectTo(int port); void connectTo(int port);
private: private:
QAudioOutput* m_audioOutput = nullptr;
QPointer<QIODevice> m_outputDevice; QPointer<QIODevice> m_outputDevice;
QThread m_workerThread; QThread m_workerThread;
QProcess m_sndcpy; QProcess m_sndcpy;
QVector<char> m_buffer; QVector<char> m_buffer;
bool m_running = false; bool m_running = false;
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QAudioOutput* m_audioOutput = nullptr;
#else
QAudioSink *m_audioSink = nullptr;
#endif
}; };
#endif // AUDIOOUTPUT_H #endif // AUDIOOUTPUT_H

View file

@ -55,12 +55,10 @@ int main(int argc, char *argv[])
QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); QApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
} }
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 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);
#endif
#endif #endif
QSurfaceFormat varFormat = QSurfaceFormat::defaultFormat(); QSurfaceFormat varFormat = QSurfaceFormat::defaultFormat();
@ -115,13 +113,8 @@ int main(int argc, char *argv[])
"following address:"); "following address:");
qInfo() << QString("QtScrcpy %1 <https://github.com/barry-ran/QtScrcpy>").arg(QCoreApplication::applicationVersion()); qInfo() << QString("QtScrcpy %1 <https://github.com/barry-ran/QtScrcpy>").arg(QCoreApplication::applicationVersion());
qInfo() << QObject::tr("If you need more professional batch control mirror software, you can try the following software:"); qInfo() << QObject::tr("If you need more professional screen projection control software, you can try the following software:");
qInfo() << QString(QObject::tr("QuickMirror") + " <https://lrbnfell4p.feishu.cn/drive/folder/KviYfz5uFlpUT8dXgdjccmfUnse>"); qInfo() << QString(QObject::tr("QuickMirror") + " <https://lrbnfell4p.feishu.cn/docx/QRMhd9nImorAGgxVLlmczxSdnYf>");
qInfo() << QObject::tr("If you need more professional game keymap mirror software, you can try the following software:");
qInfo() << QString(QObject::tr("QuickAssistant") + " <https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh>");
qInfo() << QObject::tr("You can contact me with telegram <https://t.me/+Ylf_5V_rDCMyODQ1>");
int ret = a.exec(); int ret = a.exec();
delete g_mainDlg; delete g_mainDlg;
@ -137,33 +130,19 @@ void installTranslator()
static QTranslator translator; static QTranslator translator;
QLocale locale; QLocale locale;
QLocale::Language language = locale.language(); QLocale::Language language = locale.language();
//language = QLocale::English;
if (Config::getInstance().getLanguage() == "zh_CN") {
language = QLocale::Chinese;
} else if (Config::getInstance().getLanguage() == "en_US") {
language = QLocale::English;
} else if (Config::getInstance().getLanguage() == "ja_JP") {
language = QLocale::Japanese;
}
QString languagePath = ":/i18n/"; QString languagePath = ":/i18n/";
switch (language) { switch (language) {
case QLocale::Chinese: case QLocale::Chinese:
languagePath += "zh_CN.qm"; languagePath += "zh_CN.qm";
break; break;
case QLocale::Japanese:
languagePath += "ja_JP.qm";
break;
case QLocale::English: case QLocale::English:
default: default:
languagePath += "en_US.qm"; languagePath += "en_US.qm";
break; break;
} }
auto loaded = translator.load(languagePath); translator.load(languagePath);
if (!loaded) {
qWarning() << "Failed to load translation file:" << languagePath;
}
qApp->installTranslator(&translator); qApp->installTranslator(&translator);
} }

View file

@ -157,8 +157,6 @@ void QYUVOpenGLWidget::initializeGL()
void QYUVOpenGLWidget::paintGL() void QYUVOpenGLWidget::paintGL()
{ {
m_shaderProgram.bind();
if (m_needUpdate) { if (m_needUpdate) {
deInitTextures(); deInitTextures();
initTextures(); initTextures();
@ -177,8 +175,6 @@ void QYUVOpenGLWidget::paintGL()
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
} }
m_shaderProgram.release();
} }
void QYUVOpenGLWidget::resizeGL(int width, int height) void QYUVOpenGLWidget::resizeGL(int width, int height)

View file

@ -2,7 +2,6 @@
set(QC_TS_FILES set(QC_TS_FILES
${CMAKE_CURRENT_SOURCE_DIR}/zh_CN.ts ${CMAKE_CURRENT_SOURCE_DIR}/zh_CN.ts
${CMAKE_CURRENT_SOURCE_DIR}/en_US.ts ${CMAKE_CURRENT_SOURCE_DIR}/en_US.ts
${CMAKE_CURRENT_SOURCE_DIR}/ja_JP.ts
) )
# 设置qm文件生成目录 # 设置qm文件生成目录
set_source_files_properties(${QC_TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") set_source_files_properties(${QC_TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
@ -49,4 +48,4 @@ qt5_create_translation在cmake clean的时候会删除翻译好的ts文件
2. https://doc.qt.io/qt-5/qtlinguist-cmake-qt5-add-translation.html 2. https://doc.qt.io/qt-5/qtlinguist-cmake-qt5-add-translation.html
3. https://doc.qt.io/qt-5/qtlinguist-cmake-qt5-create-translation.html 3. https://doc.qt.io/qt-5/qtlinguist-cmake-qt5-create-translation.html
4. execute_process 参考https://blog.csdn.net/u010255072/article/details/120326833 4. execute_process 参考https://blog.csdn.net/u010255072/article/details/120326833
5. add_custom_target 参考https://www.cnblogs.com/apocelipes/p/14355460.html 5. add_custom_target 参考https://www.cnblogs.com/apocelipes/p/14355460.html

Binary file not shown.

View file

@ -31,10 +31,6 @@
<source>select path</source> <source>select path</source>
<translation>select path</translation> <translation>select path</translation>
</message> </message>
<message>
<source>Clear History</source>
<translation>Clear History</translation>
</message>
</context> </context>
<context> <context>
<name>QObject</name> <name>QObject</name>
@ -42,26 +38,14 @@
<source>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</source> <source>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</source>
<translation>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</translation> <translation>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</translation>
</message> </message>
<message>
<source>If you need more professional screen projection control software, you can try the following software:</source>
<translation>If you need more professional screen projection control software, you can try the following software:</translation>
</message>
<message> <message>
<source>QuickMirror</source> <source>QuickMirror</source>
<translation>QuickMirror</translation> <translation>QuickMirror</translation>
</message> </message>
<message>
<source>If you need more professional batch control mirror software, you can try the following software:</source>
<translation>If you need more professional batch control mirror software, you can try the following software:</translation>
</message>
<message>
<source>If you need more professional game keymap mirror software, you can try the following software:</source>
<translation>If you need more professional game keymap mirror software, you can try the following software:</translation>
</message>
<message>
<source>QuickAssistant</source>
<translation>QuickAssistant</translation>
</message>
<message>
<source>You can contact me with telegram &lt;https://t.me/+Ylf_5V_rDCMyODQ1&gt;</source>
<translation>You can contact me with telegram &lt;https://t.me/+Ylf_5V_rDCMyODQ1&gt;</translation>
</message>
</context> </context>
<context> <context>
<name>ToolForm</name> <name>ToolForm</name>

Binary file not shown.

View file

@ -1,321 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS []>
<TS version="2.1" language="ja_JP">
<context>
<name>Dialog</name>
<message>
<source>show</source>
<translation></translation>
</message>
<message>
<source>quit</source>
<translation></translation>
</message>
<message>
<source>original</source>
<translation></translation>
</message>
<message>
<source>no lock</source>
<translation></translation>
</message>
<message>
<source>Notice</source>
<translation></translation>
</message>
<message>
<source>Hidden here!</source>
<translation></translation>
</message>
<message>
<source>select path</source>
<translation></translation>
</message>
<message>
<source>Clear History</source>
<translation></translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<source>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</source>
<translation>:</translation>
</message>
<message>
<source>QuickMirror</source>
<translation></translation>
</message>
<message>
<source>If you need more professional batch control mirror software, you can try the following software:</source>
<translation>:</translation>
</message>
<message>
<source>If you need more professional game keymap mirror software, you can try the following software:</source>
<translation>:</translation>
</message>
<message>
<source>QuickAssistant</source>
<translation></translation>
</message>
<message>
<source>You can contact me with telegram &lt;https://t.me/+Ylf_5V_rDCMyODQ1&gt;</source>
<translation>Telegram &lt;https://t.me/+Ylf_5V_rDCMyODQ1&gt;</translation>
</message>
</context>
<context>
<name>ToolForm</name>
<message>
<source>Tool</source>
<translation></translation>
</message>
<message>
<source>full screen</source>
<translation></translation>
</message>
<message>
<source>expand notify</source>
<translation></translation>
</message>
<message>
<source>touch switch</source>
<translation></translation>
</message>
<message>
<source>close screen</source>
<translation></translation>
</message>
<message>
<source>power</source>
<translation></translation>
</message>
<message>
<source>volume up</source>
<translation></translation>
</message>
<message>
<source>volume down</source>
<translation></translation>
</message>
<message>
<source>app switch</source>
<translation></translation>
</message>
<message>
<source>menu</source>
<translation></translation>
</message>
<message>
<source>home</source>
<translation></translation>
</message>
<message>
<source>return</source>
<translation></translation>
</message>
<message>
<source>screen shot</source>
<translation></translation>
</message>
<message>
<source>open screen</source>
<translation></translation>
</message>
<message>
<source>group control</source>
<translation></translation>
</message>
</context>
<context>
<name>VideoForm</name>
<message>
<source>file does not exist</source>
<translation></translation>
</message>
</context>
<context>
<name>Widget</name>
<message>
<source>Wireless</source>
<translation></translation>
</message>
<message>
<source>wireless connect</source>
<translation></translation>
</message>
<message>
<source>wireless disconnect</source>
<translation></translation>
</message>
<message>
<source>Start Config</source>
<translation></translation>
</message>
<message>
<source>select path</source>
<translation></translation>
</message>
<message>
<source>record format</source>
<translation>:</translation>
</message>
<message>
<source>record screen</source>
<translation></translation>
</message>
<message>
<source>frameless</source>
<translation></translation>
</message>
<message>
<source>Use Simple Mode</source>
<translatorcomment>使</translatorcomment>
<translation>使</translation>
</message>
<message>
<source>Simple Mode</source>
<translatorcomment></translatorcomment>
<translation></translation>
</message>
<message>
<source>WIFI Connect</source>
<translatorcomment>Wi-Fi </translatorcomment>
<translation>Wi-Fi </translation>
</message>
<message>
<source>USB Connect</source>
<translatorcomment>USB </translatorcomment>
<translation>USB </translation>
</message>
<message>
<source>Double click to connect:</source>
<translation>:</translation>
</message>
<message>
<source>lock orientation:</source>
<translation>:</translation>
</message>
<message>
<source>show fps</source>
<translation>FPS </translation>
</message>
<message>
<source>stay awake</source>
<translation></translation>
</message>
<message>
<source>device name:</source>
<translatorcomment>:</translatorcomment>
<translation>:</translation>
</message>
<message>
<source>update name</source>
<translatorcomment></translatorcomment>
<translation></translation>
</message>
<message>
<source>stop all server</source>
<translation></translation>
</message>
<message>
<source>adb command:</source>
<translation>adb :</translation>
</message>
<message>
<source>terminate</source>
<translation></translation>
</message>
<message>
<source>execute</source>
<translation></translation>
</message>
<message>
<source>clear</source>
<translation></translation>
</message>
<message>
<source>reverse connection</source>
<translation></translation>
</message>
<message>
<source>background record</source>
<translation></translation>
</message>
<message>
<source>screen-off</source>
<translation> OFF</translation>
</message>
<message>
<source>apply</source>
<translation></translation>
</message>
<message>
<source>max size:</source>
<translation>:</translation>
</message>
<message>
<source>always on top</source>
<translation></translation>
</message>
<message>
<source>refresh script</source>
<translation></translation>
</message>
<message>
<source>get device IP</source>
<translation> IP </translation>
</message>
<message>
<source>USB line</source>
<translation>USB </translation>
</message>
<message>
<source>stop server</source>
<translation></translation>
</message>
<message>
<source>start server</source>
<translation></translation>
</message>
<message>
<source>device serial:</source>
<translation>:</translation>
</message>
<message>
<source>bit rate:</source>
<translation>:</translation>
</message>
<message>
<source>start adbd</source>
<translation>adbd </translation>
</message>
<message>
<source>refresh devices</source>
<translation></translation>
</message>
<message>
<source>install sndcpy</source>
<translation>Sndcpy </translation>
</message>
<message>
<source>start audio</source>
<translation></translation>
</message>
<message>
<source>stop audio</source>
<translation></translation>
</message>
<message>
<source>auto update</source>
<translation></translation>
</message>
<message>
<source>show toolbar</source>
<translation></translation>
</message>
<message>
<source>record save path:</source>
<translation>:</translation>
</message>
</context>
</TS>

Binary file not shown.

View file

@ -31,10 +31,6 @@
<source>select path</source> <source>select path</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>Clear History</source>
<translation></translation>
</message>
</context> </context>
<context> <context>
<name>QObject</name> <name>QObject</name>
@ -42,26 +38,14 @@
<source>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</source> <source>This software is completely open source and free. Use it at your own risk. You can download it at the following address:</source>
<translation>使</translation> <translation>使</translation>
</message> </message>
<message>
<source>If you need more professional screen projection control software, you can try the following software:</source>
<translation></translation>
</message>
<message> <message>
<source>QuickMirror</source> <source>QuickMirror</source>
<translation></translation> <translation></translation>
</message> </message>
<message>
<source>If you need more professional batch control mirror software, you can try the following software:</source>
<translation></translation>
</message>
<message>
<source>If you need more professional game keymap mirror software, you can try the following software:</source>
<translation></translation>
</message>
<message>
<source>QuickAssistant</source>
<translation></translation>
</message>
<message>
<source>You can contact me with telegram &lt;https://t.me/+Ylf_5V_rDCMyODQ1&gt;</source>
<translation>QQ群联系我 &lt;901736468&gt;</translation>
</message>
</context> </context>
<context> <context>
<name>ToolForm</name> <name>ToolForm</name>

View file

@ -24,7 +24,6 @@
<file>qss/psblack/radiobutton_unchecked_disable.png</file> <file>qss/psblack/radiobutton_unchecked_disable.png</file>
<file>i18n/en_US.qm</file> <file>i18n/en_US.qm</file>
<file>i18n/zh_CN.qm</file> <file>i18n/zh_CN.qm</file>
<file>i18n/ja_JP.qm</file>
<file>image/tray/logo.png</file> <file>image/tray/logo.png</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -82,21 +82,21 @@ Dialog::Dialog(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)
log = "ip not find, connect to wifi?"; log = "ip not find, connect to wifi?";
break; break;
} }
ui->deviceIpEdt->setEditText(ip); ui->deviceIpEdt->setText(ip);
} else if (args.contains("ifconfig") && args.contains("wlan0")) { } else if (args.contains("ifconfig") && args.contains("wlan0")) {
QString ip = m_adb.getDeviceIPFromStdOut(); QString ip = m_adb.getDeviceIPFromStdOut();
if (ip.isEmpty()) { if (ip.isEmpty()) {
log = "ip not find, connect to wifi?"; log = "ip not find, connect to wifi?";
break; break;
} }
ui->deviceIpEdt->setEditText(ip); ui->deviceIpEdt->setText(ip);
} else if (args.contains("ip -o a")) { } else if (args.contains("ip -o a")) {
QString ip = m_adb.getDeviceIPByIpFromStdOut(); QString ip = m_adb.getDeviceIPByIpFromStdOut();
if (ip.isEmpty()) { if (ip.isEmpty()) {
log = "ip not find, connect to wifi?"; log = "ip not find, connect to wifi?";
break; break;
} }
ui->deviceIpEdt->setEditText(ip); ui->deviceIpEdt->setText(ip);
} }
break; break;
} }
@ -164,26 +164,6 @@ void Dialog::initUI()
ui->lockOrientationBox->addItem("180"); ui->lockOrientationBox->addItem("180");
ui->lockOrientationBox->addItem("270"); ui->lockOrientationBox->addItem("270");
ui->lockOrientationBox->setCurrentIndex(0); ui->lockOrientationBox->setCurrentIndex(0);
// 加载IP历史记录
loadIpHistory();
// 加载端口历史记录
loadPortHistory();
// 为deviceIpEdt添加右键菜单
if (ui->deviceIpEdt->lineEdit()) {
ui->deviceIpEdt->lineEdit()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->deviceIpEdt->lineEdit(), &QWidget::customContextMenuRequested,
this, &Dialog::showIpEditMenu);
}
// 为devicePortEdt添加右键菜单
if (ui->devicePortEdt->lineEdit()) {
ui->devicePortEdt->lineEdit()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->devicePortEdt->lineEdit(), &QWidget::customContextMenuRequested,
this, &Dialog::showPortEditMenu);
}
} }
void Dialog::updateBootConfig(bool toView) void Dialog::updateBootConfig(bool toView)
@ -236,12 +216,6 @@ void Dialog::updateBootConfig(bool toView)
config.autoUpdateDevice = ui->autoUpdatecheckBox->isChecked(); config.autoUpdateDevice = ui->autoUpdatecheckBox->isChecked();
config.showToolbar = ui->showToolbar->isChecked(); config.showToolbar = ui->showToolbar->isChecked();
// 保存当前IP到历史记录
QString currentIp = ui->deviceIpEdt->currentText().trimmed();
if (!currentIp.isEmpty()) {
saveIpHistory(currentIp);
}
Config::getInstance().setUserBootConfig(config); Config::getInstance().setUserBootConfig(config);
} }
} }
@ -370,32 +344,18 @@ void Dialog::on_wirelessConnectBtn_clicked()
if (checkAdbRun()) { if (checkAdbRun()) {
return; return;
} }
QString addr = ui->deviceIpEdt->currentText().trimmed(); QString addr = ui->deviceIpEdt->text().trimmed();
if (addr.isEmpty()) { if (!ui->devicePortEdt->text().isEmpty()) {
outLog("error: device ip is null", false);
return;
}
if (!ui->devicePortEdt->currentText().isEmpty()) {
addr += ":"; addr += ":";
addr += ui->devicePortEdt->currentText().trimmed(); addr += ui->devicePortEdt->text().trimmed();
} else if (!ui->devicePortEdt->placeholderText().isEmpty()) {
addr += ":";
addr += ui->devicePortEdt->placeholderText().trimmed();
} else { } else {
outLog("error: device port is null", false); outLog("error: device port is null", false);
return; return;
} }
// 保存IP历史记录 - 只保存IP部分,不包含端口
QString ip = addr.split(":").first();
if (!ip.isEmpty()) {
saveIpHistory(ip);
}
// 保存端口历史记录
QString port = addr.split(":").last();
if (!port.isEmpty() && port != ip) {
savePortHistory(port);
}
outLog("wireless connect...", false); outLog("wireless connect...", false);
QStringList adbArgs; QStringList adbArgs;
adbArgs << "connect"; adbArgs << "connect";
@ -556,7 +516,7 @@ void Dialog::on_wirelessDisConnectBtn_clicked()
if (checkAdbRun()) { if (checkAdbRun()) {
return; return;
} }
QString addr = ui->deviceIpEdt->currentText().trimmed(); QString addr = ui->deviceIpEdt->text().trimmed();
outLog("wireless disconnect...", false); outLog("wireless disconnect...", false);
QStringList adbArgs; QStringList adbArgs;
adbArgs << "disconnect"; adbArgs << "disconnect";
@ -658,18 +618,9 @@ void Dialog::on_usbConnectBtn_clicked()
int Dialog::findDeviceFromeSerialBox(bool wifi) int Dialog::findDeviceFromeSerialBox(bool wifi)
{ {
QString regStr = "\\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"; 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");
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QRegExp regIP(regStr);
#else
QRegularExpression regIP(regStr);
#endif
for (int i = 0; i < ui->serialBox->count(); ++i) { for (int i = 0; i < ui->serialBox->count(); ++i) {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
bool isWifi = regIP.exactMatch(ui->serialBox->itemText(i)); bool isWifi = regIP.exactMatch(ui->serialBox->itemText(i));
#else
bool isWifi = regIP.match(ui->serialBox->itemText(i)).hasMatch();
#endif
bool found = wifi ? isWifi : !isWifi; bool found = wifi ? isWifi : !isWifi;
if (found) { if (found) {
return i; return i;
@ -807,87 +758,3 @@ void Dialog::on_autoUpdatecheckBox_toggled(bool checked)
m_autoUpdatetimer.stop(); m_autoUpdatetimer.stop();
} }
} }
void Dialog::loadIpHistory()
{
QStringList ipList = Config::getInstance().getIpHistory();
ui->deviceIpEdt->clear();
ui->deviceIpEdt->addItems(ipList);
ui->deviceIpEdt->setContentsMargins(0, 0, 0, 0);
if (ui->deviceIpEdt->lineEdit()) {
ui->deviceIpEdt->lineEdit()->setMaxLength(128);
ui->deviceIpEdt->lineEdit()->setPlaceholderText("192.168.0.1");
}
}
void Dialog::saveIpHistory(const QString &ip)
{
if (ip.isEmpty()) {
return;
}
Config::getInstance().saveIpHistory(ip);
// 更新ComboBox
loadIpHistory();
ui->deviceIpEdt->setCurrentText(ip);
}
void Dialog::showIpEditMenu(const QPoint &pos)
{
QMenu *menu = ui->deviceIpEdt->lineEdit()->createStandardContextMenu();
menu->addSeparator();
QAction *clearHistoryAction = new QAction(tr("Clear History"), menu);
connect(clearHistoryAction, &QAction::triggered, this, [this]() {
Config::getInstance().clearIpHistory();
loadIpHistory();
});
menu->addAction(clearHistoryAction);
menu->exec(ui->deviceIpEdt->lineEdit()->mapToGlobal(pos));
delete menu;
}
void Dialog::loadPortHistory()
{
QStringList portList = Config::getInstance().getPortHistory();
ui->devicePortEdt->clear();
ui->devicePortEdt->addItems(portList);
ui->devicePortEdt->setContentsMargins(0, 0, 0, 0);
if (ui->devicePortEdt->lineEdit()) {
ui->devicePortEdt->lineEdit()->setMaxLength(6);
ui->devicePortEdt->lineEdit()->setPlaceholderText("5555");
}
}
void Dialog::savePortHistory(const QString &port)
{
if (port.isEmpty()) {
return;
}
Config::getInstance().savePortHistory(port);
// 更新ComboBox
loadPortHistory();
ui->devicePortEdt->setCurrentText(port);
}
void Dialog::showPortEditMenu(const QPoint &pos)
{
QMenu *menu = ui->devicePortEdt->lineEdit()->createStandardContextMenu();
menu->addSeparator();
QAction *clearHistoryAction = new QAction(tr("Clear History"), menu);
connect(clearHistoryAction, &QAction::triggered, this, [this]() {
Config::getInstance().clearPortHistory();
loadPortHistory();
});
menu->addAction(clearHistoryAction);
menu->exec(ui->devicePortEdt->lineEdit()->mapToGlobal(pos));
delete menu;
}

View file

@ -67,8 +67,6 @@ private slots:
void on_autoUpdatecheckBox_toggled(bool checked); void on_autoUpdatecheckBox_toggled(bool checked);
void showIpEditMenu(const QPoint &pos);
private: private:
bool checkAdbRun(); bool checkAdbRun();
void initUI(); void initUI();
@ -80,12 +78,6 @@ private:
int findDeviceFromeSerialBox(bool wifi); int findDeviceFromeSerialBox(bool wifi);
quint32 getBitRate(); quint32 getBitRate();
const QString &getServerPath(); const QString &getServerPath();
void loadIpHistory();
void saveIpHistory(const QString &ip);
void loadPortHistory();
void savePortHistory(const QString &port);
void showPortEditMenu(const QPoint &pos);
protected: protected:
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);

View file

@ -1059,25 +1059,22 @@
<number>5</number> <number>5</number>
</property> </property>
<item> <item>
<widget class="QComboBox" name="deviceIpEdt"> <widget class="QLineEdit" name="deviceIpEdt">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize"> <property name="text">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string/> <string/>
</property> </property>
<property name="maxLength">
<number>128</number>
</property>
<property name="placeholderText">
<string notr="true">192.168.0.1</string>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@ -1094,25 +1091,22 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QComboBox" name="devicePortEdt"> <widget class="QLineEdit" name="devicePortEdt">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred"> <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize"> <property name="text">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string/> <string/>
</property> </property>
<property name="maxLength">
<number>6</number>
</property>
<property name="placeholderText">
<string notr="true">5555</string>
</property>
</widget> </widget>
</item> </item>
<item> <item>

View file

@ -68,11 +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) {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
m_dragPosition = event->globalPos() - frameGeometry().topLeft(); m_dragPosition = event->globalPos() - frameGeometry().topLeft();
#else
m_dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft();
#endif
event->accept(); event->accept();
} }
} }
@ -85,11 +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) {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
move(event->globalPos() - m_dragPosition); move(event->globalPos() - m_dragPosition);
#else
move(event->globalPosition().toPoint() - m_dragPosition);
#endif
event->accept(); event->accept();
} }
} }

View file

@ -1,4 +1,4 @@
// #include <QDesktopWidget> #include <QDesktopWidget>
#include <QFileInfo> #include <QFileInfo>
#include <QLabel> #include <QLabel>
#include <QMessageBox> #include <QMessageBox>
@ -13,10 +13,6 @@
#include <QWindow> #include <QWindow>
#include <QtWidgets/QHBoxLayout> #include <QtWidgets/QHBoxLayout>
#if defined(Q_OS_WIN32)
#include <Windows.h>
#endif
#include "config.h" #include "config.h"
#include "iconhelper.h" #include "iconhelper.h"
#include "qyuvopenglwidget.h" #include "qyuvopenglwidget.h"
@ -367,18 +363,21 @@ void VideoForm::installShortcut()
QRect VideoForm::getScreenRect() QRect VideoForm::getScreenRect()
{ {
QRect screenRect; QRect screenRect;
QScreen *screen = QGuiApplication::primaryScreen();
QWidget *win = window(); QWidget *win = window();
if (win) { if (!win) {
QWindow *winHandle = win->windowHandle(); return screenRect;
if (winHandle) {
screen = winHandle->screen();
}
} }
if (screen) { QWindow *winHandle = win->windowHandle();
screenRect = screen->availableGeometry(); QScreen *screen = QGuiApplication::primaryScreen();
if (winHandle) {
screen = winHandle->screen();
} }
if (!screen) {
return screenRect;
}
screenRect = screen->availableGeometry();
return screenRect; return screenRect;
} }
@ -573,32 +572,23 @@ void VideoForm::mousePressEvent(QMouseEvent *event)
} }
} }
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QPointF localPos = event->localPos();
QPointF globalPos = event->globalPos();
#else
QPointF localPos = event->position();
QPointF globalPos = event->globalPosition();
#endif
if (m_videoWidget->geometry().contains(event->pos())) { if (m_videoWidget->geometry().contains(event->pos())) {
if (!device) { if (!device) {
return; return;
} }
QPointF mappedPos = m_videoWidget->mapFrom(this, localPos.toPoint()); event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
QMouseEvent newEvent(event->type(), mappedPos, globalPos, event->button(), event->buttons(), event->modifiers()); emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
emit device->mouseEvent(&newEvent, m_videoWidget->frameSize(), m_videoWidget->size());
// debug keymap pos // debug keymap pos
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
qreal x = localPos.x() / m_videoWidget->size().width(); qreal x = event->localPos().x() / m_videoWidget->size().width();
qreal y = localPos.y() / m_videoWidget->size().height(); qreal y = event->localPos().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.toStdString().c_str();
} }
} else { } else {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
m_dragPosition = globalPos.toPoint() - frameGeometry().topLeft(); m_dragPosition = event->globalPos() - frameGeometry().topLeft();
event->accept(); event->accept();
} }
} }
@ -611,15 +601,9 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
if (!device) { if (!device) {
return; return;
} }
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
QPointF localPos = event->localPos();
QPointF globalPos = event->globalPos();
#else
QPointF localPos = event->position();
QPointF globalPos = event->globalPosition();
#endif
// local check // local check
QPointF local = m_videoWidget->mapFrom(this, localPos.toPoint()); QPointF local = event->localPos();
if (local.x() < 0) { if (local.x() < 0) {
local.setX(0); local.setX(0);
} }
@ -632,8 +616,8 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
if (local.y() > m_videoWidget->height()) { if (local.y() > m_videoWidget->height()) {
local.setY(m_videoWidget->height()); local.setY(m_videoWidget->height());
} }
QMouseEvent newEvent(event->type(), local, globalPos, event->button(), event->buttons(), event->modifiers()); event->setLocalPos(local);
emit device->mouseEvent(&newEvent, m_videoWidget->frameSize(), m_videoWidget->size()); emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
} else { } else {
m_dragPosition = QPoint(0, 0); m_dragPosition = QPoint(0, 0);
} }
@ -641,24 +625,16 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
void VideoForm::mouseMoveEvent(QMouseEvent *event) void VideoForm::mouseMoveEvent(QMouseEvent *event)
{ {
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
QPointF localPos = event->localPos();
QPointF globalPos = event->globalPos();
#else
QPointF localPos = event->position();
QPointF globalPos = event->globalPosition();
#endif
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->pos())) {
if (!device) { if (!device) {
return; return;
} }
QPointF mappedPos = m_videoWidget->mapFrom(this, localPos.toPoint()); event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
QMouseEvent newEvent(event->type(), mappedPos, globalPos, event->button(), event->buttons(), event->modifiers()); emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
emit device->mouseEvent(&newEvent, m_videoWidget->frameSize(), m_videoWidget->size());
} else if (!m_dragPosition.isNull()) { } else if (!m_dragPosition.isNull()) {
if (event->buttons() & Qt::LeftButton) { if (event->buttons() & Qt::LeftButton) {
move(globalPos.toPoint() - m_dragPosition); move(event->globalPos() - m_dragPosition);
event->accept(); event->accept();
} }
} }
@ -681,16 +657,8 @@ void VideoForm::mouseDoubleClickEvent(QMouseEvent *event)
if (!device) { if (!device) {
return; return;
} }
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
QPointF localPos = event->localPos(); emit device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
QPointF globalPos = event->globalPos();
#else
QPointF localPos = event->position();
QPointF globalPos = event->globalPosition();
#endif
QPointF mappedPos = m_videoWidget->mapFrom(this, localPos.toPoint());
QMouseEvent newEvent(event->type(), mappedPos, globalPos, event->button(), event->buttons(), event->modifiers());
emit device->mouseEvent(&newEvent, m_videoWidget->frameSize(), m_videoWidget->size());
} }
} }
@ -746,11 +714,7 @@ void VideoForm::paintEvent(QPaintEvent *paint)
{ {
Q_UNUSED(paint) Q_UNUSED(paint)
QStyleOption opt; QStyleOption opt;
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
opt.init(this); opt.init(this);
#else
opt.initFrom(this);
#endif
QPainter p(this); QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
} }

View file

@ -11,9 +11,6 @@
#define GROUP_COMMON "common" #define GROUP_COMMON "common"
// config // config
#define COMMON_LANGUAGE_KEY "Language"
#define COMMON_LANGUAGE_DEF "Auto"
#define COMMON_TITLE_KEY "WindowTitle" #define COMMON_TITLE_KEY "WindowTitle"
#define COMMON_TITLE_DEF QCoreApplication::applicationName() #define COMMON_TITLE_DEF QCoreApplication::applicationName()
@ -21,7 +18,7 @@
#define COMMON_PUSHFILE_DEF "/sdcard/" #define COMMON_PUSHFILE_DEF "/sdcard/"
#define COMMON_SERVER_VERSION_KEY "ServerVersion" #define COMMON_SERVER_VERSION_KEY "ServerVersion"
#define COMMON_SERVER_VERSION_DEF "3.3.1" #define COMMON_SERVER_VERSION_DEF "3.1"
#define COMMON_SERVER_PATH_KEY "ServerPath" #define COMMON_SERVER_PATH_KEY "ServerPath"
#define COMMON_SERVER_PATH_DEF "/data/local/tmp/scrcpy-server.jar" #define COMMON_SERVER_PATH_DEF "/data/local/tmp/scrcpy-server.jar"
@ -111,26 +108,15 @@
#define SERIAL_NICK_NAME_KEY "NickName" #define SERIAL_NICK_NAME_KEY "NickName"
#define SERIAL_NICK_NAME_DEF "Phone" #define SERIAL_NICK_NAME_DEF "Phone"
// IP history
#define IP_HISTORY_KEY "IpHistory"
#define IP_HISTORY_DEF ""
#define IP_HISTORY_MAX 10
// Port history
#define PORT_HISTORY_KEY "PortHistory"
#define PORT_HISTORY_DEF ""
#define PORT_HISTORY_MAX 10
QString Config::s_configPath = ""; 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_userData = new QSettings(getConfigPath() + "/userdata.ini", QSettings::IniFormat);
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
m_settings->setIniCodec("UTF-8"); m_settings->setIniCodec("UTF-8");
m_userData = new QSettings(getConfigPath() + "/userdata.ini", QSettings::IniFormat);
m_userData->setIniCodec("UTF-8"); m_userData->setIniCodec("UTF-8");
#endif
qDebug()<<m_userData->childGroups(); qDebug()<<m_userData->childGroups();
} }
@ -377,15 +363,6 @@ void Config::deleteGroup(const QString &serial)
m_userData->remove(serial); m_userData->remove(serial);
} }
QString Config::getLanguage()
{
QString language;
m_settings->beginGroup(GROUP_COMMON);
language = m_settings->value(COMMON_LANGUAGE_KEY, COMMON_LANGUAGE_DEF).toString();
m_settings->endGroup();
return language;
}
QString Config::getTitle() QString Config::getTitle()
{ {
QString title; QString title;
@ -394,67 +371,3 @@ QString Config::getTitle()
m_settings->endGroup(); m_settings->endGroup();
return title; return title;
} }
void Config::saveIpHistory(const QString &ip)
{
QStringList ipList = getIpHistory();
// 移除已存在的相同IP避免重复
ipList.removeAll(ip);
// 将新IP添加到开头
ipList.prepend(ip);
// 限制历史记录数量
while (ipList.size() > IP_HISTORY_MAX) {
ipList.removeLast();
}
m_userData->setValue(IP_HISTORY_KEY, ipList);
m_userData->sync();
}
QStringList Config::getIpHistory()
{
QStringList ipList = m_userData->value(IP_HISTORY_KEY, IP_HISTORY_DEF).toStringList();
ipList.removeAll("");
return ipList;
}
void Config::clearIpHistory()
{
m_userData->remove(IP_HISTORY_KEY);
m_userData->sync();
}
void Config::savePortHistory(const QString &port)
{
QStringList portList = getPortHistory();
// 移除已存在的相同Port避免重复
portList.removeAll(port);
// 将新Port添加到开头
portList.prepend(port);
// 限制历史记录数量
while (portList.size() > PORT_HISTORY_MAX) {
portList.removeLast();
}
m_userData->setValue(PORT_HISTORY_KEY, portList);
m_userData->sync();
}
QStringList Config::getPortHistory()
{
QStringList portList = m_userData->value(PORT_HISTORY_KEY, PORT_HISTORY_DEF).toStringList();
portList.removeAll("");
return portList;
}
void Config::clearPortHistory()
{
m_userData->remove(PORT_HISTORY_KEY);
m_userData->sync();
}

View file

@ -34,7 +34,6 @@ public:
static Config &getInstance(); static Config &getInstance();
// config // config
QString getLanguage();
QString getTitle(); QString getTitle();
QString getServerVersion(); QString getServerVersion();
int getMaxFps(); int getMaxFps();
@ -63,16 +62,6 @@ public:
void deleteGroup(const QString &serial); void deleteGroup(const QString &serial);
// IP history methods
void saveIpHistory(const QString &ip);
QStringList getIpHistory();
void clearIpHistory();
// Port history methods
void savePortHistory(const QString &port);
QStringList getPortHistory();
void clearPortHistory();
private: private:
explicit Config(QObject *parent = nullptr); explicit Config(QObject *parent = nullptr);
const QString &getConfigPath(); const QString &getConfigPath();

View file

@ -1,10 +1,4 @@
#include <QtGlobal> #include <QX11Info>
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
#include <QtX11Extras/QX11Info>
#else
#include <QtGui/private/qtx11extras_p.h>
#endif
#include <xcb/xproto.h> #include <xcb/xproto.h>
#include <stdlib.h> #include <stdlib.h>

View file

@ -7,7 +7,6 @@
![license](https://img.shields.io/badge/license-Apache2.0-blue.svg) ![license](https://img.shields.io/badge/license-Apache2.0-blue.svg)
![release](https://img.shields.io/github/v/release/barry-ran/QtScrcpy.svg) ![release](https://img.shields.io/github/v/release/barry-ran/QtScrcpy.svg)
![star](https://img.shields.io/github/stars/barry-ran/QtScrcpy.svg)
[中文用户?点我查看中文介绍](README_zh.md) [中文用户?点我查看中文介绍](README_zh.md)
@ -32,30 +31,14 @@ It focuses on:
![linux](screenshot/linux-en.png) ![linux](screenshot/linux-en.png)
## The author has developed a more professional screen casting software called `QuickMirror`
QuickMirror function&features:
- Equipment screen casting&control: batch screen casting, individual control, batch control
- Group management
- WiFi screen mirroring/OTG screen mirroring
- Adb shell shortcut command
- File transfer, apk installation
- Multiple screen mirroring: In OTG mirroring mode, with low resolution and smoothness settings, a single computer can manage 500+phones simultaneously
- Low latency: USB screen mirroring 1080p latency is within 30ms, which is lower than all screen mirroring software on the market in terms of latency at the same resolution and smoothness
- Low CPU usage: pure C++development, high-performance GPU video rendering
- High resolution: adjustable, maximum support for native resolution of Android terminals
- Perfect Chinese input: Supports Xianyu app, supports Samsung phones
- The free version can cast up to 10 screens, with unlimited functionality (except for automatic screen mirroring)
- QuickMirror tutorial: https://lrbnfell4p.feishu.cn/docx/EMkvdfIvDowy3UxsXUCcpPV8nDh
- QuickMirror Telegram communication group: https://t.me/+Ylf_5V_rDCMyODQ1
- Preview of QuickMirror Interface:
![quickmirror](docs/image/quickmirror.png)
## Mapping Keys ## Mapping Keys
You can write your script to map keyboard and mouse actions to touches and clicks of the mobile phone according to your needs. [Here](docs/KeyMapDes.md) are the script writing rules. You can write your script to map keyboard and mouse actions to touches and clicks of the mobile phone according to your needs. [Here](docs/KeyMapDes.md) are the script writing rules.
Script for TikTok and some other games are provided by default. Once enabled, you can play the game with your keyboard and mouse. The default key mapping for PUBG Mobile is as follows: Script for TikTok and some other games are provided by default. Once enabled, you can play the game with your keyboard and mouse. The default key mapping for PUBG Mobile is as follows:
![game](screenshot/game.png) ![game](screenshot/game.jpg)
[Here is a video demonstration playing PUBG Mobile.](http://mp.weixin.qq.com/mp/video?__biz=MzU1NTg5MjYyNw==&mid=100000015&sn=3e301fdc5a364bd16d6207fa674bc8b3&vid=wxv_968792362971430913)
Instruction for adding new customized mapping files. Instruction for adding new customized mapping files.
@ -67,22 +50,6 @@ Instruction for adding new customized mapping files.
- Press the ~ key again to switch back to normal mode - Press the ~ key again to switch back to normal mode
- (For games such as PUBG Mobile) If you want to move vehicles with the STEER_WHEEL keys, you need to set the move mode to `single rocker mode`. - (For games such as PUBG Mobile) If you want to move vehicles with the STEER_WHEEL keys, you need to set the move mode to `single rocker mode`.
If you don't know how to manually write mapping rules, you can also use the `QuickAssistant` developed by the author
QuickAssistant Features&Functions:
- Play Android mobile games smoothly through keyboard and mouse
- Interface based editing of key mapping script
- Support pausing the computer screen and using only keyboard and mouse operations
- Screenshot&Recording of Mobile Screen
- Simple batch control
- Android 11+supports playing mobile audio on computers (under development...)
- Mobile app installation free
- Fast and instant connection
- Low latency: USB screen mirroring 1080p latency is within 30ms, which is lower than all screen mirroring software on the market in terms of latency at the same resolution and smoothness
- Low CPU usage: pure C++development, high-performance GPU video rendering
- High resolution: adjustable, maximum support for native resolution of Android terminals
- Telegram Grouphttps://t.me/+EnQNmb47C_liYmRl
- [QuickAssistant](https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh)
## Group control ## Group control
You can control all your phones at the same time. You can control all your phones at the same time.
@ -122,9 +89,9 @@ It details the development architecture and the development process of the entir
Course introduction[https://blog.csdn.net/rankun1/article/details/87970523](https://blog.csdn.net/rankun1/article/details/87970523) Course introduction[https://blog.csdn.net/rankun1/article/details/87970523](https://blog.csdn.net/rankun1/article/details/87970523)
You can join Telegram Group for QtScrcpy and exchange ideas with like-minded friends. You can join my QQ group for QtScrcpy and exchange ideas with like-minded friends.
Telegram Grouphttps://t.me/+EnQNmb47C_liYmRl QQ Group number901736468
## Requirements ## Requirements

View file

@ -6,8 +6,6 @@
![license](https://img.shields.io/badge/license-Apache2.0-blue.svg) ![license](https://img.shields.io/badge/license-Apache2.0-blue.svg)
![release](https://img.shields.io/github/v/release/barry-ran/QtScrcpy.svg) ![release](https://img.shields.io/github/v/release/barry-ran/QtScrcpy.svg)
![star](https://img.shields.io/github/stars/barry-ran/QtScrcpy.svg)
![star](https://gitcode.com/barry-ran/QtScrcpy/star/badge.svg)
[Speaks English? Click me for English introduction.](README.md) [Speaks English? Click me for English introduction.](README.md)
@ -55,7 +53,9 @@ QtScrcpy 可以通过 USB / 网络连接Android设备并进行显示和控制
默认自带了针对和平精英手游和抖音进行键鼠映射的映射脚本,开启平精英手游后可以用键鼠像玩端游一样玩和平精英手游,开启抖音映射以后可以使用上下左右方向键模拟上下左右滑动,你也可以按照[编写规则](docs/KeyMapDes_zh.md)编写其他游戏的映射文件,默认按键映射如下: 默认自带了针对和平精英手游和抖音进行键鼠映射的映射脚本,开启平精英手游后可以用键鼠像玩端游一样玩和平精英手游,开启抖音映射以后可以使用上下左右方向键模拟上下左右滑动,你也可以按照[编写规则](docs/KeyMapDes_zh.md)编写其他游戏的映射文件,默认按键映射如下:
![game](screenshot/game.png) ![game](screenshot/game.jpg)
[这里有玩和平精英的视频演示](http://mp.weixin.qq.com/mp/video?__biz=MzU1NTg5MjYyNw==&mid=100000015&sn=3e301fdc5a364bd16d6207fa674bc8b3&vid=wxv_968792362971430913&idx=1&vidsn=eec329cc13c3e24c187dc9b4d5eb8760&fromid=1&scene=20&xtrack=1&clicktime=1567346543&sessionid=1567346375&subscene=92&ascene=0&fasttmpl_type=0&fasttmpl_fullversion=4730859-zh_CN-zip&fasttmpl_flag=0&realreporttime=1567346543910#wechat_redirect)
自定义按键映射操作方法如下: 自定义按键映射操作方法如下:
- 编写自定义脚本放入 keymap 目录 - 编写自定义脚本放入 keymap 目录
@ -66,22 +66,6 @@ QtScrcpy 可以通过 USB / 网络连接Android设备并进行显示和控制
- 再次按~键切换为正常控制模式 - 再次按~键切换为正常控制模式
- (对于和平精英等游戏)若想使用方向盘控制载具,记得在载具设置中设置为单摇杆模式 - (对于和平精英等游戏)若想使用方向盘控制载具,记得在载具设置中设置为单摇杆模式
如果不会自己手写映射规则,也可以去使用作者开发的`极限手游助手`
极限手游助手功能&特点:
- 通过键盘鼠标畅玩安卓手机游戏
- 按键映射脚本界面化编辑
- 支持暂停电脑端画面,只使用键鼠操作
- 截图&录制手机画面
- 简单批量控制
- 安卓11+支持电脑播放手机音频(开发中...
- 手机端免安装App
- 极速秒连接
- 低延迟usb投屏1080p延迟在30ms以内在相同分辨率流畅度情况下比市面上所有投屏软件延迟都低
- cpu占用率低纯C++开发高性能GPU视频渲染
- 高分辨率:可调节,最大支持安卓终端的原生分辨率
- [QQ交流群901736468](https://qm.qq.com/q/wRJJaWLWc8)
- [极限手游助手说明文档](https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh)
## 批量操作 ## 批量操作
你可以同时控制所有的手机 你可以同时控制所有的手机

View file

@ -1,3 +1,3 @@
# https://doc.qt.io/qt-5/linguist-manager.html#lrelease # https://doc.qt.io/qt-5/linguist-manager.html#lrelease
# lrelease -help # lrelease -help
lrelease ./QtScrcpy/res/i18n/en_US.ts ./QtScrcpy/res/i18n/zh_CN.ts ./QtScrcpy/res/i18n/ja_JP.ts lrelease ./QtScrcpy/res/i18n/en_US.ts ./QtScrcpy/res/i18n/zh_CN.ts

View file

@ -1,4 +1,4 @@
# https://doc.qt.io/qt-5/linguist-manager.html#lupdate # https://doc.qt.io/qt-5/linguist-manager.html#lupdate
# lupdate -help # lupdate -help
# export PATH=/D/Qt/5.15.2/msvc2019/bin:$PATH # export PATH=/D/Qt/5.15.2/msvc2019/bin:$PATH
lupdate -no-obsolete ./QtScrcpy -ts ./QtScrcpy/res/i18n/en_US.ts ./QtScrcpy/res/i18n/zh_CN.ts ./QtScrcpy/res/i18n/ja_JP.ts lupdate -no-obsolete ./QtScrcpy -ts ./QtScrcpy/res/i18n/en_US.ts ./QtScrcpy/res/i18n/zh_CN.ts

View file

@ -8,6 +8,7 @@ echo ---------------------------------------------------------------
# 从环境变量获取必要参数 # 从环境变量获取必要参数
# 例如 /Users/barry/Qt5.12.5/5.12.5 # 例如 /Users/barry/Qt5.12.5/5.12.5
echo ENV_QT_PATH $ENV_QT_PATH echo ENV_QT_PATH $ENV_QT_PATH
qt_cmake_path=$ENV_QT_PATH/clang_64/lib/cmake/Qt5
# 获取绝对路径,保证其他目录执行此脚本依然正确 # 获取绝对路径,保证其他目录执行此脚本依然正确
{ {
@ -21,7 +22,6 @@ cd $(dirname "$0")
# 启动参数声明 # 启动参数声明
build_mode=RelWithDebInfo build_mode=RelWithDebInfo
cpu_arch=arm64
echo echo
echo echo
@ -36,30 +36,8 @@ if [[ $build_mode != "Release" && $build_mode != "Debug" && $build_mode != "MinS
exit 1 exit 1
fi fi
echo
echo
echo ---------------------------------------------------------------
echo check cpu arch[x64/arm64]
echo ---------------------------------------------------------------
cpu_arch=$(echo $2)
if [[ $cpu_arch != "x64" && $cpu_arch != "arm64" ]]; then
echo "error: unkonow cpu mode -- $2"
exit 1
fi
# 提示 # 提示
echo current build mode: $build_mode echo current build mode: $build_mode
echo current cpu mode: $cpu_arch
cmake_arch=x86_64
if [ $cpu_arch == "x64" ]; then
qt_cmake_path=$ENV_QT_PATH/clang_64/lib/cmake/Qt5
cmake_arch=x86_64
else
qt_cmake_path=$ENV_QT_PATH/macos/lib/cmake/Qt6
cmake_arch=arm64
fi
echo echo
echo echo
@ -80,7 +58,7 @@ fi
mkdir $build_path mkdir $build_path
cd $build_path cd $build_path
cmake_params="-DCMAKE_PREFIX_PATH=$qt_cmake_path -DCMAKE_BUILD_TYPE=$build_mode -DCMAKE_OSX_ARCHITECTURES=$cmake_arch" cmake_params="-DCMAKE_PREFIX_PATH=$qt_cmake_path -DCMAKE_BUILD_TYPE=$build_mode -DCMAKE_OSX_ARCHITECTURES=x86_64 -D CMAKE_OSX_DEPLOYMENT_TARGET=10.10"
cmake $cmake_params ../.. cmake $cmake_params ../..
if [ $? -ne 0 ] ;then if [ $? -ne 0 ] ;then
echo "cmake failed" echo "cmake failed"

View file

@ -7,6 +7,7 @@ echo ---------------------------------------------------------------
# 从环境变量获取必要参数 # 从环境变量获取必要参数
# 例如 /Users/barry/Qt5.12.5/5.12.5 # 例如 /Users/barry/Qt5.12.5/5.12.5
echo ENV_QT_PATH $ENV_QT_PATH echo ENV_QT_PATH $ENV_QT_PATH
qt_clang_path=$ENV_QT_PATH/clang_64
# 获取绝对路径,保证其他目录执行此脚本依然正确 # 获取绝对路径,保证其他目录执行此脚本依然正确
{ {
@ -20,27 +21,6 @@ cd $(dirname "$0")
# 启动参数声明 # 启动参数声明
publish_dir=$1 publish_dir=$1
cpu_arch=$2
echo
echo
echo ---------------------------------------------------------------
echo check cpu arch[x64/arm64]
echo ---------------------------------------------------------------
if [[ $cpu_arch != "x64" && $cpu_arch != "arm64" ]]; then
echo "error: unkonow cpu mode -- $2"
exit 1
fi
# 提示
echo current cpu mode: $cpu_arch
if [ $cpu_arch == "x64" ]; then
qt_clang_path=$ENV_QT_PATH/clang_64
else
qt_clang_path=$ENV_QT_PATH/macos
fi
# 提示 # 提示
echo current publish dir: $publish_dir echo current publish dir: $publish_dir
@ -50,7 +30,7 @@ keymap_path=$script_path/../../keymap
# config_path=$script_path/../../config # config_path=$script_path/../../config
publish_path=$script_path/$publish_dir publish_path=$script_path/$publish_dir
release_path=$script_path/../../output/$cpu_arch/RelWithDebInfo release_path=$script_path/../../output/x64/RelWithDebInfo
export PATH=$qt_clang_path/bin:$PATH export PATH=$qt_clang_path/bin:$PATH

View file

@ -86,7 +86,7 @@ if exist %temp_path% (
md %temp_path% md %temp_path%
cd %temp_path% cd %temp_path%
set cmake_params=-DCMAKE_PREFIX_PATH=%qt_cmake_path% -DCMAKE_BUILD_TYPE=%build_mode% -G "Visual Studio 17 2022" -A %cmake_vs_build_mode% set cmake_params=-DCMAKE_PREFIX_PATH=%qt_cmake_path% -DCMAKE_BUILD_TYPE=%build_mode% -G "Visual Studio 16 2019" -A %cmake_vs_build_mode%
echo cmake params: %cmake_params% echo cmake params: %cmake_params%
cmake %cmake_params% ../.. cmake %cmake_params% ../..

View file

@ -1,6 +1,4 @@
[common] [common]
# 语言 Auto=自动zh_CN=简体中文en_US=English
Language=Auto
# 窗口标题 # 窗口标题
WindowTitle=QtScrcpy WindowTitle=QtScrcpy
# 推送到安卓设备的文件保存路径(必须以/结尾) # 推送到安卓设备的文件保存路径(必须以/结尾)
@ -12,7 +10,7 @@ RenderExpiredFrames=0
# 视频解码方式:-1 自动0 软解1 dx硬解2 opengl硬解 # 视频解码方式:-1 自动0 软解1 dx硬解2 opengl硬解
UseDesktopOpenGL=-1 UseDesktopOpenGL=-1
# scrcpy-server的版本号不要修改 # scrcpy-server的版本号不要修改
ServerVersion=3.3.1 ServerVersion=3.1
# scrcpy-server推送到安卓设备的路径 # scrcpy-server推送到安卓设备的路径
ServerPath=/data/local/tmp/scrcpy-server.jar ServerPath=/data/local/tmp/scrcpy-server.jar
# 自定义adb路径例如D:/android/tools/adb.exe # 自定义adb路径例如D:/android/tools/adb.exe

View file

@ -76,11 +76,7 @@ Description of the unique attributes of different key mapping types:
## Visual Key Mapping Tool ## Visual Key Mapping Tool
1. Just use [QuickAssistant](https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh) A web-based GUI tool is available to help you create and manage key mappings visually: [ScrcpyKeyMapper](https://github.com/w4po/ScrcpyKeyMapper)
![game](../screenshot/game.png)
2. A web-based GUI tool is available to help you create and manage key mappings visually: [ScrcpyKeyMapper](https://github.com/w4po/ScrcpyKeyMapper)
![ScrcpyKeyMapper Screenshot](https://raw.githubusercontent.com/w4po/ScrcpyKeyMapper/main/assets/screenshot.png) ![ScrcpyKeyMapper Screenshot](https://raw.githubusercontent.com/w4po/ScrcpyKeyMapper/main/assets/screenshot.png)

View file

@ -75,11 +75,8 @@
- downOffset 按下下方向键后模拟拖动到相对centerPos位置水平偏下downOffset处 - downOffset 按下下方向键后模拟拖动到相对centerPos位置水平偏下downOffset处
## 可视化按键映射工具 ## 可视化按键映射工具
1. 直接使用[QuickAssistant](https://lrbnfell4p.feishu.cn/drive/folder/Hqckfxj5el1Wjpd9uezcX71lnBh)
![game](../screenshot/game.png) 现在有一个基于Web的GUI工具可以帮助你直观地创建和管理按键映射[ScrcpyKeyMapper](https://github.com/w4po/ScrcpyKeyMapper)
2. 还有一个基于Web的GUI工具可以帮助你直观地创建和管理按键映射[ScrcpyKeyMapper](https://github.com/w4po/ScrcpyKeyMapper)
![ScrcpyKeyMapper截图](https://raw.githubusercontent.com/w4po/ScrcpyKeyMapper/main/assets/screenshot.png) ![ScrcpyKeyMapper截图](https://raw.githubusercontent.com/w4po/ScrcpyKeyMapper/main/assets/screenshot.png)

BIN
screenshot/game.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 KiB