From 9610545e97e48bf8cfc998d571f4d9d8a06c87f3 Mon Sep 17 00:00:00 2001 From: rankun Date: Mon, 4 Feb 2019 13:57:34 +0800 Subject: [PATCH 1/6] =?UTF-8?q?update:=E5=85=A8=E5=B1=8F=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E4=B8=8D=E6=98=BE=E7=A4=BA=E5=B7=A5=E5=85=B7=E7=AA=97=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtScrcpy/toolform.cpp | 13 +++++++++++++ QtScrcpy/toolform.h | 3 +++ QtScrcpy/videoform.cpp | 4 +++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/QtScrcpy/toolform.cpp b/QtScrcpy/toolform.cpp index ec6de4c..835e49f 100644 --- a/QtScrcpy/toolform.cpp +++ b/QtScrcpy/toolform.cpp @@ -1,4 +1,7 @@ #include +#include +#include +#include #include "toolform.h" #include "ui_toolform.h" @@ -58,6 +61,16 @@ void ToolForm::mouseMoveEvent(QMouseEvent *event) } } +void ToolForm::showEvent(QShowEvent *event) +{ + qDebug() << "show event"; +} + +void ToolForm::hideEvent(QHideEvent *event) +{ + qDebug() << "hide event"; +} + void ToolForm::on_fullScreenBtn_clicked() { if (m_videoForm) { diff --git a/QtScrcpy/toolform.h b/QtScrcpy/toolform.h index 2c09f37..5e2ace6 100644 --- a/QtScrcpy/toolform.h +++ b/QtScrcpy/toolform.h @@ -24,6 +24,9 @@ protected: void mouseReleaseEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); + void showEvent(QShowEvent *event); + void hideEvent(QHideEvent *event); + private slots: void on_fullScreenBtn_clicked(); diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp index b98fe5e..3d02f49 100644 --- a/QtScrcpy/videoform.cpp +++ b/QtScrcpy/videoform.cpp @@ -432,7 +432,9 @@ void VideoForm::paintEvent(QPaintEvent *paint) void VideoForm::showEvent(QShowEvent *event) { Q_UNUSED(event); - showToolFrom(); + if (!isFullScreen()) { + showToolFrom(); + } } void VideoForm::dragEnterEvent(QDragEnterEvent *event) From b879451402a7e0e80f8091c38ef96490994baf74 Mon Sep 17 00:00:00 2001 From: rankun Date: Mon, 4 Feb 2019 18:05:40 +0800 Subject: [PATCH 2/6] =?UTF-8?q?update:=E5=85=A8=E5=B1=8F=E5=90=8E=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=84=A6=E7=82=B9=EF=BC=8C=E9=98=B2=E6=AD=A2=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E6=A0=8F=E6=8A=A2=E7=84=A6=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtScrcpy/inputcontrol/inputconvertgame.cpp | 4 ++-- QtScrcpy/videoform.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/QtScrcpy/inputcontrol/inputconvertgame.cpp b/QtScrcpy/inputcontrol/inputconvertgame.cpp index 2f7eeb6..bfb3f1f 100644 --- a/QtScrcpy/inputcontrol/inputconvertgame.cpp +++ b/QtScrcpy/inputcontrol/inputconvertgame.cpp @@ -413,9 +413,9 @@ bool InputConvertGame::processMouseMove(const QMouseEvent *from) m_mouseMoveLastConverPos.setY(m_mouseMoveLastConverPos.y() + distance.y() / m_showSize.height()); if (m_mouseMoveLastConverPos.x() < 0.1 - || m_mouseMoveLastConverPos.x() > 0.9 + || m_mouseMoveLastConverPos.x() > 0.8 || m_mouseMoveLastConverPos.y() < 0.1 - || m_mouseMoveLastConverPos.y() > 0.9) { + || m_mouseMoveLastConverPos.y() > 0.8) { mouseMoveStopTouch(); mouseMoveStartTouch(from); } diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp index 3d02f49..11c8928 100644 --- a/QtScrcpy/videoform.cpp +++ b/QtScrcpy/videoform.cpp @@ -267,6 +267,7 @@ void VideoForm::switchFullScreen() ::SetThreadExecutionState(ES_CONTINUOUS); #endif } else { + setFocus(Qt::ActiveWindowFocusReason); // mac fullscreen must show title bar #ifdef Q_OS_OSX setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint); From 2d94db6dbdced0721b3c1addeae9dac9e4b661b3 Mon Sep 17 00:00:00 2001 From: rankun Date: Mon, 4 Feb 2019 18:43:16 +0800 Subject: [PATCH 3/6] =?UTF-8?q?update:mac=E4=B8=8D=E5=8E=BB=E6=8E=89?= =?UTF-8?q?=E6=A0=87=E9=A2=98=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtScrcpy/videoform.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp index 11c8928..77442bd 100644 --- a/QtScrcpy/videoform.cpp +++ b/QtScrcpy/videoform.cpp @@ -80,10 +80,13 @@ void VideoForm::initUI() setAttribute(Qt::WA_DeleteOnClose); + // mac下去掉标题栏影响showfullscreen +#ifndef Q_OS_OSX // 去掉标题栏 setWindowFlags(windowFlags() | Qt::FramelessWindowHint); // 根据图片构造异形窗口 setAttribute(Qt::WA_TranslucentBackground); +#endif setMouseTracking(true); ui->loadingWidget->setAttribute(Qt::WA_DeleteOnClose); @@ -138,7 +141,6 @@ void VideoForm::initSignals() float diff = m_startTimeCount.elapsed() / 1000.0f; qInfo(QString("server start finish in %1s").arg(diff).toStdString().c_str()); - // update ui setWindowTitle(deviceName); updateShowSize(size); @@ -257,9 +259,10 @@ void VideoForm::switchFullScreen() { if (isFullScreen()) { showNormal(); + #ifdef Q_OS_OSX - setWindowFlags(windowFlags() | Qt::FramelessWindowHint); - show(); + //setWindowFlags(windowFlags() | Qt::FramelessWindowHint); + //show(); #endif updateStyleSheet(height() > width()); showToolFrom(true); @@ -267,10 +270,10 @@ void VideoForm::switchFullScreen() ::SetThreadExecutionState(ES_CONTINUOUS); #endif } else { - setFocus(Qt::ActiveWindowFocusReason); + // 这种临时增加标题栏再全屏的方案会导致收不到mousemove事件,导致setmousetrack失效 // mac fullscreen must show title bar #ifdef Q_OS_OSX - setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint); + //setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint); #endif showToolFrom(false); layout()->setContentsMargins(0, 0, 0, 0); @@ -411,6 +414,7 @@ void VideoForm::keyPressEvent(QKeyEvent *event) && isFullScreen()) { switchFullScreen(); } + //qDebug() << "keyPressEvent" << event->isAutoRepeat(); m_inputConvert.keyEvent(event, ui->videoWidget->frameSize(), ui->videoWidget->size()); } From f8908549ce9c84b513e4959c35f5a7f225e3a220 Mon Sep 17 00:00:00 2001 From: rankun Date: Sun, 10 Feb 2019 20:22:29 +0800 Subject: [PATCH 4/6] =?UTF-8?q?update:mac=E9=99=90=E5=88=B6=E9=BC=A0?= =?UTF-8?q?=E6=A0=87=E7=A7=BB=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtScrcpy/QtScrcpy.pro | 2 + QtScrcpy/main.cpp | 10 ++ QtScrcpy/util/.DS_Store | Bin 0 -> 6148 bytes QtScrcpy/util/cocoamousetap.h | 29 ++++ QtScrcpy/util/cocoamousetap.mm | 237 +++++++++++++++++++++++++++++++++ QtScrcpy/util/util.pri | 6 + QtScrcpy/videoform.cpp | 6 + TODO.txt | 3 +- 8 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 QtScrcpy/util/.DS_Store create mode 100644 QtScrcpy/util/cocoamousetap.h create mode 100644 QtScrcpy/util/cocoamousetap.mm create mode 100644 QtScrcpy/util/util.pri diff --git a/QtScrcpy/QtScrcpy.pro b/QtScrcpy/QtScrcpy.pro index fb41029..7c1364c 100644 --- a/QtScrcpy/QtScrcpy.pro +++ b/QtScrcpy/QtScrcpy.pro @@ -54,6 +54,7 @@ include ($$PWD/uibase/uibase.pri) include ($$PWD/fontawesome/fontawesome.pri) include ($$PWD/filehandler/filehandler.pri) include ($$PWD/recorder/recorder.pri) +include ($$PWD/util/util.pri) # 附加包含路径 INCLUDEPATH += \ @@ -68,6 +69,7 @@ INCLUDEPATH += \ $$PWD/uibase \ $$PWD/filehandler \ $$PWD/recorder \ + $$PWD/util \ $$PWD/fontawesome diff --git a/QtScrcpy/main.cpp b/QtScrcpy/main.cpp index 6e208e8..5f780d7 100644 --- a/QtScrcpy/main.cpp +++ b/QtScrcpy/main.cpp @@ -6,6 +6,9 @@ #include "dialog.h" #include "decoder.h" +#ifdef Q_OS_OSX +#include "cocoamousetap.h" +#endif Dialog* g_mainDlg = Q_NULLPTR; @@ -25,6 +28,10 @@ int main(int argc, char *argv[]) installTranslator(); +#ifdef Q_OS_OSX + CocoaMouseTap::getInstance()->initMouseEventTap(); +#endif + #ifdef Q_OS_WIN32 qputenv("QTSCRCPY_ADB_PATH", "../../../third_party/adb/win/adb.exe"); qputenv("QTSCRCPY_SERVER_PATH", "../../../third_party/scrcpy-server.jar"); @@ -50,6 +57,9 @@ int main(int argc, char *argv[]) int ret = a.exec(); +#ifdef Q_OS_OSX + CocoaMouseTap::getInstance()->quitMouseEventTap(); +#endif Decoder::deInit(); return ret; } diff --git a/QtScrcpy/util/.DS_Store b/QtScrcpy/util/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8z45|!R0Z1N%F(jFgL>QrFAPJ2!M?+vV1V%$(Gz3ON zU^D~25V%SxcdJP zRior+2#kinunYl47MEZbCs3t{!+W4QHvuXKVuPw;Mo^s$(F3lEVT}ML$bg~*R5_@+ b2Uo?6kTwK}57Iu`5P${HC_Nei0}uiLNUI8I literal 0 HcmV?d00001 diff --git a/QtScrcpy/util/cocoamousetap.h b/QtScrcpy/util/cocoamousetap.h new file mode 100644 index 0000000..da92cb9 --- /dev/null +++ b/QtScrcpy/util/cocoamousetap.h @@ -0,0 +1,29 @@ +#ifndef COCOAMOUSETAP_H +#define COCOAMOUSETAP_H +#include +#include + +struct MouseEventTapData; +class QWidget; +class CocoaMouseTap : public QThread +{ +private: + CocoaMouseTap(QObject *parent = Q_NULLPTR); + ~CocoaMouseTap(); + +public: + static CocoaMouseTap* getInstance(); + void initMouseEventTap(); + void quitMouseEventTap(); + void enableMouseEventTap(QWidget* widget, bool enabled); + +protected: + void run() override; + +private: + MouseEventTapData *m_tapData = Q_NULLPTR; + QSemaphore m_runloopStartedSemaphore; + static CocoaMouseTap *s_instance; +}; + +#endif // COCOAMOUSETAP_H diff --git a/QtScrcpy/util/cocoamousetap.mm b/QtScrcpy/util/cocoamousetap.mm new file mode 100644 index 0000000..3d4d5f8 --- /dev/null +++ b/QtScrcpy/util/cocoamousetap.mm @@ -0,0 +1,237 @@ +#import +#include +#include + +#include "cocoamousetap.h" + +static const CGEventMask movementEventsMask = + CGEventMaskBit(kCGEventLeftMouseDragged) + | CGEventMaskBit(kCGEventRightMouseDragged) + | CGEventMaskBit(kCGEventMouseMoved); + +static const CGEventMask allGrabbedEventsMask = + CGEventMaskBit(kCGEventLeftMouseDown) | CGEventMaskBit(kCGEventLeftMouseUp) + | CGEventMaskBit(kCGEventRightMouseDown) | CGEventMaskBit(kCGEventRightMouseUp) + | CGEventMaskBit(kCGEventOtherMouseDown) | CGEventMaskBit(kCGEventOtherMouseUp) + | CGEventMaskBit(kCGEventLeftMouseDragged) | CGEventMaskBit(kCGEventRightMouseDragged) + | CGEventMaskBit(kCGEventMouseMoved); + +typedef struct MouseEventTapData{ + CFMachPortRef tap = Q_NULLPTR; + CFRunLoopRef runloop = Q_NULLPTR; + CFRunLoopSourceRef runloopSource = Q_NULLPTR; + QWidget* widget = Q_NULLPTR; +} MouseEventTapData; + +static CGEventRef Cocoa_MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) +{ + Q_UNUSED(proxy); + MouseEventTapData *tapdata = (MouseEventTapData*)refcon; + + NSView *nsview; + NSWindow *nswindow; + NSRect windowRect; + NSRect newWindowRect; + CGPoint eventLocation; + + switch (type) { + case kCGEventTapDisabledByTimeout: + { + CGEventTapEnable(tapdata->tap, true); + return NULL; + } + case kCGEventTapDisabledByUserInput: + { + return NULL; + } + default: + break; + } + + + if (!tapdata->widget) { + return event; + } + // get nswindow from qt widget + nsview = (NSView *)tapdata->widget->window()->winId(); + if (!nsview) { + return event; + } + nswindow = [nsview window]; + + eventLocation = CGEventGetUnflippedLocation(event); + windowRect = [nswindow contentRectForFrameRect:[nswindow frame]]; + + newWindowRect = NSMakeRect(windowRect.origin.x, windowRect.origin.y, + windowRect.size.width - 10, windowRect.size.height - 10); + qDebug() << newWindowRect.origin.x << newWindowRect.origin.y + << newWindowRect.size.width << newWindowRect.size.height; + + if (!NSMouseInRect(NSPointFromCGPoint(eventLocation), newWindowRect, NO)) { + + /* This is in CGs global screenspace coordinate system, which has a + * flipped Y. + */ + CGPoint newLocation = CGEventGetLocation(event); + + if (eventLocation.x < NSMinX(windowRect)) { + newLocation.x = NSMinX(windowRect); + } else if (eventLocation.x >= NSMaxX(windowRect)) { + newLocation.x = NSMaxX(windowRect) - 1.0; + } + + if (eventLocation.y <= NSMinY(windowRect)) { + newLocation.y -= (NSMinY(windowRect) - eventLocation.y + 1); + } else if (eventLocation.y > NSMaxY(windowRect)) { + newLocation.y += (eventLocation.y - NSMaxY(windowRect)); + } + + CGWarpMouseCursorPosition(newLocation); + CGAssociateMouseAndMouseCursorPosition(YES); + + if ((CGEventMaskBit(type) & movementEventsMask) == 0) { + /* For click events, we just constrain the event to the window, so + * no other app receives the click event. We can't due the same to + * movement events, since they mean that our warp cursor above + * behaves strangely. + */ + CGEventSetLocation(event, newLocation); + } + } + + return event; +} + +static void SemaphorePostCallback(CFRunLoopTimerRef timer, void *info) +{ + Q_UNUSED(timer); + QSemaphore *runloopStartedSemaphore = (QSemaphore *)info; + if (runloopStartedSemaphore) { + runloopStartedSemaphore->release(); + } +} + +CocoaMouseTap * CocoaMouseTap::s_instance = Q_NULLPTR; + +CocoaMouseTap::CocoaMouseTap(QObject *parent) + : QThread(parent) +{ + m_tapData = new MouseEventTapData; +} + +CocoaMouseTap::~CocoaMouseTap() +{ + if (m_tapData) { + delete m_tapData; + m_tapData = Q_NULLPTR; + } +} + +CocoaMouseTap *CocoaMouseTap::getInstance() +{ + if (s_instance == Q_NULLPTR) { + s_instance = new CocoaMouseTap(); + } + return s_instance; +} + +void CocoaMouseTap::initMouseEventTap() +{ + if (!m_tapData) { + return; + } + + m_tapData->tap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, + kCGEventTapOptionDefault, allGrabbedEventsMask, + &Cocoa_MouseTapCallback, m_tapData); + if (!m_tapData->tap) { + return; + } + /* Tap starts disabled, until app requests mouse grab */ + CGEventTapEnable(m_tapData->tap, false); + start(); +} + +void CocoaMouseTap::quitMouseEventTap() +{ + bool status; + if (m_tapData == Q_NULLPTR || m_tapData->tap == Q_NULLPTR) { + /* event tap was already cleaned up (possibly due to CGEventTapCreate + * returning null.) + */ + return; + } + + /* Ensure that the runloop has been started first. + * TODO: Move this to InitMouseEventTap, check for error conditions that can + * happen in Cocoa_MouseTapThread, and fall back to the non-EventTap way of + * grabbing the mouse if it fails to Init. + */ + status = m_runloopStartedSemaphore.tryAcquire(1, 5000); + if (status) { + /* Then stop it, which will cause Cocoa_MouseTapThread to return. */ + CFRunLoopStop(m_tapData->runloop); + /* And then wait for Cocoa_MouseTapThread to finish cleaning up. It + * releases some of the pointers in tapdata. */ + wait(); + } +} + +void CocoaMouseTap::enableMouseEventTap(QWidget* widget, bool enabled) +{ + if (m_tapData && m_tapData->tap) + { + enabled ? m_tapData->widget = widget : m_tapData->widget = Q_NULLPTR; + CGEventTapEnable(m_tapData->tap, enabled); + } +} + +void CocoaMouseTap::run() +{ + /* Tap was created on main thread but we own it now. */ + CFMachPortRef eventTap = m_tapData->tap; + if (eventTap) { + /* Try to create a runloop source we can schedule. */ + CFRunLoopSourceRef runloopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); + if (runloopSource) { + m_tapData->runloopSource = runloopSource; + } else { + CFRelease(eventTap); + m_runloopStartedSemaphore.release(); + /* TODO: Both here and in the return below, set some state in + * tapdata to indicate that initialization failed, which we should + * check in InitMouseEventTap, after we move the semaphore check + * from Quit to Init. + */ + return; + } + } else { + m_runloopStartedSemaphore.release(); + return; + } + + m_tapData->runloop = CFRunLoopGetCurrent(); + CFRunLoopAddSource(m_tapData->runloop, m_tapData->runloopSource, kCFRunLoopCommonModes); + CFRunLoopTimerContext context = {.info = &m_runloopStartedSemaphore}; + /* We signal the runloop started semaphore *after* the run loop has started, indicating it's safe to CFRunLoopStop it. */ + CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent(), 0, 0, 0, &SemaphorePostCallback, &context); + CFRunLoopAddTimer(m_tapData->runloop, timer, kCFRunLoopCommonModes); + CFRelease(timer); + + /* Run the event loop to handle events in the event tap. */ + CFRunLoopRun(); + /* Make sure this is signaled so that SDL_QuitMouseEventTap knows it can safely SDL_WaitThread for us. */ + if (m_runloopStartedSemaphore.available() < 1) { + m_runloopStartedSemaphore.release(); + } + CFRunLoopRemoveSource(m_tapData->runloop, m_tapData->runloopSource, kCFRunLoopCommonModes); + + /* Clean up. */ + CGEventTapEnable(m_tapData->tap, false); + CFRelease(m_tapData->runloopSource); + CFRelease(m_tapData->tap); + m_tapData->runloopSource = Q_NULLPTR; + m_tapData->tap = Q_NULLPTR; + + return; +} diff --git a/QtScrcpy/util/util.pri b/QtScrcpy/util/util.pri new file mode 100644 index 0000000..b489d3f --- /dev/null +++ b/QtScrcpy/util/util.pri @@ -0,0 +1,6 @@ +mac { + HEADERS += $$PWD/cocoamousetap.h + OBJECTIVE_SOURCES += $$PWD/cocoamousetap.mm + LIBS += -framework Appkit + QMAKE_CFLAGS += -mmacosx-version-min=10.6 +} diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp index 77442bd..629224a 100644 --- a/QtScrcpy/videoform.cpp +++ b/QtScrcpy/videoform.cpp @@ -18,6 +18,9 @@ #include "toolform.h" #include "controlevent.h" #include "recorder.h" +#ifdef Q_OS_OSX +#include "cocoamousetap.h" +#endif VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, QWidget *parent) : QWidget(parent), @@ -126,6 +129,9 @@ void VideoForm::initSignals() } else { ClipCursor(Q_NULLPTR); } +#endif +#ifdef Q_OS_OSX + CocoaMouseTap::getInstance()->enableMouseEventTap(ui->videoWidget, grab); #endif }); connect(m_server, &Server::serverStartResult, this, [this](bool success){ diff --git a/TODO.txt b/TODO.txt index 0cf3e19..8bd218e 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,5 +1,6 @@ // TODO mac: Qt::FramelessWindowHit full screen is abnormal - +ƶƽ̨ӿ +MacϷʱƶ⡣ չģָȣ ģָ(ע⣺Ͷû) From a53fe2ad04868a67c1fff50aba132b18aa74dc56 Mon Sep 17 00:00:00 2001 From: rankun Date: Mon, 18 Feb 2019 12:46:38 +0800 Subject: [PATCH 5/6] =?UTF-8?q?update:qtquick=E5=8F=AF=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtScrcpy/QtScrcpy.pro | 7 +++++- QtScrcpy/qml/pinwheel.qml | 7 +++--- QtScrcpy/videoform.cpp | 47 ++++++++++++++++++++++++++++-------- QtScrcpy/videoform.h | 1 + QtScrcpy/videoform.ui | 50 --------------------------------------- 5 files changed, 48 insertions(+), 64 deletions(-) diff --git a/QtScrcpy/QtScrcpy.pro b/QtScrcpy/QtScrcpy.pro index 7c1364c..db01ddf 100644 --- a/QtScrcpy/QtScrcpy.pro +++ b/QtScrcpy/QtScrcpy.pro @@ -5,7 +5,7 @@ #------------------------------------------------- QT += core gui -QT += network quickwidgets +QT += network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets @@ -24,6 +24,11 @@ DEFINES += QT_DEPRECATED_WARNINGS #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 #DEFINES += SKIP_FRAMES +#DEFINES += USE_QTQUICK + +contains(DEFINES, USE_QTQUICK) { + QT += quickwidgets +} # 源码 SOURCES += \ diff --git a/QtScrcpy/qml/pinwheel.qml b/QtScrcpy/qml/pinwheel.qml index 61c328b..8893b99 100644 --- a/QtScrcpy/qml/pinwheel.qml +++ b/QtScrcpy/qml/pinwheel.qml @@ -9,11 +9,12 @@ Image { RotationAnimation { id:rotationAnimation target: wheel - to:360000 + to:360 direction: RotationAnimation.Clockwise - duration: 800000 + duration: 800 + loops:Animation.Infinite } onStatusChanged: if (wheel.status == Image.Ready) rotationAnimation.start() } -} \ No newline at end of file +} diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp index 629224a..9fe3682 100644 --- a/QtScrcpy/videoform.cpp +++ b/QtScrcpy/videoform.cpp @@ -7,7 +7,10 @@ #ifdef Q_OS_WIN32 #include #endif +#ifdef USE_QTQUICK #include +#endif +#include #include #include #include @@ -76,12 +79,40 @@ VideoForm::~VideoForm() void VideoForm::initUI() { + setAttribute(Qt::WA_DeleteOnClose); QPixmap phone; if (phone.load(":/res/phone.png")) { m_widthHeightRatio = 1.0f * phone.width() / phone.height(); } - setAttribute(Qt::WA_DeleteOnClose); +#ifdef USE_QTQUICK + // qml animation + QWidget *loadingWidget; + QHBoxLayout *horizontalLayout; + QQuickWidget *quickWidget; + loadingWidget = new QWidget(this); + loadingWidget->setObjectName(QStringLiteral("loadingWidget")); + loadingWidget->setAutoFillBackground(false); + loadingWidget->setStyleSheet(QStringLiteral("")); + loadingWidget->setAttribute(Qt::WA_DeleteOnClose); + m_loadingWidget = loadingWidget; + horizontalLayout = new QHBoxLayout(loadingWidget); + horizontalLayout->setSpacing(0); + horizontalLayout->setObjectName(QStringLiteral("horizontalLayout")); + horizontalLayout->setContentsMargins(0, 0, 0, 0); + quickWidget = new QQuickWidget(loadingWidget); + quickWidget->setObjectName(QStringLiteral("quickWidget")); + quickWidget->setAutoFillBackground(false); + quickWidget->setStyleSheet(QStringLiteral("")); + quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + quickWidget->setSource(QUrl(QStringLiteral("qrc:/qml/pinwheel.qml"))); + // 最后绘制,不设置最后绘制会影响父窗体异形异常(quickWidget的透明通道会形成穿透) + quickWidget->setAttribute(Qt::WA_AlwaysStackOnTop); + // 背景透明 + quickWidget->setClearColor(QColor(Qt::transparent)); + horizontalLayout->addWidget(quickWidget); + ui->verticalLayout->addWidget(loadingWidget); +#endif // mac下去掉标题栏影响showfullscreen #ifndef Q_OS_OSX @@ -91,15 +122,9 @@ void VideoForm::initUI() setAttribute(Qt::WA_TranslucentBackground); #endif - setMouseTracking(true); - ui->loadingWidget->setAttribute(Qt::WA_DeleteOnClose); + setMouseTracking(true); ui->videoWidget->setMouseTracking(true); - ui->videoWidget->hide(); - - // 最后绘制,不设置最后绘制会影响父窗体异形异常(quickWidget的透明通道会形成穿透) - ui->quickWidget->setAttribute(Qt::WA_AlwaysStackOnTop); - // 背景透明 - ui->quickWidget->setClearColor(QColor(Qt::transparent)); + ui->videoWidget->hide(); } void VideoForm::initSignals() @@ -178,7 +203,9 @@ void VideoForm::initSignals() // must be Qt::QueuedConnection, ui update must be main thread connect(&m_decoder, &Decoder::onNewFrame, this, [this](){ if (ui->videoWidget->isHidden()) { - ui->loadingWidget->close(); + if (m_loadingWidget) { + m_loadingWidget->close(); + } ui->videoWidget->show(); } m_frames.lock(); diff --git a/QtScrcpy/videoform.h b/QtScrcpy/videoform.h index 49b49ef..3cd7994 100644 --- a/QtScrcpy/videoform.h +++ b/QtScrcpy/videoform.h @@ -79,6 +79,7 @@ private: QPointer m_toolForm; Recorder* m_recorder = Q_NULLPTR; QTime m_startTimeCount; + QPointer m_loadingWidget; }; #endif // VIDEOFORM_H diff --git a/QtScrcpy/videoform.ui b/QtScrcpy/videoform.ui index 539e5b5..9c393cc 100644 --- a/QtScrcpy/videoform.ui +++ b/QtScrcpy/videoform.ui @@ -38,62 +38,12 @@ 62 - - - - false - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - false - - - - - - QQuickWidget::SizeRootObjectToView - - - - qrc:/qml/pinwheel.qml - - - - - - - - - QQuickWidget - QWidget -
QtQuickWidgets/QQuickWidget
-
QYUVOpenGLWidget QWidget From 7165c60cb3fc023b21daecb0b8a494bccbceec69 Mon Sep 17 00:00:00 2001 From: rankun Date: Mon, 18 Feb 2019 13:27:54 +0800 Subject: [PATCH 6/6] =?UTF-8?q?update:mousetap=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtScrcpy/QtScrcpy.pro | 3 +- QtScrcpy/main.cpp | 12 ++--- QtScrcpy/util/.DS_Store | Bin 6148 -> 0 bytes QtScrcpy/util/{ => mousetap}/cocoamousetap.h | 14 +++--- QtScrcpy/util/{ => mousetap}/cocoamousetap.mm | 10 ---- QtScrcpy/util/mousetap/mousetap.cpp | 26 +++++++++++ QtScrcpy/util/mousetap/mousetap.h | 14 ++++++ QtScrcpy/util/mousetap/mousetap.pri | 18 ++++++++ QtScrcpy/util/mousetap/winmousetap.cpp | 43 ++++++++++++++++++ QtScrcpy/util/mousetap/winmousetap.h | 17 +++++++ QtScrcpy/util/util.pri | 7 +-- QtScrcpy/videoform.cpp | 23 ++-------- TODO.txt | 7 ++- 13 files changed, 137 insertions(+), 57 deletions(-) delete mode 100644 QtScrcpy/util/.DS_Store rename QtScrcpy/util/{ => mousetap}/cocoamousetap.h (58%) rename QtScrcpy/util/{ => mousetap}/cocoamousetap.mm (97%) create mode 100644 QtScrcpy/util/mousetap/mousetap.cpp create mode 100644 QtScrcpy/util/mousetap/mousetap.h create mode 100644 QtScrcpy/util/mousetap/mousetap.pri create mode 100644 QtScrcpy/util/mousetap/winmousetap.cpp create mode 100644 QtScrcpy/util/mousetap/winmousetap.h diff --git a/QtScrcpy/QtScrcpy.pro b/QtScrcpy/QtScrcpy.pro index db01ddf..39b697c 100644 --- a/QtScrcpy/QtScrcpy.pro +++ b/QtScrcpy/QtScrcpy.pro @@ -94,8 +94,7 @@ win32 { -L$$PWD/../third_party/ffmpeg/lib -lavformat \ -L$$PWD/../third_party/ffmpeg/lib -lavcodec \ -L$$PWD/../third_party/ffmpeg/lib -lavutil \ - -L$$PWD/../third_party/ffmpeg/lib -lswscale \ - -lUser32 + -L$$PWD/../third_party/ffmpeg/lib -lswscale # windows rc file RC_FILE = $$PWD/res/QtScrcpy.rc diff --git a/QtScrcpy/main.cpp b/QtScrcpy/main.cpp index 5f780d7..e0628d6 100644 --- a/QtScrcpy/main.cpp +++ b/QtScrcpy/main.cpp @@ -6,9 +6,7 @@ #include "dialog.h" #include "decoder.h" -#ifdef Q_OS_OSX -#include "cocoamousetap.h" -#endif +#include "mousetap/mousetap.h" Dialog* g_mainDlg = Q_NULLPTR; @@ -28,9 +26,7 @@ int main(int argc, char *argv[]) installTranslator(); -#ifdef Q_OS_OSX - CocoaMouseTap::getInstance()->initMouseEventTap(); -#endif + MouseTap::getInstance()->initMouseEventTap(); #ifdef Q_OS_WIN32 qputenv("QTSCRCPY_ADB_PATH", "../../../third_party/adb/win/adb.exe"); @@ -57,9 +53,7 @@ int main(int argc, char *argv[]) int ret = a.exec(); -#ifdef Q_OS_OSX - CocoaMouseTap::getInstance()->quitMouseEventTap(); -#endif + MouseTap::getInstance()->quitMouseEventTap(); Decoder::deInit(); return ret; } diff --git a/QtScrcpy/util/.DS_Store b/QtScrcpy/util/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8z45|!R0Z1N%F(jFgL>QrFAPJ2!M?+vV1V%$(Gz3ON zU^D~25V%SxcdJP zRior+2#kinunYl47MEZbCs3t{!+W4QHvuXKVuPw;Mo^s$(F3lEVT}ML$bg~*R5_@+ b2Uo?6kTwK}57Iu`5P${HC_Nei0}uiLNUI8I diff --git a/QtScrcpy/util/cocoamousetap.h b/QtScrcpy/util/mousetap/cocoamousetap.h similarity index 58% rename from QtScrcpy/util/cocoamousetap.h rename to QtScrcpy/util/mousetap/cocoamousetap.h index da92cb9..2346a2e 100644 --- a/QtScrcpy/util/cocoamousetap.h +++ b/QtScrcpy/util/mousetap/cocoamousetap.h @@ -3,19 +3,20 @@ #include #include +#include "mousetap.h" + struct MouseEventTapData; class QWidget; -class CocoaMouseTap : public QThread +class CocoaMouseTap : public MouseTap, public QThread { private: CocoaMouseTap(QObject *parent = Q_NULLPTR); - ~CocoaMouseTap(); + virtual ~CocoaMouseTap(); public: - static CocoaMouseTap* getInstance(); - void initMouseEventTap(); - void quitMouseEventTap(); - void enableMouseEventTap(QWidget* widget, bool enabled); + void initMouseEventTap() override; + void quitMouseEventTap() override; + void enableMouseEventTap(QWidget* widget, bool enabled) override; protected: void run() override; @@ -23,7 +24,6 @@ protected: private: MouseEventTapData *m_tapData = Q_NULLPTR; QSemaphore m_runloopStartedSemaphore; - static CocoaMouseTap *s_instance; }; #endif // COCOAMOUSETAP_H diff --git a/QtScrcpy/util/cocoamousetap.mm b/QtScrcpy/util/mousetap/cocoamousetap.mm similarity index 97% rename from QtScrcpy/util/cocoamousetap.mm rename to QtScrcpy/util/mousetap/cocoamousetap.mm index 3d4d5f8..fdcd129 100644 --- a/QtScrcpy/util/cocoamousetap.mm +++ b/QtScrcpy/util/mousetap/cocoamousetap.mm @@ -111,8 +111,6 @@ static void SemaphorePostCallback(CFRunLoopTimerRef timer, void *info) } } -CocoaMouseTap * CocoaMouseTap::s_instance = Q_NULLPTR; - CocoaMouseTap::CocoaMouseTap(QObject *parent) : QThread(parent) { @@ -127,14 +125,6 @@ CocoaMouseTap::~CocoaMouseTap() } } -CocoaMouseTap *CocoaMouseTap::getInstance() -{ - if (s_instance == Q_NULLPTR) { - s_instance = new CocoaMouseTap(); - } - return s_instance; -} - void CocoaMouseTap::initMouseEventTap() { if (!m_tapData) { diff --git a/QtScrcpy/util/mousetap/mousetap.cpp b/QtScrcpy/util/mousetap/mousetap.cpp new file mode 100644 index 0000000..da1bc13 --- /dev/null +++ b/QtScrcpy/util/mousetap/mousetap.cpp @@ -0,0 +1,26 @@ +#include + +#include "mousetap.h" +#ifdef Q_OS_WIN32 +#include "winmousetap.h" +#endif +#ifdef Q_OS_OSX +#include "cocoamousetap.h" +#endif + +MouseTap *MouseTap::s_instance = Q_NULLPTR; +MouseTap *MouseTap::getInstance() +{ + if (s_instance == Q_NULLPTR) { +#ifdef Q_OS_WIN32 + s_instance = new WinMouseTap(); +#endif +#ifdef Q_OS_OSX + s_instance = new CocoaMouseTap(); +#endif +#ifdef Q_OS_LINUX + Q_ASSERT(false); +#endif + } + return s_instance; +} diff --git a/QtScrcpy/util/mousetap/mousetap.h b/QtScrcpy/util/mousetap/mousetap.h new file mode 100644 index 0000000..eab1389 --- /dev/null +++ b/QtScrcpy/util/mousetap/mousetap.h @@ -0,0 +1,14 @@ +#ifndef MOUSETAP_H +#define MOUSETAP_H +class QWidget; +class MouseTap { +public: + static MouseTap* getInstance(); + virtual void initMouseEventTap() = 0; + virtual void quitMouseEventTap() = 0; + virtual void enableMouseEventTap(QWidget* widget, bool enabled) = 0; + +private: + static MouseTap *s_instance; +}; +#endif // MOUSETAP_H diff --git a/QtScrcpy/util/mousetap/mousetap.pri b/QtScrcpy/util/mousetap/mousetap.pri new file mode 100644 index 0000000..e2d7d09 --- /dev/null +++ b/QtScrcpy/util/mousetap/mousetap.pri @@ -0,0 +1,18 @@ +HEADERS += \ + $$PWD/mousetap.h + +SOURCES += \ + $$PWD/mousetap.cpp + +win32 { + HEADERS += $$PWD/winmousetap.h + SOURCES += $$PWD/winmousetap.cpp + LIBS += -lUser32 +} + +mac { + HEADERS += $$PWD/cocoamousetap.h + OBJECTIVE_SOURCES += $$PWD/cocoamousetap.mm + LIBS += -framework Appkit + QMAKE_CFLAGS += -mmacosx-version-min=10.6 +} diff --git a/QtScrcpy/util/mousetap/winmousetap.cpp b/QtScrcpy/util/mousetap/winmousetap.cpp new file mode 100644 index 0000000..7467b89 --- /dev/null +++ b/QtScrcpy/util/mousetap/winmousetap.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include "winmousetap.h" + +WinMouseTap::WinMouseTap() +{ + +} + +WinMouseTap::~WinMouseTap() +{ + +} + +void WinMouseTap::initMouseEventTap() +{ + +} + +void WinMouseTap::quitMouseEventTap() +{ + +} + +void WinMouseTap::enableMouseEventTap(QWidget *widget, bool enabled) +{ + if (!widget) { + return; + } + if(enabled) { + QRect rc(widget->mapToGlobal(widget->pos()) + , widget->size()); + RECT mainRect; + mainRect.left = (LONG)rc.left(); + mainRect.right = (LONG)rc.right(); + mainRect.top = (LONG)rc.top(); + mainRect.bottom = (LONG)rc.bottom(); + ClipCursor(&mainRect); + } else { + ClipCursor(Q_NULLPTR); + } +} diff --git a/QtScrcpy/util/mousetap/winmousetap.h b/QtScrcpy/util/mousetap/winmousetap.h new file mode 100644 index 0000000..9b23f68 --- /dev/null +++ b/QtScrcpy/util/mousetap/winmousetap.h @@ -0,0 +1,17 @@ +#ifndef WINMOUSETAP_H +#define WINMOUSETAP_H + +#include "mousetap.h" + +class WinMouseTap : public MouseTap +{ +public: + WinMouseTap(); + virtual ~WinMouseTap(); + + void initMouseEventTap() override; + void quitMouseEventTap() override; + void enableMouseEventTap(QWidget* widget, bool enabled) override; +}; + +#endif // WINMOUSETAP_H diff --git a/QtScrcpy/util/util.pri b/QtScrcpy/util/util.pri index b489d3f..8756e35 100644 --- a/QtScrcpy/util/util.pri +++ b/QtScrcpy/util/util.pri @@ -1,6 +1 @@ -mac { - HEADERS += $$PWD/cocoamousetap.h - OBJECTIVE_SOURCES += $$PWD/cocoamousetap.mm - LIBS += -framework Appkit - QMAKE_CFLAGS += -mmacosx-version-min=10.6 -} +include ($$PWD/mousetap/mousetap.pri) diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp index 9fe3682..14416e1 100644 --- a/QtScrcpy/videoform.cpp +++ b/QtScrcpy/videoform.cpp @@ -4,9 +4,6 @@ #include #include #include -#ifdef Q_OS_WIN32 -#include -#endif #ifdef USE_QTQUICK #include #endif @@ -21,9 +18,7 @@ #include "toolform.h" #include "controlevent.h" #include "recorder.h" -#ifdef Q_OS_OSX -#include "cocoamousetap.h" -#endif +#include "mousetap/mousetap.h" VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, QWidget *parent) : QWidget(parent), @@ -141,22 +136,12 @@ void VideoForm::initSignals() } }); connect(&m_inputConvert, &InputConvertGame::grabCursor, this, [this](bool grab){ + #ifdef Q_OS_WIN32 - if(grab) { - QRect rc(mapToGlobal(ui->videoWidget->pos()) - , ui->videoWidget->size()); - RECT mainRect; - mainRect.left = (LONG)rc.left(); - mainRect.right = (LONG)rc.right(); - mainRect.top = (LONG)rc.top(); - mainRect.bottom = (LONG)rc.bottom(); - ClipCursor(&mainRect); - } else { - ClipCursor(Q_NULLPTR); - } + MouseTap::getInstance()->enableMouseEventTap(ui->videoWidget, grab); #endif #ifdef Q_OS_OSX - CocoaMouseTap::getInstance()->enableMouseEventTap(ui->videoWidget, grab); + MouseTap::getInstance()->enableMouseEventTap(ui->videoWidget, grab); #endif }); connect(m_server, &Server::serverStartResult, this, [this](bool success){ diff --git a/TODO.txt b/TODO.txt index 8bd218e..159bbb2 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,13 +1,12 @@ // TODO mac: Qt::FramelessWindowHit full screen is abnormal -ƶƽ̨ӿ +linuxƶ MacϷʱƶ⡣ չģָȣ ģָ(ע⣺Ͷû) - +루serverҪΪapkΪһ뷨ݲʵ֣ - - 7764a836f1ee02a4540cfc4118c20729018daaac +scrcpy 7764a836f1ee02a4540cfc4118c20729018daaac mark: