Skip to content

Commit

Permalink
Merge pull request #220 from barry-ran/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
barry-ran authored Jun 14, 2020
2 parents 6fb1d7d + fc2929e commit bce7e33
Show file tree
Hide file tree
Showing 60 changed files with 1,722 additions and 351 deletions.
5 changes: 5 additions & 0 deletions QtScrcpy/QtScrcpy.pro
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ msvc{
*g++*: QMAKE_CXXFLAGS += -Werror
*msvc*: QMAKE_CXXFLAGS += /WX /wd4566

# run a server debugger and wait for a client to be attached
# DEFINES += SERVER_DEBUGGER
# select the debugger method ('old' for Android < 9, 'new' for Android >= 9)
# DEFINES += SERVER_DEBUGGER_METHOD_NEW

# 源码
SOURCES += \
main.cpp \
Expand Down
2 changes: 1 addition & 1 deletion QtScrcpy/device/controller/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ void Controller::onSetDeviceClipboard()
if (!controlMsg) {
return;
}
controlMsg->setSetClipboardMsgData(text);
controlMsg->setSetClipboardMsgData(text, true);
postControlMsg(controlMsg);
}

Expand Down
8 changes: 5 additions & 3 deletions QtScrcpy/device/controller/inputconvert/controlmsg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ void ControlMsg::setInjectKeycodeMsgData(AndroidKeyeventAction action, AndroidKe
void ControlMsg::setInjectTextMsgData(QString &text)
{
// write length (2 byte) + string (non nul-terminated)
if (CONTROL_MSG_TEXT_MAX_LENGTH < text.length()) {
if (CONTROL_MSG_INJECT_TEXT_MAX_LENGTH < text.length()) {
// injecting a text takes time, so limit the text length
text = text.left(CONTROL_MSG_TEXT_MAX_LENGTH);
text = text.left(CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
}
QByteArray tmp = text.toUtf8();
m_data.injectText.text = new char[tmp.length() + 1];
Expand All @@ -55,7 +55,7 @@ void ControlMsg::setInjectScrollMsgData(QRect position, qint32 hScroll, qint32 v
m_data.injectScroll.vScroll = vScroll;
}

void ControlMsg::setSetClipboardMsgData(QString &text)
void ControlMsg::setSetClipboardMsgData(QString &text, bool paste)
{
if (text.isEmpty()) {
return;
Expand All @@ -68,6 +68,7 @@ void ControlMsg::setSetClipboardMsgData(QString &text)
m_data.setClipboard.text = new char[tmp.length() + 1];
memcpy(m_data.setClipboard.text, tmp.data(), tmp.length());
m_data.setClipboard.text[tmp.length()] = '\0';
m_data.setClipboard.paste = paste;
}

void ControlMsg::setSetScreenPowerModeData(ControlMsg::ScreenPowerMode mode)
Expand Down Expand Up @@ -124,6 +125,7 @@ QByteArray ControlMsg::serializeData()
BufferUtil::write32(buffer, m_data.injectScroll.vScroll);
break;
case CMT_SET_CLIPBOARD:
buffer.putChar(!!m_data.setClipboard.paste);
BufferUtil::write16(buffer, static_cast<quint32>(strlen(m_data.setClipboard.text)));
buffer.write(m_data.setClipboard.text, strlen(m_data.setClipboard.text));
break;
Expand Down
7 changes: 4 additions & 3 deletions QtScrcpy/device/controller/inputconvert/controlmsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
#include "keycodes.h"
#include "qscrcpyevent.h"

#define CONTROL_MSG_TEXT_MAX_LENGTH 300
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH 4093
#define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH 4092
#define POINTER_ID_MOUSE static_cast<quint64>(-1)
// ControlMsg
class ControlMsg : public QScrcpyEvent
Expand Down Expand Up @@ -48,7 +48,7 @@ class ControlMsg : public QScrcpyEvent
// position action动作对应的位置
void setInjectTouchMsgData(quint64 id, AndroidMotioneventAction action, AndroidMotioneventButtons buttons, QRect position, float pressure);
void setInjectScrollMsgData(QRect position, qint32 hScroll, qint32 vScroll);
void setSetClipboardMsgData(QString &text);
void setSetClipboardMsgData(QString &text, bool paste);
void setSetScreenPowerModeData(ControlMsg::ScreenPowerMode mode);

QByteArray serializeData();
Expand Down Expand Up @@ -90,6 +90,7 @@ class ControlMsg : public QScrcpyEvent
struct
{
char *text = Q_NULLPTR;
bool paste = true;
} setClipboard;
struct
{
Expand Down
31 changes: 20 additions & 11 deletions QtScrcpy/device/controller/inputconvert/inputconvertgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ void InputConvertGame::mouseEvent(const QMouseEvent *from, const QSize &frameSiz
return;
}
if (!switchGameMap()) {
m_needSwitchGameAgain = false;
m_needBackMouseMove = false;
}
return;
}

if (m_gameMap) {
if (!m_needBackMouseMove && m_gameMap) {
updateSize(frameSize, showSize);
// mouse move
if (m_keyMap.isValidMouseMoveMap()) {
Expand Down Expand Up @@ -57,14 +57,14 @@ void InputConvertGame::keyEvent(const QKeyEvent *from, const QSize &frameSize, c
return;
}
if (!switchGameMap()) {
m_needSwitchGameAgain = false;
m_needBackMouseMove = false;
}
return;
}

const KeyMap::KeyMapNode &node = m_keyMap.getKeyMapNodeKey(from->key());
// 处理特殊按键:可以在按键映射和普通映射间切换的按键
if (m_needSwitchGameAgain && KeyMap::KMT_CLICK == node.type && node.data.click.switchMap) {
// 处理特殊按键:可以释放出鼠标的按键
if (m_needBackMouseMove && KeyMap::KMT_CLICK == node.type && node.data.click.switchMap) {
updateSize(frameSize, showSize);
// Qt::Key_Tab Qt::Key_M for PUBG mobile
processKeyClick(node.data.click.keyNode.pos, false, node.data.click.switchMap, from);
Expand Down Expand Up @@ -281,8 +281,8 @@ void InputConvertGame::processSteerWheel(const KeyMap::KeyMapNode &node, const Q
void InputConvertGame::processKeyClick(const QPointF &clickPos, bool clickTwice, bool switchMap, const QKeyEvent *from)
{
if (switchMap && QEvent::KeyRelease == from->type()) {
m_needSwitchGameAgain = !m_needSwitchGameAgain;
switchGameMap();
m_needBackMouseMove = !m_needBackMouseMove;
hideMouseCursor(!m_needBackMouseMove);
}

if (QEvent::KeyPress == from->type()) {
Expand Down Expand Up @@ -463,18 +463,27 @@ bool InputConvertGame::switchGameMap()

// grab cursor and set cursor only mouse move map
emit grabCursor(m_gameMap);
if (m_gameMap) {
hideMouseCursor(m_gameMap);

if (!m_gameMap) {
stopMouseMoveTimer();
mouseMoveStopTouch();
}

return m_gameMap;
}

void InputConvertGame::hideMouseCursor(bool hide)
{
if (hide) {
#ifdef QT_NO_DEBUG
QGuiApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
#else
QGuiApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
#endif
} else {
stopMouseMoveTimer();
mouseMoveStopTouch();
QGuiApplication::restoreOverrideCursor();
}
return m_gameMap;
}

void InputConvertGame::timerEvent(QTimerEvent *event)
Expand Down
3 changes: 2 additions & 1 deletion QtScrcpy/device/controller/inputconvert/inputconvertgame.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class InputConvertGame : public InputConvertNormal

bool switchGameMap();
bool checkCursorPos(const QMouseEvent *from);
void hideMouseCursor(bool hide);

protected:
void timerEvent(QTimerEvent *event);
Expand All @@ -62,7 +63,7 @@ class InputConvertGame : public InputConvertNormal
QSize m_frameSize;
QSize m_showSize;
bool m_gameMap = false;
bool m_needSwitchGameAgain = false;
bool m_needBackMouseMove = false;
int m_multiTouchID[MULTI_TOUCH_MAX_NUM] = { 0 };
KeyMap m_keyMap;

Expand Down
8 changes: 6 additions & 2 deletions QtScrcpy/device/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,10 @@ void Device::initSignals()
connect(this, &Device::switchFullScreen, m_videoForm, &VideoForm::onSwitchFullScreen);
}
if (m_fileHandler) {
connect(this, &Device::pushFileRequest, m_fileHandler, &FileHandler::onPushFileRequest);
connect(this, &Device::installApkRequest, m_fileHandler, &FileHandler::onInstallApkRequest);
connect(this, &Device::pushFileRequest, this, [this](const QString &file, const QString &devicePath) {
m_fileHandler->onPushFileRequest(getSerial(), file, devicePath);
});
connect(this, &Device::installApkRequest, this, [this](const QString &apkFile) { m_fileHandler->onInstallApkRequest(getSerial(), apkFile); });
connect(m_fileHandler, &FileHandler::fileHandlerResult, this, [this](FileHandler::FILE_HANDLER_RESULT processResult, bool isApk) {
QString tipsType = "";
if (isApk) {
Expand Down Expand Up @@ -303,6 +305,8 @@ void Device::startServer()
params.crop = "-";
params.control = true;
params.useReverse = m_params.useReverse;
params.lockVideoOrientation = m_params.lockVideoOrientation;
params.stayAwake = m_params.stayAwake;
m_server->start(params);
});
}
Expand Down
6 changes: 4 additions & 2 deletions QtScrcpy/device/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class Device : public QObject
bool display = true; // 是否显示画面(或者仅仅后台录制)
QString gameScript = ""; // 游戏映射脚本
bool renderExpiredFrames = false; // 是否渲染延迟视频帧
int lockVideoOrientation = -1; // 是否锁定视频方向
int stayAwake = false; // 是否保持唤醒
};
enum GroupControlState
{
Expand Down Expand Up @@ -73,8 +75,8 @@ class Device : public QObject
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);
void pushFileRequest(const QString &file, const QString &devicePath = "");
void installApkRequest(const QString &apkFile);

// key map
void mouseEvent(const QMouseEvent *from, const QSize &frameSize, const QSize &showSize);
Expand Down
72 changes: 50 additions & 22 deletions QtScrcpy/device/server/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,29 @@ bool Server::execute()
args << "shell";
args << QString("CLASSPATH=%1").arg(Config::getInstance().getServerPath());
args << "app_process";
args << "/"; // unused;

#ifdef SERVER_DEBUGGER
#define SERVER_DEBUGGER_PORT "5005"

args <<
#ifdef SERVER_DEBUGGER_METHOD_NEW
/* Android 9 and above */
"-XjdwpProvider:internal -XjdwpOptions:transport=dt_socket,suspend=y,server=y,address="
#else
/* Android 8 and below */
"-agentlib:jdwp=transport=dt_socket,suspend=y,server=y,address="
#endif
SERVER_DEBUGGER_PORT,
#endif

args << "/"; // unused;
args << "com.genymobile.scrcpy.Server";
args << Config::getInstance().getServerVersion();
args << Config::getInstance().getLogLevel();
args << QString::number(m_params.maxSize);
args << QString::number(m_params.bitRate);
args << QString::number(m_params.maxFps);
args << QString::number(m_params.lockVideoOrientation);
args << (m_tunnelForward ? "true" : "false");
if (m_params.crop.isEmpty()) {
args << "-";
Expand All @@ -138,6 +155,24 @@ bool Server::execute()
}
args << "true"; // always send frame meta (packet boundaries + timestamp)
args << (m_params.control ? "true" : "false");
args << "0"; // display id
args << "false"; // show touch
args << (m_params.stayAwake ? "true" : "false"); // stay awake
// code option
// https://github.com/Genymobile/scrcpy/commit/080a4ee3654a9b7e96c8ffe37474b5c21c02852a
// <https://d.android.com/reference/android/media/MediaFormat>
args << "-";

#ifdef SERVER_DEBUGGER
qInfo("Server debugger waiting for a client on device port " SERVER_DEBUGGER_PORT "...");
// From the computer, run
// adb forward tcp:5005 tcp:5005
// Then, from Android Studio: Run > Debug > Edit configurations...
// On the left, click on '+', "Remote", with:
// Host: localhost
// Port: 5005
// Then click on "Debug"
#endif

// adb -s P7C0218510000537 shell CLASSPATH=/data/local/tmp/scrcpy-server app_process / com.genymobile.scrcpy.Server 0 8000000 false
// mark: crop input format: "width:height:x:y" or - for no crop, for example: "100:200:0:0"
Expand Down Expand Up @@ -245,27 +280,6 @@ bool Server::startServerByStep()
stepSuccess = enableTunnelForward();
break;
case SSS_EXECUTE_SERVER:
// if "adb reverse" does not work (e.g. over "adb connect"), it fallbacks to
// "adb forward", so the app socket is the client
if (!m_tunnelForward) {
// At the application level, the device part is "the server" because it
// serves video stream and control. However, at the network level, the
// client listens and the server connects to the client. That way, the
// client can listen before starting the server app, so there is no need to
// try to connect until the server socket is listening on the device.
m_serverSocket.setMaxPendingConnections(2);
if (!m_serverSocket.listen(QHostAddress::LocalHost, m_params.localPort)) {
qCritical() << QString("Could not listen on port %1").arg(m_params.localPort).toStdString().c_str();
m_serverStartStep = SSS_NULL;
if (m_tunnelForward) {
disableTunnelForward();
} else {
disableTunnelReverse();
}
emit serverStartResult(false);
return false;
}
}
// server will connect to our server socket
stepSuccess = execute();
break;
Expand Down Expand Up @@ -432,6 +446,20 @@ void Server::onWorkProcessResult(AdbProcess::ADB_EXEC_RESULT processResult)
break;
case SSS_ENABLE_TUNNEL_REVERSE:
if (AdbProcess::AER_SUCCESS_EXEC == processResult) {
// At the application level, the device part is "the server" because it
// serves video stream and control. However, at the network level, the
// client listens and the server connects to the client. That way, the
// client can listen before starting the server app, so there is no need to
// try to connect until the server socket is listening on the device.
m_serverSocket.setMaxPendingConnections(2);
if (!m_serverSocket.listen(QHostAddress::LocalHost, m_params.localPort)) {
qCritical() << QString("Could not listen on port %1").arg(m_params.localPort).toStdString().c_str();
m_serverStartStep = SSS_NULL;
disableTunnelReverse();
emit serverStartResult(false);
break;
}

m_serverStartStep = SSS_EXECUTE_SERVER;
startServerByStep();
} else if (AdbProcess::AER_SUCCESS_START != processResult) {
Expand Down
18 changes: 10 additions & 8 deletions QtScrcpy/device/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ class Server : public QObject
public:
struct ServerParams
{
QString serial = ""; // 设备序列号
quint16 localPort = 27183; // reverse时本地监听端口
quint16 maxSize = 720; // 视频分辨率
quint32 bitRate = 8000000; // 视频比特率
quint32 maxFps = 60; // 视频最大帧率
QString crop = "-"; // 视频裁剪
bool control = true; // 安卓端是否接收键鼠控制
bool useReverse = true; // true:先使用adb reverse,失败后自动使用adb forward;false:直接使用adb forward
QString serial = ""; // 设备序列号
quint16 localPort = 27183; // reverse时本地监听端口
quint16 maxSize = 720; // 视频分辨率
quint32 bitRate = 8000000; // 视频比特率
quint32 maxFps = 60; // 视频最大帧率
QString crop = "-"; // 视频裁剪
bool control = true; // 安卓端是否接收键鼠控制
bool useReverse = true; // true:先使用adb reverse,失败后自动使用adb forward;false:直接使用adb forward
int lockVideoOrientation = -1; // 是否锁定视频方向
int stayAwake = false; // 是否保持唤醒
};

explicit Server(QObject *parent = nullptr);
Expand Down
Loading

0 comments on commit bce7e33

Please sign in to comment.