Add sequence number to set_clipboard request

This will allow the client to request an acknowledgement.

PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
This commit is contained in:
Romain Vimont 2021-11-20 11:50:33 +01:00
parent aba1fc03c3
commit 901d837165
7 changed files with 26 additions and 9 deletions

View file

@ -118,11 +118,12 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
buf[1] = msg->inject_keycode.action; buf[1] = msg->inject_keycode.action;
return 2; return 2;
case CONTROL_MSG_TYPE_SET_CLIPBOARD: { case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
buf[1] = !!msg->set_clipboard.paste; buffer_write64be(&buf[1], msg->set_clipboard.sequence);
buf[9] = !!msg->set_clipboard.paste;
size_t len = write_string(msg->set_clipboard.text, size_t len = write_string(msg->set_clipboard.text,
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH, CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH,
&buf[2]); &buf[10]);
return 2 + len; return 10 + len;
} }
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE: case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
buf[1] = msg->set_screen_power_mode.mode; buf[1] = msg->set_screen_power_mode.mode;
@ -199,7 +200,8 @@ control_msg_log(const struct control_msg *msg) {
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action)); KEYEVENT_ACTION_LABEL(msg->inject_keycode.action));
break; break;
case CONTROL_MSG_TYPE_SET_CLIPBOARD: case CONTROL_MSG_TYPE_SET_CLIPBOARD:
LOG_CMSG("clipboard %s \"%s\"", LOG_CMSG("clipboard %" PRIu64_ " %s \"%s\"",
msg->set_clipboard.sequence,
msg->set_clipboard.paste ? "paste" : "copy", msg->set_clipboard.paste ? "paste" : "copy",
msg->set_clipboard.text); msg->set_clipboard.text);
break; break;

View file

@ -70,6 +70,7 @@ struct control_msg {
// screen may only be turned on on ACTION_DOWN // screen may only be turned on on ACTION_DOWN
} back_or_screen_on; } back_or_screen_on;
struct { struct {
uint64_t sequence;
char *text; // owned, to be freed by free() char *text; // owned, to be freed by free()
bool paste; bool paste;
} set_clipboard; } set_clipboard;

View file

@ -225,6 +225,7 @@ set_device_clipboard(struct controller *controller, bool paste) {
struct control_msg msg; struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_SET_CLIPBOARD; msg.type = CONTROL_MSG_TYPE_SET_CLIPBOARD;
msg.set_clipboard.sequence = 0; // unused for now
msg.set_clipboard.text = text_dup; msg.set_clipboard.text = text_dup;
msg.set_clipboard.paste = paste; msg.set_clipboard.paste = paste;

View file

@ -226,6 +226,7 @@ static void test_serialize_set_clipboard(void) {
struct control_msg msg = { struct control_msg msg = {
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD, .type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
.set_clipboard = { .set_clipboard = {
.sequence = UINT64_C(0x0102030405060708),
.paste = true, .paste = true,
.text = "hello, world!", .text = "hello, world!",
}, },
@ -233,10 +234,11 @@ static void test_serialize_set_clipboard(void) {
unsigned char buf[CONTROL_MSG_MAX_SIZE]; unsigned char buf[CONTROL_MSG_MAX_SIZE];
size_t size = control_msg_serialize(&msg, buf); size_t size = control_msg_serialize(&msg, buf);
assert(size == 19); assert(size == 27);
const unsigned char expected[] = { const unsigned char expected[] = {
CONTROL_MSG_TYPE_SET_CLIPBOARD, CONTROL_MSG_TYPE_SET_CLIPBOARD,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
1, // paste 1, // paste
0x00, 0x00, 0x00, 0x0d, // text length 0x00, 0x00, 0x00, 0x0d, // text length
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text 'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text

View file

@ -31,6 +31,7 @@ public final class ControlMessage {
private int vScroll; private int vScroll;
private boolean paste; private boolean paste;
private int repeat; private int repeat;
private long sequence;
private ControlMessage() { private ControlMessage() {
} }
@ -79,9 +80,10 @@ public final class ControlMessage {
return msg; return msg;
} }
public static ControlMessage createSetClipboard(String text, boolean paste) { public static ControlMessage createSetClipboard(long sequence, String text, boolean paste) {
ControlMessage msg = new ControlMessage(); ControlMessage msg = new ControlMessage();
msg.type = TYPE_SET_CLIPBOARD; msg.type = TYPE_SET_CLIPBOARD;
msg.sequence = sequence;
msg.text = text; msg.text = text;
msg.paste = paste; msg.paste = paste;
return msg; return msg;
@ -154,4 +156,8 @@ public final class ControlMessage {
public int getRepeat() { public int getRepeat() {
return repeat; return repeat;
} }
public long getSequence() {
return sequence;
}
} }

View file

@ -13,11 +13,11 @@ public class ControlMessageReader {
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20; static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
static final int BACK_OR_SCREEN_ON_LENGTH = 1; static final int BACK_OR_SCREEN_ON_LENGTH = 1;
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1; static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1; static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 9;
private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k
public static final int CLIPBOARD_TEXT_MAX_LENGTH = MESSAGE_MAX_SIZE - 6; // type: 1 byte; paste flag: 1 byte; length: 4 bytes public static final int CLIPBOARD_TEXT_MAX_LENGTH = MESSAGE_MAX_SIZE - 14; // type: 1 byte; sequence: 8 bytes; paste flag: 1 byte; length: 4 bytes
public static final int INJECT_TEXT_MAX_LENGTH = 300; public static final int INJECT_TEXT_MAX_LENGTH = 300;
private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE]; private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE];
@ -166,12 +166,13 @@ public class ControlMessageReader {
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) { if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
return null; return null;
} }
long sequence = buffer.getLong();
boolean paste = buffer.get() != 0; boolean paste = buffer.get() != 0;
String text = parseString(); String text = parseString();
if (text == null) { if (text == null) {
return null; return null;
} }
return ControlMessage.createSetClipboard(text, paste); return ControlMessage.createSetClipboard(sequence, text, paste);
} }
private ControlMessage parseSetScreenPowerMode() { private ControlMessage parseSetScreenPowerMode() {

View file

@ -235,6 +235,7 @@ public class ControlMessageReaderTest {
ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos); DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD); dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
dos.writeLong(0x0102030405060708L); // sequence
dos.writeByte(1); // paste dos.writeByte(1); // paste
byte[] text = "testé".getBytes(StandardCharsets.UTF_8); byte[] text = "testé".getBytes(StandardCharsets.UTF_8);
dos.writeInt(text.length); dos.writeInt(text.length);
@ -246,6 +247,7 @@ public class ControlMessageReaderTest {
ControlMessage event = reader.next(); ControlMessage event = reader.next();
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType()); Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
Assert.assertEquals(0x0102030405060708L, event.getSequence());
Assert.assertEquals("testé", event.getText()); Assert.assertEquals("testé", event.getText());
Assert.assertTrue(event.getPaste()); Assert.assertTrue(event.getPaste());
} }
@ -259,6 +261,7 @@ public class ControlMessageReaderTest {
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD); dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
byte[] rawText = new byte[ControlMessageReader.CLIPBOARD_TEXT_MAX_LENGTH]; byte[] rawText = new byte[ControlMessageReader.CLIPBOARD_TEXT_MAX_LENGTH];
dos.writeLong(0x0807060504030201L); // sequence
dos.writeByte(1); // paste dos.writeByte(1); // paste
Arrays.fill(rawText, (byte) 'a'); Arrays.fill(rawText, (byte) 'a');
String text = new String(rawText, 0, rawText.length); String text = new String(rawText, 0, rawText.length);
@ -272,6 +275,7 @@ public class ControlMessageReaderTest {
ControlMessage event = reader.next(); ControlMessage event = reader.next();
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType()); Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
Assert.assertEquals(0x0807060504030201L, event.getSequence());
Assert.assertEquals(text, event.getText()); Assert.assertEquals(text, event.getText());
Assert.assertTrue(event.getPaste()); Assert.assertTrue(event.getPaste());
} }