2019-05-30 06:25:37 +08:00
|
|
|
#include "receiver.h"
|
|
|
|
|
2019-11-28 04:11:40 +08:00
|
|
|
#include <assert.h>
|
2019-05-30 06:25:37 +08:00
|
|
|
#include <SDL2/SDL_clipboard.h>
|
|
|
|
|
2019-05-31 20:55:11 +08:00
|
|
|
#include "device_msg.h"
|
2019-11-24 18:53:00 +08:00
|
|
|
#include "util/log.h"
|
2019-05-30 06:25:37 +08:00
|
|
|
|
|
|
|
bool
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
receiver_init(struct receiver *receiver, sc_socket control_socket,
|
|
|
|
struct sc_acksync *acksync) {
|
2021-02-01 01:24:35 +08:00
|
|
|
bool ok = sc_mutex_init(&receiver->mutex);
|
|
|
|
if (!ok) {
|
2019-05-30 06:25:37 +08:00
|
|
|
return false;
|
|
|
|
}
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
|
2019-05-30 06:25:37 +08:00
|
|
|
receiver->control_socket = control_socket;
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
receiver->acksync = acksync;
|
|
|
|
|
2019-05-30 06:25:37 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
receiver_destroy(struct receiver *receiver) {
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_mutex_destroy(&receiver->mutex);
|
2019-05-30 06:25:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
process_msg(struct receiver *receiver, struct device_msg *msg) {
|
2019-05-31 20:55:11 +08:00
|
|
|
switch (msg->type) {
|
2020-07-17 06:00:42 +08:00
|
|
|
case DEVICE_MSG_TYPE_CLIPBOARD: {
|
|
|
|
char *current = SDL_GetClipboardText();
|
|
|
|
bool same = current && !strcmp(current, msg->clipboard.text);
|
|
|
|
SDL_free(current);
|
|
|
|
if (same) {
|
|
|
|
LOGD("Computer clipboard unchanged");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-31 21:43:25 +08:00
|
|
|
LOGI("Device clipboard copied");
|
2019-05-31 20:55:11 +08:00
|
|
|
SDL_SetClipboardText(msg->clipboard.text);
|
2019-05-30 06:25:37 +08:00
|
|
|
break;
|
2020-07-17 06:00:42 +08:00
|
|
|
}
|
2021-11-20 19:10:09 +08:00
|
|
|
case DEVICE_MSG_TYPE_ACK_CLIPBOARD:
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
assert(receiver->acksync);
|
|
|
|
LOGD("Ack device clipboard sequence=%" PRIu64_,
|
|
|
|
msg->ack_clipboard.sequence);
|
|
|
|
sc_acksync_ack(receiver->acksync, msg->ack_clipboard.sequence);
|
2021-11-20 19:10:09 +08:00
|
|
|
break;
|
2019-05-30 06:25:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
process_msgs(struct receiver *receiver, const unsigned char *buf, size_t len) {
|
2019-05-30 06:25:37 +08:00
|
|
|
size_t head = 0;
|
|
|
|
for (;;) {
|
2019-05-31 20:55:11 +08:00
|
|
|
struct device_msg msg;
|
|
|
|
ssize_t r = device_msg_deserialize(&buf[head], len - head, &msg);
|
2019-05-30 06:25:37 +08:00
|
|
|
if (r == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (r == 0) {
|
|
|
|
return head;
|
|
|
|
}
|
|
|
|
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
process_msg(receiver, &msg);
|
2019-05-31 20:55:11 +08:00
|
|
|
device_msg_destroy(&msg);
|
2019-05-30 06:25:37 +08:00
|
|
|
|
|
|
|
head += r;
|
2019-11-28 04:11:40 +08:00
|
|
|
assert(head <= len);
|
2019-05-30 06:25:37 +08:00
|
|
|
if (head == len) {
|
|
|
|
return head;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
run_receiver(void *data) {
|
|
|
|
struct receiver *receiver = data;
|
|
|
|
|
2020-06-05 05:50:08 +08:00
|
|
|
static unsigned char buf[DEVICE_MSG_MAX_SIZE];
|
2019-05-30 06:25:37 +08:00
|
|
|
size_t head = 0;
|
|
|
|
|
|
|
|
for (;;) {
|
2020-06-05 03:26:38 +08:00
|
|
|
assert(head < DEVICE_MSG_MAX_SIZE);
|
2020-06-05 04:44:43 +08:00
|
|
|
ssize_t r = net_recv(receiver->control_socket, buf + head,
|
2020-06-05 03:26:38 +08:00
|
|
|
DEVICE_MSG_MAX_SIZE - head);
|
2019-05-30 06:25:37 +08:00
|
|
|
if (r <= 0) {
|
|
|
|
LOGD("Receiver stopped");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-06-05 04:44:43 +08:00
|
|
|
head += r;
|
Wait SET_CLIPBOARD ack before Ctrl+v via HID
To allow seamless copy-paste, on Ctrl+v, a SET_CLIPBOARD request is
performed before injecting Ctrl+v.
But when HID keyboard is enabled, the Ctrl+v injection is not sent on
the same channel as the clipboard request, so they are not serialized,
and may occur in any order. If Ctrl+v happens to be injected before the
new clipboard content is set, then the old content is pasted instead,
which is incorrect.
To minimize the probability of occurrence of the wrong order, a delay of
2 milliseconds was added before injecting Ctrl+v. Then 5ms. But even
with 5ms, the wrong behavior sometimes happens.
To handle it properly, add an acknowledgement mechanism, so that Ctrl+v
is injected over AOA only after the SET_CLIPBOARD request has been
performed and acknowledged by the server.
Refs e4163321f00bb3830c6049bdb6c1515e7cc668a0
Refs 45b0f8123a52f5c73a5860d616f4ceba2766ca6a
PR #2814 <https://github.com/Genymobile/scrcpy/pull/2814>
2021-11-22 00:40:11 +08:00
|
|
|
ssize_t consumed = process_msgs(receiver, buf, head);
|
2019-05-30 06:25:37 +08:00
|
|
|
if (consumed == -1) {
|
|
|
|
// an error occurred
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (consumed) {
|
2020-06-05 04:44:43 +08:00
|
|
|
head -= consumed;
|
2019-05-30 06:25:37 +08:00
|
|
|
// shift the remaining data in the buffer
|
2020-06-05 04:44:43 +08:00
|
|
|
memmove(buf, &buf[consumed], head);
|
2019-05-30 06:25:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
receiver_start(struct receiver *receiver) {
|
|
|
|
LOGD("Starting receiver thread");
|
|
|
|
|
2021-12-10 04:32:11 +08:00
|
|
|
bool ok = sc_thread_create(&receiver->thread, run_receiver,
|
|
|
|
"scrcpy-receiver", receiver);
|
2021-02-01 01:24:35 +08:00
|
|
|
if (!ok) {
|
2019-05-30 06:25:37 +08:00
|
|
|
LOGC("Could not start receiver thread");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
receiver_join(struct receiver *receiver) {
|
2021-02-01 01:24:35 +08:00
|
|
|
sc_thread_join(&receiver->thread, NULL);
|
2019-05-30 06:25:37 +08:00
|
|
|
}
|