diff --git a/QtScrcpy/dialog.cpp b/QtScrcpy/dialog.cpp
index 5388a1d..c7603df 100644
--- a/QtScrcpy/dialog.cpp
+++ b/QtScrcpy/dialog.cpp
@@ -105,7 +105,8 @@ void Dialog::on_startServerBtn_clicked()
quint32 bitRate = ui->bitRateBox->currentText().trimmed().toUInt();
// this is ok that "native" toUshort is 0
quint16 videoSize = ui->videoSizeBox->currentText().trimmed().toUShort();
- m_videoForm = new VideoForm(ui->serialBox->currentText().trimmed(), videoSize, bitRate, absFilePath);
+ m_videoForm = new VideoForm(ui->serialBox->currentText().trimmed(), videoSize, bitRate,
+ absFilePath, ui->closeScreenCheck->isChecked());
if (ui->alwaysTopCheck->isChecked()) {
m_videoForm->staysOnTop();
}
@@ -238,3 +239,15 @@ void Dialog::on_alwaysTopCheck_stateChanged(int arg1)
m_videoForm->staysOnTop(false);
}
}
+
+void Dialog::on_closeScreenCheck_stateChanged(int arg1)
+{
+ if (!m_videoForm) {
+ return;
+ }
+ if (ui->closeScreenCheck->isChecked()) {
+ m_videoForm->setScreenPowerMode(ControlMsg::SPM_OFF);
+ } else {
+ m_videoForm->setScreenPowerMode(ControlMsg::SPM_NORMAL);
+ }
+}
diff --git a/QtScrcpy/dialog.h b/QtScrcpy/dialog.h
index 1d81f8d..43e1f63 100644
--- a/QtScrcpy/dialog.h
+++ b/QtScrcpy/dialog.h
@@ -43,6 +43,8 @@ private slots:
void on_alwaysTopCheck_stateChanged(int arg1);
+ void on_closeScreenCheck_stateChanged(int arg1);
+
private:
bool checkAdbRun();
void initUI();
diff --git a/QtScrcpy/dialog.ui b/QtScrcpy/dialog.ui
index bf6b04b..18ceff5 100644
--- a/QtScrcpy/dialog.ui
+++ b/QtScrcpy/dialog.ui
@@ -230,6 +230,13 @@
+ -
+
+
+ close screen
+
+
+
diff --git a/QtScrcpy/inputcontrol/controlmsg.cpp b/QtScrcpy/inputcontrol/controlmsg.cpp
index 9226ec4..45147ff 100644
--- a/QtScrcpy/inputcontrol/controlmsg.cpp
+++ b/QtScrcpy/inputcontrol/controlmsg.cpp
@@ -12,21 +12,21 @@ ControlMsg::ControlMsg(ControlMsgType controlMsgType)
ControlMsg::~ControlMsg()
{
if (CMT_SET_CLIPBOARD == m_data.type
- && Q_NULLPTR != m_data.setClipboardMsg.text) {
- delete m_data.setClipboardMsg.text;
- m_data.setClipboardMsg.text = Q_NULLPTR;
+ && Q_NULLPTR != m_data.setClipboard.text) {
+ delete m_data.setClipboard.text;
+ m_data.setClipboard.text = Q_NULLPTR;
} else if (CMT_INJECT_TEXT == m_data.type
- && Q_NULLPTR != m_data.injectTextMsg.text){
- delete m_data.injectTextMsg.text;
- m_data.injectTextMsg.text = Q_NULLPTR;
+ && Q_NULLPTR != m_data.injectText.text){
+ delete m_data.injectText.text;
+ m_data.injectText.text = Q_NULLPTR;
}
}
void ControlMsg::setInjectKeycodeMsgData(AndroidKeyeventAction action, AndroidKeycode keycode, AndroidMetastate metastate)
{
- m_data.injectKeycodeMsg.action = action;
- m_data.injectKeycodeMsg.keycode = keycode;
- m_data.injectKeycodeMsg.metastate = metastate;
+ m_data.injectKeycode.action = action;
+ m_data.injectKeycode.keycode = keycode;
+ m_data.injectKeycode.metastate = metastate;
}
void ControlMsg::setInjectTextMsgData(QString& text)
@@ -37,30 +37,30 @@ void ControlMsg::setInjectTextMsgData(QString& text)
text = text.left(CONTROL_MSG_TEXT_MAX_LENGTH);
}
QByteArray tmp = text.toUtf8();
- m_data.injectTextMsg.text = new char[tmp.length() + 1];
- memcpy(m_data.injectTextMsg.text, tmp.data(), tmp.length());
- m_data.injectTextMsg.text[tmp.length()] = '\0';
+ m_data.injectText.text = new char[tmp.length() + 1];
+ memcpy(m_data.injectText.text, tmp.data(), tmp.length());
+ m_data.injectText.text[tmp.length()] = '\0';
}
void ControlMsg::setInjectMouseMsgData(AndroidMotioneventAction action, AndroidMotioneventButtons buttons, QRect position)
{
- m_data.injectMouseMsg.action = action;
- m_data.injectMouseMsg.buttons = buttons;
- m_data.injectMouseMsg.position = position;
+ m_data.injectMouse.action = action;
+ m_data.injectMouse.buttons = buttons;
+ m_data.injectMouse.position = position;
}
void ControlMsg::setInjectTouchMsgData(quint32 id, AndroidMotioneventAction action, QRect position)
{
- m_data.injectTouchMsg.action = action;
- m_data.injectTouchMsg.id = id;
- m_data.injectTouchMsg.position = position;
+ m_data.injectTouch.action = action;
+ m_data.injectTouch.id = id;
+ m_data.injectTouch.position = position;
}
void ControlMsg::setInjectScrollMsgData(QRect position, qint32 hScroll, qint32 vScroll)
{
- m_data.injectScrollMsg.position = position;
- m_data.injectScrollMsg.hScroll = hScroll;
- m_data.injectScrollMsg.vScroll = vScroll;
+ m_data.injectScroll.position = position;
+ m_data.injectScroll.hScroll = hScroll;
+ m_data.injectScroll.vScroll = vScroll;
}
void ControlMsg::setSetClipboardMsgData(QString &text)
@@ -73,9 +73,14 @@ void ControlMsg::setSetClipboardMsgData(QString &text)
}
QByteArray tmp = text.toUtf8();
- m_data.setClipboardMsg.text = new char[tmp.length() + 1];
- memcpy(m_data.setClipboardMsg.text, tmp.data(), tmp.length());
- m_data.setClipboardMsg.text[tmp.length()] = '\0';
+ 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';
+}
+
+void ControlMsg::setSetScreenPowerModeData(ControlMsg::ScreenPowerMode mode)
+{
+ m_data.setScreenPowerMode.mode = mode;
}
void ControlMsg::writePosition(QBuffer &buffer, const QRect& value)
@@ -95,32 +100,35 @@ QByteArray ControlMsg::serializeData()
switch (m_data.type) {
case CMT_INJECT_KEYCODE:
- buffer.putChar(m_data.injectKeycodeMsg.action);
- BufferUtil::write32(buffer, m_data.injectKeycodeMsg.keycode);
- BufferUtil::write32(buffer, m_data.injectKeycodeMsg.metastate);
+ buffer.putChar(m_data.injectKeycode.action);
+ BufferUtil::write32(buffer, m_data.injectKeycode.keycode);
+ BufferUtil::write32(buffer, m_data.injectKeycode.metastate);
break;
case CMT_INJECT_TEXT:
- BufferUtil::write16(buffer, strlen(m_data.injectTextMsg.text));
- buffer.write(m_data.injectTextMsg.text, strlen(m_data.injectTextMsg.text));
+ BufferUtil::write16(buffer, strlen(m_data.injectText.text));
+ buffer.write(m_data.injectText.text, strlen(m_data.injectText.text));
break;
case CMT_INJECT_MOUSE:
- buffer.putChar(m_data.injectMouseMsg.action);
- BufferUtil::write32(buffer, m_data.injectMouseMsg.buttons);
- writePosition(buffer, m_data.injectMouseMsg.position);
+ buffer.putChar(m_data.injectMouse.action);
+ BufferUtil::write32(buffer, m_data.injectMouse.buttons);
+ writePosition(buffer, m_data.injectMouse.position);
break;
case CMT_INJECT_TOUCH:
- buffer.putChar(m_data.injectTouchMsg.id);
- buffer.putChar(m_data.injectTouchMsg.action);
- writePosition(buffer, m_data.injectTouchMsg.position);
+ buffer.putChar(m_data.injectTouch.id);
+ buffer.putChar(m_data.injectTouch.action);
+ writePosition(buffer, m_data.injectTouch.position);
break;
case CMT_INJECT_SCROLL:
- writePosition(buffer, m_data.injectScrollMsg.position);
- BufferUtil::write32(buffer, m_data.injectScrollMsg.hScroll);
- BufferUtil::write32(buffer, m_data.injectScrollMsg.vScroll);
+ writePosition(buffer, m_data.injectScroll.position);
+ BufferUtil::write32(buffer, m_data.injectScroll.hScroll);
+ BufferUtil::write32(buffer, m_data.injectScroll.vScroll);
break;
case CMT_SET_CLIPBOARD:
- BufferUtil::write16(buffer, strlen(m_data.setClipboardMsg.text));
- buffer.write(m_data.setClipboardMsg.text, strlen(m_data.setClipboardMsg.text));
+ BufferUtil::write16(buffer, strlen(m_data.setClipboard.text));
+ buffer.write(m_data.setClipboard.text, strlen(m_data.setClipboard.text));
+ break;
+ case CMT_SET_SCREEN_POWER_MODE:
+ buffer.putChar(m_data.setScreenPowerMode.mode);
break;
case CMT_BACK_OR_SCREEN_ON:
case CMT_EXPAND_NOTIFICATION_PANEL:
diff --git a/QtScrcpy/inputcontrol/controlmsg.h b/QtScrcpy/inputcontrol/controlmsg.h
index d137475..e226428 100644
--- a/QtScrcpy/inputcontrol/controlmsg.h
+++ b/QtScrcpy/inputcontrol/controlmsg.h
@@ -26,9 +26,16 @@ public:
CMT_COLLAPSE_NOTIFICATION_PANEL,
CMT_GET_CLIPBOARD,
CMT_SET_CLIPBOARD,
+ CMT_SET_SCREEN_POWER_MODE,
CMT_INJECT_TOUCH,
- };
+ };
+
+ enum ScreenPowerMode {
+ // see
+ SPM_OFF = 0,
+ SPM_NORMAL = 2,
+ };
ControlMsg(ControlMsgType controlMsgType);
virtual ~ControlMsg();
@@ -42,6 +49,7 @@ public:
void setInjectTouchMsgData(quint32 id, AndroidMotioneventAction action, QRect position);
void setInjectScrollMsgData(QRect position, qint32 hScroll, qint32 vScroll);
void setSetClipboardMsgData(QString& text);
+ void setSetScreenPowerModeData(ControlMsg::ScreenPowerMode mode);
QByteArray serializeData();
@@ -56,28 +64,31 @@ private:
AndroidKeyeventAction action;
AndroidKeycode keycode;
AndroidMetastate metastate;
- } injectKeycodeMsg;
+ } injectKeycode;
struct {
char* text = Q_NULLPTR;
- } injectTextMsg;
+ } injectText;
struct {
AndroidMotioneventAction action;
AndroidMotioneventButtons buttons;
QRect position;
- } injectMouseMsg;
+ } injectMouse;
struct {
quint32 id;
AndroidMotioneventAction action;
QRect position;
- } injectTouchMsg;
+ } injectTouch;
struct {
QRect position;
qint32 hScroll;
qint32 vScroll;
- } injectScrollMsg;
+ } injectScroll;
struct {
char *text = Q_NULLPTR;
- } setClipboardMsg;
+ } setClipboard;
+ struct {
+ ScreenPowerMode mode;
+ } setScreenPowerMode;
};
ControlMsgData(){}
diff --git a/QtScrcpy/inputcontrol/receiver.cpp b/QtScrcpy/inputcontrol/receiver.cpp
index d59a443..af5dead 100644
--- a/QtScrcpy/inputcontrol/receiver.cpp
+++ b/QtScrcpy/inputcontrol/receiver.cpp
@@ -41,6 +41,7 @@ void Receiver::processMsg(DeviceMsg *deviceMsg)
switch (deviceMsg->type()) {
case DeviceMsg::DMT_GET_CLIPBOARD:
{
+ qInfo("Device clipboard copied");
QClipboard *board = QApplication::clipboard();
QString text;
deviceMsg->getClipboardMsgData(text);
diff --git a/QtScrcpy/server/server.cpp b/QtScrcpy/server/server.cpp
index f042ba1..04d68ad 100644
--- a/QtScrcpy/server/server.cpp
+++ b/QtScrcpy/server/server.cpp
@@ -65,7 +65,7 @@ bool Server::pushServer()
if (m_workProcess.isRuning()) {
m_workProcess.kill();
}
- m_workProcess.push(m_serial, getServerPath(), DEVICE_SERVER_PATH);
+ m_workProcess.push(m_params.serial, getServerPath(), DEVICE_SERVER_PATH);
return true;
}
@@ -74,7 +74,7 @@ bool Server::enableTunnelReverse()
if (m_workProcess.isRuning()) {
m_workProcess.kill();
}
- m_workProcess.reverse(m_serial, SOCKET_NAME, m_localPort);
+ m_workProcess.reverse(m_params.serial, SOCKET_NAME, m_params.localPort);
return true;
}
@@ -89,7 +89,7 @@ bool Server::disableTunnelReverse()
sender()->deleteLater();
}
});
- adb->reverseRemove(m_serial, SOCKET_NAME);
+ adb->reverseRemove(m_params.serial, SOCKET_NAME);
return true;
}
@@ -98,7 +98,7 @@ bool Server::enableTunnelForward()
if (m_workProcess.isRuning()) {
m_workProcess.kill();
}
- m_workProcess.forward(m_serial, m_localPort, SOCKET_NAME);
+ m_workProcess.forward(m_params.serial, m_params.localPort, SOCKET_NAME);
return true;
}
bool Server::disableTunnelForward()
@@ -112,7 +112,7 @@ bool Server::disableTunnelForward()
sender()->deleteLater();
}
});
- adb->forwardRemove(m_serial, m_localPort);
+ adb->forwardRemove(m_params.serial, m_params.localPort);
return true;
}
@@ -127,31 +127,27 @@ bool Server::execute()
args << "app_process";
args << "/"; // unused;
args << "com.genymobile.scrcpy.Server";
- args << QString::number(m_maxSize);
- args << QString::number(m_bitRate);
+ args << QString::number(m_params.maxSize);
+ args << QString::number(m_params.bitRate);
args << (m_tunnelForward ? "true" : "false");
- if (m_crop.isEmpty()) {
+ if (m_params.crop.isEmpty()) {
args << "-";
} else {
- args << m_crop;
+ args << m_params.crop;
}
- args << (m_sendFrameMeta ? "true" : "false");
+ args << (m_params.sendFrameMeta ? "true" : "false");
+ args << (m_params.control ? "true" : "false");
+
// adb -s P7C0218510000537 shell CLASSPATH=/data/local/tmp/scrcpy-server.jar 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"
// 这条adb命令是阻塞运行的,m_serverProcess进程不会退出了
- m_serverProcess.execute(m_serial, args);
+ m_serverProcess.execute(m_params.serial, args);
return true;
}
-bool Server::start(const QString& serial, quint16 localPort, quint16 maxSize, quint32 bitRate, const QString& crop, bool sendFrameMeta)
+bool Server::start(Server::ServerParams params)
{
- m_serial = serial;
- m_localPort = localPort;
- m_maxSize = maxSize;
- m_bitRate = bitRate;
- m_crop = crop;
- m_sendFrameMeta = sendFrameMeta;
-
+ m_params = params;
m_serverStartStep = SSS_PUSH;
return startServerByStep();
}
@@ -179,7 +175,7 @@ bool Server::connectTo()
// video socket
m_videoSocket = new VideoSocket();
- m_videoSocket->connectToHost(QHostAddress::LocalHost, m_localPort);
+ m_videoSocket->connectToHost(QHostAddress::LocalHost, m_params.localPort);
if (!m_videoSocket->waitForConnected(1000)) {
stop();
qWarning("video socket connect to server failed");
@@ -206,7 +202,7 @@ bool Server::connectTo()
// control socket
m_controlSocket = new QTcpSocket();
- m_controlSocket->connectToHost(QHostAddress::LocalHost, m_localPort);
+ m_controlSocket->connectToHost(QHostAddress::LocalHost, m_params.localPort);
if (!m_controlSocket->waitForConnected(1000)) {
stop();
qWarning("control socket connect to server failed");
@@ -294,8 +290,8 @@ bool Server::startServerByStep()
// 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_localPort)) {
- qCritical(QString("Could not listen on port %1").arg(m_localPort).toStdString().c_str());
+ 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();
diff --git a/QtScrcpy/server/server.h b/QtScrcpy/server/server.h
index bccad71..00d7a87 100644
--- a/QtScrcpy/server/server.h
+++ b/QtScrcpy/server/server.h
@@ -22,10 +22,20 @@ class Server : public QObject
SSS_RUNNING,
};
public:
+ struct ServerParams {
+ QString serial = "";
+ quint16 localPort = 27183;
+ quint16 maxSize = 0;
+ quint32 bitRate = 8000000;
+ QString crop = "-";
+ bool sendFrameMeta = false;
+ bool control = true;
+ };
+
explicit Server(QObject *parent = nullptr);
virtual ~Server();
- bool start(const QString& serial, quint16 localPort, quint16 maxSize, quint32 bitRate, const QString& crop, bool sendFrameMeta = false);
+ bool start(Server::ServerParams params);
bool connectTo();
VideoSocket* getVideoSocket();
@@ -61,21 +71,16 @@ private:
private:
QString m_serverPath = "";
AdbProcess m_workProcess;
- QString m_serial = "";
AdbProcess m_serverProcess;
TcpServer m_serverSocket; // only used if !tunnel_forward
QPointer m_videoSocket = Q_NULLPTR;
QPointer m_controlSocket = Q_NULLPTR;
- quint16 m_localPort = 0;
bool m_tunnelEnabled = false;
bool m_tunnelForward = false; // use "adb forward" instead of "adb reverse"
- bool m_sendFrameMeta = false;
- quint16 m_maxSize = 0;
- quint32 m_bitRate = 0;
- QString m_crop = "";
quint32 m_acceptTimeoutTimer = 0;
QString m_deviceName = "";
QSize m_deviceSize = QSize();
+ ServerParams m_params;
SERVER_START_STEP m_serverStartStep = SSS_NULL;
};
diff --git a/QtScrcpy/stream/stream.cpp b/QtScrcpy/stream/stream.cpp
index 46110c3..42938e5 100644
--- a/QtScrcpy/stream/stream.cpp
+++ b/QtScrcpy/stream/stream.cpp
@@ -145,7 +145,7 @@ static qint32 readPacketWithMeta(void *opaque, uint8_t *buf, int bufSize) {
quint8 header[HEADER_SIZE];
qint32 r = stream->recvData(header, HEADER_SIZE);
if (r == -1) {
- return AVERROR(errno);
+ return errno ? AVERROR(errno) : AVERROR_EOF;
}
if (r == 0) {
return AVERROR_EOF;
@@ -173,7 +173,7 @@ static qint32 readPacketWithMeta(void *opaque, uint8_t *buf, int bufSize) {
qint32 r = stream->recvData(buf, bufSize);
if (r == -1) {
- return AVERROR(errno);
+ return errno ? AVERROR(errno) : AVERROR_EOF;
}
if (r == 0) {
return AVERROR_EOF;
diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp
index 4546d9d..55cc744 100644
--- a/QtScrcpy/videoform.cpp
+++ b/QtScrcpy/videoform.cpp
@@ -23,7 +23,7 @@
#include "controlmsg.h"
#include "mousetap/mousetap.h"
-VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, QWidget *parent) :
+VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, bool closeScreen, QWidget *parent) :
QWidget(parent),
ui(new Ui::videoForm),
m_serial(serial),
@@ -33,6 +33,7 @@ VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, co
ui->setupUi(this);
initUI();
+ m_closeScreen = closeScreen;
m_server = new Server();
m_vb = new VideoBuffer();
m_vb->init();
@@ -55,7 +56,15 @@ VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, co
// only one devices, serial can be null
// mark: crop input format: "width:height:x:y" or - for no crop, for example: "100:200:0:0"
// sendFrameMeta for recorder mp4
- m_server->start(m_serial, 27183, m_maxSize, m_bitRate, "-", sendFrameMeta);
+ Server::ServerParams params;
+ params.serial = m_serial;
+ params.localPort = 27183;
+ params.maxSize = m_maxSize;
+ params.bitRate = m_bitRate;
+ params.crop = "-";
+ params.sendFrameMeta = sendFrameMeta;
+ params.control = true;
+ m_server->start(params);
});
updateShowSize(size());
@@ -177,6 +186,10 @@ void VideoForm::initSignals()
// init controller
m_inputConvert.setControlSocket(m_server->getControlSocket());
+
+ if (m_closeScreen) {
+ setScreenPowerMode(ControlMsg::SPM_OFF);
+ }
}
});
@@ -404,6 +417,16 @@ void VideoForm::postTextInput(QString& text)
m_inputConvert.sendControlMsg(controlMsg);
}
+void VideoForm::setScreenPowerMode(ControlMsg::ScreenPowerMode mode)
+{
+ ControlMsg* controlMsg = new ControlMsg(ControlMsg::CMT_SET_SCREEN_POWER_MODE);
+ if (!controlMsg) {
+ return;
+ }
+ controlMsg->setSetScreenPowerModeData(mode);
+ m_inputConvert.sendControlMsg(controlMsg);
+}
+
void VideoForm::staysOnTop(bool top)
{
bool needShow = false;
diff --git a/QtScrcpy/videoform.h b/QtScrcpy/videoform.h
index 1b229c7..edb8deb 100644
--- a/QtScrcpy/videoform.h
+++ b/QtScrcpy/videoform.h
@@ -24,7 +24,7 @@ class VideoForm : public QWidget
Q_OBJECT
public:
- explicit VideoForm(const QString& serial, quint16 maxSize = 720, quint32 bitRate = 8000000, const QString& fileName = "", QWidget *parent = 0);
+ explicit VideoForm(const QString& serial, quint16 maxSize = 720, quint32 bitRate = 8000000, const QString& fileName = "", bool closeScreen = false, QWidget *parent = 0);
~VideoForm();
void switchFullScreen();
@@ -43,6 +43,7 @@ public:
void setDeviceClipboard();
void clipboardPaste();
void postTextInput(QString& text);
+ void setScreenPowerMode(ControlMsg::ScreenPowerMode mode);
void staysOnTop(bool top = true);
@@ -89,6 +90,7 @@ private:
Recorder* m_recorder = Q_NULLPTR;
QTime m_startTimeCount;
QPointer m_loadingWidget;
+ bool m_closeScreen = false;
};
#endif // VIDEOFORM_H
diff --git a/TODO.txt b/TODO.txt
index dcbd103..85b82f3 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -5,11 +5,17 @@ Mac
루serverҪΪapkΪһ뷨ݲʵ֣
-scrcpy 7764a836f1ee02a4540cfc4118c20729018daaac
+ͬscrcpy b91ecf52256da73f5c8dca04fb82c13ec826cbd7
b35733edb6df2a00b6af9b1c98627d344c377963 ¼ϵ
ֻ¼ƲڣعĿǰvideoform
+֡Ϊ̬ãǾ̬ https://github.com/Genymobile/scrcpy/commit/ebccb9f6cc111e8acfbe10d656cac5c1f1b744a0
+ճԱ
+ճIJ
+ʻ
+̴߳ӡ֡ https://github.com/Genymobile/scrcpy/commit/e2a272bf99ecf48fcb050177113f903b3fb323c4
+
mark:
diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java b/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java
index 73bb4b5..0a8fe7c 100644
--- a/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java
+++ b/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java
@@ -14,14 +14,15 @@ public final class ControlMessage {
public static final int TYPE_COLLAPSE_NOTIFICATION_PANEL = 6;
public static final int TYPE_GET_CLIPBOARD = 7;
public static final int TYPE_SET_CLIPBOARD = 8;
+ public static final int TYPE_SET_SCREEN_POWER_MODE = 9;
- public static final int TYPE_INJECT_TOUCH = 9;
+ public static final int TYPE_INJECT_TOUCH = 10;
private int type;
private String text;
private int metaState; // KeyEvent.META_*
- private int action; // KeyEvent.ACTION_* or MotionEvent.ACTION_*
+ private int action; // KeyEvent.ACTION_* or MotionEvent.ACTION_* or POWER_MODE_*
private int keycode; // KeyEvent.KEYCODE_*
private int buttons; // MotionEvent.BUTTON_*
private int id;
@@ -82,6 +83,16 @@ public final class ControlMessage {
return event;
}
+ /**
+ * @param mode one of the {@code Device.SCREEN_POWER_MODE_*} constants
+ */
+ public static ControlMessage createSetScreenPowerMode(int mode) {
+ ControlMessage event = new ControlMessage();
+ event.type = TYPE_SET_SCREEN_POWER_MODE;
+ event.action = mode;
+ return event;
+ }
+
public static ControlMessage createEmpty(int type) {
ControlMessage event = new ControlMessage();
event.type = type;
diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java b/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java
index c06b599..2d1d96f 100644
--- a/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java
+++ b/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java
@@ -12,6 +12,7 @@ public class ControlMessageReader {
private static final int INJECT_MOUSE_PAYLOAD_LENGTH = 13;
private static final int INJECT_SCROLL_PAYLOAD_LENGTH = 16;
private static final int INJECT_TOUCH_PAYLOAD_LENGTH = 10;
+ private static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
public static final int TEXT_MAX_LENGTH = 300;
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093;
@@ -50,43 +51,46 @@ public class ControlMessageReader {
}
int savedPosition = buffer.position();
int type = buffer.get();
- ControlMessage controlEvent;
+ ControlMessage msg;
switch (type) {
case ControlMessage.TYPE_INJECT_KEYCODE:
- controlEvent = parseInjectKeycode();
+ msg = parseInjectKeycode();
break;
case ControlMessage.TYPE_INJECT_TEXT:
- controlEvent = parseInjectText();
+ msg = parseInjectText();
break;
case ControlMessage.TYPE_INJECT_MOUSE:
- controlEvent = parseInjectMouse();
+ msg = parseInjectMouse();
break;
case ControlMessage.TYPE_INJECT_TOUCH:
- controlEvent = parseInjectMouseTouch();
+ msg = parseInjectMouseTouch();
break;
case ControlMessage.TYPE_INJECT_SCROLL:
- controlEvent = parseInjectScroll();
+ msg = parseInjectScroll();
break;
case ControlMessage.TYPE_SET_CLIPBOARD:
- controlEvent = parseSetClipboard();
+ msg = parseSetClipboard();
+ break;
+ case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
+ msg = parseSetScreenPowerMode();
break;
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL:
case ControlMessage.TYPE_GET_CLIPBOARD:
- controlEvent = ControlMessage.createEmpty(type);
+ msg = ControlMessage.createEmpty(type);
break;
default:
Ln.w("Unknown event type: " + type);
- controlEvent = null;
+ msg = null;
break;
}
- if (controlEvent == null) {
+ if (msg == null) {
// failure, reset savedPosition
buffer.position(savedPosition);
}
- return controlEvent;
+ return msg;
}
private ControlMessage parseInjectKeycode() {
@@ -157,6 +161,14 @@ public class ControlMessageReader {
return ControlMessage.createSetClipboard(text);
}
+ private ControlMessage parseSetScreenPowerMode() {
+ if (buffer.remaining() < SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH) {
+ return null;
+ }
+ int mode = buffer.get();
+ return ControlMessage.createSetScreenPowerMode(mode);
+ }
+
private static Position readPosition(ByteBuffer buffer) {
int x = toUnsigned(buffer.getShort());
int y = toUnsigned(buffer.getShort());
diff --git a/server/src/main/java/com/genymobile/scrcpy/Controller.java b/server/src/main/java/com/genymobile/scrcpy/Controller.java
index 5aeb252..490ce05 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Controller.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Controller.java
@@ -102,9 +102,21 @@ public class Controller {
return sender;
}
+ @SuppressWarnings("checkstyle:MagicNumber")
public void control() throws IOException {
- // on start, turn screen on
- turnScreenOn();
+ // on start, power on the device
+ if (!device.isScreenOn()) {
+ injectKeycode(KeyEvent.KEYCODE_POWER);
+
+ // dirty hack
+ // After POWER is injected, the device is powered on asynchronously.
+ // To turn the device screen off while mirroring, the client will send a message that
+ // would be handled before the device is actually powered on, so its effect would
+ // be "canceled" once the device is turned back on.
+ // Adding this delay prevents to handle the message before the device is actually
+ // powered on.
+ SystemClock.sleep(500);
+ }
while (true) {
handleEvent();
@@ -145,6 +157,9 @@ public class Controller {
case ControlMessage.TYPE_SET_CLIPBOARD:
device.setClipboardText(msg.getText());
break;
+ case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
+ device.setScreenPowerMode(msg.getAction());
+ break;
default:
// do nothing
}
@@ -309,10 +324,6 @@ public class Controller {
return device.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
- private boolean turnScreenOn() {
- return device.isScreenOn() || injectKeycode(KeyEvent.KEYCODE_POWER);
- }
-
private boolean pressBackOrTurnScreenOn() {
int keycode = device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_POWER;
return injectKeycode(keycode);
diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java
index 93b0302..0420587 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Device.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Device.java
@@ -1,16 +1,21 @@
package com.genymobile.scrcpy;
import com.genymobile.scrcpy.wrappers.ServiceManager;
+import com.genymobile.scrcpy.wrappers.SurfaceControl;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
+import android.os.IBinder;
import android.os.RemoteException;
import android.view.IRotationWatcher;
import android.view.InputEvent;
public final class Device {
+ public static final int POWER_MODE_OFF = SurfaceControl.POWER_MODE_OFF;
+ public static final int POWER_MODE_NORMAL = SurfaceControl.POWER_MODE_NORMAL;
+
public interface RotationListener {
void onRotationChanged(int rotation);
}
@@ -190,6 +195,16 @@ public final class Device {
public void setClipboardText(String text) {
serviceManager.getClipboardManager().setText(text);
+ Ln.i("Device clipboard set");
+ }
+
+ /**
+ * @param mode one of the {@code SCREEN_POWER_MODE_*} constants
+ */
+ public void setScreenPowerMode(int mode) {
+ IBinder d = SurfaceControl.getBuiltInDisplay(0);
+ SurfaceControl.setDisplayPowerMode(d, mode);
+ Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on"));
}
static Rect flipRect(Rect crop) {
diff --git a/server/src/main/java/com/genymobile/scrcpy/Ln.java b/server/src/main/java/com/genymobile/scrcpy/Ln.java
index cd466b3..d991419 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Ln.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Ln.java
@@ -8,7 +8,8 @@ import android.util.Log;
*/
public final class Ln {
- private static final String TAG = "scrcpy";
+ private static final String TAG = "qtscrcpy";
+ private static final String PREFIX = "[server] ";
enum Level {
DEBUG,
@@ -30,28 +31,28 @@ public final class Ln {
public static void d(String message) {
if (isEnabled(Level.DEBUG)) {
Log.d(TAG, message);
- System.out.println("DEBUG: " + message);
+ System.out.println(PREFIX + "DEBUG: " + message);
}
}
public static void i(String message) {
if (isEnabled(Level.INFO)) {
Log.i(TAG, message);
- System.out.println("INFO: " + message);
+ System.out.println(PREFIX + "INFO: " + message);
}
}
public static void w(String message) {
if (isEnabled(Level.WARN)) {
Log.w(TAG, message);
- System.out.println("WARN: " + message);
+ System.out.println(PREFIX + "WARN: " + message);
}
}
public static void e(String message, Throwable throwable) {
if (isEnabled(Level.ERROR)) {
Log.e(TAG, message, throwable);
- System.out.println("ERROR: " + message);
+ System.out.println(PREFIX + "ERROR: " + message);
if (throwable != null) {
throwable.printStackTrace();
}
diff --git a/server/src/main/java/com/genymobile/scrcpy/Options.java b/server/src/main/java/com/genymobile/scrcpy/Options.java
index 0d02451..697cc96 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Options.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Options.java
@@ -8,6 +8,7 @@ public class Options {
private boolean tunnelForward;
private Rect crop;
private boolean sendFrameMeta;
+ private boolean control;
public int getMaxSize() {
return maxSize;
@@ -48,4 +49,12 @@ public class Options {
public void setSendFrameMeta(boolean sendFrameMeta) {
this.sendFrameMeta = sendFrameMeta;
}
+
+ public boolean getControl() {
+ return control;
+ }
+
+ public void setControl(boolean control) {
+ this.control = control;
+ }
}
diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java
index 95dbdb3..1c76afd 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Server.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Server.java
@@ -20,11 +20,13 @@ public final class Server {
try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) {
ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate());
- Controller controller = new Controller(device, connection);
+ if (options.getControl()) {
+ Controller controller = new Controller(device, connection);
- // asynchronous
- startController(controller);
- startDeviceMessageSender(controller.getSender());
+ // asynchronous
+ startController(controller);
+ startDeviceMessageSender(controller.getSender());
+ }
try {
// synchronous
@@ -66,7 +68,7 @@ public final class Server {
@SuppressWarnings("checkstyle:MagicNumber")
private static Options createOptions(String... args) {
- if (args.length != 5) {
+ if (args.length != 6) {
throw new IllegalArgumentException("Expecting 5 parameters");
}
@@ -88,6 +90,9 @@ public final class Server {
boolean sendFrameMeta = Boolean.parseBoolean(args[4]);
options.setSendFrameMeta(sendFrameMeta);
+ boolean control = Boolean.parseBoolean(args[5]);
+ options.setControl(control);
+
return options;
}
diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java
index 8573386..5b5586f 100644
--- a/server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java
+++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/SurfaceControl.java
@@ -2,6 +2,7 @@ package com.genymobile.scrcpy.wrappers;
import android.annotation.SuppressLint;
import android.graphics.Rect;
+import android.os.Build;
import android.os.IBinder;
import android.view.Surface;
@@ -10,6 +11,10 @@ public final class SurfaceControl {
private static final Class> CLASS;
+ // see
+ public static final int POWER_MODE_OFF = 0;
+ public static final int POWER_MODE_NORMAL = 2;
+
static {
try {
CLASS = Class.forName("android.view.SurfaceControl");
@@ -71,6 +76,27 @@ public final class SurfaceControl {
}
}
+ public static IBinder getBuiltInDisplay(int builtInDisplayId) {
+ try {
+ // the method signature has changed in Android Q
+ //
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+ return (IBinder) CLASS.getMethod("getBuiltInDisplay", int.class).invoke(null, builtInDisplayId);
+ }
+ return (IBinder) CLASS.getMethod("getPhysicalDisplayToken", long.class).invoke(null, builtInDisplayId);
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static void setDisplayPowerMode(IBinder displayToken, int mode) {
+ try {
+ CLASS.getMethod("setDisplayPowerMode", IBinder.class, int.class).invoke(null, displayToken, mode);
+ } catch (Exception e) {
+ throw new AssertionError(e);
+ }
+ }
+
public static void destroyDisplay(IBinder displayToken) {
try {
CLASS.getMethod("destroyDisplay", IBinder.class).invoke(null, displayToken);
diff --git a/third_party/scrcpy-server.jar b/third_party/scrcpy-server.jar
index aaad381..7abbf27 100644
Binary files a/third_party/scrcpy-server.jar and b/third_party/scrcpy-server.jar differ