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:
parent
aba1fc03c3
commit
901d837165
7 changed files with 26 additions and 9 deletions
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue