Merge pull request #105 from barry-ran/dev

Dev
This commit is contained in:
Barry 2020-03-16 12:51:35 +08:00 committed by GitHub
commit 467f3ae6ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 1167 additions and 374 deletions

View file

@ -46,15 +46,18 @@ jobs:
- uses: actions/checkout@v1
with:
fetch-depth: 1
# 编译
- name: Build MacOS
run: |
export ENV_QT_CLANG=$(pwd)/${{env.Qt5_Dir}}
ci/mac/build_for_mac.sh release
# 发布
- name: Publish
if: startsWith(github.event.ref, 'refs/tags/')
run: |
export ENV_QT_CLANG=$(pwd)/${{env.Qt5_Dir}}
ci/mac/publish_for_mac.sh ../build
ci/mac/package_for_mac.sh
# tag 打包
- name: Package
if: startsWith(github.event.ref, 'refs/tags/')
@ -65,7 +68,7 @@ jobs:
[string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
[string]$name = 'QtScrcpy-mac-x64-' + ${tag}
# 打包zip
Compress-Archive -Path ci\build\QtScrcpy.app ci\build\${name}.zip
Compress-Archive -Path ci\build\QtScrcpy.dmg ci\build\${name}.zip
# 查询Release
- name: Query Release
if: startsWith(github.event.ref, 'refs/tags/')
@ -73,12 +76,20 @@ jobs:
env:
githubFullName: ${{ github.event.repository.full_name }}
ref: ${{ github.event.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}
run: |
[string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
[string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
$token = ${env:github_token}
$authInfo = ("{0}" -f $token)
$authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo)
$authInfo = [System.Convert]::ToBase64String($authInfo)
$headers = @{Authorization=("barry-ran {0}" -f $authInfo)}
$response={}
try {
$response = Invoke-RestMethod -Uri $url -Method Get
$response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
} catch {
Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
@ -102,12 +113,14 @@ jobs:
run: |
[string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
[string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
# github token防止api rate limite否则一个小时只能60个api请求
$token = ${env:github_token}
$authInfo = ("{0}" -f $token)
$authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo)
$authInfo = [System.Convert]::ToBase64String($authInfo)
$headers = @{Authorization=("barry-ran {0}" -f $authInfo)}
$response = Invoke-RestMethod -Uri $url -ContentType 'text/json' -Headers $headers -Method Get
[string]$latestUpUrl = $response.upload_url
Write-Host 'latestUpUrl:'$latestUpUrl

View file

@ -103,12 +103,20 @@ jobs:
env:
githubFullName: ${{ github.event.repository.full_name }}
ref: ${{ github.event.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}
run: |
[string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
[string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag}
$token = ${env:github_token}
$authInfo = ("{0}" -f $token)
$authInfo = [System.Text.Encoding]::UTF8.GetBytes($authInfo)
$authInfo = [System.Convert]::ToBase64String($authInfo)
$headers = @{Authorization=("barry-ran {0}" -f $authInfo)}
$response={}
try {
$response = Invoke-RestMethod -Uri $url -Method Get
$response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
} catch {
Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription

View file

@ -62,7 +62,7 @@ void Controller::updateScript(QString gameScript)
connect(m_inputConvert, &InputConvertBase::grabCursor, this, &Controller::grabCursor);
}
void Controller::postTurnOn()
void Controller::onPostBackOrScreenOn()
{
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_BACK_OR_SCREEN_ON);
if (!controlMsg) {
@ -71,42 +71,42 @@ void Controller::postTurnOn()
postControlMsg(controlMsg);
}
void Controller::postGoHome()
void Controller::onPostGoHome()
{
postKeyCodeClick(AKEYCODE_HOME);
}
void Controller::postGoMenu()
void Controller::onPostGoMenu()
{
postKeyCodeClick(AKEYCODE_MENU);
}
void Controller::postGoBack()
void Controller::onPostGoBack()
{
postKeyCodeClick(AKEYCODE_BACK);
}
void Controller::postAppSwitch()
void Controller::onPostAppSwitch()
{
postKeyCodeClick(AKEYCODE_APP_SWITCH);
}
void Controller::postPower()
void Controller::onPostPower()
{
postKeyCodeClick(AKEYCODE_POWER);
}
void Controller::postVolumeUp()
void Controller::onPostVolumeUp()
{
postKeyCodeClick(AKEYCODE_VOLUME_UP);
}
void Controller::postVolumeDown()
void Controller::onPostVolumeDown()
{
postKeyCodeClick(AKEYCODE_VOLUME_DOWN);
}
void Controller::expandNotificationPanel()
void Controller::onExpandNotificationPanel()
{
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_EXPAND_NOTIFICATION_PANEL);
if (!controlMsg) {
@ -115,7 +115,7 @@ void Controller::expandNotificationPanel()
postControlMsg(controlMsg);
}
void Controller::collapseNotificationPanel()
void Controller::onCollapseNotificationPanel()
{
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_COLLAPSE_NOTIFICATION_PANEL);
if (!controlMsg) {
@ -124,7 +124,7 @@ void Controller::collapseNotificationPanel()
postControlMsg(controlMsg);
}
void Controller::requestDeviceClipboard()
void Controller::onRequestDeviceClipboard()
{
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_GET_CLIPBOARD);
if (!controlMsg) {
@ -133,7 +133,7 @@ void Controller::requestDeviceClipboard()
postControlMsg(controlMsg);
}
void Controller::setDeviceClipboard()
void Controller::onSetDeviceClipboard()
{
QClipboard *board = QApplication::clipboard();
QString text = board->text();
@ -145,14 +145,14 @@ void Controller::setDeviceClipboard()
postControlMsg(controlMsg);
}
void Controller::clipboardPaste()
void Controller::onClipboardPaste()
{
QClipboard *board = QApplication::clipboard();
QString text = board->text();
postTextInput(text);
onPostTextInput(text);
}
void Controller::postTextInput(QString& text)
void Controller::onPostTextInput(QString& text)
{
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_INJECT_TEXT);
if (!controlMsg) {
@ -162,7 +162,7 @@ void Controller::postTextInput(QString& text)
postControlMsg(controlMsg);
}
void Controller::setScreenPowerMode(ControlMsg::ScreenPowerMode mode)
void Controller::onSetScreenPowerMode(ControlMsg::ScreenPowerMode mode)
{
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_SET_SCREEN_POWER_MODE);
if (!controlMsg) {
@ -172,21 +172,21 @@ void Controller::setScreenPowerMode(ControlMsg::ScreenPowerMode mode)
postControlMsg(controlMsg);
}
void Controller::mouseEvent(const QMouseEvent *from, const QSize &frameSize, const QSize &showSize)
void Controller::onMouseEvent(const QMouseEvent *from, const QSize &frameSize, const QSize &showSize)
{
if (m_inputConvert) {
m_inputConvert->mouseEvent(from, frameSize, showSize);
}
}
void Controller::wheelEvent(const QWheelEvent *from, const QSize &frameSize, const QSize &showSize)
void Controller::onWheelEvent(const QWheelEvent *from, const QSize &frameSize, const QSize &showSize)
{
if (m_inputConvert) {
m_inputConvert->wheelEvent(from, frameSize, showSize);
}
}
void Controller::keyEvent(const QKeyEvent *from, const QSize &frameSize, const QSize &showSize)
void Controller::onKeyEvent(const QKeyEvent *from, const QSize &frameSize, const QSize &showSize)
{
if (m_inputConvert) {
m_inputConvert->keyEvent(from, frameSize, showSize);

View file

@ -22,27 +22,29 @@ public:
void updateScript(QString gameScript = "");
// turn the screen on if it was off, press BACK otherwise
void postTurnOn();
void postGoHome();
void postGoMenu();
void postGoBack();
void postAppSwitch();
void postPower();
void postVolumeUp();
void postVolumeDown();
void expandNotificationPanel();
void collapseNotificationPanel();
void requestDeviceClipboard();
void setDeviceClipboard();
void clipboardPaste();
void postTextInput(QString& text);
void setScreenPowerMode(ControlMsg::ScreenPowerMode mode);
public slots:
void onPostGoBack();
void onPostGoHome();
void onPostGoMenu();
void onPostAppSwitch();
void onPostPower();
void onPostVolumeUp();
void onPostVolumeDown();
void onExpandNotificationPanel();
void onCollapseNotificationPanel();
void onSetScreenPowerMode(ControlMsg::ScreenPowerMode mode);
// for input convert
void mouseEvent(const QMouseEvent* from, const QSize& frameSize, const QSize& showSize);
void wheelEvent(const QWheelEvent* from, const QSize& frameSize, const QSize& showSize);
void keyEvent(const QKeyEvent* from, const QSize& frameSize, const QSize& showSize);
void onMouseEvent(const QMouseEvent* from, const QSize& frameSize, const QSize& showSize);
void onWheelEvent(const QWheelEvent* from, const QSize& frameSize, const QSize& showSize);
void onKeyEvent(const QKeyEvent* from, const QSize& frameSize, const QSize& showSize);
// turn the screen on if it was off, press BACK otherwise
void onPostBackOrScreenOn();
void onRequestDeviceClipboard();
void onSetDeviceClipboard();
void onClipboardPaste();
void onPostTextInput(QString& text);
signals:
void grabCursor(bool grab);

View file

@ -1,3 +1,5 @@
#include <cmath>
#include "inputconvertnormal.h"
InputConvertNormal::InputConvertNormal(Controller* controller)
@ -63,10 +65,10 @@ void InputConvertNormal::wheelEvent(const QWheelEvent *from, const QSize& frameS
qint32 vScroll = 0;
switch (from->orientation()) {
case Qt::Horizontal:
hScroll = from->delta();
hScroll = from->delta() / abs(from->delta()) * 2;
break;
case Qt::Vertical:
vScroll = from->delta();
vScroll = from->delta() / abs(from->delta()) * 2;
break;
}

View file

@ -13,6 +13,7 @@
#include "controller.h"
#include "config.h"
#include "avframeconvert.h"
#include "mousetap/mousetap.h"
extern "C"
{
#include "libavutil/imgutils.h"
@ -34,15 +35,8 @@ Device::Device(DeviceParams params, QObject *parent)
m_decoder = new Decoder(m_vb, this);
m_fileHandler = new FileHandler(this);
m_controller = new Controller(params.gameScript, this);
m_videoForm = new VideoForm(Config::getInstance().getSkin());
m_videoForm->setSerial(m_params.serial);
if (m_controller) {
m_videoForm->setController(m_controller);
}
if (m_fileHandler) {
m_videoForm->setFileHandler(m_fileHandler);
}
m_videoForm->show();
m_videoForm = new VideoForm(Config::getInstance().getFramelessWindow(), Config::getInstance().getSkin());
m_videoForm->setDevice(this);
}
m_stream = new Stream(this);
@ -76,6 +70,7 @@ Device::~Device()
delete m_vb;
}
if (m_videoForm) {
m_videoForm->close();
delete m_videoForm;
}
emit deviceDisconnect(m_params.serial);
@ -86,16 +81,25 @@ VideoForm *Device::getVideoForm()
return m_videoForm;
}
Controller *Device::getController()
{
return m_controller;
}
Server *Device::getServer()
{
return m_server;
}
const QString &Device::getSerial()
{
return m_params.serial;
}
const QSize Device::frameSize()
{
QSize size;
if (!m_videoForm) {
return size;
}
return m_videoForm->frameSize();
}
void Device::updateScript(QString script)
{
if(m_controller){
@ -115,35 +119,86 @@ void Device::onScreenshot()
m_vb->unLock();
}
void Device::onShowTouch(bool show)
{
AdbProcess* adb = new AdbProcess();
if (!adb) {
return;
}
connect(adb, &AdbProcess::adbProcessResult, this, [this](AdbProcess::ADB_EXEC_RESULT processResult){
if (AdbProcess::AER_SUCCESS_START != processResult) {
sender()->deleteLater();
}
});
adb->setShowTouchesEnabled(getSerial(), show);
qInfo() << getSerial() << " show touch " << (show ? "enable" : "disable");
}
void Device::initSignals()
{
if (m_controller && m_videoForm) {
connect(m_controller, &Controller::grabCursor, m_videoForm, &VideoForm::onGrabCursor);
connect(m_videoForm, &VideoForm::screenshot, this, &Device::onScreenshot);
connect(this, &Device::screenshot, this, &Device::onScreenshot);
connect(this, &Device::showTouch, this, &Device::onShowTouch);
connect(this, &Device::setControlState, this, &Device::onSetControlState);
connect(this, &Device::grabCursor, this, &Device::onGrabCursor);
if (m_controller) {
connect(m_controller, &Controller::grabCursor, this, &Device::grabCursor);
}
if (m_controller) {
connect(this, &Device::postGoBack, m_controller, &Controller::onPostGoBack);
connect(this, &Device::postGoHome, m_controller, &Controller::onPostGoHome);
connect(this, &Device::postGoMenu, m_controller, &Controller::onPostGoMenu);
connect(this, &Device::postAppSwitch, m_controller, &Controller::onPostAppSwitch);
connect(this, &Device::postPower, m_controller, &Controller::onPostPower);
connect(this, &Device::postVolumeUp, m_controller, &Controller::onPostVolumeUp);
connect(this, &Device::postVolumeDown, m_controller, &Controller::onPostVolumeDown);
connect(this, &Device::setScreenPowerMode, m_controller, &Controller::onSetScreenPowerMode);
connect(this, &Device::expandNotificationPanel, m_controller, &Controller::onExpandNotificationPanel);
connect(this, &Device::collapseNotificationPanel, m_controller, &Controller::onCollapseNotificationPanel);
connect(this, &Device::mouseEvent, m_controller, &Controller::onMouseEvent);
connect(this, &Device::wheelEvent, m_controller, &Controller::onWheelEvent);
connect(this, &Device::keyEvent, m_controller, &Controller::onKeyEvent);
connect(this, &Device::postBackOrScreenOn, m_controller, &Controller::onPostBackOrScreenOn);
connect(this, &Device::requestDeviceClipboard, m_controller, &Controller::onRequestDeviceClipboard);
connect(this, &Device::setDeviceClipboard, m_controller, &Controller::onSetDeviceClipboard);
connect(this, &Device::clipboardPaste, m_controller, &Controller::onClipboardPaste);
connect(this, &Device::postTextInput, m_controller, &Controller::onPostTextInput);
}
if (m_videoForm) {
connect(m_videoForm, &VideoForm::destroyed, this, [this](QObject *obj){
Q_UNUSED(obj)
deleteLater();
});
connect(this, &Device::switchFullScreen, m_videoForm, &VideoForm::onSwitchFullScreen);
}
if (m_fileHandler) {
connect(this, &Device::pushFileRequest, m_fileHandler, &FileHandler::onPushFileRequest);
connect(this, &Device::installApkRequest, m_fileHandler, &FileHandler::onInstallApkRequest);
connect(m_fileHandler, &FileHandler::fileHandlerResult, this, [this](FileHandler::FILE_HANDLER_RESULT processResult, bool isApk){
QString tips = "";
QString tipsType = "";
if (isApk) {
tips = tr("install apk");
tipsType = tr("install apk");
} else {
tips = tr("file transfer");
tipsType = tr("file transfer");
}
QString tips;
if (FileHandler::FAR_IS_RUNNING == processResult && m_videoForm) {
QMessageBox::warning(m_videoForm, "QtScrcpy", tr("wait current %1 to complete").arg(tips), QMessageBox::Ok);
tips = tr("wait current %1 to complete").arg(tipsType);
}
if (FileHandler::FAR_SUCCESS_EXEC == processResult && m_videoForm) {
QMessageBox::information(m_videoForm, "QtScrcpy", tr("%1 complete, save in %2").arg(tips).arg(Config::getInstance().getPushFilePath()), QMessageBox::Ok);
tips = tr("%1 complete, save in %2").arg(tipsType).arg(Config::getInstance().getPushFilePath());
}
if (FileHandler::FAR_ERROR_EXEC == processResult && m_videoForm) {
QMessageBox::information(m_videoForm, "QtScrcpy", tr("%1 failed").arg(tips), QMessageBox::Ok);
tips = tr("%1 failed").arg(tipsType);
}
qInfo() << tips;
if (m_controlState == GCS_CLIENT) {
return;
}
QMessageBox::information(m_videoForm, "QtScrcpy", tips, QMessageBox::Ok);
});
}
@ -164,6 +219,16 @@ void Device::initSignals()
if (m_videoForm) {
m_videoForm->setWindowTitle(deviceName);
m_videoForm->updateShowSize(size);
QRect rc = Config::getInstance().getRect(getSerial());
if (rc.isValid()) {
m_videoForm->move(rc.topLeft());
m_videoForm->resize(rc.size());
// TODO: setGeometry magneticwidget bug
//m_videoForm->setGeometry(rc);
}
// videoForm delay show
m_videoForm->show();
}
// init recorder
@ -182,7 +247,7 @@ void Device::initSignals()
// 显示界面时才自动息屏m_params.display
if (m_params.closeScreen && m_params.display && m_controller) {
m_controller->setScreenPowerMode(ControlMsg::SPM_OFF);
emit m_controller->onSetScreenPowerMode(ControlMsg::SPM_OFF);
}
}
});
@ -235,6 +300,34 @@ void Device::startServer()
});
}
void Device::onSetControlState(Device* device, Device::GroupControlState state)
{
Q_UNUSED(device)
if (m_controlState == state) {
return;
}
GroupControlState oldState = m_controlState;
m_controlState = state;
emit controlStateChange(this, oldState, m_controlState);
}
void Device::onGrabCursor(bool grab)
{
if (!m_videoForm) {
return;
}
if (m_controlState == GCS_CLIENT) {
return;
}
QRect rc = m_videoForm->getGrabCursorRect();
MouseTap::getInstance()->enableMouseEventTap(rc, grab);
}
Device::GroupControlState Device::controlState()
{
return m_controlState;
}
bool Device::saveFrame(const AVFrame* frame)
{
if (!frame) {
@ -276,10 +369,10 @@ bool Device::saveFrame(const AVFrame* frame)
}
QDateTime dateTime = QDateTime::currentDateTime();
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss_zzz");
fileName = Config::getInstance().getTitle() + fileName + ".jpg";
fileName = Config::getInstance().getTitle() + fileName + ".png";
QDir dir(fileDir);
absFilePath = dir.absoluteFilePath(fileName);
ret = rgbImage.save(absFilePath);
ret = rgbImage.save(absFilePath, "PNG", 100);
if (!ret) {
return false;
}

View file

@ -4,6 +4,11 @@
#include <QPointer>
#include <QTime>
#include "controlmsg.h"
class QMouseEvent;
class QWheelEvent;
class QKeyEvent;
class Recorder;
class Server;
class VideoBuffer;
@ -30,20 +35,64 @@ public:
QString gameScript = ""; // 游戏映射脚本
bool renderExpiredFrames = false; // 是否渲染延迟视频帧
};
enum GroupControlState {
GCS_FREE = 0,
GCS_HOST,
GCS_CLIENT,
};
explicit Device(DeviceParams params, QObject *parent = nullptr);
virtual ~Device();
VideoForm *getVideoForm();
Controller *getController();
Server *getServer();
const QString &getSerial();
const QSize frameSize();
void updateScript(QString script);
Device::GroupControlState controlState();
signals:
void deviceDisconnect(QString serial);
// tool bar
void switchFullScreen();
void postGoBack();
void postGoHome();
void postGoMenu();
void postAppSwitch();
void postPower();
void postVolumeUp();
void postVolumeDown();
void setScreenPowerMode(ControlMsg::ScreenPowerMode mode);
void expandNotificationPanel();
void collapseNotificationPanel();
void postBackOrScreenOn();
void postTextInput(QString& text);
void requestDeviceClipboard();
void setDeviceClipboard();
void clipboardPaste();
void pushFileRequest(const QString& serial, const QString& file, const QString& devicePath = "");
void installApkRequest(const QString& serial, const QString& apkFile);
// key map
void mouseEvent(const QMouseEvent* from, const QSize& frameSize, const QSize& showSize);
void wheelEvent(const QWheelEvent* from, const QSize& frameSize, const QSize& showSize);
void keyEvent(const QKeyEvent* from, const QSize& frameSize, const QSize& showSize);
// self connect signal and slots
void screenshot();
void showTouch(bool show);
void setControlState(Device* device, Device::GroupControlState state);
void grabCursor(bool grab);
// for notify
void controlStateChange(Device* device, Device::GroupControlState oldState, Device::GroupControlState newState);
public slots:
void onScreenshot();
void onShowTouch(bool show);
void onSetControlState(Device* device, Device::GroupControlState state);
void onGrabCursor(bool grab);
private:
void initSignals();
@ -65,6 +114,8 @@ private:
QTime m_startTimeCount;
DeviceParams m_params;
GroupControlState m_controlState = GCS_FREE;
};
#endif // DEVICE_H

View file

@ -24,7 +24,7 @@ FileHandler::~FileHandler()
}
void FileHandler::pushFileRequest(const QString &serial, const QString &file, const QString& devicePath)
void FileHandler::onPushFileRequest(const QString &serial, const QString &file, const QString& devicePath)
{
if (m_adb.isRuning()) {
emit fileHandlerResult(FAR_IS_RUNNING, false);
@ -35,7 +35,7 @@ void FileHandler::pushFileRequest(const QString &serial, const QString &file, co
m_adb.push(serial, file, devicePath);
}
void FileHandler::installApkRequest(const QString &serial, const QString &apkFile)
void FileHandler::onInstallApkRequest(const QString &serial, const QString &apkFile)
{
if (m_adb.isRuning()) {
emit fileHandlerResult(FAR_IS_RUNNING, true);

View file

@ -17,10 +17,12 @@ public:
FileHandler(QObject *parent = nullptr);
virtual ~FileHandler();
void pushFileRequest(const QString& serial, const QString& file, const QString& devicePath = "");
void installApkRequest(const QString& serial, const QString& apkFile);
const QString &getDevicePath();
public slots:
void onPushFileRequest(const QString& serial, const QString& file, const QString& devicePath = "");
void onInstallApkRequest(const QString& serial, const QString& apkFile);
signals:
void fileHandlerResult(FILE_HANDLER_RESULT processResult, bool isApk = false);

View file

@ -6,9 +6,7 @@
#include "toolform.h"
#include "ui_toolform.h"
#include "iconhelper.h"
#include "videoform.h"
#include "controller.h"
#include "adbprocess.h"
#include "device.h"
ToolForm::ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos)
: MagneticWidget(adsorbWidget, adsorbPos)
@ -18,8 +16,6 @@ ToolForm::ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos)
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
//setWindowFlags(windowFlags() & ~Qt::WindowMinMaxButtonsHint);
m_videoForm = dynamic_cast<VideoForm*>(adsorbWidget);
initStyle();
}
@ -28,6 +24,15 @@ ToolForm::~ToolForm()
delete ui;
}
void ToolForm::setDevice(Device *device)
{
if (!device) {
return;
}
m_device = device;
connect(m_device, &Device::controlStateChange, this, &ToolForm::onControlStateChange);
}
void ToolForm::initStyle()
{
IconHelper::Instance()->SetIcon(ui->fullScreenBtn, QChar(0xf0b2), 15);
@ -43,6 +48,25 @@ void ToolForm::initStyle()
IconHelper::Instance()->SetIcon(ui->expandNotifyBtn, QChar(0xf103), 15);
IconHelper::Instance()->SetIcon(ui->screenShotBtn, QChar(0xf0c4), 15);
IconHelper::Instance()->SetIcon(ui->touchBtn, QChar(0xf111), 15);
IconHelper::Instance()->SetIcon(ui->groupControlBtn, QChar(0xf0c0), 15);
}
void ToolForm::updateGroupControl()
{
if (!m_device) {
return;
}
switch (m_device->controlState()) {
case Device::GroupControlState::GCS_FREE:
ui->groupControlBtn->setStyleSheet("color: #DCDCDC");
break;
case Device::GroupControlState::GCS_HOST:
ui->groupControlBtn->setStyleSheet("color: red");
break;
case Device::GroupControlState::GCS_CLIENT:
ui->groupControlBtn->setStyleSheet("color: green");
break;
}
}
void ToolForm::mousePressEvent(QMouseEvent *event)
@ -80,97 +104,121 @@ void ToolForm::hideEvent(QHideEvent *event)
void ToolForm::on_fullScreenBtn_clicked()
{
if (m_videoForm) {
m_videoForm->switchFullScreen();
if (!m_device) {
return;
}
emit m_device->switchFullScreen();
}
void ToolForm::on_returnBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->postGoBack();
if (!m_device) {
return;
}
emit m_device->postGoBack();
}
void ToolForm::on_homeBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->postGoHome();
if (!m_device) {
return;
}
emit m_device->postGoHome();
}
void ToolForm::on_menuBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->postGoMenu();
if (!m_device) {
return;
}
emit m_device->postGoMenu();
}
void ToolForm::on_appSwitchBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->postAppSwitch();
if (!m_device) {
return;
}
emit m_device->postAppSwitch();
}
void ToolForm::on_powerBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->postPower();
if (!m_device) {
return;
}
emit m_device->postPower();
}
void ToolForm::on_screenShotBtn_clicked()
{
emit screenshot();
if (!m_device) {
return;
}
emit m_device->screenshot();
}
void ToolForm::on_volumeUpBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->postVolumeUp();
if (!m_device) {
return;
}
emit m_device->postVolumeUp();
}
void ToolForm::on_volumeDownBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->postVolumeDown();
if (!m_device) {
return;
}
emit m_device->postVolumeDown();
}
void ToolForm::on_closeScreenBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->setScreenPowerMode(ControlMsg::SPM_OFF);
if (!m_device) {
return;
}
emit m_device->setScreenPowerMode(ControlMsg::SPM_OFF);
}
void ToolForm::on_expandNotifyBtn_clicked()
{
if (m_videoForm && m_videoForm->getController()) {
m_videoForm->getController()->expandNotificationPanel();
if (!m_device) {
return;
}
emit m_device->expandNotificationPanel();
}
void ToolForm::on_touchBtn_clicked()
{
if (!m_videoForm) {
if (!m_device) {
return;
}
m_showTouch = !m_showTouch;
emit m_device->showTouch(m_showTouch);
}
AdbProcess* adb = new AdbProcess();
if (!adb) {
void ToolForm::on_groupControlBtn_clicked()
{
if (!m_device) {
return;
}
connect(adb, &AdbProcess::adbProcessResult, this, [this](AdbProcess::ADB_EXEC_RESULT processResult){
if (AdbProcess::AER_SUCCESS_START != processResult) {
sender()->deleteLater();
}
});
adb->setShowTouchesEnabled(m_videoForm->getSerial(), m_showTouch);
qInfo() << "show touch " << (m_showTouch ? "enable" : "disable");
Device::GroupControlState state = m_device->controlState();
if (state == Device::GroupControlState::GCS_FREE) {
emit m_device->setControlState(m_device, Device::GroupControlState::GCS_HOST);
}
if (state == Device::GroupControlState::GCS_HOST) {
emit m_device->setControlState(m_device, Device::GroupControlState::GCS_FREE);
}
}
void ToolForm::onControlStateChange(Device *device, Device::GroupControlState oldState, Device::GroupControlState newState)
{
Q_UNUSED(device)
Q_UNUSED(oldState)
Q_UNUSED(newState)
updateGroupControl();
}

View file

@ -5,12 +5,13 @@
#include <QPointer>
#include "magneticwidget.h"
#include "device.h"
namespace Ui {
class ToolForm;
}
class VideoForm;
class Device;
class ToolForm : public MagneticWidget
{
Q_OBJECT
@ -19,6 +20,8 @@ public:
explicit ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos);
~ToolForm();
void setDevice(Device *device);
protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
@ -27,41 +30,31 @@ protected:
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
signals:
void screenshot();
private slots:
void on_fullScreenBtn_clicked();
void on_returnBtn_clicked();
void on_homeBtn_clicked();
void on_menuBtn_clicked();
void on_appSwitchBtn_clicked();
void on_powerBtn_clicked();
void on_screenShotBtn_clicked();
void on_volumeUpBtn_clicked();
void on_volumeDownBtn_clicked();
void on_closeScreenBtn_clicked();
void on_expandNotifyBtn_clicked();
void on_touchBtn_clicked();
void on_groupControlBtn_clicked();
void onControlStateChange(Device* device, Device::GroupControlState oldState, Device::GroupControlState newState);
private:
void initStyle();
void updateGroupControl();
private:
Ui::ToolForm *ui;
QPoint m_dragPosition;
QPointer<VideoForm> m_videoForm;
QPointer<Device> m_device;
bool m_showTouch = false;
};

View file

@ -20,6 +20,13 @@
<property name="topMargin">
<number>30</number>
</property>
<item>
<widget class="QPushButton" name="groupControlBtn">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fullScreenBtn">
<property name="toolTip">

View file

@ -8,33 +8,39 @@
#include <QMimeData>
#include <QFileInfo>
#include <QMessageBox>
#include <QShortcut>
#include <QWindow>
#include <QScreen>
#include "videoform.h"
#include "qyuvopenglwidget.h"
#include "mousetap/mousetap.h"
#include "ui_videoform.h"
#include "iconhelper.h"
#include "toolform.h"
#include "device.h"
#include "controller.h"
#include "filehandler.h"
#include "config.h"
extern "C"
{
#include "libavutil/frame.h"
}
VideoForm::VideoForm(bool skin, QWidget *parent)
VideoForm::VideoForm(bool framelessWindow, bool skin, QWidget *parent)
: QWidget(parent)
, ui(new Ui::videoForm)
, m_skin(skin)
{
ui->setupUi(this);
initUI();
installShortcut();
updateShowSize(size());
bool vertical = size().height() > size().width();
if (m_skin) {
updateStyleSheet(vertical);
}
if (framelessWindow) {
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
}
}
VideoForm::~VideoForm()
@ -70,13 +76,47 @@ void VideoForm::initUI()
ui->keepRadioWidget->setMouseTracking(true);
}
void VideoForm::onGrabCursor(bool grab)
QRect VideoForm::getGrabCursorRect()
{
#if defined(Q_OS_WIN32) || defined(Q_OS_OSX)
MouseTap::getInstance()->enableMouseEventTap(m_videoWidget, grab);
QRect rc;
#if defined(Q_OS_WIN32)
rc = QRect(m_videoWidget->mapToGlobal(m_videoWidget->pos())
, m_videoWidget->size());
// high dpi support
rc.setTopLeft(rc.topLeft() * m_videoWidget->devicePixelRatio());
rc.setBottomRight(rc.bottomRight() * m_videoWidget->devicePixelRatio());
#elif defined(Q_OS_OSX)
rc = m_videoWidget->geometry();
rc.setTopLeft(m_videoWidget->mapToGlobal(rc.topLeft()));
rc.setBottomRight(m_videoWidget->mapToGlobal(rc.bottomRight()));
rc.setX(rc.x() + 100);
rc.setY(rc.y() + 30);
rc.setWidth(rc.width() - 180);
rc.setHeight(rc.height() - 60);
#else
Q_UNUSED(grab)
#endif
return rc;
}
const QSize &VideoForm::frameSize()
{
return m_frameSize;
}
void VideoForm::resizeSquare()
{
QRect screenRect = getScreenRect();
if (screenRect.isEmpty()) {
qWarning() << "getScreenRect is empty";
return;
}
resize(screenRect.height(), screenRect.height());
}
void VideoForm::removeBlackRect()
{
resize(ui->keepRadioWidget->goodSize());
}
void VideoForm::updateRender(const AVFrame *frame)
@ -98,7 +138,7 @@ void VideoForm::showToolForm(bool show)
{
if (!m_toolForm) {
m_toolForm = new ToolForm(this, ToolForm::AP_OUTSIDE_RIGHT);
connect(m_toolForm, &ToolForm::screenshot, this, &VideoForm::screenshot);
m_toolForm->setDevice(m_device);
}
m_toolForm->move(pos().x() + geometry().width(), pos().y() + 30);
m_toolForm->setVisible(show);
@ -106,16 +146,178 @@ void VideoForm::showToolForm(bool show)
void VideoForm::moveCenter()
{
QDesktopWidget* desktop = QApplication::desktop();
if (!desktop) {
qWarning() << "QApplication::desktop() is nullptr";
QRect screenRect = getScreenRect();
if (screenRect.isEmpty()) {
qWarning() << "getScreenRect is empty";
return;
}
QRect screenRect = desktop->availableGeometry();
// 窗口居中
move(screenRect.center() - QRect(0, 0, size().width(), size().height()).center());
}
void VideoForm::installShortcut()
{
QShortcut *shortcut = nullptr;
// switchFullScreen
shortcut = new QShortcut(QKeySequence("Ctrl+f"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->switchFullScreen();
});
// resizeSquare
shortcut = new QShortcut(QKeySequence("Ctrl+g"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
resizeSquare();
});
// removeBlackRect
shortcut = new QShortcut(QKeySequence("Ctrl+x"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
removeBlackRect();
});
// postGoHome
shortcut = new QShortcut(QKeySequence("Ctrl+h"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->postGoHome();
});
// postGoBack
shortcut = new QShortcut(QKeySequence("Ctrl+b"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->postGoBack();
});
// postAppSwitch
shortcut = new QShortcut(QKeySequence("Ctrl+s"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->postAppSwitch();
});
// postGoMenu
shortcut = new QShortcut(QKeySequence("Ctrl+m"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->postGoMenu();
});
// postVolumeUp
shortcut = new QShortcut(QKeySequence("Ctrl+up"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->postVolumeUp();
});
// postVolumeDown
shortcut = new QShortcut(QKeySequence("Ctrl+down"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->postVolumeDown();
});
// postPower
shortcut = new QShortcut(QKeySequence("Ctrl+p"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->postPower();
});
// setScreenPowerMode(ControlMsg::SPM_OFF)
shortcut = new QShortcut(QKeySequence("Ctrl+o"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->setScreenPowerMode(ControlMsg::SPM_OFF);
});
// expandNotificationPanel
shortcut = new QShortcut(QKeySequence("Ctrl+n"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->expandNotificationPanel();
});
// collapseNotificationPanel
shortcut = new QShortcut(QKeySequence("Ctrl+Shift+n"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->collapseNotificationPanel();
});
// requestDeviceClipboard
shortcut = new QShortcut(QKeySequence("Ctrl+c"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->requestDeviceClipboard();
});
// clipboardPaste
shortcut = new QShortcut(QKeySequence("Ctrl+v"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->clipboardPaste();
});
// setDeviceClipboard
shortcut = new QShortcut(QKeySequence("Ctrl+Shift+v"), this);
connect(shortcut, &QShortcut::activated, this, [this](){
if (!m_device) {
return;
}
emit m_device->setDeviceClipboard();
});
}
QRect VideoForm::getScreenRect()
{
QRect screenRect;
QWidget *win = window();
if (!win) {
return screenRect;
}
QWindow *winHandle = win->windowHandle();
if (!winHandle) {
return screenRect;
}
QScreen *screen = winHandle->screen();
if (!screen) {
return screenRect;
}
screenRect = screen->availableGeometry();
return screenRect;
}
void VideoForm::updateStyleSheet(bool vertical)
{
if (vertical) {
@ -157,12 +359,11 @@ void VideoForm::updateShowSize(const QSize &newSize)
bool vertical = m_widthHeightRatio < 1.0f ? true : false;
QSize showSize = newSize;
QDesktopWidget* desktop = QApplication::desktop();
if (!desktop) {
qWarning() << "QApplication::desktop() is nullptr";
QRect screenRect = getScreenRect();
if (screenRect.isEmpty()) {
qWarning() << "getScreenRect is empty";
return;
}
QRect screenRect = desktop->availableGeometry();
if (vertical) {
showSize.setHeight(qMin(newSize.height(), screenRect.height() - 200));
showSize.setWidth(showSize.height() * m_widthHeightRatio);
@ -171,8 +372,8 @@ void VideoForm::updateShowSize(const QSize &newSize)
showSize.setHeight(showSize.width() / m_widthHeightRatio);
}
if (isFullScreen()) {
switchFullScreen();
if (isFullScreen() && m_device) {
emit m_device->switchFullScreen();
}
if (m_skin) {
QMargins m = getMargins(vertical);
@ -190,7 +391,7 @@ void VideoForm::updateShowSize(const QSize &newSize)
}
}
void VideoForm::switchFullScreen()
void VideoForm::onSwitchFullScreen()
{
if (isFullScreen()) {
// 横屏全屏铺满全屏,恢复时,恢复保持宽高比
@ -253,39 +454,25 @@ void VideoForm::staysOnTop(bool top)
}
}
Controller *VideoForm::getController()
void VideoForm::setDevice(Device *device)
{
return m_controller;
}
void VideoForm::setFileHandler(FileHandler *fileHandler)
{
m_fileHandler = fileHandler;
}
void VideoForm::setSerial(const QString &serial)
{
m_serial = serial;
}
const QString &VideoForm::getSerial()
{
return m_serial;
}
void VideoForm::setController(Controller *controller)
{
m_controller = controller;
m_device = device;
}
void VideoForm::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::MiddleButton) {
if (m_device) {
emit m_device->postGoHome();
}
}
if (m_videoWidget->geometry().contains(event->pos())) {
if (!m_controller) {
if (!m_device) {
return;
}
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
m_controller->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
emit m_device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
} else {
if (event->button() == Qt::LeftButton) {
m_dragPosition = event->globalPos() - frameGeometry().topLeft();
@ -297,7 +484,7 @@ void VideoForm::mousePressEvent(QMouseEvent *event)
void VideoForm::mouseReleaseEvent(QMouseEvent *event)
{
if (m_dragPosition.isNull()) {
if (!m_controller) {
if (!m_device) {
return;
}
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
@ -316,7 +503,7 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
local.setY(m_videoWidget->height());
}
event->setLocalPos(local);
m_controller->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
emit m_device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
} else {
m_dragPosition = QPoint(0, 0);
}
@ -325,11 +512,11 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
void VideoForm::mouseMoveEvent(QMouseEvent *event)
{
if (m_videoWidget->geometry().contains(event->pos())) {
if (!m_controller) {
if (!m_device) {
return;
}
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
m_controller->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
emit m_device->mouseEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
} else if (!m_dragPosition.isNull()){
if (event->buttons() & Qt::LeftButton) {
move(event->globalPos() - m_dragPosition);
@ -338,10 +525,22 @@ void VideoForm::mouseMoveEvent(QMouseEvent *event)
}
}
void VideoForm::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton
&& !m_videoWidget->geometry().contains(event->pos())) {
removeBlackRect();
}
if (event->button() == Qt::RightButton && m_device) {
emit m_device->postBackOrScreenOn();
}
}
void VideoForm::wheelEvent(QWheelEvent *event)
{
if (m_videoWidget->geometry().contains(event->pos())) {
if (!m_controller) {
if (!m_device) {
return;
}
QPointF pos = m_videoWidget->mapFrom(this, event->pos());
@ -352,41 +551,30 @@ void VideoForm::wheelEvent(QWheelEvent *event)
*/
QWheelEvent wheelEvent(pos, event->globalPosF(), event->delta(),
event->buttons(), event->modifiers(), event->orientation());
m_controller->wheelEvent(&wheelEvent, m_videoWidget->frameSize(), m_videoWidget->size());
emit m_device->wheelEvent(&wheelEvent, m_videoWidget->frameSize(), m_videoWidget->size());
}
}
void VideoForm::keyPressEvent(QKeyEvent *event)
{
if (!m_device) {
return;
}
if (Qt::Key_Escape == event->key()
&& !event->isAutoRepeat()
&& isFullScreen()) {
switchFullScreen();
}
if (!m_controller) {
return;
}
if (event->key() == Qt::Key_C && (event->modifiers() & Qt::ControlModifier)) {
m_controller->requestDeviceClipboard();
}
if (event->key() == Qt::Key_V && (event->modifiers() & Qt::ControlModifier)) {
if (event->modifiers() & Qt::ShiftModifier) {
m_controller->setDeviceClipboard();
} else {
m_controller->clipboardPaste();
}
return;
emit m_device->switchFullScreen();
}
m_controller->keyEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
emit m_device->keyEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
}
void VideoForm::keyReleaseEvent(QKeyEvent *event)
{
if (!m_controller) {
if (!m_device) {
return;
}
m_controller->keyEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
emit m_device->keyEvent(event, m_videoWidget->frameSize(), m_videoWidget->size());
}
void VideoForm::paintEvent(QPaintEvent *paint)
@ -432,6 +620,15 @@ void VideoForm::resizeEvent(QResizeEvent *event)
}
}
void VideoForm::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event)
if (!m_device) {
return;
}
Config::getInstance().setRect(m_device->getSerial(), geometry());
}
void VideoForm::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
@ -449,7 +646,7 @@ void VideoForm::dragLeaveEvent(QDragLeaveEvent *event)
void VideoForm::dropEvent(QDropEvent *event)
{
if (!m_fileHandler) {
if (!m_device) {
return;
}
const QMimeData* qm = event->mimeData();
@ -462,8 +659,8 @@ void VideoForm::dropEvent(QDropEvent *event)
}
if (fileInfo.isFile() && fileInfo.suffix() == "apk") {
m_fileHandler->installApkRequest(m_serial, file);
emit m_device->installApkRequest(m_device->getSerial(), file);
return;
}
m_fileHandler->pushFileRequest(m_serial, file, Config::getInstance().getPushFilePath() + fileInfo.fileName());
emit m_device->pushFileRequest(m_device->getSerial(), file, Config::getInstance().getPushFilePath() + fileInfo.fileName());
}

View file

@ -10,31 +10,27 @@ class videoForm;
struct AVFrame;
class ToolForm;
class Controller;
class Device;
class FileHandler;
class QYUVOpenGLWidget;
class VideoForm : public QWidget
{
Q_OBJECT
public:
explicit VideoForm(bool skin = true, QWidget *parent = 0);
explicit VideoForm(bool framelessWindow = false, bool skin = true, QWidget *parent = 0);
~VideoForm();
void switchFullScreen();
void staysOnTop(bool top = true);
void updateShowSize(const QSize &newSize);
void updateRender(const AVFrame *frame);
void setController(Controller *controller);
Controller* getController();
void setFileHandler(FileHandler *fileHandler);
void setSerial(const QString &serial);
const QString& getSerial();
signals:
void screenshot();
void setDevice(Device *device);
QRect getGrabCursorRect();
const QSize &frameSize();
void resizeSquare();
void removeBlackRect();
public slots:
void onGrabCursor(bool grab);
void onSwitchFullScreen();
private:
void updateStyleSheet(bool vertical);
@ -43,11 +39,14 @@ private:
void showToolForm(bool show = true);
void moveCenter();
void installShortcut();
QRect getScreenRect();
protected:
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
@ -55,6 +54,7 @@ protected:
void paintEvent(QPaintEvent *);
void showEvent(QShowEvent *event);
void resizeEvent(QResizeEvent *event);
void closeEvent(QCloseEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
@ -76,9 +76,7 @@ private:
QPoint m_fullScreenBeforePos;
//outside member
QString m_serial = "";
QPointer<Controller> m_controller;
QPointer<FileHandler> m_fileHandler;
QPointer<Device> m_device;
};
#endif // VIDEOFORM_H

View file

@ -1,4 +1,7 @@
#include <QDebug>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QKeyEvent>
#include "devicemanage.h"
#include "server.h"
@ -44,6 +47,7 @@ bool DeviceManage::connectDevice(Device::DeviceParams params)
*/
Device *device = new Device(params);
connect(device, &Device::deviceDisconnect, this, &DeviceManage::onDeviceDisconnect);
connect(device, &Device::controlStateChange, this, &DeviceManage::onControlStateChange);
m_devices[params.serial] = device;
return true;
}
@ -102,13 +106,166 @@ void DeviceManage::disconnectAllDevice()
}
}
void DeviceManage::setGroupControlSignals(Device *host, Device *client, bool install)
{
if (!host || !client) {
return;
}
if (install) {
connect(host, &Device::postGoBack, client, &Device::postGoBack);
connect(host, &Device::postGoHome, client, &Device::postGoHome);
connect(host, &Device::postGoMenu, client, &Device::postGoMenu);
connect(host, &Device::postAppSwitch, client, &Device::postAppSwitch);
connect(host, &Device::postPower, client, &Device::postPower);
connect(host, &Device::postVolumeUp, client, &Device::postVolumeUp);
connect(host, &Device::postVolumeDown, client, &Device::postVolumeDown);
connect(host, &Device::setScreenPowerMode, client, &Device::setScreenPowerMode);
connect(host, &Device::expandNotificationPanel, client, &Device::expandNotificationPanel);
connect(host, &Device::collapseNotificationPanel, client, &Device::collapseNotificationPanel);
connect(host, &Device::postBackOrScreenOn, client, &Device::postBackOrScreenOn);
connect(host, &Device::postTextInput, client, &Device::postTextInput);
connect(host, &Device::setDeviceClipboard, client, &Device::setDeviceClipboard);
connect(host, &Device::clipboardPaste, client, &Device::clipboardPaste);
connect(host, &Device::pushFileRequest, client, &Device::pushFileRequest);
connect(host, &Device::installApkRequest, client, &Device::installApkRequest);
connect(host, &Device::screenshot, client, &Device::screenshot);
connect(host, &Device::showTouch, client, &Device::showTouch);
// dont connect requestDeviceClipboard
//connect(host, &Device::requestDeviceClipboard, client, &Device::requestDeviceClipboard);
} else {
disconnect(host, &Device::postGoBack, client, &Device::postGoBack);
disconnect(host, &Device::postGoHome, client, &Device::postGoHome);
disconnect(host, &Device::postGoMenu, client, &Device::postGoMenu);
disconnect(host, &Device::postAppSwitch, client, &Device::postAppSwitch);
disconnect(host, &Device::postPower, client, &Device::postPower);
disconnect(host, &Device::postVolumeUp, client, &Device::postVolumeUp);
disconnect(host, &Device::postVolumeDown, client, &Device::postVolumeDown);
disconnect(host, &Device::setScreenPowerMode, client, &Device::setScreenPowerMode);
disconnect(host, &Device::expandNotificationPanel, client, &Device::expandNotificationPanel);
disconnect(host, &Device::collapseNotificationPanel, client, &Device::collapseNotificationPanel);
disconnect(host, &Device::postBackOrScreenOn, client, &Device::postBackOrScreenOn);
disconnect(host, &Device::postTextInput, client, &Device::postTextInput);
disconnect(host, &Device::setDeviceClipboard, client, &Device::setDeviceClipboard);
disconnect(host, &Device::clipboardPaste, client, &Device::clipboardPaste);
disconnect(host, &Device::pushFileRequest, client, &Device::pushFileRequest);
disconnect(host, &Device::installApkRequest, client, &Device::installApkRequest);
disconnect(host, &Device::screenshot, client, &Device::screenshot);
disconnect(host, &Device::showTouch, client, &Device::showTouch);
}
}
void DeviceManage::setGroupControlHost(Device *host, bool install)
{
QMapIterator<QString, QPointer<Device>> i(m_devices);
while (i.hasNext()) {
i.next();
if (!i.value()) {
continue;
}
if (i.value() == host) {
continue;
}
if (install) {
if (host) {
setGroupControlSignals(host, i.value(), true);
}
emit i.value()->setControlState(i.value(), Device::GroupControlState::GCS_CLIENT);
} else {
if (host) {
setGroupControlSignals(host, i.value(), false);
}
emit i.value()->setControlState(i.value(), Device::GroupControlState::GCS_FREE);
}
}
}
void DeviceManage::onDeviceDisconnect(QString serial)
{
if (!serial.isEmpty() && m_devices.contains(serial)) {
if (m_devices[serial]->controlState() == Device::GroupControlState::GCS_HOST) {
setGroupControlHost(nullptr, false);
}
m_devices.remove(serial);
}
}
void DeviceManage::onControlStateChange(Device *device, Device::GroupControlState oldState, Device::GroupControlState newState)
{
if (!device) {
return;
}
// free to host
if (oldState == Device::GroupControlState::GCS_FREE
&& newState == Device::GroupControlState::GCS_HOST) {
// install direct control signals
setGroupControlHost(device, true);
// install convert control signals(frameSize need convert)
connect(device, &Device::mouseEvent, this, &DeviceManage::onMouseEvent, Qt::UniqueConnection);
connect(device, &Device::wheelEvent, this, &DeviceManage::onWheelEvent, Qt::UniqueConnection);
connect(device, &Device::keyEvent, this, &DeviceManage::onKeyEvent, Qt::UniqueConnection);
return;
}
// host to free
if (oldState == Device::GroupControlState::GCS_HOST
&& newState == Device::GroupControlState::GCS_FREE) {
// uninstall direct control signals
setGroupControlHost(device, false);
// uninstall convert control signals(frameSize need convert)
disconnect(device, &Device::mouseEvent, this, &DeviceManage::onMouseEvent);
disconnect(device, &Device::wheelEvent, this, &DeviceManage::onWheelEvent);
disconnect(device, &Device::keyEvent, this, &DeviceManage::onKeyEvent);
return;
}
}
void DeviceManage::onMouseEvent(const QMouseEvent *from, const QSize &frameSize, const QSize &showSize)
{
QMapIterator<QString, QPointer<Device>> i(m_devices);
while (i.hasNext()) {
i.next();
if (!i.value()) {
continue;
}
if (i.value() == sender()) {
continue;
}
// neend convert frameSize to its frameSize
emit i.value()->mouseEvent(from, i.value()->frameSize(), showSize);
}
}
void DeviceManage::onWheelEvent(const QWheelEvent *from, const QSize &frameSize, const QSize &showSize)
{
QMapIterator<QString, QPointer<Device>> i(m_devices);
while (i.hasNext()) {
i.next();
if (!i.value()) {
continue;
}
if (i.value() == sender()) {
continue;
}
// neend convert frameSize to its frameSize
emit i.value()->wheelEvent(from, i.value()->frameSize(), showSize);
}
}
void DeviceManage::onKeyEvent(const QKeyEvent *from, const QSize &frameSize, const QSize &showSize)
{
QMapIterator<QString, QPointer<Device>> i(m_devices);
while (i.hasNext()) {
i.next();
if (!i.value()) {
continue;
}
if (i.value() == sender()) {
continue;
}
// neend convert frameSize to its frameSize
emit i.value()->keyEvent(from, i.value()->frameSize(), showSize);
}
}
quint16 DeviceManage::getFreePort()
{
quint16 port = m_localPortStart;

View file

@ -20,8 +20,18 @@ public:
bool disconnectDevice(const QString &serial);
void disconnectAllDevice();
protected:
void setGroupControlSignals(Device *host, Device *client, bool install);
void setGroupControlHost(Device *host, bool install);
protected slots:
void onDeviceDisconnect(QString serial);
void onControlStateChange(Device* device, Device::GroupControlState oldState, Device::GroupControlState newState);
// neend convert frameSize to its frameSize
void onMouseEvent(const QMouseEvent* from, const QSize& frameSize, const QSize& showSize);
void onWheelEvent(const QWheelEvent* from, const QSize& frameSize, const QSize& showSize);
void onKeyEvent(const QKeyEvent* from, const QSize& frameSize, const QSize& showSize);
private:
quint16 getFreePort();

View file

@ -98,6 +98,7 @@ void Dialog::initUI()
ui->formatBox->setCurrentIndex(Config::getInstance().getRecordFormatIndex());
ui->recordPathEdt->setText(Config::getInstance().getRecordPath());
ui->framelessCheck->setChecked(Config::getInstance().getFramelessWindow());
#ifdef Q_OS_OSX
// mac need more width
@ -384,3 +385,9 @@ void Dialog::on_formatBox_activated(int index)
{
Config::getInstance().setRecordFormatIndex(index);
}
void Dialog::on_framelessCheck_stateChanged(int arg1)
{
Q_UNUSED(arg1)
Config::getInstance().setFramelessWindow(ui->framelessCheck->isChecked());
}

View file

@ -62,6 +62,8 @@ private slots:
void on_formatBox_activated(int index);
void on_framelessCheck_stateChanged(int arg1);
private:
bool checkAdbRun();
void initUI();

View file

@ -215,6 +215,22 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="alwaysTopCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>always on top</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="closeScreenCheck">
<property name="sizePolicy">
@ -228,22 +244,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="notDisplayCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>background record</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QCheckBox" name="useReverseCheck">
<property name="sizePolicy">
@ -260,8 +260,8 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="alwaysTopCheck">
<item row="0" column="1">
<widget class="QCheckBox" name="notDisplayCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -269,13 +269,20 @@
</sizepolicy>
</property>
<property name="text">
<string>always on top</string>
<string>background record</string>
</property>
<property name="checked">
<property name="checkable">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QCheckBox" name="framelessCheck">
<property name="text">
<string>frameless</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

Binary file not shown.

View file

@ -16,22 +16,22 @@
<translation type="vanished">file transfer failed</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="134"/>
<location filename="../../device/device.cpp" line="183"/>
<source>install apk</source>
<translation>install apk</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="136"/>
<location filename="../../device/device.cpp" line="185"/>
<source>file transfer</source>
<translation>file transfer</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="139"/>
<location filename="../../device/device.cpp" line="189"/>
<source>wait current %1 to complete</source>
<translation>wait current %1 to complete</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="142"/>
<location filename="../../device/device.cpp" line="192"/>
<source>%1 complete, save in %2</source>
<translation>%1 complete, save in %2</translation>
</message>
@ -41,7 +41,7 @@
<translation type="vanished">%1 complete\n save in %2</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="145"/>
<location filename="../../device/device.cpp" line="195"/>
<source>%1 failed</source>
<translation>%1 failed</translation>
</message>
@ -49,17 +49,17 @@
<context>
<name>Dialog</name>
<message>
<location filename="../../dialog.ui" line="415"/>
<location filename="../../dialog.ui" line="422"/>
<source>Wireless</source>
<translation>Wireless</translation>
</message>
<message>
<location filename="../../dialog.ui" line="499"/>
<location filename="../../dialog.ui" line="506"/>
<source>wireless connect</source>
<translation>wireless connect</translation>
</message>
<message>
<location filename="../../dialog.ui" line="515"/>
<location filename="../../dialog.ui" line="522"/>
<source>wireless disconnect</source>
<translation>wireless disconnect</translation>
</message>
@ -75,7 +75,7 @@
</message>
<message>
<location filename="../../dialog.ui" line="144"/>
<location filename="../../dialog.cpp" line="294"/>
<location filename="../../dialog.cpp" line="305"/>
<source>select path</source>
<translation>select path</translation>
</message>
@ -90,27 +90,32 @@
<translation>record screen</translation>
</message>
<message>
<location filename="../../dialog.ui" line="372"/>
<location filename="../../dialog.ui" line="282"/>
<source>frameless</source>
<translation>frameless</translation>
</message>
<message>
<location filename="../../dialog.ui" line="379"/>
<source>stop all server</source>
<translation>stop all server</translation>
</message>
<message>
<location filename="../../dialog.ui" line="549"/>
<location filename="../../dialog.ui" line="556"/>
<source>adb command:</source>
<translation>adb command:</translation>
</message>
<message>
<location filename="../../dialog.ui" line="585"/>
<location filename="../../dialog.ui" line="592"/>
<source>terminate</source>
<translation>terminate</translation>
</message>
<message>
<location filename="../../dialog.ui" line="572"/>
<location filename="../../dialog.ui" line="579"/>
<source>execute</source>
<translation>execute</translation>
</message>
<message>
<location filename="../../dialog.ui" line="598"/>
<location filename="../../dialog.ui" line="605"/>
<source>clear</source>
<translation>clear</translation>
</message>
@ -124,12 +129,12 @@
<translation type="vanished">auto enable</translation>
</message>
<message>
<location filename="../../dialog.ui" line="240"/>
<location filename="../../dialog.ui" line="272"/>
<source>background record</source>
<translation>background record</translation>
</message>
<message>
<location filename="../../dialog.ui" line="227"/>
<location filename="../../dialog.ui" line="243"/>
<source>screen-off</source>
<translation>screen-off</translation>
</message>
@ -144,7 +149,7 @@
<translation>max size:</translation>
</message>
<message>
<location filename="../../dialog.ui" line="272"/>
<location filename="../../dialog.ui" line="227"/>
<source>always on top</source>
<translation>always on top</translation>
</message>
@ -154,27 +159,27 @@
<translation>refresh script</translation>
</message>
<message>
<location filename="../../dialog.ui" line="389"/>
<location filename="../../dialog.ui" line="396"/>
<source>get device IP</source>
<translation>get device IP</translation>
</message>
<message>
<location filename="../../dialog.ui" line="288"/>
<location filename="../../dialog.ui" line="295"/>
<source>USB line</source>
<translation>USB line</translation>
</message>
<message>
<location filename="../../dialog.ui" line="344"/>
<location filename="../../dialog.ui" line="351"/>
<source>stop server</source>
<translation>stop server</translation>
</message>
<message>
<location filename="../../dialog.ui" line="334"/>
<location filename="../../dialog.ui" line="341"/>
<source>start server</source>
<translation>start server</translation>
</message>
<message>
<location filename="../../dialog.ui" line="324"/>
<location filename="../../dialog.ui" line="331"/>
<source>device serial:</source>
<translation>device serial:</translation>
</message>
@ -188,12 +193,12 @@
<translation>bit rate:</translation>
</message>
<message>
<location filename="../../dialog.ui" line="399"/>
<location filename="../../dialog.ui" line="406"/>
<source>start adbd</source>
<translation>start adbd</translation>
</message>
<message>
<location filename="../../dialog.ui" line="379"/>
<location filename="../../dialog.ui" line="386"/>
<source>refresh devices</source>
<translation>refresh devices</translation>
</message>
@ -206,7 +211,7 @@
<context>
<name>QObject</name>
<message>
<location filename="../../main.cpp" line="80"/>
<location filename="../../main.cpp" line="101"/>
<source>This software is completely open source and free, you can download it at the following address:</source>
<translation>This software is completely open source and free, you can download it at the following address:</translation>
</message>
@ -219,12 +224,12 @@
<translation>Tool</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="26"/>
<location filename="../../device/ui/toolform.ui" line="33"/>
<source>full screen</source>
<translation>full screen</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="49"/>
<location filename="../../device/ui/toolform.ui" line="56"/>
<source>expand notify</source>
<translation>expand notify</translation>
</message>
@ -237,52 +242,52 @@
<translation type="vanished">turn on</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="59"/>
<location filename="../../device/ui/toolform.ui" line="66"/>
<source>touch switch</source>
<translation>touch switch</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="69"/>
<location filename="../../device/ui/toolform.ui" line="76"/>
<source>close screen</source>
<translation>close screen</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="79"/>
<location filename="../../device/ui/toolform.ui" line="86"/>
<source>power</source>
<translation>power</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="89"/>
<location filename="../../device/ui/toolform.ui" line="96"/>
<source>volume up</source>
<translation>volume up</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="99"/>
<location filename="../../device/ui/toolform.ui" line="106"/>
<source>volume down</source>
<translation>volume down</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="109"/>
<location filename="../../device/ui/toolform.ui" line="116"/>
<source>app switch</source>
<translation>app switch</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="119"/>
<location filename="../../device/ui/toolform.ui" line="126"/>
<source>menu</source>
<translation>menu</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="129"/>
<location filename="../../device/ui/toolform.ui" line="136"/>
<source>home</source>
<translation>home</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="139"/>
<location filename="../../device/ui/toolform.ui" line="146"/>
<source>return</source>
<translation>return</translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="149"/>
<location filename="../../device/ui/toolform.ui" line="156"/>
<source>screen shot</source>
<translation>screen shot</translation>
</message>
@ -302,7 +307,7 @@
<translation type="vanished">file transfer failed</translation>
</message>
<message>
<location filename="../../device/ui/videoform.cpp" line="415"/>
<location filename="../../device/ui/videoform.cpp" line="657"/>
<source>file does not exist</source>
<translation>file does not exist</translation>
</message>

Binary file not shown.

View file

@ -16,22 +16,22 @@
<translation type="vanished"></translation>
</message>
<message>
<location filename="../../device/device.cpp" line="134"/>
<location filename="../../device/device.cpp" line="183"/>
<source>install apk</source>
<translation>apk</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="136"/>
<location filename="../../device/device.cpp" line="185"/>
<source>file transfer</source>
<translation></translation>
</message>
<message>
<location filename="../../device/device.cpp" line="139"/>
<location filename="../../device/device.cpp" line="189"/>
<source>wait current %1 to complete</source>
<translation>%1</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="142"/>
<location filename="../../device/device.cpp" line="192"/>
<source>%1 complete, save in %2</source>
<translation>%1,%2</translation>
</message>
@ -41,7 +41,7 @@
<translation type="vanished">%1\n %2</translation>
</message>
<message>
<location filename="../../device/device.cpp" line="145"/>
<location filename="../../device/device.cpp" line="195"/>
<source>%1 failed</source>
<translation>%1 </translation>
</message>
@ -49,17 +49,17 @@
<context>
<name>Dialog</name>
<message>
<location filename="../../dialog.ui" line="415"/>
<location filename="../../dialog.ui" line="422"/>
<source>Wireless</source>
<translation>线</translation>
</message>
<message>
<location filename="../../dialog.ui" line="499"/>
<location filename="../../dialog.ui" line="506"/>
<source>wireless connect</source>
<translation>线</translation>
</message>
<message>
<location filename="../../dialog.ui" line="515"/>
<location filename="../../dialog.ui" line="522"/>
<source>wireless disconnect</source>
<translation>线</translation>
</message>
@ -75,7 +75,7 @@
</message>
<message>
<location filename="../../dialog.ui" line="144"/>
<location filename="../../dialog.cpp" line="294"/>
<location filename="../../dialog.cpp" line="305"/>
<source>select path</source>
<translation></translation>
</message>
@ -90,27 +90,32 @@
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="372"/>
<location filename="../../dialog.ui" line="282"/>
<source>frameless</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="379"/>
<source>stop all server</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="549"/>
<location filename="../../dialog.ui" line="556"/>
<source>adb command:</source>
<translation>adb命令</translation>
</message>
<message>
<location filename="../../dialog.ui" line="585"/>
<location filename="../../dialog.ui" line="592"/>
<source>terminate</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="572"/>
<location filename="../../dialog.ui" line="579"/>
<source>execute</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="598"/>
<location filename="../../dialog.ui" line="605"/>
<source>clear</source>
<translation></translation>
</message>
@ -124,12 +129,12 @@
<translation type="vanished"></translation>
</message>
<message>
<location filename="../../dialog.ui" line="240"/>
<location filename="../../dialog.ui" line="272"/>
<source>background record</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="227"/>
<location filename="../../dialog.ui" line="243"/>
<source>screen-off</source>
<translation></translation>
</message>
@ -144,7 +149,7 @@
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="272"/>
<location filename="../../dialog.ui" line="227"/>
<source>always on top</source>
<translation></translation>
</message>
@ -154,27 +159,27 @@
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="389"/>
<location filename="../../dialog.ui" line="396"/>
<source>get device IP</source>
<translation>IP</translation>
</message>
<message>
<location filename="../../dialog.ui" line="288"/>
<location filename="../../dialog.ui" line="295"/>
<source>USB line</source>
<translation>USB线</translation>
</message>
<message>
<location filename="../../dialog.ui" line="344"/>
<location filename="../../dialog.ui" line="351"/>
<source>stop server</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="334"/>
<location filename="../../dialog.ui" line="341"/>
<source>start server</source>
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="324"/>
<location filename="../../dialog.ui" line="331"/>
<source>device serial:</source>
<translation></translation>
</message>
@ -188,12 +193,12 @@
<translation></translation>
</message>
<message>
<location filename="../../dialog.ui" line="399"/>
<location filename="../../dialog.ui" line="406"/>
<source>start adbd</source>
<translation>adbd</translation>
</message>
<message>
<location filename="../../dialog.ui" line="379"/>
<location filename="../../dialog.ui" line="386"/>
<source>refresh devices</source>
<translation></translation>
</message>
@ -206,7 +211,7 @@
<context>
<name>QObject</name>
<message>
<location filename="../../main.cpp" line="80"/>
<location filename="../../main.cpp" line="101"/>
<source>This software is completely open source and free, you can download it at the following address:</source>
<translation></translation>
</message>
@ -219,12 +224,12 @@
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="26"/>
<location filename="../../device/ui/toolform.ui" line="33"/>
<source>full screen</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="49"/>
<location filename="../../device/ui/toolform.ui" line="56"/>
<source>expand notify</source>
<translation></translation>
</message>
@ -237,52 +242,52 @@
<translation type="vanished"></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="59"/>
<location filename="../../device/ui/toolform.ui" line="66"/>
<source>touch switch</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="69"/>
<location filename="../../device/ui/toolform.ui" line="76"/>
<source>close screen</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="79"/>
<location filename="../../device/ui/toolform.ui" line="86"/>
<source>power</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="89"/>
<location filename="../../device/ui/toolform.ui" line="96"/>
<source>volume up</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="99"/>
<location filename="../../device/ui/toolform.ui" line="106"/>
<source>volume down</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="109"/>
<location filename="../../device/ui/toolform.ui" line="116"/>
<source>app switch</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="119"/>
<location filename="../../device/ui/toolform.ui" line="126"/>
<source>menu</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="129"/>
<location filename="../../device/ui/toolform.ui" line="136"/>
<source>home</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="139"/>
<location filename="../../device/ui/toolform.ui" line="146"/>
<source>return</source>
<translation></translation>
</message>
<message>
<location filename="../../device/ui/toolform.ui" line="149"/>
<location filename="../../device/ui/toolform.ui" line="156"/>
<source>screen shot</source>
<translation></translation>
</message>
@ -302,7 +307,7 @@
<translation type="vanished"></translation>
</message>
<message>
<location filename="../../device/ui/videoform.cpp" line="415"/>
<location filename="../../device/ui/videoform.cpp" line="657"/>
<source>file does not exist</source>
<translation></translation>
</message>

View file

@ -44,6 +44,15 @@
#define COMMON_RECORD_FORMAT_INDEX_KEY "RecordFormatIndex"
#define COMMON_RECORD_FORMAT_INDEX_DEF 0
#define SERIAL_WINDOW_RECT_KEY_X "WindowRectX"
#define SERIAL_WINDOW_RECT_KEY_Y "WindowRectY"
#define SERIAL_WINDOW_RECT_KEY_W "WindowRectW"
#define SERIAL_WINDOW_RECT_KEY_H "WindowRectH"
#define SERIAL_WINDOW_RECT_KEY_DEF -1
#define COMMON_FRAMELESS_WINDOW_KEY "FramelessWindow"
#define COMMON_FRAMELESS_WINDOW_DEF false
// 最大尺寸 录制格式
QString Config::s_configPath = "";
@ -140,6 +149,45 @@ void Config::setRecordFormatIndex(int recordFormatIndex)
m_userData->endGroup();
}
void Config::setRect(const QString &serial, const QRect &rc)
{
m_userData->beginGroup(serial);
m_userData->setValue(SERIAL_WINDOW_RECT_KEY_X, rc.left());
m_userData->setValue(SERIAL_WINDOW_RECT_KEY_Y, rc.top());
m_userData->setValue(SERIAL_WINDOW_RECT_KEY_W, rc.width());
m_userData->setValue(SERIAL_WINDOW_RECT_KEY_H, rc.height());
m_userData->endGroup();
m_userData->sync();
}
QRect Config::getRect(const QString &serial)
{
QRect rc;
m_userData->beginGroup(serial);
rc.setX(m_userData->value(SERIAL_WINDOW_RECT_KEY_X, SERIAL_WINDOW_RECT_KEY_DEF).toInt());
rc.setY(m_userData->value(SERIAL_WINDOW_RECT_KEY_Y, SERIAL_WINDOW_RECT_KEY_DEF).toInt());
rc.setWidth(m_userData->value(SERIAL_WINDOW_RECT_KEY_W, SERIAL_WINDOW_RECT_KEY_DEF).toInt());
rc.setHeight(m_userData->value(SERIAL_WINDOW_RECT_KEY_H, SERIAL_WINDOW_RECT_KEY_DEF).toInt());
m_userData->endGroup();
return rc;
}
void Config::setFramelessWindow(bool frameless)
{
m_userData->beginGroup(GROUP_COMMON);
m_userData->setValue(COMMON_FRAMELESS_WINDOW_KEY, frameless);
m_userData->endGroup();
}
bool Config::getFramelessWindow()
{
bool framelessWindow = false;
m_userData->beginGroup(GROUP_COMMON);
framelessWindow = m_userData->value(COMMON_FRAMELESS_WINDOW_KEY, COMMON_FRAMELESS_WINDOW_DEF).toBool();
m_userData->endGroup();
return framelessWindow;
}
QString Config::getServerVersion()
{
QString server;

View file

@ -3,6 +3,7 @@
#include <QObject>
#include <QPointer>
#include <QRect>
class QSettings;
class Config : public QObject
@ -29,6 +30,10 @@ public:
void setMaxSizeIndex(int maxSizeIndex);
int getRecordFormatIndex();
void setRecordFormatIndex(int recordFormatIndex);
void setRect(const QString &serial, const QRect &rc);
QRect getRect(const QString &serial);
bool getFramelessWindow();
void setFramelessWindow(bool frameless);
private:
explicit Config(QObject *parent = nullptr);

View file

@ -15,7 +15,7 @@ public:
void initMouseEventTap() override;
void quitMouseEventTap() override;
void enableMouseEventTap(QWidget* widget, bool enabled) override;
void enableMouseEventTap(QRect rc, bool enabled) override;
protected:
void run() override;

View file

@ -1,6 +1,5 @@
#import <Cocoa/Cocoa.h>
#include <QDebug>
#include <QWidget>
#include "cocoamousetap.h"
@ -20,77 +19,55 @@ typedef struct MouseEventTapData{
CFMachPortRef tap = Q_NULLPTR;
CFRunLoopRef runloop = Q_NULLPTR;
CFRunLoopSourceRef runloopSource = Q_NULLPTR;
QWidget* widget = Q_NULLPTR;
QRect rc;
} 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;
return nullptr;
}
case kCGEventTapDisabledByUserInput:
{
return NULL;
return nullptr;
}
default:
break;
}
if (!tapdata->widget) {
if (tapdata->rc.isEmpty()) {
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]];
windowRect.origin.x += 100;
windowRect.origin.y += 30;
windowRect.size.width -= 180;
windowRect.size.height -= 60;
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;
NSRect limitWindowRect = NSMakeRect(tapdata->rc.left(), tapdata->rc.top(),
tapdata->rc.width(), tapdata->rc.height());
// check rect samll than limit rect
NSRect checkWindowRect = NSMakeRect(limitWindowRect.origin.x + 10, limitWindowRect.origin.y + 10,
limitWindowRect.size.width - 10, limitWindowRect.size.height - 10);
/* This is in CGs global screenspace coordinate system, which has a
* flipped Y.
*/
CGPoint eventLocation = CGEventGetLocation(event);
if (!NSMouseInRect(NSPointFromCGPoint(eventLocation), checkWindowRect, NO)) {
if (eventLocation.x <= NSMinX(limitWindowRect)) {
eventLocation.x = NSMinX(limitWindowRect) + 1.0;
} else if (eventLocation.x >= NSMaxX(limitWindowRect)) {
eventLocation.x = NSMaxX(limitWindowRect) - 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));
if (eventLocation.y <= NSMinY(limitWindowRect)) {
eventLocation.y = NSMinY(limitWindowRect) + 1.0;
} else if (eventLocation.y >= NSMaxY(limitWindowRect)) {
eventLocation.y = NSMaxY(limitWindowRect) - 1.0;
}
CGWarpMouseCursorPosition(newLocation);
CGWarpMouseCursorPosition(eventLocation);
CGAssociateMouseAndMouseCursorPosition(YES);
if ((CGEventMaskBit(type) & movementEventsMask) == 0) {
@ -99,7 +76,7 @@ static CGEventRef Cocoa_MouseTapCallback(CGEventTapProxy proxy, CGEventType type
* movement events, since they mean that our warp cursor above
* behaves strangely.
*/
CGEventSetLocation(event, newLocation);
CGEventSetLocation(event, eventLocation);
}
}
@ -171,11 +148,11 @@ void CocoaMouseTap::quitMouseEventTap()
}
}
void CocoaMouseTap::enableMouseEventTap(QWidget* widget, bool enabled)
void CocoaMouseTap::enableMouseEventTap(QRect rc, bool enabled)
{
if (m_tapData && m_tapData->tap)
{
enabled ? m_tapData->widget = widget : m_tapData->widget = Q_NULLPTR;
enabled ? m_tapData->rc = rc : m_tapData->rc = QRect();
CGEventTapEnable(m_tapData->tap, enabled);
}
}

View file

@ -1,12 +1,15 @@
#ifndef MOUSETAP_H
#define MOUSETAP_H
#include <QRect>
class QWidget;
class MouseTap {
public:
static MouseTap* getInstance();
virtual void initMouseEventTap() = 0;
virtual void quitMouseEventTap() = 0;
virtual void enableMouseEventTap(QWidget* widget, bool enabled) = 0;
// rc base global screenspace coordinate system, which has a flipped Y.
virtual void enableMouseEventTap(QRect rc, bool enabled) = 0;
private:
static MouseTap *s_instance;

View file

@ -24,17 +24,12 @@ void WinMouseTap::quitMouseEventTap()
}
void WinMouseTap::enableMouseEventTap(QWidget *widget, bool enabled)
void WinMouseTap::enableMouseEventTap(QRect rc, bool enabled)
{
if (!widget) {
if (enabled && rc.isEmpty()) {
return;
}
if(enabled) {
QRect rc(widget->parentWidget()->mapToGlobal(widget->pos())
, widget->size());
// high dpi support
rc.setTopLeft(rc.topLeft() * widget->devicePixelRatio());
rc.setBottomRight(rc.bottomRight() * widget->devicePixelRatio());
RECT mainRect;
mainRect.left = (LONG)rc.left();
mainRect.right = (LONG)rc.right();

View file

@ -11,7 +11,7 @@ public:
void initMouseEventTap() override;
void quitMouseEventTap() override;
void enableMouseEventTap(QWidget* widget, bool enabled) override;
void enableMouseEventTap(QRect rc, bool enabled) override;
};
#endif // WINMOUSETAP_H

View file

@ -160,6 +160,7 @@ Note: it is not necessary to keep you Android device connected via USB after you
- Display Android device screens in real time
- Real-time mouse and keyboard control of Android devices
- Screen recording
- Screenshot to png
- Wireless connection
- Supports up to 16 device connections (the number can be higher if your PC performance allows. You need to compile it by yourself)
- Full-screen display
@ -176,6 +177,33 @@ Note: it is not necessary to keep you Android device connected via USB after you
- `Ctrl`+`Shift`+`v` copies the computer clipboard to the device clipboard;
- `Ctrl`+`v` _pastes_ the computer clipboard as a sequence of text events (but
breaks non-ASCII characters).
- Group control
## Shortcuts
| Action | Shortcut (Windows) | Shortcut (macOS)
| -------------------------------------- |:----------------------------- |:-----------------------------
| Switch fullscreen mode | `Ctrl`+`f` | `Cmd`+`f`
| Resize window to 1:1 (pixel-perfect) | `Ctrl`+`g` | `Cmd`+`g`
| Resize window to remove black borders | `Ctrl`+`x` \| _Double-click¹_ | `Cmd`+`x` \| _Double-click¹_
| Click on `HOME` | `Ctrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-click_
| Click on `BACK` | `Ctrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_
| Click on `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s`
| Click on `MENU` | `Ctrl`+`m` | `Ctrl`+`m`
| Click on `VOLUME_UP` | `Ctrl`+`↑` _(up)_ | `Cmd`+`↑` _(up)_
| Click on `VOLUME_DOWN` | `Ctrl`+`↓` _(down)_ | `Cmd`+`↓` _(down)_
| Click on `POWER` | `Ctrl`+`p` | `Cmd`+`p`
| Power on | _Right-click²_ | _Right-click²_
| Turn device screen off (keep mirroring)| `Ctrl`+`o` | `Cmd`+`o`
| Expand notification panel | `Ctrl`+`n` | `Cmd`+`n`
| Collapse notification panel | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| Copy device clipboard to computer | `Ctrl`+`c` | `Cmd`+`c`
| Paste computer clipboard to device | `Ctrl`+`v` | `Cmd`+`v`
| Copy computer clipboard to device | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
_¹Double-click on black borders to remove them._
_²Right-click turns the screen on if it was off, presses BACK otherwise._
## TODO
[TODO](docs/TODO.md)
@ -198,7 +226,7 @@ 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.9.7, vs >= 2015 (mingw not supported))
1. Set up the Qt development environment on the target platform (Qt >= 5.12.0, vs >= 2017 (mingw not supported))
2. Clone the project
3. Open the project root directory all.pro with QtCreator
4. Compile and run

View file

@ -163,6 +163,7 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
- 实时显示Android设备屏幕
- 实时键鼠控制Android设备
- 屏幕录制
- 截图为png
- 无线连接
- 最多支持16台设备连接PC性能允许的情况下可以增加需要自己编译
- 全屏显示
@ -176,6 +177,33 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
- `Ctrl` + `c`将设备剪贴板复制到计算机剪贴板;
- `Ctrl` + `Shift` + `v`将计算机剪贴板复制到设备剪贴板;
- `Ctrl` +`v` 将计算机剪贴板作为一系列文本事件发送到设备不支持非ASCII字符
- 群控
## 快捷键
| 功能 | 快捷键(Windows) | 快捷键 (macOS)
| -------------------------------------- |:----------------------------- |:-----------------------------
| 切换全屏 | `Ctrl`+`f` | `Cmd`+`f`
| 调整窗口大小为 1:1 | `Ctrl`+`g` | `Cmd`+`g`
| 调整窗口大小去除黑边 | `Ctrl`+`x` \| _左键双击_ | `Cmd`+`x` \| _左键双击_
| 点击 `主页` | `Ctrl`+`h` \| _点击鼠标中键_ | `Ctrl`+`h` \| _点击鼠标中键_
| 点击 `BACK` | `Ctrl`+`b` \| _右键双击_ | `Cmd`+`b` \| _右键双击_
| 点击 `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s`
| 点击 `MENU` | `Ctrl`+`m` | `Ctrl`+`m`
| 点击 `VOLUME_UP` | `Ctrl`+`↑` _(上)_ | `Cmd`+`↑` _(上)_
| 点击 `VOLUME_DOWN` | `Ctrl`+`↓` _(下)_ | `Cmd`+`↓` _(下)_
| 点击 `POWER` | `Ctrl`+`p` | `Cmd`+`p`
| 打开电源 | _右键双击_ | _右键双击_
| 关闭屏幕 (保持投屏) | `Ctrl`+`o` | `Cmd`+`o`
| 打开下拉菜单 | `Ctrl`+`n` | `Cmd`+`n`
| 关闭下拉菜单 | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| 复制设备剪切板到电脑 | `Ctrl`+`c` | `Cmd`+`c`
| 粘贴电脑剪切板到设备 | `Ctrl`+`v` | `Cmd`+`v`
| 复制电脑剪切板到设备 | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
鼠标左键双击黑色区域可以去除黑色区域
如果电源关闭,鼠标右键双击打开电源;如果电源开启,鼠标右键双击相当于返回
## TODO
[后期计划](docs/TODO.md)
@ -198,7 +226,7 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
尽量提供了所有依赖资源,方便傻瓜式编译。
### PC端
1. 目标平台上搭建Qt开发环境(Qt >= 5.9.7, vs >= 2015 (**不支持mingw**))
1. 目标平台上搭建Qt开发环境(Qt >= 5.12.0, vs >= 2017 (**不支持mingw**))
2. 克隆该项目
3. 使用QtCreator打开项目根目录all.pro
4. 编译,运行即可

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

55
ci/mac/package/package.py Normal file
View file

@ -0,0 +1,55 @@
import dmgbuild
import os
import json
import sys
current_file_path = os.path.dirname(os.path.realpath(__file__))
dmg_settings_path = '%s/dmg-settings.json' % current_file_path
dmg_background_img = '%s/dmg-background.jpg' % current_file_path
app_path = '%s/../../build/QtScrcpy.app' % current_file_path
dmg_path = '%s/../../build/QtScrcpy.dmg' % current_file_path
app_name = 'QtScrcpy'
def console_print(msg):
print(msg)
sys.stdout.flush()
def generate_dmg_info():
with open(dmg_settings_path, 'w') as file:
info = {
'title': app_name,
'icon-size': 120,
'background': dmg_background_img,
'format': 'UDZO',
'compression-level': 9,
'window': {
'position': {'x': 400, 'y': 200},
'size': {'width': 780, 'height': 480}
},
'contents': [
{
'x': 223,
'y': 227,
'type': 'file',
'path': app_path
},
{
'x': 550,
'y': 227,
'type': 'link',
'path': '/Applications'
}
]
}
json.dump(info, file)
if __name__ == '__main__':
console_print('generate dmg info')
generate_dmg_info()
console_print('build dmg: %s' % dmg_path)
dmgbuild.build_dmg(dmg_path, app_name, dmg_settings_path)
if not os.path.exists(dmg_path):
console_print('fail to create %s' % dmg_path)
sys.exit(1)
sys.exit(0)

View file

@ -0,0 +1 @@
dmgbuild==1.3.3

37
ci/mac/package_for_mac.sh Executable file
View file

@ -0,0 +1,37 @@
# 获取绝对路径,保证其他目录执行此脚本依然正确
{
cd $(dirname "$0")
script_path=$(pwd)
cd -
} &> /dev/null # disable output
# 设置当前目录cd的目录影响接下来执行程序的工作目录
old_cd=$(pwd)
cd $(dirname "$0")
echo
echo
echo ---------------------------------------------------------------
echo pip install requirements
echo ---------------------------------------------------------------
pip install -r $script_path/package/requirements.txt
if [ $? -ne 0 ] ;then
echo "pip install requirements failed"
exit 1
fi
echo
echo
echo ---------------------------------------------------------------
echo create package
echo ---------------------------------------------------------------
python $script_path/package/package.py
if [ $? -ne 0 ] ;then
echo "create package failed"
exit 1
fi
# 恢复当前目录
cd $old_cd
exit 0

View file

@ -3,16 +3,26 @@
如果在此文档没有解决你的问题描述你的问题截图软件控制台中打印的日志一起发到QQ群里提问。
## 支持声音(软件不做支持)
[关于转发安卓声音到PC的讨论](https://github.com/Genymobile/scrcpy/issues/14#issuecomment-543204526)
## 无法输入中文
安装搜狗输入法/QQ输入法就可以支持输入中文了
手机端安装搜狗输入法/QQ输入法就可以支持输入中文了
## 可以看到画面,但无法控制
有些手机(小米等手机)需要额外打开控制权限检查是否USB调试里打开了允许模拟点击
![image](image/USB调试(安全设置).jpg)
## 错误信息Could not open video stream
## 手机通过数据线连接电脑,刷新设备列表以后,没有任何设备出现
随便下载一个手机助手尝试连接成功以后再用QtScrcpy刷新设备列表连接
## 错误信息AdbProcess::error:adb server version (40) doesnt match this client (41)
任务管理找到adb进程并杀死重新操作即可
## 错误信息Could not open video stream
导致这个错误的原因有很多,最简单的解决方法是在分辨率设置中,选择一个较低的分辨率
## 声音
[关于转发安卓声音到PC的讨论](https://github.com/Genymobile/scrcpy/issues/14#issuecomment-543204526)
## 错误信息QOpenGLShaderProgram::attributeLocation(vertexIn): shader program is not linked
config.ini里修改下解码方式改成1或者2试试

View file

@ -7,7 +7,6 @@
## 中优先级
- 脚本
- 群控
- 软解
- opengles 3.0 兼容性参考[这里](https://github.com/libretro/glsl-shaders/blob/master/nnedi3/shaders/yuv-to-rgb-2x.glsl)