Add ScrcpyWindow integration for screen mirroring
Introduced a ScrcpyWindow to enable integration of the scrcpy tool for device screen mirroring within the application. Platform-specific embedding is supported for macOS and Windows, with structure adjustments made in MainWindow and the build system (CMakeLists.txt).
This commit is contained in:
parent
c1b34ce7d7
commit
327b206fe8
@ -19,8 +19,15 @@ elseif (APPLE)
|
|||||||
set(CMAKE_PREFIX_PATH "/opt/homebrew/opt/qt")
|
set(CMAKE_PREFIX_PATH "/opt/homebrew/opt/qt")
|
||||||
include_directories("/opt/homebrew/opt/tesseract/include")
|
include_directories("/opt/homebrew/opt/tesseract/include")
|
||||||
link_directories("/opt/homebrew/opt/tesseract/lib")
|
link_directories("/opt/homebrew/opt/tesseract/lib")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17) # или 20, если нужно
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ObjC++")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
set(SCRCPY
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/views/scrcpy/ScrcpyWindow_mac.mm
|
||||||
|
)
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS
|
find_package(Qt6 REQUIRED COMPONENTS
|
||||||
Widgets
|
Widgets
|
||||||
Sql
|
Sql
|
||||||
@ -52,6 +59,7 @@ add_executable(ARCDesktopProject
|
|||||||
${SERVICES_SOURCES}
|
${SERVICES_SOURCES}
|
||||||
${DB_SOURCES}
|
${DB_SOURCES}
|
||||||
${MODELS_SOURCES}
|
${MODELS_SOURCES}
|
||||||
|
${SCRCPY}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
|
|||||||
Binary file not shown.
@ -48,6 +48,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
|||||||
stackedWidget->setCurrentWidget(accountPage);
|
stackedWidget->setCurrentWidget(accountPage);
|
||||||
deleteDevicePage(); // освобождаем ресурсы
|
deleteDevicePage(); // освобождаем ресурсы
|
||||||
});
|
});
|
||||||
|
|
||||||
|
scrcpyWindow = new ScrcpyWindow();
|
||||||
|
scrcpyWindow->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "db/DeviceInfo.h"
|
#include "db/DeviceInfo.h"
|
||||||
|
#include "scrcpy/ScrcpyWindow.h"
|
||||||
#include "widget/FlowLayout.h"
|
#include "widget/FlowLayout.h"
|
||||||
|
|
||||||
class MainWindow final : public QMainWindow {
|
class MainWindow final : public QMainWindow {
|
||||||
@ -21,6 +22,8 @@ private:
|
|||||||
QWidget* devicePage = nullptr;
|
QWidget* devicePage = nullptr;
|
||||||
QWidget* accountPage = nullptr;
|
QWidget* accountPage = nullptr;
|
||||||
|
|
||||||
|
ScrcpyWindow *scrcpyWindow;
|
||||||
|
|
||||||
void createDevicePage();
|
void createDevicePage();
|
||||||
void deleteDevicePage();
|
void deleteDevicePage();
|
||||||
};
|
};
|
||||||
|
|||||||
68
views/scrcpy/ScrcpyWindow.cpp
Normal file
68
views/scrcpy/ScrcpyWindow.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "ScrcpyWindow.h"
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ScrcpyWindow::ScrcpyWindow(QWidget *parent) : QWidget(parent), m_process(nullptr) {
|
||||||
|
setWindowFlag(Qt::WindowStaysOnTopHint);
|
||||||
|
startScrcpy();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrcpyWindow::~ScrcpyWindow() {
|
||||||
|
stopScrcpy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrcpyWindow::startScrcpy() {
|
||||||
|
m_process = new QProcess(this);
|
||||||
|
m_process->start("scrcpy", {"--window-title", "scrcpy", "--always-on-top"});
|
||||||
|
|
||||||
|
// Подождём немного, чтобы окно scrcpy запустилось
|
||||||
|
QTimer::singleShot(5000, this, &ScrcpyWindow::embedPlatformSpecific);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrcpyWindow::stopScrcpy() {
|
||||||
|
if (m_process) {
|
||||||
|
m_process->terminate();
|
||||||
|
m_process->waitForFinished();
|
||||||
|
delete m_process;
|
||||||
|
m_process = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ScrcpyWindow::embedPlatformSpecific() {
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
|
HWND hwndScrcpy = FindWindowW(nullptr, L"scrcpy");
|
||||||
|
if (!hwndScrcpy) {
|
||||||
|
qDebug() << "scrcpy window not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND hwndTarget = (HWND)this->winId();
|
||||||
|
SetParent(hwndScrcpy, hwndTarget);
|
||||||
|
|
||||||
|
LONG style = GetWindowLong(hwndScrcpy, GWL_STYLE);
|
||||||
|
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_BORDER);
|
||||||
|
SetWindowLong(hwndScrcpy, GWL_STYLE, style);
|
||||||
|
|
||||||
|
RECT rect;
|
||||||
|
GetClientRect(hwndTarget, &rect);
|
||||||
|
SetWindowPos(hwndScrcpy, HWND_TOP, 0, 0,
|
||||||
|
rect.right - rect.left, rect.bottom - rect.top,
|
||||||
|
SWP_SHOWWINDOW);
|
||||||
|
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
|
||||||
|
extern void embedScrcpyMac(QWidget *container);
|
||||||
|
embedScrcpyMac(this);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
qDebug() << "Scrcpy embedding not implemented for this OS.";
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
22
views/scrcpy/ScrcpyWindow.h
Normal file
22
views/scrcpy/ScrcpyWindow.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
|
class ScrcpyWindow final : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ScrcpyWindow(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
~ScrcpyWindow() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QProcess *m_process;
|
||||||
|
|
||||||
|
void startScrcpy();
|
||||||
|
|
||||||
|
void stopScrcpy();
|
||||||
|
|
||||||
|
void embedPlatformSpecific();
|
||||||
|
};
|
||||||
61
views/scrcpy/ScrcpyWindow_mac.mm
Normal file
61
views/scrcpy/ScrcpyWindow_mac.mm
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <QtCore/QDebug>
|
||||||
|
#import <ApplicationServices/ApplicationServices.h>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QWindow>
|
||||||
|
|
||||||
|
void listAllWindows() {
|
||||||
|
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
|
||||||
|
|
||||||
|
for (NSDictionary *entry in (__bridge NSArray *)windowList) {
|
||||||
|
NSString *name = entry[(NSString *)kCGWindowName];
|
||||||
|
NSString *owner = entry[(NSString *)kCGWindowOwnerName];
|
||||||
|
NSNumber *windowNumber = entry[(NSString *)kCGWindowNumber];
|
||||||
|
if (name.length > 0) {
|
||||||
|
qDebug() << "Window:" << owner.UTF8String << "-" << name.UTF8String
|
||||||
|
<< "ID:" << windowNumber.intValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(windowList);
|
||||||
|
}
|
||||||
|
|
||||||
|
void embedScrcpyMac(QWidget *container) {
|
||||||
|
// Получаем список окон
|
||||||
|
NSArray *windows = [NSApp windows];
|
||||||
|
NSWindow *scrcpyWindow = nil;
|
||||||
|
|
||||||
|
listAllWindows();
|
||||||
|
|
||||||
|
for (NSWindow *window in windows) {
|
||||||
|
NSString *title = [window title];
|
||||||
|
qDebug() << "Found window title:" << title.UTF8String;
|
||||||
|
|
||||||
|
if ([[window title] isEqualToString:@"scrcpy"]) {
|
||||||
|
scrcpyWindow = window;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scrcpyWindow) {
|
||||||
|
qDebug() << "scrcpy window not found";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Убираем заголовок и рамку
|
||||||
|
[scrcpyWindow setStyleMask:NSWindowStyleMaskBorderless];
|
||||||
|
|
||||||
|
// Получаем координаты окна Qt
|
||||||
|
NSView *nativeView = (NSView *)container->winId();
|
||||||
|
NSWindow *qtWindow = [nativeView window];
|
||||||
|
NSRect frame = [qtWindow frame];
|
||||||
|
|
||||||
|
// Задаём новый размер и позицию для окна scrcpy
|
||||||
|
CGFloat width = frame.size.width;
|
||||||
|
CGFloat height = frame.size.height;
|
||||||
|
CGFloat x = frame.origin.x;
|
||||||
|
CGFloat y = frame.origin.y;
|
||||||
|
|
||||||
|
[scrcpyWindow setFrame:NSMakeRect(x, y, width, height) display:YES];
|
||||||
|
[scrcpyWindow orderFront:nil];
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user