mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-08-02 21:58:42 +00:00
Merge branch 'master' of https://gitee.com/Barryda/QtScrcpy
This commit is contained in:
commit
6d216191d9
18 changed files with 470 additions and 92 deletions
|
@ -5,7 +5,7 @@
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
|
|
||||||
QT += core gui
|
QT += core gui
|
||||||
QT += network quickwidgets
|
QT += network
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
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 += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
#DEFINES += SKIP_FRAMES
|
#DEFINES += SKIP_FRAMES
|
||||||
|
#DEFINES += USE_QTQUICK
|
||||||
|
|
||||||
|
contains(DEFINES, USE_QTQUICK) {
|
||||||
|
QT += quickwidgets
|
||||||
|
}
|
||||||
|
|
||||||
# 源码
|
# 源码
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
@ -54,6 +59,7 @@ include ($$PWD/uibase/uibase.pri)
|
||||||
include ($$PWD/fontawesome/fontawesome.pri)
|
include ($$PWD/fontawesome/fontawesome.pri)
|
||||||
include ($$PWD/filehandler/filehandler.pri)
|
include ($$PWD/filehandler/filehandler.pri)
|
||||||
include ($$PWD/recorder/recorder.pri)
|
include ($$PWD/recorder/recorder.pri)
|
||||||
|
include ($$PWD/util/util.pri)
|
||||||
|
|
||||||
# 附加包含路径
|
# 附加包含路径
|
||||||
INCLUDEPATH += \
|
INCLUDEPATH += \
|
||||||
|
@ -68,6 +74,7 @@ INCLUDEPATH += \
|
||||||
$$PWD/uibase \
|
$$PWD/uibase \
|
||||||
$$PWD/filehandler \
|
$$PWD/filehandler \
|
||||||
$$PWD/recorder \
|
$$PWD/recorder \
|
||||||
|
$$PWD/util \
|
||||||
$$PWD/fontawesome
|
$$PWD/fontawesome
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,8 +94,7 @@ win32 {
|
||||||
-L$$PWD/../third_party/ffmpeg/lib -lavformat \
|
-L$$PWD/../third_party/ffmpeg/lib -lavformat \
|
||||||
-L$$PWD/../third_party/ffmpeg/lib -lavcodec \
|
-L$$PWD/../third_party/ffmpeg/lib -lavcodec \
|
||||||
-L$$PWD/../third_party/ffmpeg/lib -lavutil \
|
-L$$PWD/../third_party/ffmpeg/lib -lavutil \
|
||||||
-L$$PWD/../third_party/ffmpeg/lib -lswscale \
|
-L$$PWD/../third_party/ffmpeg/lib -lswscale
|
||||||
-lUser32
|
|
||||||
|
|
||||||
# windows rc file
|
# windows rc file
|
||||||
RC_FILE = $$PWD/res/QtScrcpy.rc
|
RC_FILE = $$PWD/res/QtScrcpy.rc
|
||||||
|
|
|
@ -413,9 +413,9 @@ bool InputConvertGame::processMouseMove(const QMouseEvent *from)
|
||||||
m_mouseMoveLastConverPos.setY(m_mouseMoveLastConverPos.y() + distance.y() / m_showSize.height());
|
m_mouseMoveLastConverPos.setY(m_mouseMoveLastConverPos.y() + distance.y() / m_showSize.height());
|
||||||
|
|
||||||
if (m_mouseMoveLastConverPos.x() < 0.1
|
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.1
|
||||||
|| m_mouseMoveLastConverPos.y() > 0.9) {
|
|| m_mouseMoveLastConverPos.y() > 0.8) {
|
||||||
mouseMoveStopTouch();
|
mouseMoveStopTouch();
|
||||||
mouseMoveStartTouch(from);
|
mouseMoveStartTouch(from);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "dialog.h"
|
#include "dialog.h"
|
||||||
#include "decoder.h"
|
#include "decoder.h"
|
||||||
|
#include "mousetap/mousetap.h"
|
||||||
|
|
||||||
Dialog* g_mainDlg = Q_NULLPTR;
|
Dialog* g_mainDlg = Q_NULLPTR;
|
||||||
|
|
||||||
|
@ -25,6 +26,8 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
installTranslator();
|
installTranslator();
|
||||||
|
|
||||||
|
MouseTap::getInstance()->initMouseEventTap();
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
qputenv("QTSCRCPY_ADB_PATH", "../../../third_party/adb/win/adb.exe");
|
qputenv("QTSCRCPY_ADB_PATH", "../../../third_party/adb/win/adb.exe");
|
||||||
qputenv("QTSCRCPY_SERVER_PATH", "../../../third_party/scrcpy-server.jar");
|
qputenv("QTSCRCPY_SERVER_PATH", "../../../third_party/scrcpy-server.jar");
|
||||||
|
@ -50,6 +53,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
int ret = a.exec();
|
int ret = a.exec();
|
||||||
|
|
||||||
|
MouseTap::getInstance()->quitMouseEventTap();
|
||||||
Decoder::deInit();
|
Decoder::deInit();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,12 @@ Image {
|
||||||
RotationAnimation {
|
RotationAnimation {
|
||||||
id:rotationAnimation
|
id:rotationAnimation
|
||||||
target: wheel
|
target: wheel
|
||||||
to:360000
|
to:360
|
||||||
direction: RotationAnimation.Clockwise
|
direction: RotationAnimation.Clockwise
|
||||||
duration: 800000
|
duration: 800
|
||||||
|
loops:Animation.Infinite
|
||||||
}
|
}
|
||||||
|
|
||||||
onStatusChanged: if (wheel.status == Image.Ready) rotationAnimation.start()
|
onStatusChanged: if (wheel.status == Image.Ready) rotationAnimation.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QShowEvent>
|
||||||
|
#include <QHideEvent>
|
||||||
|
|
||||||
#include "toolform.h"
|
#include "toolform.h"
|
||||||
#include "ui_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()
|
void ToolForm::on_fullScreenBtn_clicked()
|
||||||
{
|
{
|
||||||
if (m_videoForm) {
|
if (m_videoForm) {
|
||||||
|
|
|
@ -24,6 +24,9 @@ protected:
|
||||||
void mouseReleaseEvent(QMouseEvent *event);
|
void mouseReleaseEvent(QMouseEvent *event);
|
||||||
void mouseMoveEvent(QMouseEvent *event);
|
void mouseMoveEvent(QMouseEvent *event);
|
||||||
|
|
||||||
|
void showEvent(QShowEvent *event);
|
||||||
|
void hideEvent(QHideEvent *event);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_fullScreenBtn_clicked();
|
void on_fullScreenBtn_clicked();
|
||||||
|
|
||||||
|
|
29
QtScrcpy/util/mousetap/cocoamousetap.h
Normal file
29
QtScrcpy/util/mousetap/cocoamousetap.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef COCOAMOUSETAP_H
|
||||||
|
#define COCOAMOUSETAP_H
|
||||||
|
#include <QThread>
|
||||||
|
#include <QSemaphore>
|
||||||
|
|
||||||
|
#include "mousetap.h"
|
||||||
|
|
||||||
|
struct MouseEventTapData;
|
||||||
|
class QWidget;
|
||||||
|
class CocoaMouseTap : public MouseTap, public QThread
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CocoaMouseTap(QObject *parent = Q_NULLPTR);
|
||||||
|
virtual ~CocoaMouseTap();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void initMouseEventTap() override;
|
||||||
|
void quitMouseEventTap() override;
|
||||||
|
void enableMouseEventTap(QWidget* widget, bool enabled) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void run() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MouseEventTapData *m_tapData = Q_NULLPTR;
|
||||||
|
QSemaphore m_runloopStartedSemaphore;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCOAMOUSETAP_H
|
227
QtScrcpy/util/mousetap/cocoamousetap.mm
Normal file
227
QtScrcpy/util/mousetap/cocoamousetap.mm
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#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(QObject *parent)
|
||||||
|
: QThread(parent)
|
||||||
|
{
|
||||||
|
m_tapData = new MouseEventTapData;
|
||||||
|
}
|
||||||
|
|
||||||
|
CocoaMouseTap::~CocoaMouseTap()
|
||||||
|
{
|
||||||
|
if (m_tapData) {
|
||||||
|
delete m_tapData;
|
||||||
|
m_tapData = Q_NULLPTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
26
QtScrcpy/util/mousetap/mousetap.cpp
Normal file
26
QtScrcpy/util/mousetap/mousetap.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
14
QtScrcpy/util/mousetap/mousetap.h
Normal file
14
QtScrcpy/util/mousetap/mousetap.h
Normal file
|
@ -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
|
18
QtScrcpy/util/mousetap/mousetap.pri
Normal file
18
QtScrcpy/util/mousetap/mousetap.pri
Normal file
|
@ -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
|
||||||
|
}
|
43
QtScrcpy/util/mousetap/winmousetap.cpp
Normal file
43
QtScrcpy/util/mousetap/winmousetap.cpp
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
17
QtScrcpy/util/mousetap/winmousetap.h
Normal file
17
QtScrcpy/util/mousetap/winmousetap.h
Normal file
|
@ -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
|
1
QtScrcpy/util/util.pri
Normal file
1
QtScrcpy/util/util.pri
Normal file
|
@ -0,0 +1 @@
|
||||||
|
include ($$PWD/mousetap/mousetap.pri)
|
|
@ -4,10 +4,10 @@
|
||||||
#include <QStyle>
|
#include <QStyle>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef USE_QTQUICK
|
||||||
#include <Windows.h>
|
|
||||||
#endif
|
|
||||||
#include <QQuickWidget>
|
#include <QQuickWidget>
|
||||||
|
#endif
|
||||||
|
#include <QtWidgets/QHBoxLayout>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
#include "toolform.h"
|
#include "toolform.h"
|
||||||
#include "controlevent.h"
|
#include "controlevent.h"
|
||||||
#include "recorder.h"
|
#include "recorder.h"
|
||||||
|
#include "mousetap/mousetap.h"
|
||||||
|
|
||||||
VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, QWidget *parent) :
|
VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
|
@ -73,27 +74,52 @@ VideoForm::~VideoForm()
|
||||||
|
|
||||||
void VideoForm::initUI()
|
void VideoForm::initUI()
|
||||||
{
|
{
|
||||||
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
QPixmap phone;
|
QPixmap phone;
|
||||||
if (phone.load(":/res/phone.png")) {
|
if (phone.load(":/res/phone.png")) {
|
||||||
m_widthHeightRatio = 1.0f * phone.width() / phone.height();
|
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
|
||||||
// 去掉标题栏
|
// 去掉标题栏
|
||||||
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||||
// 根据图片构造异形窗口
|
// 根据图片构造异形窗口
|
||||||
setAttribute(Qt::WA_TranslucentBackground);
|
setAttribute(Qt::WA_TranslucentBackground);
|
||||||
|
#endif
|
||||||
|
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
ui->loadingWidget->setAttribute(Qt::WA_DeleteOnClose);
|
|
||||||
ui->videoWidget->setMouseTracking(true);
|
ui->videoWidget->setMouseTracking(true);
|
||||||
ui->videoWidget->hide();
|
ui->videoWidget->hide();
|
||||||
|
|
||||||
// 最后绘制,不设置最后绘制会影响父窗体异形异常(quickWidget的透明通道会形成穿透)
|
|
||||||
ui->quickWidget->setAttribute(Qt::WA_AlwaysStackOnTop);
|
|
||||||
// 背景透明
|
|
||||||
ui->quickWidget->setClearColor(QColor(Qt::transparent));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoForm::initSignals()
|
void VideoForm::initSignals()
|
||||||
|
@ -110,19 +136,12 @@ void VideoForm::initSignals()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(&m_inputConvert, &InputConvertGame::grabCursor, this, [this](bool grab){
|
connect(&m_inputConvert, &InputConvertGame::grabCursor, this, [this](bool grab){
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
if(grab) {
|
MouseTap::getInstance()->enableMouseEventTap(ui->videoWidget, grab);
|
||||||
QRect rc(mapToGlobal(ui->videoWidget->pos())
|
#endif
|
||||||
, ui->videoWidget->size());
|
#ifdef Q_OS_OSX
|
||||||
RECT mainRect;
|
MouseTap::getInstance()->enableMouseEventTap(ui->videoWidget, grab);
|
||||||
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);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
});
|
});
|
||||||
connect(m_server, &Server::serverStartResult, this, [this](bool success){
|
connect(m_server, &Server::serverStartResult, this, [this](bool success){
|
||||||
|
@ -138,7 +157,6 @@ void VideoForm::initSignals()
|
||||||
float diff = m_startTimeCount.elapsed() / 1000.0f;
|
float diff = m_startTimeCount.elapsed() / 1000.0f;
|
||||||
qInfo(QString("server start finish in %1s").arg(diff).toStdString().c_str());
|
qInfo(QString("server start finish in %1s").arg(diff).toStdString().c_str());
|
||||||
|
|
||||||
|
|
||||||
// update ui
|
// update ui
|
||||||
setWindowTitle(deviceName);
|
setWindowTitle(deviceName);
|
||||||
updateShowSize(size);
|
updateShowSize(size);
|
||||||
|
@ -170,7 +188,9 @@ void VideoForm::initSignals()
|
||||||
// must be Qt::QueuedConnection, ui update must be main thread
|
// must be Qt::QueuedConnection, ui update must be main thread
|
||||||
connect(&m_decoder, &Decoder::onNewFrame, this, [this](){
|
connect(&m_decoder, &Decoder::onNewFrame, this, [this](){
|
||||||
if (ui->videoWidget->isHidden()) {
|
if (ui->videoWidget->isHidden()) {
|
||||||
ui->loadingWidget->close();
|
if (m_loadingWidget) {
|
||||||
|
m_loadingWidget->close();
|
||||||
|
}
|
||||||
ui->videoWidget->show();
|
ui->videoWidget->show();
|
||||||
}
|
}
|
||||||
m_frames.lock();
|
m_frames.lock();
|
||||||
|
@ -257,9 +277,10 @@ void VideoForm::switchFullScreen()
|
||||||
{
|
{
|
||||||
if (isFullScreen()) {
|
if (isFullScreen()) {
|
||||||
showNormal();
|
showNormal();
|
||||||
|
|
||||||
#ifdef Q_OS_OSX
|
#ifdef Q_OS_OSX
|
||||||
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
//setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||||
show();
|
//show();
|
||||||
#endif
|
#endif
|
||||||
updateStyleSheet(height() > width());
|
updateStyleSheet(height() > width());
|
||||||
showToolFrom(true);
|
showToolFrom(true);
|
||||||
|
@ -267,9 +288,10 @@ void VideoForm::switchFullScreen()
|
||||||
::SetThreadExecutionState(ES_CONTINUOUS);
|
::SetThreadExecutionState(ES_CONTINUOUS);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
|
// 这种临时增加标题栏再全屏的方案会导致收不到mousemove事件,导致setmousetrack失效
|
||||||
// mac fullscreen must show title bar
|
// mac fullscreen must show title bar
|
||||||
#ifdef Q_OS_OSX
|
#ifdef Q_OS_OSX
|
||||||
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
|
//setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
|
||||||
#endif
|
#endif
|
||||||
showToolFrom(false);
|
showToolFrom(false);
|
||||||
layout()->setContentsMargins(0, 0, 0, 0);
|
layout()->setContentsMargins(0, 0, 0, 0);
|
||||||
|
@ -410,6 +432,7 @@ void VideoForm::keyPressEvent(QKeyEvent *event)
|
||||||
&& isFullScreen()) {
|
&& isFullScreen()) {
|
||||||
switchFullScreen();
|
switchFullScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
//qDebug() << "keyPressEvent" << event->isAutoRepeat();
|
//qDebug() << "keyPressEvent" << event->isAutoRepeat();
|
||||||
m_inputConvert.keyEvent(event, ui->videoWidget->frameSize(), ui->videoWidget->size());
|
m_inputConvert.keyEvent(event, ui->videoWidget->frameSize(), ui->videoWidget->size());
|
||||||
}
|
}
|
||||||
|
@ -432,7 +455,9 @@ void VideoForm::paintEvent(QPaintEvent *paint)
|
||||||
void VideoForm::showEvent(QShowEvent *event)
|
void VideoForm::showEvent(QShowEvent *event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event);
|
Q_UNUSED(event);
|
||||||
showToolFrom();
|
if (!isFullScreen()) {
|
||||||
|
showToolFrom();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoForm::dragEnterEvent(QDragEnterEvent *event)
|
void VideoForm::dragEnterEvent(QDragEnterEvent *event)
|
||||||
|
|
|
@ -79,6 +79,7 @@ private:
|
||||||
QPointer<ToolForm> m_toolForm;
|
QPointer<ToolForm> m_toolForm;
|
||||||
Recorder* m_recorder = Q_NULLPTR;
|
Recorder* m_recorder = Q_NULLPTR;
|
||||||
QTime m_startTimeCount;
|
QTime m_startTimeCount;
|
||||||
|
QPointer<QWidget> m_loadingWidget;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // VIDEOFORM_H
|
#endif // VIDEOFORM_H
|
||||||
|
|
|
@ -38,62 +38,12 @@
|
||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>62</number>
|
<number>62</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
|
||||||
<widget class="QWidget" name="loadingWidget" native="true">
|
|
||||||
<property name="autoFillBackground">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true"/>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QQuickWidget" name="quickWidget">
|
|
||||||
<property name="autoFillBackground">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true"/>
|
|
||||||
</property>
|
|
||||||
<property name="resizeMode">
|
|
||||||
<enum>QQuickWidget::SizeRootObjectToView</enum>
|
|
||||||
</property>
|
|
||||||
<property name="source">
|
|
||||||
<url>
|
|
||||||
<string>qrc:/qml/pinwheel.qml</string>
|
|
||||||
</url>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QYUVOpenGLWidget" name="videoWidget" native="true"/>
|
<widget class="QYUVOpenGLWidget" name="videoWidget" native="true"/>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
|
||||||
<class>QQuickWidget</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>QtQuickWidgets/QQuickWidget</header>
|
|
||||||
</customwidget>
|
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>QYUVOpenGLWidget</class>
|
<class>QYUVOpenGLWidget</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
|
|
8
TODO.txt
8
TODO.txt
|
@ -1,12 +1,12 @@
|
||||||
// TODO mac: Qt::FramelessWindowHit full screen is abnormal
|
// TODO mac: Qt::FramelessWindowHit full screen is abnormal
|
||||||
|
linux下限制鼠标移动
|
||||||
|
Mac游戏时向右移动不流畅问题。
|
||||||
工具栏扩展(模拟点击指定次数等)
|
工具栏扩展(模拟点击指定次数等)
|
||||||
|
|
||||||
模拟点击改用手指(注意:辅助按键就都没了)
|
模拟点击改用手指(注意:辅助按键就都没了)
|
||||||
中文输入
|
中文输入(server需要改为apk,作为一个输入法,暂不实现)
|
||||||
|
|
||||||
|
最后更新scrcpy 7764a836f1ee02a4540cfc4118c20729018daaac
|
||||||
最后更新 7764a836f1ee02a4540cfc4118c20729018daaac
|
|
||||||
|
|
||||||
|
|
||||||
mark:
|
mark:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue