feat: sync scrcpy

This commit is contained in:
Barry 2021-03-06 20:48:05 +08:00
commit b5a7b8b399
22 changed files with 121 additions and 42 deletions

View file

@ -109,6 +109,16 @@ void Controller::onPostVolumeDown()
postKeyCodeClick(AKEYCODE_VOLUME_DOWN); postKeyCodeClick(AKEYCODE_VOLUME_DOWN);
} }
void Controller::onCopy()
{
postKeyCodeClick(AKEYCODE_COPY);
}
void Controller::onCut()
{
postKeyCodeClick(AKEYCODE_CUT);
}
void Controller::onExpandNotificationPanel() void Controller::onExpandNotificationPanel()
{ {
ControlMsg *controlMsg = new ControlMsg(ControlMsg::CMT_EXPAND_NOTIFICATION_PANEL); ControlMsg *controlMsg = new ControlMsg(ControlMsg::CMT_EXPAND_NOTIFICATION_PANEL);
@ -136,7 +146,7 @@ void Controller::onRequestDeviceClipboard()
postControlMsg(controlMsg); postControlMsg(controlMsg);
} }
void Controller::onSetDeviceClipboard() void Controller::onSetDeviceClipboard(bool pause)
{ {
QClipboard *board = QApplication::clipboard(); QClipboard *board = QApplication::clipboard();
QString text = board->text(); QString text = board->text();
@ -144,7 +154,7 @@ void Controller::onSetDeviceClipboard()
if (!controlMsg) { if (!controlMsg) {
return; return;
} }
controlMsg->setSetClipboardMsgData(text, true); controlMsg->setSetClipboardMsgData(text, pause);
postControlMsg(controlMsg); postControlMsg(controlMsg);
} }
@ -226,13 +236,13 @@ void Controller::postKeyCodeClick(AndroidKeycode keycode)
if (!controlEventDown) { if (!controlEventDown) {
return; return;
} }
controlEventDown->setInjectKeycodeMsgData(AKEY_EVENT_ACTION_DOWN, keycode, AMETA_NONE); controlEventDown->setInjectKeycodeMsgData(AKEY_EVENT_ACTION_DOWN, keycode, 0, AMETA_NONE);
postControlMsg(controlEventDown); postControlMsg(controlEventDown);
ControlMsg *controlEventUp = new ControlMsg(ControlMsg::CMT_INJECT_KEYCODE); ControlMsg *controlEventUp = new ControlMsg(ControlMsg::CMT_INJECT_KEYCODE);
if (!controlEventUp) { if (!controlEventUp) {
return; return;
} }
controlEventUp->setInjectKeycodeMsgData(AKEY_EVENT_ACTION_UP, keycode, AMETA_NONE); controlEventUp->setInjectKeycodeMsgData(AKEY_EVENT_ACTION_UP, keycode, 0, AMETA_NONE);
postControlMsg(controlEventUp); postControlMsg(controlEventUp);
} }

View file

@ -31,6 +31,8 @@ public slots:
void onPostPower(); void onPostPower();
void onPostVolumeUp(); void onPostVolumeUp();
void onPostVolumeDown(); void onPostVolumeDown();
void onCopy();
void onCut();
void onExpandNotificationPanel(); void onExpandNotificationPanel();
void onCollapseNotificationPanel(); void onCollapseNotificationPanel();
void onSetScreenPowerMode(ControlMsg::ScreenPowerMode mode); void onSetScreenPowerMode(ControlMsg::ScreenPowerMode mode);
@ -43,7 +45,7 @@ public slots:
// turn the screen on if it was off, press BACK otherwise // turn the screen on if it was off, press BACK otherwise
void onPostBackOrScreenOn(); void onPostBackOrScreenOn();
void onRequestDeviceClipboard(); void onRequestDeviceClipboard();
void onSetDeviceClipboard(); void onSetDeviceClipboard(bool pause = true);
void onClipboardPaste(); void onClipboardPaste();
void onPostTextInput(QString &text); void onPostTextInput(QString &text);

View file

@ -19,10 +19,11 @@ ControlMsg::~ControlMsg()
} }
} }
void ControlMsg::setInjectKeycodeMsgData(AndroidKeyeventAction action, AndroidKeycode keycode, AndroidMetastate metastate) void ControlMsg::setInjectKeycodeMsgData(AndroidKeyeventAction action, AndroidKeycode keycode, quint32 repeat, AndroidMetastate metastate)
{ {
m_data.injectKeycode.action = action; m_data.injectKeycode.action = action;
m_data.injectKeycode.keycode = keycode; m_data.injectKeycode.keycode = keycode;
m_data.injectKeycode.repeat = repeat;
m_data.injectKeycode.metastate = metastate; m_data.injectKeycode.metastate = metastate;
} }
@ -105,10 +106,11 @@ QByteArray ControlMsg::serializeData()
case CMT_INJECT_KEYCODE: case CMT_INJECT_KEYCODE:
buffer.putChar(m_data.injectKeycode.action); buffer.putChar(m_data.injectKeycode.action);
BufferUtil::write32(buffer, m_data.injectKeycode.keycode); BufferUtil::write32(buffer, m_data.injectKeycode.keycode);
BufferUtil::write32(buffer, m_data.injectKeycode.repeat);
BufferUtil::write32(buffer, m_data.injectKeycode.metastate); BufferUtil::write32(buffer, m_data.injectKeycode.metastate);
break; break;
case CMT_INJECT_TEXT: case CMT_INJECT_TEXT:
BufferUtil::write16(buffer, static_cast<quint32>(strlen(m_data.injectText.text))); BufferUtil::write32(buffer, static_cast<quint32>(strlen(m_data.injectText.text)));
buffer.write(m_data.injectText.text, strlen(m_data.injectText.text)); buffer.write(m_data.injectText.text, strlen(m_data.injectText.text));
break; break;
case CMT_INJECT_TOUCH: { case CMT_INJECT_TOUCH: {

View file

@ -9,9 +9,15 @@
#include "keycodes.h" #include "keycodes.h"
#include "qscrcpyevent.h" #include "qscrcpyevent.h"
#define CONTROL_MSG_MAX_SIZE (1 << 18) // 256k
#define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300 #define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH 4092 // type: 1 byte; paste flag: 1 byte; length: 4 bytes
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH \
(CONTROL_MSG_MAX_SIZE - 6)
#define POINTER_ID_MOUSE static_cast<quint64>(-1) #define POINTER_ID_MOUSE static_cast<quint64>(-1)
// ControlMsg // ControlMsg
class ControlMsg : public QScrcpyEvent class ControlMsg : public QScrcpyEvent
{ {
@ -41,7 +47,7 @@ public:
ControlMsg(ControlMsgType controlMsgType); ControlMsg(ControlMsgType controlMsgType);
virtual ~ControlMsg(); virtual ~ControlMsg();
void setInjectKeycodeMsgData(AndroidKeyeventAction action, AndroidKeycode keycode, AndroidMetastate metastate); void setInjectKeycodeMsgData(AndroidKeyeventAction action, AndroidKeycode keycode, quint32 repeat, AndroidMetastate metastate);
void setInjectTextMsgData(QString &text); void setInjectTextMsgData(QString &text);
// id 代表一个触摸点最多支持10个触摸点[0,9] // id 代表一个触摸点最多支持10个触摸点[0,9]
// action 只能是AMOTION_EVENT_ACTION_DOWNAMOTION_EVENT_ACTION_UPAMOTION_EVENT_ACTION_MOVE // action 只能是AMOTION_EVENT_ACTION_DOWNAMOTION_EVENT_ACTION_UPAMOTION_EVENT_ACTION_MOVE
@ -67,6 +73,7 @@ private:
{ {
AndroidKeyeventAction action; AndroidKeyeventAction action;
AndroidKeycode keycode; AndroidKeycode keycode;
quint32 repeat;
AndroidMetastate metastate; AndroidMetastate metastate;
} injectKeycode; } injectKeycode;
struct struct

View file

@ -32,7 +32,6 @@ signals:
protected: protected:
void sendControlMsg(ControlMsg *msg); void sendControlMsg(ControlMsg *msg);
private:
QPointer<Controller> m_controller; QPointer<Controller> m_controller;
}; };

View file

@ -176,11 +176,15 @@ void InputConvertGame::sendTouchEvent(int id, QPointF pos, AndroidMotioneventAct
QPoint absolutePos = calcFrameAbsolutePos(pos).toPoint(); QPoint absolutePos = calcFrameAbsolutePos(pos).toPoint();
static QPoint lastAbsolutePos = absolutePos; static QPoint lastAbsolutePos = absolutePos;
if (AMOTION_EVENT_ACTION_MOVE == action && lastAbsolutePos == absolutePos) { if (AMOTION_EVENT_ACTION_MOVE == action && lastAbsolutePos == absolutePos) {
delete controlMsg;
return; return;
} }
lastAbsolutePos = absolutePos; lastAbsolutePos = absolutePos;
controlMsg->setInjectTouchMsgData(static_cast<quint64>(id), action, static_cast<AndroidMotioneventButtons>(0), QRect(absolutePos, m_frameSize), 1.0f); controlMsg->setInjectTouchMsgData(static_cast<quint64>(id), action,
static_cast<AndroidMotioneventButtons>(0),
QRect(absolutePos, m_frameSize),
AMOTION_EVENT_ACTION_DOWN == action? 1.0f : 0.0f);
sendControlMsg(controlMsg); sendControlMsg(controlMsg);
} }

View file

@ -1,6 +1,7 @@
#include <cmath> #include <cmath>
#include "inputconvertnormal.h" #include "inputconvertnormal.h"
#include "controller.h"
InputConvertNormal::InputConvertNormal(Controller *controller) : InputConvertBase(controller) {} InputConvertNormal::InputConvertNormal(Controller *controller) : InputConvertBase(controller) {}
@ -44,7 +45,10 @@ void InputConvertNormal::mouseEvent(const QMouseEvent *from, const QSize &frameS
return; return;
} }
controlMsg->setInjectTouchMsgData( controlMsg->setInjectTouchMsgData(
static_cast<quint64>(POINTER_ID_MOUSE), action, convertMouseButtons(from->buttons()), QRect(pos.toPoint(), frameSize), 1.0f); static_cast<quint64>(POINTER_ID_MOUSE), action,
convertMouseButtons(from->buttons()),
QRect(pos.toPoint(), frameSize),
AMOTION_EVENT_ACTION_DOWN == action? 1.0f : 0.0f);
sendControlMsg(controlMsg); sendControlMsg(controlMsg);
} }
@ -81,6 +85,19 @@ void InputConvertNormal::keyEvent(const QKeyEvent *from, const QSize &frameSize,
return; return;
} }
bool ctrl = from->modifiers() & Qt::ControlModifier;
bool shift = from->modifiers() & Qt::ShiftModifier;
bool down = from->type() == QEvent::KeyPress;
bool repeat = from->isAutoRepeat();
if (ctrl && !shift && from->key() == Qt::Key_V && down && !repeat) {
// Synchronize the computer clipboard to the device clipboard before
// sending Ctrl+v, to allow seamless copy-paste.
if (m_controller) {
m_controller->onSetDeviceClipboard(false);
}
}
// action // action
AndroidKeyeventAction action; AndroidKeyeventAction action;
switch (from->type()) { switch (from->type()) {
@ -105,7 +122,7 @@ void InputConvertNormal::keyEvent(const QKeyEvent *from, const QSize &frameSize,
if (!controlMsg) { if (!controlMsg) {
return; return;
} }
controlMsg->setInjectKeycodeMsgData(action, keyCode, convertMetastate(from->modifiers())); controlMsg->setInjectKeycodeMsgData(action, keyCode, 0, convertMetastate(from->modifiers()));
sendControlMsg(controlMsg); sendControlMsg(controlMsg);
} }

View file

@ -32,7 +32,7 @@ qint32 DeviceMsg::deserialize(QByteArray &byteArray)
char c = 0; char c = 0;
qint32 ret = 0; qint32 ret = 0;
if (len < 3) { if (len < 5) {
// at least type + empty string length // at least type + empty string length
return 0; // not available return 0; // not available
} }
@ -42,8 +42,8 @@ qint32 DeviceMsg::deserialize(QByteArray &byteArray)
switch (m_data.type) { switch (m_data.type) {
case DMT_GET_CLIPBOARD: { case DMT_GET_CLIPBOARD: {
m_data.clipboardMsg.text = Q_NULLPTR; m_data.clipboardMsg.text = Q_NULLPTR;
quint16 clipboardLen = BufferUtil::read16(buf); quint16 clipboardLen = BufferUtil::read32(buf);
if (clipboardLen > len - 3) { if (clipboardLen > len - 5) {
ret = 0; // not available ret = 0; // not available
break; break;
} }
@ -53,7 +53,7 @@ qint32 DeviceMsg::deserialize(QByteArray &byteArray)
memcpy(m_data.clipboardMsg.text, text.data(), text.length()); memcpy(m_data.clipboardMsg.text, text.data(), text.length());
m_data.clipboardMsg.text[text.length()] = '\0'; m_data.clipboardMsg.text[text.length()] = '\0';
ret = 3 + clipboardLen; ret = 5 + clipboardLen;
break; break;
} }
default: default:

View file

@ -3,9 +3,9 @@
#include <QBuffer> #include <QBuffer>
#define DEVICE_MSG_QUEUE_SIZE 64 #define DEVICE_MSG_MAX_SIZE (1 << 18) // 256k
#define DEVICE_MSG_TEXT_MAX_LENGTH 4093 // type: 1 byte; length: 4 bytes
#define DEVICE_MSG_SERIALIZED_MAX_SIZE (3 + DEVICE_MSG_TEXT_MAX_LENGTH) #define DEVICE_MSG_TEXT_MAX_LENGTH (DEVICE_MSG_MAX_SIZE - 5)
class DeviceMsg : public QObject class DeviceMsg : public QObject
{ {

View file

@ -44,6 +44,11 @@ void Receiver::processMsg(DeviceMsg *deviceMsg)
QClipboard *board = QApplication::clipboard(); QClipboard *board = QApplication::clipboard();
QString text; QString text;
deviceMsg->getClipboardMsgData(text); deviceMsg->getClipboardMsgData(text);
if (board->text() == text) {
qDebug("Computer clipboard unchanged");
break;
}
board->setText(text); board->setText(text);
break; break;
} }

View file

@ -151,6 +151,8 @@ void Device::initSignals()
connect(this, &Device::postPower, m_controller, &Controller::onPostPower); connect(this, &Device::postPower, m_controller, &Controller::onPostPower);
connect(this, &Device::postVolumeUp, m_controller, &Controller::onPostVolumeUp); connect(this, &Device::postVolumeUp, m_controller, &Controller::onPostVolumeUp);
connect(this, &Device::postVolumeDown, m_controller, &Controller::onPostVolumeDown); connect(this, &Device::postVolumeDown, m_controller, &Controller::onPostVolumeDown);
connect(this, &Device::postCopy, m_controller, &Controller::onCopy);
connect(this, &Device::postCut, m_controller, &Controller::onCut);
connect(this, &Device::setScreenPowerMode, m_controller, &Controller::onSetScreenPowerMode); connect(this, &Device::setScreenPowerMode, m_controller, &Controller::onSetScreenPowerMode);
connect(this, &Device::expandNotificationPanel, m_controller, &Controller::onExpandNotificationPanel); connect(this, &Device::expandNotificationPanel, m_controller, &Controller::onExpandNotificationPanel);
connect(this, &Device::collapseNotificationPanel, m_controller, &Controller::onCollapseNotificationPanel); connect(this, &Device::collapseNotificationPanel, m_controller, &Controller::onCollapseNotificationPanel);
@ -159,7 +161,6 @@ void Device::initSignals()
connect(this, &Device::keyEvent, m_controller, &Controller::onKeyEvent); connect(this, &Device::keyEvent, m_controller, &Controller::onKeyEvent);
connect(this, &Device::postBackOrScreenOn, m_controller, &Controller::onPostBackOrScreenOn); 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::setDeviceClipboard, m_controller, &Controller::onSetDeviceClipboard);
connect(this, &Device::clipboardPaste, m_controller, &Controller::onClipboardPaste); connect(this, &Device::clipboardPaste, m_controller, &Controller::onClipboardPaste);
connect(this, &Device::postTextInput, m_controller, &Controller::onPostTextInput); connect(this, &Device::postTextInput, m_controller, &Controller::onPostTextInput);

View file

@ -70,13 +70,15 @@ signals:
void postPower(); void postPower();
void postVolumeUp(); void postVolumeUp();
void postVolumeDown(); void postVolumeDown();
void postCopy();
void postCut();
void setScreenPowerMode(ControlMsg::ScreenPowerMode mode); void setScreenPowerMode(ControlMsg::ScreenPowerMode mode);
void expandNotificationPanel(); void expandNotificationPanel();
void collapseNotificationPanel(); void collapseNotificationPanel();
void postBackOrScreenOn(); void postBackOrScreenOn();
void postTextInput(QString &text); void postTextInput(QString &text);
void requestDeviceClipboard(); void requestDeviceClipboard();
void setDeviceClipboard(); void setDeviceClipboard(bool pause = true);
void clipboardPaste(); void clipboardPaste();
void pushFileRequest(const QString &file, const QString &devicePath = ""); void pushFileRequest(const QString &file, const QString &devicePath = "");
void installApkRequest(const QString &apkFile); void installApkRequest(const QString &apkFile);

View file

@ -162,6 +162,7 @@ bool Server::execute()
// https://github.com/Genymobile/scrcpy/commit/080a4ee3654a9b7e96c8ffe37474b5c21c02852a // https://github.com/Genymobile/scrcpy/commit/080a4ee3654a9b7e96c8ffe37474b5c21c02852a
// <https://d.android.com/reference/android/media/MediaFormat> // <https://d.android.com/reference/android/media/MediaFormat>
args << Config::getInstance().getCodecOptions(); args << Config::getInstance().getCodecOptions();
args << Config::getInstance().getCodecName();
#ifdef SERVER_DEBUGGER #ifdef SERVER_DEBUGGER
qInfo("Server debugger waiting for a client on device port " SERVER_DEBUGGER_PORT "..."); qInfo("Server debugger waiting for a client on device port " SERVER_DEBUGGER_PORT "...");

View file

@ -201,7 +201,7 @@ void VideoForm::installShortcut()
connect(shortcut, &QShortcut::activated, this, [this]() { resizeSquare(); }); connect(shortcut, &QShortcut::activated, this, [this]() { resizeSquare(); });
// removeBlackRect // removeBlackRect
shortcut = new QShortcut(QKeySequence("Ctrl+x"), this); shortcut = new QShortcut(QKeySequence("Ctrl+w"), this);
connect(shortcut, &QShortcut::activated, this, [this]() { removeBlackRect(); }); connect(shortcut, &QShortcut::activated, this, [this]() { removeBlackRect(); });
// postGoHome // postGoHome
@ -294,13 +294,22 @@ void VideoForm::installShortcut()
emit m_device->collapseNotificationPanel(); emit m_device->collapseNotificationPanel();
}); });
// requestDeviceClipboard // copy
shortcut = new QShortcut(QKeySequence("Ctrl+c"), this); shortcut = new QShortcut(QKeySequence("Ctrl+c"), this);
connect(shortcut, &QShortcut::activated, this, [this]() { connect(shortcut, &QShortcut::activated, this, [this]() {
if (!m_device) { if (!m_device) {
return; return;
} }
emit m_device->requestDeviceClipboard(); emit m_device->postCopy();
});
// cut
shortcut = new QShortcut(QKeySequence("Ctrl+x"), this);
connect(shortcut, &QShortcut::activated, this, [this]() {
if (!m_device) {
return;
}
emit m_device->postCut();
}); });
// clipboardPaste // clipboardPaste
@ -309,7 +318,7 @@ void VideoForm::installShortcut()
if (!m_device) { if (!m_device) {
return; return;
} }
emit m_device->clipboardPaste(); emit m_device->setDeviceClipboard();
}); });
// setDeviceClipboard // setDeviceClipboard
@ -318,7 +327,7 @@ void VideoForm::installShortcut()
if (!m_device) { if (!m_device) {
return; return;
} }
emit m_device->setDeviceClipboard(); emit m_device->clipboardPaste();
}); });
} }

View file

@ -139,8 +139,6 @@ void DeviceManage::setGroupControlSignals(Device *host, Device *client, bool ins
connect(host, &Device::installApkRequest, client, &Device::installApkRequest); connect(host, &Device::installApkRequest, client, &Device::installApkRequest);
connect(host, &Device::screenshot, client, &Device::screenshot); connect(host, &Device::screenshot, client, &Device::screenshot);
connect(host, &Device::showTouch, client, &Device::showTouch); connect(host, &Device::showTouch, client, &Device::showTouch);
// dont connect requestDeviceClipboard
//connect(host, &Device::requestDeviceClipboard, client, &Device::requestDeviceClipboard);
} else { } else {
disconnect(host, &Device::postGoBack, client, &Device::postGoBack); disconnect(host, &Device::postGoBack, client, &Device::postGoBack);
disconnect(host, &Device::postGoHome, client, &Device::postGoHome); disconnect(host, &Device::postGoHome, client, &Device::postGoHome);

View file

@ -14,7 +14,7 @@
#define COMMON_PUSHFILE_DEF "/sdcard/" #define COMMON_PUSHFILE_DEF "/sdcard/"
#define COMMON_SERVER_VERSION_KEY "ServerVersion" #define COMMON_SERVER_VERSION_KEY "ServerVersion"
#define COMMON_SERVER_VERSION_DEF "1.14" #define COMMON_SERVER_VERSION_DEF "1.17"
#define COMMON_SERVER_PATH_KEY "ServerPath" #define COMMON_SERVER_PATH_KEY "ServerPath"
#define COMMON_SERVER_PATH_DEF "/data/local/tmp/scrcpy-server.jar" #define COMMON_SERVER_PATH_DEF "/data/local/tmp/scrcpy-server.jar"
@ -40,6 +40,9 @@
#define COMMON_CODEC_OPTIONS_KEY "CodecOptions" #define COMMON_CODEC_OPTIONS_KEY "CodecOptions"
#define COMMON_CODEC_OPTIONS_DEF "-" #define COMMON_CODEC_OPTIONS_DEF "-"
#define COMMON_CODEC_NAME_KEY "CodecName"
#define COMMON_CODEC_NAME_DEF "-"
// user data // user data
#define COMMON_RECORD_KEY "RecordPath" #define COMMON_RECORD_KEY "RecordPath"
#define COMMON_RECORD_DEF "" #define COMMON_RECORD_DEF ""
@ -289,6 +292,15 @@ QString Config::getCodecOptions()
return codecOptions; return codecOptions;
} }
QString Config::getCodecName()
{
QString codecName;
m_settings->beginGroup(GROUP_COMMON);
codecName = m_settings->value(COMMON_CODEC_NAME_KEY, COMMON_CODEC_NAME_DEF).toString();
m_settings->endGroup();
return codecName;
}
QString Config::getTitle() QString Config::getTitle()
{ {
QString title; QString title;

View file

@ -23,6 +23,7 @@ public:
QString getAdbPath(); QString getAdbPath();
QString getLogLevel(); QString getLogLevel();
QString getCodecOptions(); QString getCodecOptions();
QString getCodecName();
// user data // user data
QString getRecordPath(); QString getRecordPath();

View file

@ -194,7 +194,7 @@ Note: it is not necessary to keep you Android device connected via USB after you
| -------------------------------------- |:----------------------------- |:----------------------------- | -------------------------------------- |:----------------------------- |:-----------------------------
| Switch fullscreen mode | `Ctrl`+`f` | `Cmd`+`f` | Switch fullscreen mode | `Ctrl`+`f` | `Cmd`+`f`
| Resize window to 1:1 (pixel-perfect) | `Ctrl`+`g` | `Cmd`+`g` | 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¹_ | Resize window to remove black borders | `Ctrl`+`w` \| _Double-click¹_ | `Cmd`+`w` \| _Double-click¹_
| Click on `HOME` | `Ctrl`+`h` \| _Middle-click_ | `Ctrl`+`h` \| _Middle-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 `BACK` | `Ctrl`+`b` \| _Right-click²_ | `Cmd`+`b` \| _Right-click²_
| Click on `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s` | Click on `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s`
@ -206,14 +206,17 @@ Note: it is not necessary to keep you Android device connected via USB after you
| Turn device screen off (keep mirroring)| `Ctrl`+`o` | `Cmd`+`o` | Turn device screen off (keep mirroring)| `Ctrl`+`o` | `Cmd`+`o`
| Expand notification panel | `Ctrl`+`n` | `Cmd`+`n` | Expand notification panel | `Ctrl`+`n` | `Cmd`+`n`
| Collapse notification panel | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n` | Collapse notification panel | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| Copy device clipboard to computer | `Ctrl`+`c` | `Cmd`+`c` | Copy to clipboard³ | `Ctrl`+`c` | `Cmd`+`c`
| Paste computer clipboard to device | `Ctrl`+`v` | `Cmd`+`v` | Cut to clipboard³ | `Ctrl`+`x` | `Cmd`+`x`
| Copy computer clipboard to device | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v` | Synchronize clipboards and paste³ | `Ctrl`+`v` | `Cmd`+`v`
| Inject computer clipboard text | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
_¹Double-click on black borders to remove them._ _¹Double-click on black borders to remove them._
_²Right-click turns the screen on if it was off, presses BACK otherwise._ _²Right-click turns the screen on if it was off, presses BACK otherwise._
_³Only on Android >= 7._
## TODO ## TODO
[TODO](docs/TODO.md) [TODO](docs/TODO.md)
@ -241,7 +244,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.15.0, vs == 2017 (mingw not supported)) 1. Set up the Qt development environment on the target platform (Qt == 5.15.2, vs == 2019 (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

@ -193,7 +193,7 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
| -------------------------------------- |:----------------------------- |:----------------------------- | -------------------------------------- |:----------------------------- |:-----------------------------
| 切换全屏 | `Ctrl`+`f` | `Cmd`+`f` | 切换全屏 | `Ctrl`+`f` | `Cmd`+`f`
| 调整窗口大小为 1:1 | `Ctrl`+`g` | `Cmd`+`g` | 调整窗口大小为 1:1 | `Ctrl`+`g` | `Cmd`+`g`
| 调整窗口大小去除黑边 | `Ctrl`+`x` \| _左键双击_ | `Cmd`+`x` \| _左键双击_ | 调整窗口大小去除黑边 | `Ctrl`+`w` \| _左键双击_ | `Cmd`+`w` \| _左键双击_
| 点击 `主页` | `Ctrl`+`h` \| _点击鼠标中键_ | `Ctrl`+`h` \| _点击鼠标中键_ | 点击 `主页` | `Ctrl`+`h` \| _点击鼠标中键_ | `Ctrl`+`h` \| _点击鼠标中键_
| 点击 `BACK` | `Ctrl`+`b` \| _右键双击_ | `Cmd`+`b` \| _右键双击_ | 点击 `BACK` | `Ctrl`+`b` \| _右键双击_ | `Cmd`+`b` \| _右键双击_
| 点击 `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s` | 点击 `APP_SWITCH` | `Ctrl`+`s` | `Cmd`+`s`
@ -205,9 +205,10 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
| 关闭屏幕 (保持投屏) | `Ctrl`+`o` | `Cmd`+`o` | 关闭屏幕 (保持投屏) | `Ctrl`+`o` | `Cmd`+`o`
| 打开下拉菜单 | `Ctrl`+`n` | `Cmd`+`n` | 打开下拉菜单 | `Ctrl`+`n` | `Cmd`+`n`
| 关闭下拉菜单 | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n` | 关闭下拉菜单 | `Ctrl`+`Shift`+`n` | `Cmd`+`Shift`+`n`
| 复制设备剪切板到电脑 | `Ctrl`+`c` | `Cmd`+`c` | 复制到剪切板 | `Ctrl`+`c` | `Cmd`+`c`
| 粘贴电脑剪切板到设备 | `Ctrl`+`v` | `Cmd`+`v` | 剪切到剪切板 | `Ctrl`+`x` | `Cmd`+`x`
| 复制电脑剪切板到设备 | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v` | 同步剪切板并粘贴 | `Ctrl`+`v` | `Cmd`+`v`
| 注入电脑剪切板文本 | `Ctrl`+`Shift`+`v` | `Cmd`+`Shift`+`v`
鼠标左键双击黑色区域可以去除黑色区域 鼠标左键双击黑色区域可以去除黑色区域
@ -240,7 +241,7 @@ Mac OS平台你可以直接使用我编译好的可执行程序:
尽量提供了所有依赖资源,方便傻瓜式编译。 尽量提供了所有依赖资源,方便傻瓜式编译。
### PC端 ### PC端
1. 目标平台上搭建Qt开发环境(Qt == 5.15, vs == 2017 (**不支持mingw**)) 1. 目标平台上搭建Qt开发环境(Qt == 5.15.2, vs == 2019 (**不支持mingw**))
2. 克隆该项目 2. 克隆该项目
3. 使用QtCreator打开项目根目录all.pro 3. 使用QtCreator打开项目根目录all.pro
4. 编译,运行即可 4. 编译,运行即可

View file

@ -10,7 +10,7 @@ RenderExpiredFrames=0
# 视频解码方式:-1 自动0 软解1 dx硬解2 opengl硬解 # 视频解码方式:-1 自动0 软解1 dx硬解2 opengl硬解
UseDesktopOpenGL=-1 UseDesktopOpenGL=-1
# scrcpy-server的版本号不要修改 # scrcpy-server的版本号不要修改
ServerVersion=1.14 ServerVersion=1.17
# scrcpy-server推送到安卓设备的路径 # scrcpy-server推送到安卓设备的路径
ServerPath=/data/local/tmp/scrcpy-server.jar ServerPath=/data/local/tmp/scrcpy-server.jar
# 自定义adb路径例如D:/android/tools/adb.exe # 自定义adb路径例如D:/android/tools/adb.exe
@ -19,6 +19,9 @@ AdbPath=
# 例如 CodecOptions="profile=1,level=2" # 例如 CodecOptions="profile=1,level=2"
# 更多编码选项参考 https://d.android.com/reference/android/media/MediaFormat # 更多编码选项参考 https://d.android.com/reference/android/media/MediaFormat
CodecOptions="-" CodecOptions="-"
# 指定编码器名称必须是H.264编码器
# 例如 CodecName="OMX.qcom.video.encoder.avc"
CodecName="-"
# Set the log level (debug, info, warn, error) # Set the log level (debug, info, warn, error)
LogLevel=info LogLevel=info

View file

@ -1,4 +1,4 @@
最后同步scrcpy 3c0fc8f54f42bf6e7eca35b352a7d343749b65c4 最后同步scrcpy 08baaf4b575aef7ee56d14683be3f4e3a86d39aa
# TODO # TODO
## 低优先级 ## 低优先级
@ -12,6 +12,8 @@
- 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)
- 通过host:track-devices实现自动连接 https://www.jianshu.com/p/2cb86c6de76c - 通过host:track-devices实现自动连接 https://www.jianshu.com/p/2cb86c6de76c
- 旋转 https://github.com/Genymobile/scrcpy/commit/d48b375a1dbc8bed92e3424b5967e59c2d8f6ca1 - 旋转 https://github.com/Genymobile/scrcpy/commit/d48b375a1dbc8bed92e3424b5967e59c2d8f6ca1
- 禁用屏幕保护 https://github.com/Genymobile/scrcpy/commit/dc7b60e6199b90a45ea26751988f6f30f8b2efdf
- 自定义快捷键 https://github.com/Genymobile/scrcpy/commit/1b76d9fd78c3a88a8503a72d4cd2f65bdb836aa4
## 高优先级 ## 高优先级
- linux打包以及版本号 - linux打包以及版本号

Binary file not shown.