diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..4666405 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.19 FATAL_ERROR) + +# Read version numbers from file +file (STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/QtScrcpy/version STRING_VERSION) +message(STATUS "QtScrcpy Version ${STRING_VERSION}") +project(QtScrcpy + VERSION ${STRING_VERSION} + LANGUAGES C CXX +) + +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + enable_language(OBJCXX) +endif() + +# Split version numbers +string(REPLACE "." ";" VERSION_LIST ${STRING_VERSION}) +list(GET VERSION_LIST 0 VERSION_MAJOR) +list(GET VERSION_LIST 1 VERSION_MINOR) +list(GET VERSION_LIST 2 VERSION_PATCH) + +add_subdirectory(QtScrcpy) diff --git a/QtScrcpy/CMakeLists.txt b/QtScrcpy/CMakeLists.txt new file mode 100755 index 0000000..b70a7f8 --- /dev/null +++ b/QtScrcpy/CMakeLists.txt @@ -0,0 +1,318 @@ +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# *********************************************************** +# Qt Package finding +# *********************************************************** + +find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets Network LinguistTools REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets Network LinguistTools REQUIRED) + +# *********************************************************** +# Cross-platform settings +# *********************************************************** + +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + + # FFmpeg cannot be compiled natively by MSVC version < 12.0 (2013) + if(MSVC_VERSION LESS 1800) + message(FATAL_ERROR "[QtScrcpy] FATAL ERROR: MSVC version is older than 12.0 (2013).") + endif() + + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8") + +endif() + + +# ==================== macOS ==================== +if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # QS_MAC_RESOURCES: esource file list stored in Contents/MacOS + file(GLOB QS_MAC_RESOURCES "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/lib/*.dylib") + list(APPEND QS_MAC_RESOURCES + "${PROJECT_SOURCE_DIR}/third_party/scrcpy-server" + "${PROJECT_SOURCE_DIR}/adb/mac/adb" + ) + + # QS_MAC_CONFIG: Config file stored in Contents/MacOS/config + set(QS_MAC_CONFIG "${PROJECT_SOURCE_DIR}/config/config.ini") +endif() + +set(QS_TS_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/res/i18n/zh_CN.ts + ${CMAKE_CURRENT_SOURCE_DIR}/res/i18n/en_US.ts + ) +set_source_files_properties(${QS_TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/res/i18n") + +set(QS_SOURCES_MAIN + dialog.cpp + dialog.h + dialog.ui + ${QS_TS_FILES} +) + +set(QS_QRC_MAIN "${CMAKE_CURRENT_SOURCE_DIR}/res/res.qrc") + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) # Qt version 6 + qt_create_translation(QS_QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${QS_TS_FILES}) + + if(WIN32) + qt_add_executable(${CMAKE_PROJECT_NAME} WIN32 MANUAL_FINALIZATION + main.cpp + ${QS_SOURCES_MAIN} + ${QS_QRC_MAIN} + ) + + elseif(UNIX) + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + qt_add_executable(${CMAKE_PROJECT_NAME} MACOSX_BUNDLE MANUAL_FINALIZATION + main.cpp + ${QS_SOURCES_MAIN} + ${QS_MAC_RESOURCES} + ${QS_MAC_CONFIG} + ${QS_QRC_MAIN} + ) + + else() + qt_add_executable(${CMAKE_PROJECT_NAME} MANUAL_FINALIZATION + main.cpp + ${QS_SOURCES_MAIN} + ${QS_QRC_MAIN} + ) + + endif() + endif() + +else() # Qt version 5 + qt5_create_translation(QS_QM_FILES ${CMAKE_CURRENT_SOURCE_DIR} ${QS_TS_FILES}) + + if(WIN32) + add_executable(${CMAKE_PROJECT_NAME} WIN32 + main.cpp + ${QS_SOURCES_MAIN} + ${QS_QRC_MAIN} + ) + elseif(UNIX) + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + add_executable(${CMAKE_PROJECT_NAME} MACOSX_BUNDLE + main.cpp + ${QS_SOURCES_MAIN} + ${QS_MAC_RESOURCES} + ${QS_MAC_CONFIG} + ${QS_QRC_MAIN} + ) + else() + add_executable(${CMAKE_PROJECT_NAME} + main.cpp + ${QS_SOURCES_MAIN} + ${QS_QRC_MAIN} + ) + endif() + endif() + +endif() + +# ******************** Microsoft Windows ******************** +if(WIN32) + message(STATUS "[QtScrcpy] Make for Microsoft Windows.") + + # 通过rc的方式的话,VERSION变量rc中获取不到,定义为宏方便rc中使用 + # Define macros for .rc file + add_compile_definitions( + VERSION_MAJOR=${VERSION_MAJOR} + VERSION_MINOR=${VERSION_MINOR} + VERSION_PATCH=${VERSION_PATCH} + VERSION_RC_STR=\\\"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}\\\" + ) + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) # Compiler is 64-bit + message(STATUS "[QtScrcpy] 64-bit compiler detected.") + + set(QS_LIB_PATH "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/lib/x64") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + message(STATUS "[QtScrcpy] In debug mode.") + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/win/x64/debug" + ) + else() + message(STATUS "[QtScrcpy] In release mode.") + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/win/x64/release") + endif() + + set(QS_DLL_PATH "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/bin/x64") + elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) # Compiler is 32-bit + message(STATUS "[QtScrcpy] 32-bit compiler detected.") + + set(QS_LIB_PATH "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/lib/x86") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + message(STATUS "[QtScrcpy] In debug mode.") + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/win/x86/debug") + else() + message(STATUS "[QtScrcpy] In release mode.") + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/win/x86/release") + endif() + + set(QS_DLL_PATH "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/bin/x86") + endif() + + # 构建完成后复制DLL依赖库 + # Copy DLL dependencies after building + get_target_property(QS_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_PROJECT_NAME} RUNTIME_OUTPUT_DIRECTORY) + file(GLOB QS_DLL_FILES "${QS_DLL_PATH}/*.dll") + foreach(QS_DLL_FILE ${QS_DLL_FILES}) + add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND + ${CMAKE_COMMAND} -E copy_if_different + "${QS_DLL_FILE}" "${QS_RUNTIME_OUTPUT_DIRECTORY}" + ) + endforeach() + + # If MinGW is used, it is not appropriate to link static MSVC libs. + # Instead, we link DLLs directly + if(MSVC) + message(STATUS "[QtScrcpy] Microsoft Visual C++ is used.") + link_directories(${QS_LIB_PATH}) + set(QS_EXTERNAL_LIBS_FFMPEG + avformat + avcodec + avutil + swscale + ) + elseif(MINGW) + message(STATUS "[QtScrcpy] MinGW GCC is used.") + target_link_options(${CMAKE_PROJECT_NAME} PRIVATE + "-static" + ${QS_DLL_FILES} + "-Wl,--enable-stdcall-fixup" + ) + endif() + + set(RC_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/QtScrcpy.rc") + +# ******************** Unix-like OSs ******************** +elseif(UNIX) + set(QS_LIB_PATH "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/lib") + + # ==================== macOS ==================== + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + message(STATUS "[QtScrcpy] Make for macOS.") + target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE ${QS_LIB_PATH}) + + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/mac/debug") + else() + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/mac/release") + endif() + + # Icon file stored in Contents/Resources + set(QS_MAC_ICON_NAME "QtScrcpy.icns") + set(QS_MAC_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/res/${QS_MAC_ICON_NAME}") + + set_source_files_properties(${QS_MAC_RESOURCES} PROPERTIES + MACOSX_PACKAGE_LOCATION "MacOS" + ) + set_source_files_properties(${QS_MAC_CONFIG} PROPERTIES + MACOSX_PACKAGE_LOCATION "MacOS/config" + ) + + set(QS_EXTERNAL_LIBS_FFMPEG + avformat.58 + avcodec.58 + avutil.56 + swscale.5 + ) + + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + # The base plist template file + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/res/Info_Mac.plist" + # The elements to be overwritten + MACOSX_BUNDLE_ICON_FILE "${QS_MAC_ICON_NAME}" + MACOSX_BUNDLE_BUNDLE_VERSION "${STRING_VERSION}" + MACOSX_BUNDLE_SHORT_VERSION_STRING "${STRING_VERSION}" + MACOSX_BUNDLE_LONG_VERSION_STRING "${STRING_VERSION}" + + # Copy file(s) to Contents/Resources + RESOURCE "${QS_MAC_ICON_PATH}" + ) + + # =============== Non-Mac OSs (Linux, BSD, etc.) =============== + else() + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/linux/debug") + else() + set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/output/linux/release") + endif() + + find_package(Threads REQUIRED) + + message(STATUS "[QtScrcpy] Make for non-Mac Unix-like OS.") + set(INSTALLED_FFMPEG_FOUND false) + + find_package(PkgConfig) + if(PkgConfig_FOUND) + pkg_check_modules(FFmpeg libavformat>=58 libavcodec>=58 libavutil>=56 libswscale>=5) + if(FFmpeg_FOUND) + set(INSTALLED_FFMPEG_FOUND true) + message(STATUS "[QtScrcpy] Development files of FFmpeg were detected in your OS and will be used.") + target_link_options(${CMAKE_PROJECT_NAME} PRIVATE ${FFmpeg_LDFLAGS}) + target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE ${FFmpeg_CFLAGS}) + set(QS_EXTERNAL_LIBS_FFMPEG ${FFmpeg_LIBRARIES}) + endif() + endif() + + if(NOT INSTALLED_FFMPEG_FOUND) + message(STATUS "[QtScrcpy] Development files of FFmpeg were not detected in your OS. Files within third_party/ffmpeg/ will be used.") + target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE ${QS_LIB_PATH}) + set(QS_EXTERNAL_LIBS_FFMPEG + avformat + avcodec + avutil + swscale + Threads::Threads + ) + endif() + endif() +endif() + +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +set(QS_SUBDIRECTORIES_MAIN + adb + common + device + devicemanage + fontawesome + uibase + util +) +foreach(QS_SUBDIRECTORY_MAIN ${QS_SUBDIRECTORIES_MAIN}) + add_subdirectory(${QS_SUBDIRECTORY_MAIN}) +endforeach() + +target_link_libraries(${CMAKE_PROJECT_NAME} PUBLIC + adb + devicemanage + ) + +target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Network + device + stream + ui + util + ) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(${CMAKE_PROJECT_NAME}) +endif() diff --git a/QtScrcpy/QtScrcpy.pro b/QtScrcpy/QtScrcpy.pro index e61704c..990537e 100644 --- a/QtScrcpy/QtScrcpy.pro +++ b/QtScrcpy/QtScrcpy.pro @@ -48,10 +48,6 @@ HEADERS += \ FORMS += \ dialog.ui -# 试用检查 -# DEFINES += TRIAL_EXPIRE_CHECK -DEFINES += TRIAL_TIMES=10 - # 子工程 include ($$PWD/common/common.pri) include ($$PWD/adb/adb.pri) diff --git a/QtScrcpy/adb/CMakeLists.txt b/QtScrcpy/adb/CMakeLists.txt new file mode 100755 index 0000000..3644ade --- /dev/null +++ b/QtScrcpy/adb/CMakeLists.txt @@ -0,0 +1,11 @@ +set(QS_SOURCES_ADB + adbprocess.h + adbprocess.cpp +) + +add_library(adb ${QS_SOURCES_ADB}) +target_include_directories(adb PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(adb PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + util + ) diff --git a/QtScrcpy/common/CMakeLists.txt b/QtScrcpy/common/CMakeLists.txt new file mode 100755 index 0000000..cd2b0c6 --- /dev/null +++ b/QtScrcpy/common/CMakeLists.txt @@ -0,0 +1,6 @@ +set(QS_SOURCES_COMMON + qscrcpyevent.h +) + +add_library(common INTERFACE ${QS_SOURCES_COMMON}) +target_include_directories(common INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/QtScrcpy/device/CMakeLists.txt b/QtScrcpy/device/CMakeLists.txt new file mode 100755 index 0000000..6e8b837 --- /dev/null +++ b/QtScrcpy/device/CMakeLists.txt @@ -0,0 +1,40 @@ +set(QS_SUBDIRECTORIES_DEVICE + android + controller + decoder + filehandler + recorder + render + server + stream + ui +) + +set(QS_SOURCES_DEVICE + device.h + device.cpp +) + +add_library(device ${QS_SOURCES_DEVICE}) + +target_include_directories(device PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(QS_SUBDIRECTORY_DEVICE ${QS_SUBDIRECTORIES_DEVICE}) + add_subdirectory (${QS_SUBDIRECTORY_DEVICE}) +endforeach() + +target_link_libraries(device INTERFACE inputconvert) +target_link_libraries(device PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + # device (self) + controller + decoder + filehandler + recorder + server + stream + ui + util + mousetap + ) + diff --git a/QtScrcpy/device/android/CMakeLists.txt b/QtScrcpy/device/android/CMakeLists.txt new file mode 100755 index 0000000..432d749 --- /dev/null +++ b/QtScrcpy/device/android/CMakeLists.txt @@ -0,0 +1,7 @@ +set(QS_SOURCES_DEVICE_ANDROID + input.h + keycodes.h +) + +add_library(android INTERFACE ${QS_SOURCES_DEVICE_ANDROID}) +target_include_directories(android INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/QtScrcpy/device/controller/CMakeLists.txt b/QtScrcpy/device/controller/CMakeLists.txt new file mode 100755 index 0000000..cf34254 --- /dev/null +++ b/QtScrcpy/device/controller/CMakeLists.txt @@ -0,0 +1,26 @@ +SET(QS_SUBDIRECTORIES_DEVICE_CONTROLLER + inputconvert + receiver +) + +SET(QS_SOURCES_DEVICE_CONTROLLER + controller.h + controller.cpp +) + +add_library(controller ${QS_SOURCES_DEVICE_CONTROLLER}) + +target_include_directories(controller PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(QS_SUBDIRECTORY_DEVICE_CONTROLLER ${QS_SUBDIRECTORIES_DEVICE_CONTROLLER}) + add_subdirectory (${QS_SUBDIRECTORY_DEVICE_CONTROLLER}) +endforeach() + +target_link_libraries(controller PUBLIC + inputconvert + ) +target_link_libraries(controller PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + receiver + server + ) diff --git a/QtScrcpy/device/controller/inputconvert/CMakeLists.txt b/QtScrcpy/device/controller/inputconvert/CMakeLists.txt new file mode 100755 index 0000000..2c5cd44 --- /dev/null +++ b/QtScrcpy/device/controller/inputconvert/CMakeLists.txt @@ -0,0 +1,39 @@ +SET(QS_SUBDIRECTORIES_DEVICE_CONTROLLER_INPUTCONVERT + keymap +) + +set(QS_SOURCES_DEVICE_CONTROLLER_INPUTCONVERT + controlmsg.h + controlmsg.cpp + inputconvertbase.h + inputconvertbase.cpp + inputconvertgame.h + inputconvertgame.cpp + inputconvertnormal.h + inputconvertnormal.cpp +) + +add_library(inputconvert ${QS_SOURCES_DEVICE_CONTROLLER_INPUTCONVERT}) + +target_include_directories(inputconvert PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(QS_SUBDIRECTORY_DEVICE_CONTROLLER_INPUTCONVERT ${QS_SUBDIRECTORIES_DEVICE_CONTROLLER_INPUTCONVERT}) + add_subdirectory (${QS_SUBDIRECTORY_DEVICE_CONTROLLER_INPUTCONVERT}) +endforeach() + +target_link_libraries(inputconvert PUBLIC + common + # controller + android + ) +target_link_libraries(inputconvert INTERFACE + # controller + # inputconvert (self) + keymap + ) +target_link_libraries(inputconvert PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + + controller + util + ) diff --git a/QtScrcpy/device/controller/inputconvert/inputconvertgame.cpp b/QtScrcpy/device/controller/inputconvert/inputconvertgame.cpp index d568759..e0871f8 100644 --- a/QtScrcpy/device/controller/inputconvert/inputconvertgame.cpp +++ b/QtScrcpy/device/controller/inputconvert/inputconvertgame.cpp @@ -2,12 +2,18 @@ #include #include #include +#include +#include #include "inputconvertgame.h" #define CURSOR_POS_CHECK 50 -InputConvertGame::InputConvertGame(Controller *controller) : InputConvertNormal(controller) {} +InputConvertGame::InputConvertGame(Controller *controller) : InputConvertNormal(controller) { + m_ctrlSteerWheel.delayData.timer = new QTimer(this); + m_ctrlSteerWheel.delayData.timer->setSingleShot(true); + connect(m_ctrlSteerWheel.delayData.timer, &QTimer::timeout, this, &InputConvertGame::onSteerWheelTimer); +} InputConvertGame::~InputConvertGame() {} @@ -138,8 +144,10 @@ void InputConvertGame::updateSize(const QSize &frameSize, const QSize &showSize) { if (showSize != m_showSize) { if (m_gameMap && m_keyMap.isValidMouseMoveMap()) { +#ifdef QT_NO_DEBUG // show size change, resize grab cursor emit grabCursor(true); +#endif } } m_frameSize = frameSize; @@ -237,6 +245,55 @@ int InputConvertGame::getTouchID(int key) // -------- steer wheel event -------- +void InputConvertGame::getDelayQueue(const QPointF& start, const QPointF& end, + const double& distanceStep, const double& posStepconst, + quint32 lowestTimer, quint32 highestTimer, + QQueue& queuePos, QQueue& queueTimer) { + double x1 = start.x(); + double y1 = start.y(); + double x2 = end.x(); + double y2 = end.y(); + + double dx=x2-x1; + double dy=y2-y1; + double e=(fabs(dx)>fabs(dy))?fabs(dx):fabs(dy); + e /= distanceStep; + dx/=e; + dy/=e; + + QQueue queue; + QQueue queue2; + for(int i=1;i<=e;i++) { + QPointF pos(x1+(QRandomGenerator::global()->bounded(posStepconst*2)-posStepconst), y1+(QRandomGenerator::global()->bounded(posStepconst*2)-posStepconst)); + queue.enqueue(pos); + queue2.enqueue(QRandomGenerator::global()->bounded(lowestTimer, highestTimer)); + x1+=dx; + y1+=dy; + } + + queuePos = queue; + queueTimer = queue2; +} + +void InputConvertGame::onSteerWheelTimer() { + if(m_ctrlSteerWheel.delayData.queuePos.empty()) { + return; + } + int id = getTouchID(m_ctrlSteerWheel.touchKey); + m_ctrlSteerWheel.delayData.currentPos = m_ctrlSteerWheel.delayData.queuePos.dequeue(); + sendTouchMoveEvent(id, m_ctrlSteerWheel.delayData.currentPos); + + if(m_ctrlSteerWheel.delayData.queuePos.empty() && m_ctrlSteerWheel.delayData.pressedNum == 0) { + sendTouchUpEvent(id, m_ctrlSteerWheel.delayData.currentPos); + detachTouchID(m_ctrlSteerWheel.touchKey); + return; + } + + if(!m_ctrlSteerWheel.delayData.queuePos.empty()) { + m_ctrlSteerWheel.delayData.timer->start(m_ctrlSteerWheel.delayData.queueTimer.dequeue()); + } +} + void InputConvertGame::processSteerWheel(const KeyMap::KeyMapNode &node, const QKeyEvent *from) { int key = from->key(); @@ -271,27 +328,43 @@ void InputConvertGame::processSteerWheel(const KeyMap::KeyMapNode &node, const Q ++pressedNum; offset.rx() -= node.data.steerWheel.left.extendOffset; } + m_ctrlSteerWheel.delayData.pressedNum = pressedNum; - // action + // last key release and timer no active, active timer to detouch if (pressedNum == 0) { - // touch up release all - int id = getTouchID(m_ctrlSteerWheel.touchKey); - sendTouchUpEvent(id, node.data.steerWheel.centerPos + m_ctrlSteerWheel.lastOffset); - detachTouchID(m_ctrlSteerWheel.touchKey); - } else { - int id; - // first press, get key and touch down - if (pressedNum == 1 && flag) { - m_ctrlSteerWheel.touchKey = from->key(); - id = attachTouchID(m_ctrlSteerWheel.touchKey); - sendTouchDownEvent(id, node.data.steerWheel.centerPos); - } else { - // jsut get touch id and move - id = getTouchID(m_ctrlSteerWheel.touchKey); + if (m_ctrlSteerWheel.delayData.timer->isActive()) { + m_ctrlSteerWheel.delayData.timer->stop(); + m_ctrlSteerWheel.delayData.queueTimer.clear(); + m_ctrlSteerWheel.delayData.queuePos.clear(); } - sendTouchMoveEvent(id, node.data.steerWheel.centerPos + offset); + + sendTouchUpEvent(getTouchID(m_ctrlSteerWheel.touchKey), m_ctrlSteerWheel.delayData.currentPos); + detachTouchID(m_ctrlSteerWheel.touchKey); + return; } - m_ctrlSteerWheel.lastOffset = offset; + + // process steer wheel key event + m_ctrlSteerWheel.delayData.timer->stop(); + m_ctrlSteerWheel.delayData.queueTimer.clear(); + m_ctrlSteerWheel.delayData.queuePos.clear(); + + // first press, get key and touch down + if (pressedNum == 1 && flag) { + m_ctrlSteerWheel.touchKey = from->key(); + int id = attachTouchID(m_ctrlSteerWheel.touchKey); + sendTouchDownEvent(id, node.data.steerWheel.centerPos); + + getDelayQueue(node.data.steerWheel.centerPos, node.data.steerWheel.centerPos+offset, + 0.01f, 0.002f, 2, 8, + m_ctrlSteerWheel.delayData.queuePos, + m_ctrlSteerWheel.delayData.queueTimer); + } else { + getDelayQueue(m_ctrlSteerWheel.delayData.currentPos, node.data.steerWheel.centerPos+offset, + 0.01f, 0.002f, 2, 8, + m_ctrlSteerWheel.delayData.queuePos, + m_ctrlSteerWheel.delayData.queueTimer); + } + m_ctrlSteerWheel.delayData.timer->start(); return; } @@ -349,18 +422,65 @@ void InputConvertGame::processKeyClickMulti(const KeyMap::DelayClickNode *nodes, } } +void InputConvertGame::onDragTimer() { + if(m_dragDelayData.queuePos.empty()) { + return; + } + int id = getTouchID(m_dragDelayData.pressKey); + m_dragDelayData.currentPos = m_dragDelayData.queuePos.dequeue(); + sendTouchMoveEvent(id, m_dragDelayData.currentPos); + + if(m_dragDelayData.queuePos.empty()) { + delete m_dragDelayData.timer; + m_dragDelayData.timer = nullptr; + + sendTouchUpEvent(id, m_dragDelayData.currentPos); + detachTouchID(m_dragDelayData.pressKey); + + m_dragDelayData.currentPos = QPointF(); + m_dragDelayData.pressKey = 0; + return; + } + + if(!m_dragDelayData.queuePos.empty()) { + m_dragDelayData.timer->start(m_dragDelayData.queueTimer.dequeue()); + } +} + void InputConvertGame::processKeyDrag(const QPointF &startPos, QPointF endPos, const QKeyEvent *from) { if (QEvent::KeyPress == from->type()) { + // stop last + if (m_dragDelayData.timer && m_dragDelayData.timer->isActive()) { + m_dragDelayData.timer->stop(); + delete m_dragDelayData.timer; + m_dragDelayData.timer = nullptr; + m_dragDelayData.queuePos.clear(); + m_dragDelayData.queueTimer.clear(); + + sendTouchUpEvent(getTouchID(m_dragDelayData.pressKey), m_dragDelayData.currentPos); + detachTouchID(m_dragDelayData.pressKey); + + m_dragDelayData.currentPos = QPointF(); + m_dragDelayData.pressKey = 0; + } + + // start this int id = attachTouchID(from->key()); sendTouchDownEvent(id, startPos); - sendTouchMoveEvent(id, endPos); - } - if (QEvent::KeyRelease == from->type()) { - int id = getTouchID(from->key()); - sendTouchUpEvent(id, endPos); - detachTouchID(from->key()); + m_dragDelayData.timer = new QTimer(this); + m_dragDelayData.timer->setSingleShot(true); + connect(m_dragDelayData.timer, &QTimer::timeout, this, &InputConvertGame::onDragTimer); + m_dragDelayData.pressKey = from->key(); + m_dragDelayData.currentPos = startPos; + m_dragDelayData.queuePos.clear(); + m_dragDelayData.queueTimer.clear(); + getDelayQueue(startPos, endPos, + 0.01f, 0.002f, 0, 2, + m_dragDelayData.queuePos, + m_dragDelayData.queueTimer); + m_dragDelayData.timer->start(); } } @@ -509,9 +629,10 @@ bool InputConvertGame::switchGameMap() if (!m_keyMap.isValidMouseMoveMap()) { return m_gameMap; } - +#ifdef QT_NO_DEBUG // grab cursor and set cursor only mouse move map emit grabCursor(m_gameMap); +#endif hideMouseCursor(m_gameMap); if (!m_gameMap) { diff --git a/QtScrcpy/device/controller/inputconvert/inputconvertgame.h b/QtScrcpy/device/controller/inputconvert/inputconvertgame.h index b286d77..d8ff4d1 100644 --- a/QtScrcpy/device/controller/inputconvert/inputconvertgame.h +++ b/QtScrcpy/device/controller/inputconvert/inputconvertgame.h @@ -2,6 +2,7 @@ #define INPUTCONVERTGAME_H #include +#include #include "inputconvertnormal.h" #include "keymap.h" @@ -60,9 +61,18 @@ protected: bool checkCursorPos(const QMouseEvent *from); void hideMouseCursor(bool hide); + void getDelayQueue(const QPointF& start, const QPointF& end, + const double& distanceStep, const double& posStepconst, + quint32 lowestTimer, quint32 highestTimer, + QQueue& queuePos, QQueue& queueTimer); + protected: void timerEvent(QTimerEvent *event); +private slots: + void onSteerWheelTimer(); + void onDragTimer(); + private: QSize m_frameSize; QSize m_showSize; @@ -82,8 +92,15 @@ private: bool pressedDown = false; bool pressedLeft = false; bool pressedRight = false; - // for last up - QPointF lastOffset; + + // for delay + struct { + QPointF currentPos; + QTimer* timer = nullptr; + QQueue queuePos; + QQueue queueTimer; + int pressedNum = 0; + } delayData; } m_ctrlSteerWheel; // mouse move @@ -95,6 +112,15 @@ private: int timer = 0; bool smallEyes = false; } m_ctrlMouseMove; + + // for drag delay + struct { + QPointF currentPos; + QTimer* timer = nullptr; + QQueue queuePos; + QQueue queueTimer; + int pressKey = 0; + } m_dragDelayData; }; #endif // INPUTCONVERTGAME_H diff --git a/QtScrcpy/device/controller/inputconvert/keymap/CMakeLists.txt b/QtScrcpy/device/controller/inputconvert/keymap/CMakeLists.txt new file mode 100755 index 0000000..a74b052 --- /dev/null +++ b/QtScrcpy/device/controller/inputconvert/keymap/CMakeLists.txt @@ -0,0 +1,8 @@ +set(QS_SOURCES_DEVICE_CONTROLLER_INPUTCONVERT_KEYMAP + keymap.h + keymap.cpp +) + +add_library(keymap ${QS_SOURCES_DEVICE_CONTROLLER_INPUTCONVERT_KEYMAP}) +target_include_directories(keymap PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(keymap PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) diff --git a/QtScrcpy/device/controller/receiver/CMakeLists.txt b/QtScrcpy/device/controller/receiver/CMakeLists.txt new file mode 100755 index 0000000..ee6ced2 --- /dev/null +++ b/QtScrcpy/device/controller/receiver/CMakeLists.txt @@ -0,0 +1,14 @@ +SET(QS_SOURCES_DEVICE_CONTROLLER_RECEIVER + devicemsg.h + devicemsg.cpp + receiver.h + receiver.cpp + ) + +add_library(receiver ${QS_SOURCES_DEVICE_CONTROLLER_RECEIVER}) +target_include_directories(receiver PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(receiver PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Network + util + ) diff --git a/QtScrcpy/device/decoder/CMakeLists.txt b/QtScrcpy/device/decoder/CMakeLists.txt new file mode 100755 index 0000000..b2931a2 --- /dev/null +++ b/QtScrcpy/device/decoder/CMakeLists.txt @@ -0,0 +1,21 @@ +set(QS_SOURCES_DEVICE_DECODER + avframeconvert.h + avframeconvert.cpp + decoder.h + decoder.cpp + fpscounter.h + fpscounter.cpp + videobuffer.h + videobuffer.cpp +) + +add_library(decoder ${QS_SOURCES_DEVICE_DECODER}) +target_include_directories(decoder PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/include" + ) +target_link_libraries(decoder PUBLIC ${QS_EXTERNAL_LIBS_FFMPEG}) +target_link_libraries(decoder PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + util + ) diff --git a/QtScrcpy/device/device.cpp b/QtScrcpy/device/device.cpp index fc0b959..7c833a9 100644 --- a/QtScrcpy/device/device.cpp +++ b/QtScrcpy/device/device.cpp @@ -212,6 +212,7 @@ void Device::initSignals() } }); connect(m_server, &Server::connectToResult, this, [this](bool success, const QString &deviceName, const QSize &size) { + Q_UNUSED(deviceName); if (success) { double diff = m_startTimeCount.elapsed() / 1000.0; qInfo() << QString("server start finish in %1s").arg(diff).toStdString().c_str(); @@ -220,8 +221,11 @@ void Device::initSignals() if (m_videoForm) { // must be show before updateShowSize m_videoForm->show(); - - m_videoForm->setWindowTitle(deviceName); + QString name = Config::getInstance().getNickName(m_params.serial); + if (name.isEmpty()) { + name = Config::getInstance().getTitle(); + } + m_videoForm->setWindowTitle(name + "-" + m_params.serial); m_videoForm->updateShowSize(size); bool deviceVer = size.height() > size.width(); diff --git a/QtScrcpy/device/filehandler/CMakeLists.txt b/QtScrcpy/device/filehandler/CMakeLists.txt new file mode 100755 index 0000000..17de9e2 --- /dev/null +++ b/QtScrcpy/device/filehandler/CMakeLists.txt @@ -0,0 +1,9 @@ +set(QS_SOURCES_DEVICE_FILEHANDLER + filehandler.h + filehandler.cpp +) + +add_library(filehandler ${QS_SOURCES_DEVICE_FILEHANDLER}) +target_include_directories(filehandler PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(filehandler PUBLIC adb) +target_link_libraries(filehandler PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) diff --git a/QtScrcpy/device/recorder/CMakeLists.txt b/QtScrcpy/device/recorder/CMakeLists.txt new file mode 100755 index 0000000..12144db --- /dev/null +++ b/QtScrcpy/device/recorder/CMakeLists.txt @@ -0,0 +1,14 @@ +set(QS_SOURCES_DEVICE_RECORDER + recorder.h + recorder.cpp +) + +add_library(recorder ${QS_SOURCES_DEVICE_RECORDER}) +target_include_directories(recorder PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/include" + ) +target_link_libraries(recorder PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + util + ) diff --git a/QtScrcpy/device/render/CMakeLists.txt b/QtScrcpy/device/render/CMakeLists.txt new file mode 100755 index 0000000..ee3a140 --- /dev/null +++ b/QtScrcpy/device/render/CMakeLists.txt @@ -0,0 +1,8 @@ +set(QS_SOURCES_DEVICE_RENDER + qyuvopenglwidget.h + qyuvopenglwidget.cpp +) + +add_library(render ${QS_SOURCES_DEVICE_RENDER}) +target_include_directories(render PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(render PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) diff --git a/QtScrcpy/device/server/CMakeLists.txt b/QtScrcpy/device/server/CMakeLists.txt new file mode 100755 index 0000000..eb7fe84 --- /dev/null +++ b/QtScrcpy/device/server/CMakeLists.txt @@ -0,0 +1,20 @@ +set(QS_SOURCES_DEVICE_SERVER + server.h + server.cpp + tcpserver.h + tcpserver.cpp + videosocket.h + videosocket.cpp +) + +add_library(server ${QS_SOURCES_DEVICE_SERVER}) +target_include_directories(server PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(server PUBLIC + Qt${QT_VERSION_MAJOR}::Network + adb + ) +target_link_libraries(server PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + common + util + ) diff --git a/QtScrcpy/device/stream/CMakeLists.txt b/QtScrcpy/device/stream/CMakeLists.txt new file mode 100755 index 0000000..469d2d3 --- /dev/null +++ b/QtScrcpy/device/stream/CMakeLists.txt @@ -0,0 +1,20 @@ +set(QS_SOURCES_DEVICE_STREAM + stream.h + stream.cpp +) + +add_library(stream ${QS_SOURCES_DEVICE_STREAM}) +target_include_directories(stream PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} + "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/include" + ) + +target_link_libraries(stream PUBLIC ${QS_EXTERNAL_LIBS_FFMPEG}) +target_link_libraries(stream PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + #controller + decoder + recorder + server + util + ) diff --git a/QtScrcpy/device/ui/CMakeLists.txt b/QtScrcpy/device/ui/CMakeLists.txt new file mode 100755 index 0000000..f8f6325 --- /dev/null +++ b/QtScrcpy/device/ui/CMakeLists.txt @@ -0,0 +1,23 @@ +set(QS_SOURCES_DEVICE_UI + toolform.h + toolform.cpp + toolform.ui + videoform.h + videoform.cpp + videoform.ui +) + +add_library(ui ${QS_SOURCES_DEVICE_UI}) +target_include_directories(ui PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(ui PRIVATE "${PROJECT_SOURCE_DIR}/third_party/ffmpeg/include") +target_link_libraries(ui PUBLIC + device + uibase + ) +target_link_libraries(ui PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + controller + render + fontawesome + util + ) diff --git a/QtScrcpy/device/ui/videoform.cpp b/QtScrcpy/device/ui/videoform.cpp index 2d75c9a..e752768 100644 --- a/QtScrcpy/device/ui/videoform.cpp +++ b/QtScrcpy/device/ui/videoform.cpp @@ -367,16 +367,6 @@ QRect VideoForm::getScreenRect() return screenRect; } -bool VideoForm::checkTrialExpire() -{ - static int trialTimes = 0; - if (++trialTimes > TRIAL_TIMES) { - QMessageBox::warning(this, "QtScrcpy", QStringLiteral("试用已结束,购买正式版本请联系作者"), QMessageBox::Ok); - return true; - } - return false; -} - void VideoForm::updateStyleSheet(bool vertical) { if (vertical) { @@ -534,12 +524,6 @@ void VideoForm::setDevice(Device *device) void VideoForm::mousePressEvent(QMouseEvent *event) { -#ifdef TRIAL_EXPIRE_CHECK - if (checkTrialExpire()) { - return; - } -#endif - if (event->button() == Qt::MiddleButton) { if (m_device && !m_device->isCurrentCustomKeymap()) { emit m_device->postGoHome(); diff --git a/QtScrcpy/device/ui/videoform.h b/QtScrcpy/device/ui/videoform.h index 0b07c0c..bda37a4 100644 --- a/QtScrcpy/device/ui/videoform.h +++ b/QtScrcpy/device/ui/videoform.h @@ -45,7 +45,6 @@ private: void moveCenter(); void installShortcut(); QRect getScreenRect(); - bool checkTrialExpire(); protected: void mousePressEvent(QMouseEvent *event); diff --git a/QtScrcpy/devicemanage/CMakeLists.txt b/QtScrcpy/devicemanage/CMakeLists.txt new file mode 100755 index 0000000..8ce0ab7 --- /dev/null +++ b/QtScrcpy/devicemanage/CMakeLists.txt @@ -0,0 +1,13 @@ +set(QS_SOURCES_DEVICEMANAGE + devicemanage.h + devicemanage.cpp +) + +add_library(devicemanage ${QS_SOURCES_DEVICEMANAGE}) +target_include_directories(devicemanage PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(devicemanage PUBLIC device) +target_link_libraries(devicemanage PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + server + ui + ) diff --git a/QtScrcpy/dialog.cpp b/QtScrcpy/dialog.cpp index 71a4a07..08aa86b 100644 --- a/QtScrcpy/dialog.cpp +++ b/QtScrcpy/dialog.cpp @@ -46,7 +46,7 @@ Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) ui->connectedPhoneList->clear(); for (auto &item : devices) { ui->serialBox->addItem(item); - ui->connectedPhoneList->addItem(item+"-"+Config::getInstance().getNickName(item)); + ui->connectedPhoneList->addItem(Config::getInstance().getNickName(item) + "-" + item); } } else if (args.contains("show") && args.contains("wlan0")) { QString ip = m_adb.getDeviceIPFromStdOut(); @@ -77,18 +77,22 @@ Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) } }); - m_hideIcon = new QSystemTrayIcon(); + m_hideIcon = new QSystemTrayIcon(this); m_hideIcon->setIcon(QIcon(":/image/tray/logo.png")); - m_menu = new QMenu(); - m_quit = new QAction(); - m_showWindow = new QAction();; + m_menu = new QMenu(this); + m_quit = new QAction(this); + m_showWindow = new QAction(this); m_showWindow->setText(tr("show")); m_quit->setText(tr("quit")); m_menu->addAction(m_showWindow); m_menu->addAction(m_quit); m_hideIcon->setContextMenu(m_menu); + m_hideIcon->show(); connect(m_showWindow, &QAction::triggered, this, &Dialog::slotShow); - connect(m_quit, SIGNAL(triggered()), this, SLOT(close())); + connect(m_quit, &QAction::triggered, this, [this](){ + m_hideIcon->hide(); + qApp->quit(); + }); connect(m_hideIcon, &QSystemTrayIcon::activated,this,&Dialog::slotActivated); } @@ -240,26 +244,12 @@ void Dialog::slotActivated(QSystemTrayIcon::ActivationReason reason) void Dialog::closeEvent(QCloseEvent *event) { - int res = QMessageBox::question(this,tr("warning"),tr("Quit or set tray?"),tr("Quit"),tr("Set tray"),tr("Cancel")); - - if(res == 0) - { - event->accept(); - } - else if(res == 1) - { - this->hide(); - m_hideIcon->show(); - m_hideIcon->showMessage(tr("Notice"), - tr("Hidden here!"), - QSystemTrayIcon::Information, - 3000); - event->ignore(); - } - else - { - event->ignore(); - } + this->hide(); + m_hideIcon->showMessage(tr("Notice"), + tr("Hidden here!"), + QSystemTrayIcon::Information, + 3000); + event->ignore(); } void Dialog::on_updateDevice_clicked() @@ -621,6 +611,10 @@ void Dialog::on_useSingleModeCheck_clicked() ui->wirelessGroupBox->show(); ui->usbGroupBox->show(); } + + QTimer::singleShot(0, this, [this](){ + resize(width(), layout()->sizeHint().height()); + }); } void Dialog::on_serialBox_currentIndexChanged(const QString &arg1) diff --git a/QtScrcpy/dialog.ui b/QtScrcpy/dialog.ui index b098da0..16daf24 100644 --- a/QtScrcpy/dialog.ui +++ b/QtScrcpy/dialog.ui @@ -7,7 +7,7 @@ 0 0 500 - 745 + 769 @@ -72,10 +72,22 @@ + + + 0 + 0 + + + + + 0 + 100 + + 16777215 - 16777215 + 100 @@ -751,10 +763,22 @@ + + + 0 + 0 + + 0 - 140 + 120 + + + + + 16777215 + 120 @@ -768,6 +792,19 @@ + + + + Qt::Vertical + + + + 20 + 0 + + + + diff --git a/QtScrcpy/fontawesome/CMakeLists.txt b/QtScrcpy/fontawesome/CMakeLists.txt new file mode 100755 index 0000000..ead0947 --- /dev/null +++ b/QtScrcpy/fontawesome/CMakeLists.txt @@ -0,0 +1,8 @@ +set(QS_SOURCES_FONTAWESOME + iconhelper.h + iconhelper.cpp +) + +add_library(fontawesome ${QS_SOURCES_FONTAWESOME}) +target_include_directories(fontawesome PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(fontawesome PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) diff --git a/QtScrcpy/main.cpp b/QtScrcpy/main.cpp index 50178f0..21e9dc2 100644 --- a/QtScrcpy/main.cpp +++ b/QtScrcpy/main.cpp @@ -56,6 +56,10 @@ int main(int argc, char *argv[]) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#if (QT_VERSION >= QT_VERSION_CHECK(5,14,0)) + QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); +#endif + QSurfaceFormat varFormat = QSurfaceFormat::defaultFormat(); varFormat.setVersion(2, 0); varFormat.setProfile(QSurfaceFormat::NoProfile); @@ -104,13 +108,9 @@ int main(int argc, char *argv[]) g_mainDlg->setWindowTitle(Config::getInstance().getTitle()); g_mainDlg->show(); - qInfo( - "%s", - QObject::tr("This software is completely open source and free. Strictly used for illegal purposes, or at your own risk. You can download it at the " - "following address:") - .toUtf8() - .data()); - qInfo() << QString("QtScrcpy %1 ").arg(QCoreApplication::applicationVersion()).toUtf8(); + qInfo() << QObject::tr("This software is completely open source and free. Use it at your own risk. You can download it at the " + "following address:"); + qInfo() << QString("QtScrcpy %1 ").arg(QCoreApplication::applicationVersion()); int ret = a.exec(); @@ -131,11 +131,11 @@ void installTranslator() QString languagePath = ":/i18n/"; switch (language) { case QLocale::Chinese: - languagePath += "QtScrcpy_zh.qm"; + languagePath += "zh_CN.qm"; break; case QLocale::English: default: - languagePath += "QtScrcpy_en.qm"; + languagePath += "en_US.qm"; } translator.load(languagePath); diff --git a/QtScrcpy/res/i18n/QtScrcpy_en.qm b/QtScrcpy/res/i18n/en_US.qm similarity index 78% rename from QtScrcpy/res/i18n/QtScrcpy_en.qm rename to QtScrcpy/res/i18n/en_US.qm index 32fa730..b0be366 100644 Binary files a/QtScrcpy/res/i18n/QtScrcpy_en.qm and b/QtScrcpy/res/i18n/en_US.qm differ diff --git a/QtScrcpy/res/i18n/QtScrcpy_en.ts b/QtScrcpy/res/i18n/en_US.ts similarity index 71% rename from QtScrcpy/res/i18n/QtScrcpy_en.ts rename to QtScrcpy/res/i18n/en_US.ts index 2161044..c84b132 100644 --- a/QtScrcpy/res/i18n/QtScrcpy_en.ts +++ b/QtScrcpy/res/i18n/en_US.ts @@ -16,22 +16,18 @@ file transfer failed - install apk install apk - file transfer file transfer - wait current %1 to complete wait current %1 to complete - %1 complete, save in %2 %1 complete, save in %2 @@ -41,7 +37,6 @@ %1 complete\n save in %2 - %1 failed %1 failed @@ -49,134 +44,108 @@ Dialog - Wireless Wireless - wireless connect wireless connect - wireless disconnect wireless disconnect - Start Config Start Config - record save path: record save path: - - select path select path - record format: record format: - record screen record screen - frameless frameless - Use Simple Mode Use Simple Mode Use Simple Mode - Simple Mode Simple Mode Simple Mode - WIFI Connect WIFI Connect WIFI Connect - USB Connect USB Connect USB Connect - Double click to connect: Double click to connect: - lock orientation: lock orientation: - show fps show fps - stay awake stay awake - device name: device name: device name: - update name update name update name - stop all server stop all server - adb command: adb command: - terminate terminate - execute execute - clear clear - reverse connection reverse connection @@ -185,57 +154,46 @@ auto enable - background record background record - screen-off screen-off - apply apply - max size: max size: - always on top always on top - refresh script refresh script - get device IP get device IP - USB line USB line - stop server stop server - start server start server - device serial: device serial: @@ -244,80 +202,66 @@ Config - bit rate: bit rate: - start adbd start adbd - refresh devices refresh devices - show show show - quit quit quit - original original - no lock no lock - warning Warning Warning - Quit or set tray? Quit or set tray? Quit or set tray? - Quit Quit Quit - Set tray Set tray Set tray - Cancel Cancel Cancel - Notice Notice Notice - Hidden here! Hidden here! Hidden here! @@ -326,17 +270,14 @@ InputConvertGame - current keymap mode: %1 - custom - normal @@ -344,7 +285,6 @@ KeyMap - Script updated, current keymap mode:normal, Press ~ key to switch keymap mode @@ -362,25 +302,25 @@ You can download it at the following address: This software is completely open source and free.\nStrictly used for illegal purposes, or at your own risk.\nYou can download it at the following address: - This software is completely open source and free. Strictly used for illegal purposes, or at your own risk. You can download it at the following address: - This software is completely open source and free. Strictly used for illegal purposes, or at your own risk. You can download it at the following address: + This software is completely open source and free. Strictly used for illegal purposes, or at your own risk. You can download it at the following address: + + + This software is completely open source and free. Use it at your own risk. You can download it at the following address: + ToolForm - Tool Tool - full screen full screen - expand notify expand notify @@ -393,52 +333,42 @@ You can download it at the following address: turn on - touch switch touch switch - close screen close screen - power power - volume up volume up - volume down volume down - app switch app switch - menu menu - home home - return return - screen shot screen shot @@ -458,7 +388,6 @@ You can download it at the following address: file transfer failed - file does not exist file does not exist diff --git a/QtScrcpy/res/i18n/QtScrcpy_zh.qm b/QtScrcpy/res/i18n/zh_CN.qm similarity index 77% rename from QtScrcpy/res/i18n/QtScrcpy_zh.qm rename to QtScrcpy/res/i18n/zh_CN.qm index e8b1e21..a4c5948 100644 Binary files a/QtScrcpy/res/i18n/QtScrcpy_zh.qm and b/QtScrcpy/res/i18n/zh_CN.qm differ diff --git a/QtScrcpy/res/i18n/QtScrcpy_zh.ts b/QtScrcpy/res/i18n/zh_CN.ts similarity index 67% rename from QtScrcpy/res/i18n/QtScrcpy_zh.ts rename to QtScrcpy/res/i18n/zh_CN.ts index 8b6fcb4..0c67d3a 100644 --- a/QtScrcpy/res/i18n/QtScrcpy_zh.ts +++ b/QtScrcpy/res/i18n/zh_CN.ts @@ -16,22 +16,18 @@ 文件传输失败 - install apk 安装apk - file transfer 文件传输 - wait current %1 to complete 等待当前%1完成 - %1 complete, save in %2 %1完成,保存在%2 @@ -41,7 +37,6 @@ %1完成\n 保存在 %2 - %1 failed %1 失败 @@ -49,134 +44,108 @@ Dialog - Wireless 无线 - wireless connect 无线连接 - wireless disconnect 无线断开 - Start Config 启动配置 - record save path: 录像保存路径: - - select path 选择路径 - record format: 录制格式: - record screen 录制屏幕 - frameless 无边框 - Use Simple Mode 启用精简模式 启用精简模式 - Simple Mode 精简模式 精简模式 - WIFI Connect 一键WIFI连接 一键WIFI连接 - USB Connect 一键USB连接 一键USB连接 - Double click to connect: 双击连接: - lock orientation: 锁定方向: - show fps 显示fps - stay awake 保持唤醒 - device name: 设备名称: 设备名称: - update name 更新设置名称 更新设置名称 - stop all server 停止所有服务 - adb command: adb命令: - terminate 终止 - execute 执行 - clear 清理 - reverse connection 反向连接 @@ -185,57 +154,46 @@ 自动启用脚本 - background record 后台录制 - screen-off 自动息屏 - apply 应用脚本 - max size: 最大尺寸: - always on top 窗口置顶 - refresh script 刷新脚本 - get device IP 获取设备IP - USB line USB线 - stop server 停止服务 - start server 启动服务 - device serial: 设备序列号: @@ -244,80 +202,66 @@ 配置 - bit rate: 比特率: - start adbd 启动adbd - refresh devices 刷新设备列表 - show 显示 显示 - quit 退出 退出 - original 原始 - no lock 不锁定 - warning 警告 警告 - Quit or set tray? 退出还是最小化到托盘? 退出还是最小化到托盘? - Quit 退出 退出 - Set tray 最小化到系统托盘 最小化到系统托盘 - Cancel 取消 取消 - Notice 提示 提示 - Hidden here! 安卓录屏程序隐藏在这! 安卓录屏程序隐藏在这! @@ -326,17 +270,14 @@ InputConvertGame - current keymap mode: %1 - custom - normal @@ -344,7 +285,6 @@ KeyMap - Script updated, current keymap mode:normal, Press ~ key to switch keymap mode @@ -352,35 +292,21 @@ QObject - This software is completely open source and free, you can download it at the following address: - 本软件完全开源免费,你可以在下面的地址下载: - - - This software is completely open source and free. -Strictly used for illegal purposes, or at your own risk. -You can download it at the following address: - 本软件完全开源免费.\n严禁用于非法用途,否则后果自负.\n你可以在下面地址下载: - - - - This software is completely open source and free. Strictly used for illegal purposes, or at your own risk. You can download it at the following address: - 本软件完全开源免费,严禁用于非法用途,否则后果自负,你可以在下面地址下载: + This software is completely open source and free. Use it at your own risk. You can download it at the following address: + 本软件完全开源免费,作者不对使用该软件产生的一切后果负责。你可以在以下地址下载: ToolForm - Tool 工具 - full screen 全屏 - expand notify 下拉通知 @@ -393,52 +319,42 @@ You can download it at the following address: 解锁 - touch switch 触摸显示开关 - close screen 关闭屏幕 - power 电源 - volume up 音量加 - volume down 音量减 - app switch 切换应用 - menu 菜单 - home 主界面 - return 返回 - screen shot 截图 @@ -458,7 +374,6 @@ You can download it at the following address: 文件传输失败 - file does not exist 文件不存在 diff --git a/QtScrcpy/res/res.qrc b/QtScrcpy/res/res.qrc index d2f53a4..05b447f 100644 --- a/QtScrcpy/res/res.qrc +++ b/QtScrcpy/res/res.qrc @@ -22,8 +22,8 @@ qss/psblack/radiobutton_checked_disable.png qss/psblack/radiobutton_unchecked.png qss/psblack/radiobutton_unchecked_disable.png - i18n/QtScrcpy_en.qm - i18n/QtScrcpy_zh.qm + i18n/en_US.qm + i18n/zh_CN.qm image/tray/logo.png diff --git a/QtScrcpy/uibase/CMakeLists.txt b/QtScrcpy/uibase/CMakeLists.txt new file mode 100755 index 0000000..861883a --- /dev/null +++ b/QtScrcpy/uibase/CMakeLists.txt @@ -0,0 +1,10 @@ +set(QS_SOURCES_UIBASE + keepratiowidget.h + keepratiowidget.cpp + magneticwidget.h + magneticwidget.cpp +) + +add_library(uibase ${QS_SOURCES_UIBASE}) +target_include_directories(uibase PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(uibase PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) diff --git a/QtScrcpy/util/CMakeLists.txt b/QtScrcpy/util/CMakeLists.txt new file mode 100755 index 0000000..2d92d13 --- /dev/null +++ b/QtScrcpy/util/CMakeLists.txt @@ -0,0 +1,21 @@ +set(QS_SUBDIRECTORIES_UTIL + mousetap +) + +set(QS_SOURCES_UTIL + bufferutil.h + bufferutil.cpp + compat.h + config.h + config.cpp +) + +add_library(util ${QS_SOURCES_UTIL}) + +target_include_directories(util PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(QS_SUBDIRECTORY_UTIL ${QS_SUBDIRECTORIES_UTIL}) + add_subdirectory (${QS_SUBDIRECTORY_UTIL}) +endforeach() + +target_link_libraries(util PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) diff --git a/QtScrcpy/util/mousetap/CMakeLists.txt b/QtScrcpy/util/mousetap/CMakeLists.txt new file mode 100755 index 0000000..846851b --- /dev/null +++ b/QtScrcpy/util/mousetap/CMakeLists.txt @@ -0,0 +1,50 @@ +set(QS_SOURCES_UTIL_MOUSETAP + mousetap.h + mousetap.cpp +) + +# Microsoft Windows +if(WIN32) + + list(APPEND QS_SOURCES_UTIL_MOUSETAP + winmousetap.h + winmousetap.cpp + ) + set(QS_EXTERNAL_LIBS_UTIL_MOUSETAP User32) + +elseif(UNIX) +# macOS + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + + find_library(APPKIT AppKit REQUIRED) + set(QS_EXTERNAL_LIBS_UTIL_MOUSETAP ${APPKIT}) + + list(APPEND QS_SOURCES_UTIL_MOUSETAP + cocoamousetap.h + cocoamousetap.mm + ) + + target_compile_options(mousetap "-mmacosx-version-min=10.6") + + # Linux, BSD, etc. + else() + + find_package(QT NAMES Qt6 Qt5 COMPONENTS X11Extras REQUIRED) + find_package(Qt${QT_VERSION_MAJOR} COMPONENTS X11Extras REQUIRED) + set(QS_EXTERNAL_LIBS_UTIL_MOUSETAP + Qt${QT_VERSION_MAJOR}::X11Extras + xcb + ) + + list(APPEND QS_SOURCES_UTIL_MOUSETAP + xmousetap.h + xmousetap.cpp + ) + + endif() +endif() + +add_library(mousetap ${QS_SOURCES_UTIL_MOUSETAP}) +target_link_libraries(mousetap PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + ${QS_EXTERNAL_LIBS_UTIL_MOUSETAP}) diff --git a/QtScrcpy/version b/QtScrcpy/version index 77d6f4c..dc1e644 100644 --- a/QtScrcpy/version +++ b/QtScrcpy/version @@ -1 +1 @@ -0.0.0 +1.6.0 diff --git a/README.md b/README.md index 8d6ea46..1b461b9 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ cross-platform|self implemented|provided by Qt language|C|C++ style|sync|async keymap|no custom keymap|support custom keymap -build|meson+gradle|Qt Creator +build|meson+gradle|qmake or CMake - It's very easy to customize your GUI with Qt - Asynchronous programming of Qt-based signal slot mechanism improves performance @@ -246,9 +246,10 @@ There are several reasons listed as below according to importance (high to low). All the dependencies are provided and it is easy to compile. ### PC client -1. Set up the Qt development environment on the target platform (Qt == 5.15.2, vs == 2019 (mingw not supported)) +1. Set up the Qt development environment on the target platform. +An Up-to-date Qt5 (i.e. 5.15.2 or later) is recommended. For Windows, you can choose MSVC 2019 or MinGW 8.1.0, but please be noted that currently only **CMake** scripts support MinGW. 2. Clone the project -3. Open the project root directory all.pro with QtCreator +3. Open the project root directory `all.pro` or `CMakeLists.txt` with QtCreator 4. Compile and run ### Android (If you do not have special requirements, you can directly use the built-in scrcpy-server.jar) @@ -280,7 +281,7 @@ Since it is based on scrcpy, respect its Licence [Barry CSDN](https://blog.csdn.net/rankun1) -An ordinary programmer, working mainly in C++ for desktop client development, graduated from Shandong for more than a year of steel simulation education software, and later moved to Shanghai to work in security, online education related fields, familiar with audio and video. I have an understanding of audio and video fields such as voice calls, live education, video conferencing and other related solutions. At the same time have android, linux server and other development experience. +An ordinary programmer, working mainly in C++ for desktop client development, graduated from Shandong for more than a year of steel simulation education software, and later moved to Shanghai to work in security, online education related fields, familiar with audio and video. I have an understanding of audio and video fields such as voice calls, live education, video conferencing and other related solutions. I also have experience in Android, Linux server and other kinds of development. ## Contributors @@ -310,4 +311,4 @@ Support this project with your organization. Your logo will show up here with a - \ No newline at end of file + diff --git a/README_zh.md b/README_zh.md index 4aba9f1..7e04c8f 100644 --- a/README_zh.md +++ b/README_zh.md @@ -69,7 +69,7 @@ QtScrcpy可以通过USB(或通过TCP/IP)连接Android设备,并进行显示和 编程语言|C|C++ 编程方式|同步|异步 按键映射|不支持自定义|支持自定义按键映射 -编译方式|meson+gradle|Qt Creator +编译方式|meson+gradle|qmake or CMake - 使用Qt可以非常容易的定制自己的界面 - 基于Qt的信号槽机制的异步编程提高性能 @@ -243,10 +243,11 @@ Mac OS平台,你可以直接使用我编译好的可执行程序: 尽量提供了所有依赖资源,方便傻瓜式编译。 ### PC端 -1. 目标平台上搭建Qt开发环境(Qt == 5.15.2, vs == 2019 (**不支持mingw**)) +1. 在目标平台上搭建Qt开发环境 +我们建议使用最新的Qt5版本(5.15.2或更高)。在Windows上你可以自由选择MSVC 2019或MinGW 8.1.0,但需要注意的是现阶段只有**CMake**脚本提供了对MinGW的支持。 2. 克隆该项目 -3. 使用QtCreator打开项目根目录all.pro -4. 编译,运行即可 +3. 使用QtCreator打开项目根目录`all.pro`或`CMakeLists.txt` +4. 编译,运行 ### Android端 (没有修改需求的话直接使用自带的scrcpy-server即可) 1. 目标平台上搭建Android开发环境 @@ -276,4 +277,4 @@ Mac OS平台,你可以直接使用我编译好的可执行程序: [Barry的CSDN](https://blog.csdn.net/rankun1) -一枚普通的程序员,工作中主要使用C++进行桌面客户端开发,一毕业在山东做过一年多钢铁仿真教育软件,后来转战上海先后从事安防,在线教育相关领域工作,对音视频比较熟悉,对音视频领域如语音通话,直播教育,视频会议等相关解决方案有所了解。同时具有android,linux服务器等开发经验。 \ No newline at end of file +一枚普通的程序员,工作中主要使用C++进行桌面客户端开发,一毕业在山东做过一年多钢铁仿真教育软件,后来转战上海先后从事安防,在线教育相关领域工作,对音视频比较熟悉,对音视频领域如语音通话,直播教育,视频会议等相关解决方案有所了解。同时具有Android,Linux服务器等开发经验。 diff --git a/all.pro b/all.pro index aa4e301..86c354d 100644 --- a/all.pro +++ b/all.pro @@ -3,5 +3,5 @@ SUBDIRS = QtScrcpy # 多语言翻译文件 TRANSLATIONS = \ - $$PWD/QtScrcpy/res/i18n/QtScrcpy_zh.ts \ - $$PWD/QtScrcpy/res/i18n/QtScrcpy_en.ts + $$PWD/QtScrcpy/res/i18n/zh_CN.ts \ + $$PWD/QtScrcpy/res/i18n/en_US.ts