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 8e76585997
38 changed files with 1167 additions and 374 deletions

View file

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

View file

@ -103,12 +103,20 @@ jobs:
env: env:
githubFullName: ${{ github.event.repository.full_name }} githubFullName: ${{ github.event.repository.full_name }}
ref: ${{ github.event.ref }} ref: ${{ github.event.ref }}
github_token: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
[string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1) [string]$tag = ${env:ref}.Substring(${env:ref}.LastIndexOf('/') + 1)
[string]$url = 'https://api.github.com/repos/' + ${env:githubFullName} + '/releases/tags/' + ${tag} [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={} $response={}
try { try {
$response = Invoke-RestMethod -Uri $url -Method Get $response = Invoke-RestMethod -Uri $url -Headers $headers -Method Get
} catch { } catch {
Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription 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); connect(m_inputConvert, &InputConvertBase::grabCursor, this, &Controller::grabCursor);
} }
void Controller::postTurnOn() void Controller::onPostBackOrScreenOn()
{ {
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_BACK_OR_SCREEN_ON); ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_BACK_OR_SCREEN_ON);
if (!controlMsg) { if (!controlMsg) {
@ -71,42 +71,42 @@ void Controller::postTurnOn()
postControlMsg(controlMsg); postControlMsg(controlMsg);
} }
void Controller::postGoHome() void Controller::onPostGoHome()
{ {
postKeyCodeClick(AKEYCODE_HOME); postKeyCodeClick(AKEYCODE_HOME);
} }
void Controller::postGoMenu() void Controller::onPostGoMenu()
{ {
postKeyCodeClick(AKEYCODE_MENU); postKeyCodeClick(AKEYCODE_MENU);
} }
void Controller::postGoBack() void Controller::onPostGoBack()
{ {
postKeyCodeClick(AKEYCODE_BACK); postKeyCodeClick(AKEYCODE_BACK);
} }
void Controller::postAppSwitch() void Controller::onPostAppSwitch()
{ {
postKeyCodeClick(AKEYCODE_APP_SWITCH); postKeyCodeClick(AKEYCODE_APP_SWITCH);
} }
void Controller::postPower() void Controller::onPostPower()
{ {
postKeyCodeClick(AKEYCODE_POWER); postKeyCodeClick(AKEYCODE_POWER);
} }
void Controller::postVolumeUp() void Controller::onPostVolumeUp()
{ {
postKeyCodeClick(AKEYCODE_VOLUME_UP); postKeyCodeClick(AKEYCODE_VOLUME_UP);
} }
void Controller::postVolumeDown() void Controller::onPostVolumeDown()
{ {
postKeyCodeClick(AKEYCODE_VOLUME_DOWN); postKeyCodeClick(AKEYCODE_VOLUME_DOWN);
} }
void Controller::expandNotificationPanel() void Controller::onExpandNotificationPanel()
{ {
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_EXPAND_NOTIFICATION_PANEL); ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_EXPAND_NOTIFICATION_PANEL);
if (!controlMsg) { if (!controlMsg) {
@ -115,7 +115,7 @@ void Controller::expandNotificationPanel()
postControlMsg(controlMsg); postControlMsg(controlMsg);
} }
void Controller::collapseNotificationPanel() void Controller::onCollapseNotificationPanel()
{ {
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_COLLAPSE_NOTIFICATION_PANEL); ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_COLLAPSE_NOTIFICATION_PANEL);
if (!controlMsg) { if (!controlMsg) {
@ -124,7 +124,7 @@ void Controller::collapseNotificationPanel()
postControlMsg(controlMsg); postControlMsg(controlMsg);
} }
void Controller::requestDeviceClipboard() void Controller::onRequestDeviceClipboard()
{ {
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_GET_CLIPBOARD); ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_GET_CLIPBOARD);
if (!controlMsg) { if (!controlMsg) {
@ -133,7 +133,7 @@ void Controller::requestDeviceClipboard()
postControlMsg(controlMsg); postControlMsg(controlMsg);
} }
void Controller::setDeviceClipboard() void Controller::onSetDeviceClipboard()
{ {
QClipboard *board = QApplication::clipboard(); QClipboard *board = QApplication::clipboard();
QString text = board->text(); QString text = board->text();
@ -145,14 +145,14 @@ void Controller::setDeviceClipboard()
postControlMsg(controlMsg); postControlMsg(controlMsg);
} }
void Controller::clipboardPaste() void Controller::onClipboardPaste()
{ {
QClipboard *board = QApplication::clipboard(); QClipboard *board = QApplication::clipboard();
QString text = board->text(); 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); ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_INJECT_TEXT);
if (!controlMsg) { if (!controlMsg) {
@ -162,7 +162,7 @@ void Controller::postTextInput(QString& text)
postControlMsg(controlMsg); postControlMsg(controlMsg);
} }
void Controller::setScreenPowerMode(ControlMsg::ScreenPowerMode mode) void Controller::onSetScreenPowerMode(ControlMsg::ScreenPowerMode mode)
{ {
ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_SET_SCREEN_POWER_MODE); ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_SET_SCREEN_POWER_MODE);
if (!controlMsg) { if (!controlMsg) {
@ -172,21 +172,21 @@ void Controller::setScreenPowerMode(ControlMsg::ScreenPowerMode mode)
postControlMsg(controlMsg); 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) { if (m_inputConvert) {
m_inputConvert->mouseEvent(from, frameSize, showSize); 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) { if (m_inputConvert) {
m_inputConvert->wheelEvent(from, frameSize, showSize); 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) { if (m_inputConvert) {
m_inputConvert->keyEvent(from, frameSize, showSize); m_inputConvert->keyEvent(from, frameSize, showSize);

View file

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

View file

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

View file

@ -13,6 +13,7 @@
#include "controller.h" #include "controller.h"
#include "config.h" #include "config.h"
#include "avframeconvert.h" #include "avframeconvert.h"
#include "mousetap/mousetap.h"
extern "C" extern "C"
{ {
#include "libavutil/imgutils.h" #include "libavutil/imgutils.h"
@ -34,15 +35,8 @@ Device::Device(DeviceParams params, QObject *parent)
m_decoder = new Decoder(m_vb, this); m_decoder = new Decoder(m_vb, this);
m_fileHandler = new FileHandler(this); m_fileHandler = new FileHandler(this);
m_controller = new Controller(params.gameScript, this); m_controller = new Controller(params.gameScript, this);
m_videoForm = new VideoForm(Config::getInstance().getSkin()); m_videoForm = new VideoForm(Config::getInstance().getFramelessWindow(), Config::getInstance().getSkin());
m_videoForm->setSerial(m_params.serial); m_videoForm->setDevice(this);
if (m_controller) {
m_videoForm->setController(m_controller);
}
if (m_fileHandler) {
m_videoForm->setFileHandler(m_fileHandler);
}
m_videoForm->show();
} }
m_stream = new Stream(this); m_stream = new Stream(this);
@ -76,6 +70,7 @@ Device::~Device()
delete m_vb; delete m_vb;
} }
if (m_videoForm) { if (m_videoForm) {
m_videoForm->close();
delete m_videoForm; delete m_videoForm;
} }
emit deviceDisconnect(m_params.serial); emit deviceDisconnect(m_params.serial);
@ -86,16 +81,25 @@ VideoForm *Device::getVideoForm()
return m_videoForm; return m_videoForm;
} }
Controller *Device::getController()
{
return m_controller;
}
Server *Device::getServer() Server *Device::getServer()
{ {
return m_server; 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) void Device::updateScript(QString script)
{ {
if(m_controller){ if(m_controller){
@ -115,35 +119,86 @@ void Device::onScreenshot()
m_vb->unLock(); 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() void Device::initSignals()
{ {
if (m_controller && m_videoForm) { connect(this, &Device::screenshot, this, &Device::onScreenshot);
connect(m_controller, &Controller::grabCursor, m_videoForm, &VideoForm::onGrabCursor); connect(this, &Device::showTouch, this, &Device::onShowTouch);
connect(m_videoForm, &VideoForm::screenshot, this, &Device::onScreenshot); 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) { if (m_videoForm) {
connect(m_videoForm, &VideoForm::destroyed, this, [this](QObject *obj){ connect(m_videoForm, &VideoForm::destroyed, this, [this](QObject *obj){
Q_UNUSED(obj) Q_UNUSED(obj)
deleteLater(); deleteLater();
}); });
connect(this, &Device::switchFullScreen, m_videoForm, &VideoForm::onSwitchFullScreen);
} }
if (m_fileHandler) { 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){ connect(m_fileHandler, &FileHandler::fileHandlerResult, this, [this](FileHandler::FILE_HANDLER_RESULT processResult, bool isApk){
QString tips = ""; QString tipsType = "";
if (isApk) { if (isApk) {
tips = tr("install apk"); tipsType = tr("install apk");
} else { } else {
tips = tr("file transfer"); tipsType = tr("file transfer");
} }
QString tips;
if (FileHandler::FAR_IS_RUNNING == processResult && m_videoForm) { 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) { 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) { 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) { if (m_videoForm) {
m_videoForm->setWindowTitle(deviceName); m_videoForm->setWindowTitle(deviceName);
m_videoForm->updateShowSize(size); 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 // init recorder
@ -182,7 +247,7 @@ void Device::initSignals()
// 显示界面时才自动息屏m_params.display // 显示界面时才自动息屏m_params.display
if (m_params.closeScreen && m_params.display && m_controller) { 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) bool Device::saveFrame(const AVFrame* frame)
{ {
if (!frame) { if (!frame) {
@ -276,10 +369,10 @@ bool Device::saveFrame(const AVFrame* frame)
} }
QDateTime dateTime = QDateTime::currentDateTime(); QDateTime dateTime = QDateTime::currentDateTime();
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss_zzz"); QString fileName = dateTime.toString("_yyyyMMdd_hhmmss_zzz");
fileName = Config::getInstance().getTitle() + fileName + ".jpg"; fileName = Config::getInstance().getTitle() + fileName + ".png";
QDir dir(fileDir); QDir dir(fileDir);
absFilePath = dir.absoluteFilePath(fileName); absFilePath = dir.absoluteFilePath(fileName);
ret = rgbImage.save(absFilePath); ret = rgbImage.save(absFilePath, "PNG", 100);
if (!ret) { if (!ret) {
return false; return false;
} }

View file

@ -4,6 +4,11 @@
#include <QPointer> #include <QPointer>
#include <QTime> #include <QTime>
#include "controlmsg.h"
class QMouseEvent;
class QWheelEvent;
class QKeyEvent;
class Recorder; class Recorder;
class Server; class Server;
class VideoBuffer; class VideoBuffer;
@ -30,20 +35,64 @@ public:
QString gameScript = ""; // 游戏映射脚本 QString gameScript = ""; // 游戏映射脚本
bool renderExpiredFrames = false; // 是否渲染延迟视频帧 bool renderExpiredFrames = false; // 是否渲染延迟视频帧
}; };
enum GroupControlState {
GCS_FREE = 0,
GCS_HOST,
GCS_CLIENT,
};
explicit Device(DeviceParams params, QObject *parent = nullptr); explicit Device(DeviceParams params, QObject *parent = nullptr);
virtual ~Device(); virtual ~Device();
VideoForm *getVideoForm(); VideoForm *getVideoForm();
Controller *getController();
Server *getServer(); Server *getServer();
const QString &getSerial();
const QSize frameSize();
void updateScript(QString script); void updateScript(QString script);
Device::GroupControlState controlState();
signals: signals:
void deviceDisconnect(QString serial); 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: public slots:
void onScreenshot(); void onScreenshot();
void onShowTouch(bool show);
void onSetControlState(Device* device, Device::GroupControlState state);
void onGrabCursor(bool grab);
private: private:
void initSignals(); void initSignals();
@ -65,6 +114,8 @@ private:
QTime m_startTimeCount; QTime m_startTimeCount;
DeviceParams m_params; DeviceParams m_params;
GroupControlState m_controlState = GCS_FREE;
}; };
#endif // DEVICE_H #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()) { if (m_adb.isRuning()) {
emit fileHandlerResult(FAR_IS_RUNNING, false); 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); 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()) { if (m_adb.isRuning()) {
emit fileHandlerResult(FAR_IS_RUNNING, true); emit fileHandlerResult(FAR_IS_RUNNING, true);

View file

@ -17,10 +17,12 @@ public:
FileHandler(QObject *parent = nullptr); FileHandler(QObject *parent = nullptr);
virtual ~FileHandler(); virtual ~FileHandler();
void pushFileRequest(const QString& serial, const QString& file, const QString& devicePath = "");
void installApkRequest(const QString& serial, const QString& apkFile);
const QString &getDevicePath(); 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: signals:
void fileHandlerResult(FILE_HANDLER_RESULT processResult, bool isApk = false); void fileHandlerResult(FILE_HANDLER_RESULT processResult, bool isApk = false);

View file

@ -6,9 +6,7 @@
#include "toolform.h" #include "toolform.h"
#include "ui_toolform.h" #include "ui_toolform.h"
#include "iconhelper.h" #include "iconhelper.h"
#include "videoform.h" #include "device.h"
#include "controller.h"
#include "adbprocess.h"
ToolForm::ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos) ToolForm::ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos)
: MagneticWidget(adsorbWidget, adsorbPos) : MagneticWidget(adsorbWidget, adsorbPos)
@ -18,8 +16,6 @@ ToolForm::ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos)
setWindowFlags(windowFlags() | Qt::FramelessWindowHint); setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
//setWindowFlags(windowFlags() & ~Qt::WindowMinMaxButtonsHint); //setWindowFlags(windowFlags() & ~Qt::WindowMinMaxButtonsHint);
m_videoForm = dynamic_cast<VideoForm*>(adsorbWidget);
initStyle(); initStyle();
} }
@ -28,6 +24,15 @@ ToolForm::~ToolForm()
delete ui; delete ui;
} }
void ToolForm::setDevice(Device *device)
{
if (!device) {
return;
}
m_device = device;
connect(m_device, &Device::controlStateChange, this, &ToolForm::onControlStateChange);
}
void ToolForm::initStyle() void ToolForm::initStyle()
{ {
IconHelper::Instance()->SetIcon(ui->fullScreenBtn, QChar(0xf0b2), 15); 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->expandNotifyBtn, QChar(0xf103), 15);
IconHelper::Instance()->SetIcon(ui->screenShotBtn, QChar(0xf0c4), 15); IconHelper::Instance()->SetIcon(ui->screenShotBtn, QChar(0xf0c4), 15);
IconHelper::Instance()->SetIcon(ui->touchBtn, QChar(0xf111), 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) void ToolForm::mousePressEvent(QMouseEvent *event)
@ -80,97 +104,121 @@ void ToolForm::hideEvent(QHideEvent *event)
void ToolForm::on_fullScreenBtn_clicked() void ToolForm::on_fullScreenBtn_clicked()
{ {
if (m_videoForm) { if (!m_device) {
m_videoForm->switchFullScreen(); return;
} }
emit m_device->switchFullScreen();
} }
void ToolForm::on_returnBtn_clicked() void ToolForm::on_returnBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->postGoBack(); return;
} }
emit m_device->postGoBack();
} }
void ToolForm::on_homeBtn_clicked() void ToolForm::on_homeBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->postGoHome(); return;
} }
emit m_device->postGoHome();
} }
void ToolForm::on_menuBtn_clicked() void ToolForm::on_menuBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->postGoMenu(); return;
} }
emit m_device->postGoMenu();
} }
void ToolForm::on_appSwitchBtn_clicked() void ToolForm::on_appSwitchBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->postAppSwitch(); return;
} }
emit m_device->postAppSwitch();
} }
void ToolForm::on_powerBtn_clicked() void ToolForm::on_powerBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->postPower(); return;
} }
emit m_device->postPower();
} }
void ToolForm::on_screenShotBtn_clicked() void ToolForm::on_screenShotBtn_clicked()
{ {
emit screenshot(); if (!m_device) {
return;
}
emit m_device->screenshot();
} }
void ToolForm::on_volumeUpBtn_clicked() void ToolForm::on_volumeUpBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->postVolumeUp(); return;
} }
emit m_device->postVolumeUp();
} }
void ToolForm::on_volumeDownBtn_clicked() void ToolForm::on_volumeDownBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->postVolumeDown(); return;
} }
emit m_device->postVolumeDown();
} }
void ToolForm::on_closeScreenBtn_clicked() void ToolForm::on_closeScreenBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->setScreenPowerMode(ControlMsg::SPM_OFF); return;
} }
emit m_device->setScreenPowerMode(ControlMsg::SPM_OFF);
} }
void ToolForm::on_expandNotifyBtn_clicked() void ToolForm::on_expandNotifyBtn_clicked()
{ {
if (m_videoForm && m_videoForm->getController()) { if (!m_device) {
m_videoForm->getController()->expandNotificationPanel(); return;
} }
emit m_device->expandNotificationPanel();
} }
void ToolForm::on_touchBtn_clicked() void ToolForm::on_touchBtn_clicked()
{ {
if (!m_videoForm) { if (!m_device) {
return; return;
} }
m_showTouch = !m_showTouch; m_showTouch = !m_showTouch;
emit m_device->showTouch(m_showTouch);
}
AdbProcess* adb = new AdbProcess(); void ToolForm::on_groupControlBtn_clicked()
if (!adb) { {
if (!m_device) {
return; return;
} }
connect(adb, &AdbProcess::adbProcessResult, this, [this](AdbProcess::ADB_EXEC_RESULT processResult){ Device::GroupControlState state = m_device->controlState();
if (AdbProcess::AER_SUCCESS_START != processResult) { if (state == Device::GroupControlState::GCS_FREE) {
sender()->deleteLater(); 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);
}
} }
});
adb->setShowTouchesEnabled(m_videoForm->getSerial(), m_showTouch);
qInfo() << "show touch " << (m_showTouch ? "enable" : "disable"); 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 <QPointer>
#include "magneticwidget.h" #include "magneticwidget.h"
#include "device.h"
namespace Ui { namespace Ui {
class ToolForm; class ToolForm;
} }
class VideoForm; class Device;
class ToolForm : public MagneticWidget class ToolForm : public MagneticWidget
{ {
Q_OBJECT Q_OBJECT
@ -19,6 +20,8 @@ public:
explicit ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos); explicit ToolForm(QWidget* adsorbWidget, AdsorbPositions adsorbPos);
~ToolForm(); ~ToolForm();
void setDevice(Device *device);
protected: protected:
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event);
@ -27,41 +30,31 @@ protected:
void showEvent(QShowEvent *event); void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event); void hideEvent(QHideEvent *event);
signals:
void screenshot();
private slots: private slots:
void on_fullScreenBtn_clicked(); void on_fullScreenBtn_clicked();
void on_returnBtn_clicked(); void on_returnBtn_clicked();
void on_homeBtn_clicked(); void on_homeBtn_clicked();
void on_menuBtn_clicked(); void on_menuBtn_clicked();
void on_appSwitchBtn_clicked(); void on_appSwitchBtn_clicked();
void on_powerBtn_clicked(); void on_powerBtn_clicked();
void on_screenShotBtn_clicked(); void on_screenShotBtn_clicked();
void on_volumeUpBtn_clicked(); void on_volumeUpBtn_clicked();
void on_volumeDownBtn_clicked(); void on_volumeDownBtn_clicked();
void on_closeScreenBtn_clicked(); void on_closeScreenBtn_clicked();
void on_expandNotifyBtn_clicked(); void on_expandNotifyBtn_clicked();
void on_touchBtn_clicked(); void on_touchBtn_clicked();
void on_groupControlBtn_clicked();
void onControlStateChange(Device* device, Device::GroupControlState oldState, Device::GroupControlState newState);
private: private:
void initStyle(); void initStyle();
void updateGroupControl();
private: private:
Ui::ToolForm *ui; Ui::ToolForm *ui;
QPoint m_dragPosition; QPoint m_dragPosition;
QPointer<VideoForm> m_videoForm; QPointer<Device> m_device;
bool m_showTouch = false; bool m_showTouch = false;
}; };

View file

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

View file

@ -8,33 +8,39 @@
#include <QMimeData> #include <QMimeData>
#include <QFileInfo> #include <QFileInfo>
#include <QMessageBox> #include <QMessageBox>
#include <QShortcut>
#include <QWindow>
#include <QScreen>
#include "videoform.h" #include "videoform.h"
#include "qyuvopenglwidget.h" #include "qyuvopenglwidget.h"
#include "mousetap/mousetap.h"
#include "ui_videoform.h" #include "ui_videoform.h"
#include "iconhelper.h" #include "iconhelper.h"
#include "toolform.h" #include "toolform.h"
#include "device.h"
#include "controller.h" #include "controller.h"
#include "filehandler.h"
#include "config.h" #include "config.h"
extern "C" extern "C"
{ {
#include "libavutil/frame.h" #include "libavutil/frame.h"
} }
VideoForm::VideoForm(bool skin, QWidget *parent) VideoForm::VideoForm(bool framelessWindow, bool skin, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, ui(new Ui::videoForm) , ui(new Ui::videoForm)
, m_skin(skin) , m_skin(skin)
{ {
ui->setupUi(this); ui->setupUi(this);
initUI(); initUI();
installShortcut();
updateShowSize(size()); updateShowSize(size());
bool vertical = size().height() > size().width(); bool vertical = size().height() > size().width();
if (m_skin) { if (m_skin) {
updateStyleSheet(vertical); updateStyleSheet(vertical);
} }
if (framelessWindow) {
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
}
} }
VideoForm::~VideoForm() VideoForm::~VideoForm()
@ -70,13 +76,47 @@ void VideoForm::initUI()
ui->keepRadioWidget->setMouseTracking(true); ui->keepRadioWidget->setMouseTracking(true);
} }
void VideoForm::onGrabCursor(bool grab) QRect VideoForm::getGrabCursorRect()
{ {
#if defined(Q_OS_WIN32) || defined(Q_OS_OSX) QRect rc;
MouseTap::getInstance()->enableMouseEventTap(m_videoWidget, grab); #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 #else
Q_UNUSED(grab)
#endif #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) void VideoForm::updateRender(const AVFrame *frame)
@ -98,7 +138,7 @@ void VideoForm::showToolForm(bool show)
{ {
if (!m_toolForm) { if (!m_toolForm) {
m_toolForm = new ToolForm(this, ToolForm::AP_OUTSIDE_RIGHT); 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->move(pos().x() + geometry().width(), pos().y() + 30);
m_toolForm->setVisible(show); m_toolForm->setVisible(show);
@ -106,16 +146,178 @@ void VideoForm::showToolForm(bool show)
void VideoForm::moveCenter() void VideoForm::moveCenter()
{ {
QDesktopWidget* desktop = QApplication::desktop(); QRect screenRect = getScreenRect();
if (!desktop) { if (screenRect.isEmpty()) {
qWarning() << "QApplication::desktop() is nullptr"; qWarning() << "getScreenRect is empty";
return; return;
} }
QRect screenRect = desktop->availableGeometry();
// 窗口居中 // 窗口居中
move(screenRect.center() - QRect(0, 0, size().width(), size().height()).center()); 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) void VideoForm::updateStyleSheet(bool vertical)
{ {
if (vertical) { if (vertical) {
@ -157,12 +359,11 @@ void VideoForm::updateShowSize(const QSize &newSize)
bool vertical = m_widthHeightRatio < 1.0f ? true : false; bool vertical = m_widthHeightRatio < 1.0f ? true : false;
QSize showSize = newSize; QSize showSize = newSize;
QDesktopWidget* desktop = QApplication::desktop(); QRect screenRect = getScreenRect();
if (!desktop) { if (screenRect.isEmpty()) {
qWarning() << "QApplication::desktop() is nullptr"; qWarning() << "getScreenRect is empty";
return; return;
} }
QRect screenRect = desktop->availableGeometry();
if (vertical) { if (vertical) {
showSize.setHeight(qMin(newSize.height(), screenRect.height() - 200)); showSize.setHeight(qMin(newSize.height(), screenRect.height() - 200));
showSize.setWidth(showSize.height() * m_widthHeightRatio); showSize.setWidth(showSize.height() * m_widthHeightRatio);
@ -171,8 +372,8 @@ void VideoForm::updateShowSize(const QSize &newSize)
showSize.setHeight(showSize.width() / m_widthHeightRatio); showSize.setHeight(showSize.width() / m_widthHeightRatio);
} }
if (isFullScreen()) { if (isFullScreen() && m_device) {
switchFullScreen(); emit m_device->switchFullScreen();
} }
if (m_skin) { if (m_skin) {
QMargins m = getMargins(vertical); QMargins m = getMargins(vertical);
@ -190,7 +391,7 @@ void VideoForm::updateShowSize(const QSize &newSize)
} }
} }
void VideoForm::switchFullScreen() void VideoForm::onSwitchFullScreen()
{ {
if (isFullScreen()) { if (isFullScreen()) {
// 横屏全屏铺满全屏,恢复时,恢复保持宽高比 // 横屏全屏铺满全屏,恢复时,恢复保持宽高比
@ -253,39 +454,25 @@ void VideoForm::staysOnTop(bool top)
} }
} }
Controller *VideoForm::getController() void VideoForm::setDevice(Device *device)
{ {
return m_controller; m_device = device;
}
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;
} }
void VideoForm::mousePressEvent(QMouseEvent *event) 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_videoWidget->geometry().contains(event->pos())) {
if (!m_controller) { if (!m_device) {
return; return;
} }
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); 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 { } else {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
m_dragPosition = event->globalPos() - frameGeometry().topLeft(); m_dragPosition = event->globalPos() - frameGeometry().topLeft();
@ -297,7 +484,7 @@ void VideoForm::mousePressEvent(QMouseEvent *event)
void VideoForm::mouseReleaseEvent(QMouseEvent *event) void VideoForm::mouseReleaseEvent(QMouseEvent *event)
{ {
if (m_dragPosition.isNull()) { if (m_dragPosition.isNull()) {
if (!m_controller) { if (!m_device) {
return; return;
} }
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint()));
@ -316,7 +503,7 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
local.setY(m_videoWidget->height()); local.setY(m_videoWidget->height());
} }
event->setLocalPos(local); 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 { } else {
m_dragPosition = QPoint(0, 0); m_dragPosition = QPoint(0, 0);
} }
@ -325,11 +512,11 @@ void VideoForm::mouseReleaseEvent(QMouseEvent *event)
void VideoForm::mouseMoveEvent(QMouseEvent *event) void VideoForm::mouseMoveEvent(QMouseEvent *event)
{ {
if (m_videoWidget->geometry().contains(event->pos())) { if (m_videoWidget->geometry().contains(event->pos())) {
if (!m_controller) { if (!m_device) {
return; return;
} }
event->setLocalPos(m_videoWidget->mapFrom(this, event->localPos().toPoint())); 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()){ } else if (!m_dragPosition.isNull()){
if (event->buttons() & Qt::LeftButton) { if (event->buttons() & Qt::LeftButton) {
move(event->globalPos() - m_dragPosition); 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) void VideoForm::wheelEvent(QWheelEvent *event)
{ {
if (m_videoWidget->geometry().contains(event->pos())) { if (m_videoWidget->geometry().contains(event->pos())) {
if (!m_controller) { if (!m_device) {
return; return;
} }
QPointF pos = m_videoWidget->mapFrom(this, event->pos()); QPointF pos = m_videoWidget->mapFrom(this, event->pos());
@ -352,41 +551,30 @@ void VideoForm::wheelEvent(QWheelEvent *event)
*/ */
QWheelEvent wheelEvent(pos, event->globalPosF(), event->delta(), QWheelEvent wheelEvent(pos, event->globalPosF(), event->delta(),
event->buttons(), event->modifiers(), event->orientation()); 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) void VideoForm::keyPressEvent(QKeyEvent *event)
{ {
if (!m_device) {
return;
}
if (Qt::Key_Escape == event->key() if (Qt::Key_Escape == event->key()
&& !event->isAutoRepeat() && !event->isAutoRepeat()
&& isFullScreen()) { && isFullScreen()) {
switchFullScreen(); emit m_device->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;
} }
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) void VideoForm::keyReleaseEvent(QKeyEvent *event)
{ {
if (!m_controller) { if (!m_device) {
return; 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) 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) void VideoForm::dragEnterEvent(QDragEnterEvent *event)
{ {
event->acceptProposedAction(); event->acceptProposedAction();
@ -449,7 +646,7 @@ void VideoForm::dragLeaveEvent(QDragLeaveEvent *event)
void VideoForm::dropEvent(QDropEvent *event) void VideoForm::dropEvent(QDropEvent *event)
{ {
if (!m_fileHandler) { if (!m_device) {
return; return;
} }
const QMimeData* qm = event->mimeData(); const QMimeData* qm = event->mimeData();
@ -462,8 +659,8 @@ void VideoForm::dropEvent(QDropEvent *event)
} }
if (fileInfo.isFile() && fileInfo.suffix() == "apk") { if (fileInfo.isFile() && fileInfo.suffix() == "apk") {
m_fileHandler->installApkRequest(m_serial, file); emit m_device->installApkRequest(m_device->getSerial(), file);
return; 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; struct AVFrame;
class ToolForm; class ToolForm;
class Controller; class Device;
class FileHandler; class FileHandler;
class QYUVOpenGLWidget; class QYUVOpenGLWidget;
class VideoForm : public QWidget class VideoForm : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VideoForm(bool skin = true, QWidget *parent = 0); explicit VideoForm(bool framelessWindow = false, bool skin = true, QWidget *parent = 0);
~VideoForm(); ~VideoForm();
void switchFullScreen();
void staysOnTop(bool top = true); void staysOnTop(bool top = true);
void updateShowSize(const QSize &newSize); void updateShowSize(const QSize &newSize);
void updateRender(const AVFrame *frame); void updateRender(const AVFrame *frame);
void setController(Controller *controller); void setDevice(Device *device);
Controller* getController(); QRect getGrabCursorRect();
void setFileHandler(FileHandler *fileHandler); const QSize &frameSize();
void setSerial(const QString &serial); void resizeSquare();
const QString& getSerial(); void removeBlackRect();
signals:
void screenshot();
public slots: public slots:
void onGrabCursor(bool grab); void onSwitchFullScreen();
private: private:
void updateStyleSheet(bool vertical); void updateStyleSheet(bool vertical);
@ -43,11 +39,14 @@ private:
void showToolForm(bool show = true); void showToolForm(bool show = true);
void moveCenter(); void moveCenter();
void installShortcut();
QRect getScreenRect();
protected: protected:
void mousePressEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event);
void keyPressEvent(QKeyEvent *event); void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event); void keyReleaseEvent(QKeyEvent *event);
@ -55,6 +54,7 @@ protected:
void paintEvent(QPaintEvent *); void paintEvent(QPaintEvent *);
void showEvent(QShowEvent *event); void showEvent(QShowEvent *event);
void resizeEvent(QResizeEvent *event); void resizeEvent(QResizeEvent *event);
void closeEvent(QCloseEvent *event);
void dragEnterEvent(QDragEnterEvent *event); void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event); void dragMoveEvent(QDragMoveEvent *event);
@ -76,9 +76,7 @@ private:
QPoint m_fullScreenBeforePos; QPoint m_fullScreenBeforePos;
//outside member //outside member
QString m_serial = ""; QPointer<Device> m_device;
QPointer<Controller> m_controller;
QPointer<FileHandler> m_fileHandler;
}; };
#endif // VIDEOFORM_H #endif // VIDEOFORM_H

View file

@ -1,4 +1,7 @@
#include <QDebug> #include <QDebug>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QKeyEvent>
#include "devicemanage.h" #include "devicemanage.h"
#include "server.h" #include "server.h"
@ -44,6 +47,7 @@ bool DeviceManage::connectDevice(Device::DeviceParams params)
*/ */
Device *device = new Device(params); Device *device = new Device(params);
connect(device, &Device::deviceDisconnect, this, &DeviceManage::onDeviceDisconnect); connect(device, &Device::deviceDisconnect, this, &DeviceManage::onDeviceDisconnect);
connect(device, &Device::controlStateChange, this, &DeviceManage::onControlStateChange);
m_devices[params.serial] = device; m_devices[params.serial] = device;
return true; 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) void DeviceManage::onDeviceDisconnect(QString serial)
{ {
if (!serial.isEmpty() && m_devices.contains(serial)) { if (!serial.isEmpty() && m_devices.contains(serial)) {
if (m_devices[serial]->controlState() == Device::GroupControlState::GCS_HOST) {
setGroupControlHost(nullptr, false);
}
m_devices.remove(serial); 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 DeviceManage::getFreePort()
{ {
quint16 port = m_localPortStart; quint16 port = m_localPortStart;

View file

@ -20,8 +20,18 @@ public:
bool disconnectDevice(const QString &serial); bool disconnectDevice(const QString &serial);
void disconnectAllDevice(); void disconnectAllDevice();
protected:
void setGroupControlSignals(Device *host, Device *client, bool install);
void setGroupControlHost(Device *host, bool install);
protected slots: protected slots:
void onDeviceDisconnect(QString serial); 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: private:
quint16 getFreePort(); quint16 getFreePort();

View file

@ -98,6 +98,7 @@ void Dialog::initUI()
ui->formatBox->setCurrentIndex(Config::getInstance().getRecordFormatIndex()); ui->formatBox->setCurrentIndex(Config::getInstance().getRecordFormatIndex());
ui->recordPathEdt->setText(Config::getInstance().getRecordPath()); ui->recordPathEdt->setText(Config::getInstance().getRecordPath());
ui->framelessCheck->setChecked(Config::getInstance().getFramelessWindow());
#ifdef Q_OS_OSX #ifdef Q_OS_OSX
// mac need more width // mac need more width
@ -384,3 +385,9 @@ void Dialog::on_formatBox_activated(int index)
{ {
Config::getInstance().setRecordFormatIndex(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_formatBox_activated(int index);
void on_framelessCheck_stateChanged(int arg1);
private: private:
bool checkAdbRun(); bool checkAdbRun();
void initUI(); void initUI();

View file

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

Binary file not shown.

View file

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

Binary file not shown.

View file

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

View file

@ -44,6 +44,15 @@
#define COMMON_RECORD_FORMAT_INDEX_KEY "RecordFormatIndex" #define COMMON_RECORD_FORMAT_INDEX_KEY "RecordFormatIndex"
#define COMMON_RECORD_FORMAT_INDEX_DEF 0 #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 = ""; QString Config::s_configPath = "";
@ -140,6 +149,45 @@ void Config::setRecordFormatIndex(int recordFormatIndex)
m_userData->endGroup(); 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 Config::getServerVersion()
{ {
QString server; QString server;

View file

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

View file

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

View file

@ -1,6 +1,5 @@
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#include <QDebug> #include <QDebug>
#include <QWidget>
#include "cocoamousetap.h" #include "cocoamousetap.h"
@ -20,77 +19,55 @@ typedef struct MouseEventTapData{
CFMachPortRef tap = Q_NULLPTR; CFMachPortRef tap = Q_NULLPTR;
CFRunLoopRef runloop = Q_NULLPTR; CFRunLoopRef runloop = Q_NULLPTR;
CFRunLoopSourceRef runloopSource = Q_NULLPTR; CFRunLoopSourceRef runloopSource = Q_NULLPTR;
QWidget* widget = Q_NULLPTR; QRect rc;
} MouseEventTapData; } MouseEventTapData;
static CGEventRef Cocoa_MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) static CGEventRef Cocoa_MouseTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{ {
Q_UNUSED(proxy); Q_UNUSED(proxy);
MouseEventTapData *tapdata = (MouseEventTapData*)refcon; MouseEventTapData *tapdata = (MouseEventTapData*)refcon;
NSView *nsview;
NSWindow *nswindow;
NSRect windowRect;
NSRect newWindowRect;
CGPoint eventLocation;
switch (type) { switch (type) {
case kCGEventTapDisabledByTimeout: case kCGEventTapDisabledByTimeout:
{ {
CGEventTapEnable(tapdata->tap, true); CGEventTapEnable(tapdata->tap, true);
return NULL; return nullptr;
} }
case kCGEventTapDisabledByUserInput: case kCGEventTapDisabledByUserInput:
{ {
return NULL; return nullptr;
} }
default: default:
break; break;
} }
if (!tapdata->widget) { if (tapdata->rc.isEmpty()) {
return event; 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)) {
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 /* This is in CGs global screenspace coordinate system, which has a
* flipped Y. * flipped Y.
*/ */
CGPoint newLocation = CGEventGetLocation(event); CGPoint eventLocation = CGEventGetLocation(event);
if (!NSMouseInRect(NSPointFromCGPoint(eventLocation), checkWindowRect, NO)) {
if (eventLocation.x < NSMinX(windowRect)) { if (eventLocation.x <= NSMinX(limitWindowRect)) {
newLocation.x = NSMinX(windowRect); eventLocation.x = NSMinX(limitWindowRect) + 1.0;
} else if (eventLocation.x >= NSMaxX(windowRect)) { } else if (eventLocation.x >= NSMaxX(limitWindowRect)) {
newLocation.x = NSMaxX(windowRect) - 1.0; eventLocation.x = NSMaxX(limitWindowRect) - 1.0;
} }
if (eventLocation.y <= NSMinY(windowRect)) { if (eventLocation.y <= NSMinY(limitWindowRect)) {
newLocation.y -= (NSMinY(windowRect) - eventLocation.y + 1); eventLocation.y = NSMinY(limitWindowRect) + 1.0;
} else if (eventLocation.y > NSMaxY(windowRect)) { } else if (eventLocation.y >= NSMaxY(limitWindowRect)) {
newLocation.y += (eventLocation.y - NSMaxY(windowRect)); eventLocation.y = NSMaxY(limitWindowRect) - 1.0;
} }
CGWarpMouseCursorPosition(newLocation); CGWarpMouseCursorPosition(eventLocation);
CGAssociateMouseAndMouseCursorPosition(YES); CGAssociateMouseAndMouseCursorPosition(YES);
if ((CGEventMaskBit(type) & movementEventsMask) == 0) { 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 * movement events, since they mean that our warp cursor above
* behaves strangely. * 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) 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); CGEventTapEnable(m_tapData->tap, enabled);
} }
} }

View file

@ -1,12 +1,15 @@
#ifndef MOUSETAP_H #ifndef MOUSETAP_H
#define MOUSETAP_H #define MOUSETAP_H
#include <QRect>
class QWidget; class QWidget;
class MouseTap { class MouseTap {
public: public:
static MouseTap* getInstance(); static MouseTap* getInstance();
virtual void initMouseEventTap() = 0; virtual void initMouseEventTap() = 0;
virtual void quitMouseEventTap() = 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: private:
static MouseTap *s_instance; 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; return;
} }
if(enabled) { 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; RECT mainRect;
mainRect.left = (LONG)rc.left(); mainRect.left = (LONG)rc.left();
mainRect.right = (LONG)rc.right(); mainRect.right = (LONG)rc.right();

View file

@ -11,7 +11,7 @@ public:
void initMouseEventTap() override; void initMouseEventTap() override;
void quitMouseEventTap() override; void quitMouseEventTap() override;
void enableMouseEventTap(QWidget* widget, bool enabled) override; void enableMouseEventTap(QRect rc, bool enabled) override;
}; };
#endif // WINMOUSETAP_H #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 - Display Android device screens in real time
- Real-time mouse and keyboard control of Android devices - Real-time mouse and keyboard control of Android devices
- Screen recording - Screen recording
- Screenshot to png
- Wireless connection - 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) - 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 - 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`+`Shift`+`v` copies the computer clipboard to the device clipboard;
- `Ctrl`+`v` _pastes_ the computer clipboard as a sequence of text events (but - `Ctrl`+`v` _pastes_ the computer clipboard as a sequence of text events (but
breaks non-ASCII characters). 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
[TODO](docs/TODO.md) [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. All the dependencies are provided and it is easy to compile.
### PC client ### 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 2. Clone the project
3. Open the project root directory all.pro with QtCreator 3. Open the project root directory all.pro with QtCreator
4. Compile and run 4. Compile and run

View file

@ -163,6 +163,7 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
- 实时显示Android设备屏幕 - 实时显示Android设备屏幕
- 实时键鼠控制Android设备 - 实时键鼠控制Android设备
- 屏幕录制 - 屏幕录制
- 截图为png
- 无线连接 - 无线连接
- 最多支持16台设备连接PC性能允许的情况下可以增加需要自己编译 - 最多支持16台设备连接PC性能允许的情况下可以增加需要自己编译
- 全屏显示 - 全屏显示
@ -176,6 +177,33 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
- `Ctrl` + `c`将设备剪贴板复制到计算机剪贴板; - `Ctrl` + `c`将设备剪贴板复制到计算机剪贴板;
- `Ctrl` + `Shift` + `v`将计算机剪贴板复制到设备剪贴板; - `Ctrl` + `Shift` + `v`将计算机剪贴板复制到设备剪贴板;
- `Ctrl` +`v` 将计算机剪贴板作为一系列文本事件发送到设备不支持非ASCII字符 - `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 ## TODO
[后期计划](docs/TODO.md) [后期计划](docs/TODO.md)
@ -198,7 +226,7 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
尽量提供了所有依赖资源,方便傻瓜式编译。 尽量提供了所有依赖资源,方便傻瓜式编译。
### PC端 ### PC端
1. 目标平台上搭建Qt开发环境(Qt >= 5.9.7, vs >= 2015 (**不支持mingw**)) 1. 目标平台上搭建Qt开发环境(Qt >= 5.12.0, vs >= 2017 (**不支持mingw**))
2. 克隆该项目 2. 克隆该项目
3. 使用QtCreator打开项目根目录all.pro 3. 使用QtCreator打开项目根目录all.pro
4. 编译,运行即可 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群里提问。 如果在此文档没有解决你的问题描述你的问题截图软件控制台中打印的日志一起发到QQ群里提问。
## 支持声音(软件不做支持)
[关于转发安卓声音到PC的讨论](https://github.com/Genymobile/scrcpy/issues/14#issuecomment-543204526)
## 无法输入中文 ## 无法输入中文
安装搜狗输入法/QQ输入法就可以支持输入中文了 手机端安装搜狗输入法/QQ输入法就可以支持输入中文了
## 可以看到画面,但无法控制 ## 可以看到画面,但无法控制
有些手机(小米等手机)需要额外打开控制权限检查是否USB调试里打开了允许模拟点击 有些手机(小米等手机)需要额外打开控制权限检查是否USB调试里打开了允许模拟点击
![image](image/USB调试(安全设置).jpg) ![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
导致这个错误的原因有很多,最简单的解决方法是在分辨率设置中,选择一个较低的分辨率 导致这个错误的原因有很多,最简单的解决方法是在分辨率设置中,选择一个较低的分辨率
## 声音 ## 错误信息QOpenGLShaderProgram::attributeLocation(vertexIn): shader program is not linked
[关于转发安卓声音到PC的讨论](https://github.com/Genymobile/scrcpy/issues/14#issuecomment-543204526) 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) - opengles 3.0 兼容性参考[这里](https://github.com/libretro/glsl-shaders/blob/master/nnedi3/shaders/yuv-to-rgb-2x.glsl)