Compare commits
4 Commits
no_clipboa
...
pr2807
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f56be59a0c | ||
|
|
64400c8740 | ||
|
|
46f7cd31b9 | ||
|
|
d290b44248 |
@@ -730,9 +730,6 @@ of <kbd>Ctrl</kbd>+<kbd>v</kbd> and <kbd>MOD</kbd>+<kbd>v</kbd> so that they
|
||||
also inject the computer clipboard text as a sequence of key events (the same
|
||||
way as <kbd>MOD</kbd>+<kbd>Shift</kbd>+<kbd>v</kbd>).
|
||||
|
||||
To disable automatic clipboard synchronization, use
|
||||
`--no-clipboard-autosync`.
|
||||
|
||||
#### Pinch-to-zoom
|
||||
|
||||
To simulate "pinch-to-zoom": <kbd>Ctrl</kbd>+_click-and-move_.
|
||||
|
||||
@@ -25,7 +25,6 @@ src = [
|
||||
'src/server.c',
|
||||
'src/stream.c',
|
||||
'src/video_buffer.c',
|
||||
'src/util/acksync.c',
|
||||
'src/util/file.c',
|
||||
'src/util/intr.c',
|
||||
'src/util/log.c',
|
||||
@@ -40,26 +39,16 @@ src = [
|
||||
'src/util/tick.c',
|
||||
]
|
||||
|
||||
conf = configuration_data()
|
||||
|
||||
if host_machine.system() == 'windows'
|
||||
src += [
|
||||
'src/sys/win/file.c',
|
||||
'src/sys/win/process.c',
|
||||
]
|
||||
conf.set('_WIN32_WINNT', '0x0600')
|
||||
conf.set('WINVER', '0x0600')
|
||||
else
|
||||
src += [
|
||||
'src/sys/unix/file.c',
|
||||
'src/sys/unix/process.c',
|
||||
]
|
||||
conf.set('_POSIX_C_SOURCE', '200809L')
|
||||
conf.set('_XOPEN_SOURCE', '700')
|
||||
conf.set('_GNU_SOURCE', true)
|
||||
if host_machine.system() == 'darwin'
|
||||
conf.set('_DARWIN_C_SOURCE', true)
|
||||
endif
|
||||
endif
|
||||
|
||||
v4l2_support = host_machine.system() == 'linux'
|
||||
@@ -139,6 +128,8 @@ if host_machine.system() == 'windows'
|
||||
dependencies += cc.find_library('ws2_32')
|
||||
endif
|
||||
|
||||
conf = configuration_data()
|
||||
|
||||
foreach f : check_functions
|
||||
if cc.has_function(f)
|
||||
define = 'HAVE_' + f.underscorify().to_upper()
|
||||
|
||||
@@ -114,12 +114,6 @@ Limit both the width and height of the video to \fIvalue\fR. The other dimension
|
||||
|
||||
Default is 0 (unlimited).
|
||||
|
||||
.TP
|
||||
.B \-\-no\-clipboard\-autosync
|
||||
By default, scrcpy automatically synchronizes the computer clipboard to the device clipboard before injecting Ctrl+v, and the device clipboard to the computer clipboard whenever it changes.
|
||||
|
||||
This option disables this automatic synchronization.
|
||||
|
||||
.TP
|
||||
.B \-n, \-\-no\-control
|
||||
Disable device control (mirror the device in read\-only).
|
||||
|
||||
@@ -35,7 +35,7 @@ sc_hid_event_init(struct sc_hid_event *hid_event, uint16_t accessory_id,
|
||||
hid_event->accessory_id = accessory_id;
|
||||
hid_event->buffer = buffer;
|
||||
hid_event->size = buffer_size;
|
||||
hid_event->ack_to_wait = SC_SEQUENCE_INVALID;
|
||||
hid_event->delay = 0;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -118,10 +118,7 @@ sc_aoa_open_usb_handle(libusb_device *device, libusb_device_handle **handle) {
|
||||
}
|
||||
|
||||
bool
|
||||
sc_aoa_init(struct sc_aoa *aoa, const char *serial,
|
||||
struct sc_acksync *acksync) {
|
||||
assert(acksync);
|
||||
|
||||
sc_aoa_init(struct sc_aoa *aoa, const char *serial) {
|
||||
cbuf_init(&aoa->queue);
|
||||
|
||||
if (!sc_mutex_init(&aoa->mutex)) {
|
||||
@@ -158,7 +155,6 @@ sc_aoa_init(struct sc_aoa *aoa, const char *serial,
|
||||
}
|
||||
|
||||
aoa->stopped = false;
|
||||
aoa->acksync = acksync;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -336,28 +332,23 @@ run_aoa_thread(void *data) {
|
||||
assert(non_empty);
|
||||
(void) non_empty;
|
||||
|
||||
uint64_t ack_to_wait = event.ack_to_wait;
|
||||
sc_mutex_unlock(&aoa->mutex);
|
||||
|
||||
if (ack_to_wait != SC_SEQUENCE_INVALID) {
|
||||
LOGD("Waiting ack from server sequence=%" PRIu64_, ack_to_wait);
|
||||
// Do not block the loop indefinitely if the ack never comes (it should
|
||||
// never happen)
|
||||
sc_tick deadline = sc_tick_now() + SC_TICK_FROM_MS(500);
|
||||
enum sc_acksync_wait_result result =
|
||||
sc_acksync_wait(aoa->acksync, ack_to_wait, deadline);
|
||||
|
||||
if (result == SC_ACKSYNC_WAIT_TIMEOUT) {
|
||||
LOGW("Ack not received after 500ms, discarding HID event");
|
||||
sc_hid_event_destroy(&event);
|
||||
continue;
|
||||
} else if (result == SC_ACKSYNC_WAIT_INTR) {
|
||||
// stopped
|
||||
sc_hid_event_destroy(&event);
|
||||
assert(event.delay >= 0);
|
||||
if (event.delay) {
|
||||
// Wait during the specified delay before injecting the HID event
|
||||
sc_tick deadline = sc_tick_now() + event.delay;
|
||||
bool timed_out = false;
|
||||
while (!aoa->stopped && !timed_out) {
|
||||
timed_out = !sc_cond_timedwait(&aoa->event_cond, &aoa->mutex,
|
||||
deadline);
|
||||
}
|
||||
if (aoa->stopped) {
|
||||
sc_mutex_unlock(&aoa->mutex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sc_mutex_unlock(&aoa->mutex);
|
||||
|
||||
bool ok = sc_aoa_send_hid_event(aoa, &event);
|
||||
sc_hid_event_destroy(&event);
|
||||
if (!ok) {
|
||||
@@ -386,8 +377,6 @@ sc_aoa_stop(struct sc_aoa *aoa) {
|
||||
aoa->stopped = true;
|
||||
sc_cond_signal(&aoa->event_cond);
|
||||
sc_mutex_unlock(&aoa->mutex);
|
||||
|
||||
sc_acksync_interrupt(aoa->acksync);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#include "util/acksync.h"
|
||||
#include "util/cbuf.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/tick.h"
|
||||
@@ -15,7 +14,7 @@ struct sc_hid_event {
|
||||
uint16_t accessory_id;
|
||||
unsigned char *buffer;
|
||||
uint16_t size;
|
||||
uint64_t ack_to_wait;
|
||||
sc_tick delay;
|
||||
};
|
||||
|
||||
// Takes ownership of buffer
|
||||
@@ -37,12 +36,10 @@ struct sc_aoa {
|
||||
sc_cond event_cond;
|
||||
bool stopped;
|
||||
struct sc_hid_event_queue queue;
|
||||
|
||||
struct sc_acksync *acksync;
|
||||
};
|
||||
|
||||
bool
|
||||
sc_aoa_init(struct sc_aoa *aoa, const char *serial, struct sc_acksync *acksync);
|
||||
sc_aoa_init(struct sc_aoa *aoa, const char *serial);
|
||||
|
||||
void
|
||||
sc_aoa_destroy(struct sc_aoa *aoa);
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
#define OPT_V4L2_BUFFER 1029
|
||||
#define OPT_TUNNEL_HOST 1030
|
||||
#define OPT_TUNNEL_PORT 1031
|
||||
#define OPT_NO_CLIPBOARD_AUTOSYNC 1032
|
||||
|
||||
struct sc_option {
|
||||
char shortopt;
|
||||
@@ -209,15 +208,6 @@ static const struct sc_option options[] = {
|
||||
"is preserved.\n"
|
||||
"Default is 0 (unlimited).",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_NO_CLIPBOARD_AUTOSYNC,
|
||||
.longopt = "no-clipboard-autosync",
|
||||
.text = "By default, scrcpy automatically synchronizes the computer "
|
||||
"clipboard to the device clipboard before injecting Ctrl+v, "
|
||||
"and the device clipboard to the computer clipboard whenever "
|
||||
"it changes.\n"
|
||||
"This option disables this automatic synchronization."
|
||||
},
|
||||
{
|
||||
.shortopt = 'n',
|
||||
.longopt = "no-control",
|
||||
@@ -1374,9 +1364,6 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OPT_NO_CLIPBOARD_AUTOSYNC:
|
||||
opts->clipboard_autosync = false;
|
||||
break;
|
||||
#ifdef HAVE_V4L2
|
||||
case OPT_V4L2_SINK:
|
||||
opts->v4l2_device = optarg;
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
#ifndef COMPAT_H
|
||||
#define COMPAT_H
|
||||
|
||||
#include "config.h"
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#define _XOPEN_SOURCE 700
|
||||
#define _GNU_SOURCE
|
||||
#ifdef __APPLE__
|
||||
# define _DARWIN_C_SOURCE
|
||||
#endif
|
||||
|
||||
#include <libavformat/version.h>
|
||||
#include <SDL2/SDL_version.h>
|
||||
|
||||
#ifndef __WIN32
|
||||
# define PRIu64_ PRIu64
|
||||
#else
|
||||
# define PRIu64_ "I64u" // Windows...
|
||||
#endif
|
||||
|
||||
// In ffmpeg/doc/APIchanges:
|
||||
// 2018-02-06 - 0694d87024 - lavf 58.9.100 - avformat.h
|
||||
// Deprecate use of av_register_input_format(), av_register_output_format(),
|
||||
|
||||
@@ -118,12 +118,11 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
||||
buf[1] = msg->inject_keycode.action;
|
||||
return 2;
|
||||
case CONTROL_MSG_TYPE_SET_CLIPBOARD: {
|
||||
buffer_write64be(&buf[1], msg->set_clipboard.sequence);
|
||||
buf[9] = !!msg->set_clipboard.paste;
|
||||
buf[1] = !!msg->set_clipboard.paste;
|
||||
size_t len = write_string(msg->set_clipboard.text,
|
||||
CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH,
|
||||
&buf[10]);
|
||||
return 10 + len;
|
||||
&buf[2]);
|
||||
return 2 + len;
|
||||
}
|
||||
case CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE:
|
||||
buf[1] = msg->set_screen_power_mode.mode;
|
||||
@@ -171,6 +170,11 @@ control_msg_log(const struct control_msg *msg) {
|
||||
(long) msg->inject_touch_event.buttons);
|
||||
} else {
|
||||
// numeric pointer id
|
||||
#ifndef __WIN32
|
||||
# define PRIu64_ PRIu64
|
||||
#else
|
||||
# define PRIu64_ "I64u" // Windows...
|
||||
#endif
|
||||
LOG_CMSG("touch [id=%" PRIu64_ "] %-4s position=%" PRIi32 ",%"
|
||||
PRIi32 " pressure=%g buttons=%06lx",
|
||||
id,
|
||||
@@ -195,8 +199,7 @@ control_msg_log(const struct control_msg *msg) {
|
||||
KEYEVENT_ACTION_LABEL(msg->inject_keycode.action));
|
||||
break;
|
||||
case CONTROL_MSG_TYPE_SET_CLIPBOARD:
|
||||
LOG_CMSG("clipboard %" PRIu64_ " %s \"%s\"",
|
||||
msg->set_clipboard.sequence,
|
||||
LOG_CMSG("clipboard %s \"%s\"",
|
||||
msg->set_clipboard.paste ? "paste" : "copy",
|
||||
msg->set_clipboard.text);
|
||||
break;
|
||||
|
||||
@@ -70,7 +70,6 @@ struct control_msg {
|
||||
// screen may only be turned on on ACTION_DOWN
|
||||
} back_or_screen_on;
|
||||
struct {
|
||||
uint64_t sequence;
|
||||
char *text; // owned, to be freed by free()
|
||||
bool paste;
|
||||
} set_clipboard;
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
#include "util/log.h"
|
||||
|
||||
bool
|
||||
controller_init(struct controller *controller, sc_socket control_socket,
|
||||
struct sc_acksync *acksync) {
|
||||
controller_init(struct controller *controller, sc_socket control_socket) {
|
||||
cbuf_init(&controller->queue);
|
||||
|
||||
bool ok = receiver_init(&controller->receiver, control_socket, acksync);
|
||||
bool ok = receiver_init(&controller->receiver, control_socket);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include "control_msg.h"
|
||||
#include "receiver.h"
|
||||
#include "util/acksync.h"
|
||||
#include "util/cbuf.h"
|
||||
#include "util/net.h"
|
||||
#include "util/thread.h"
|
||||
@@ -25,8 +24,7 @@ struct controller {
|
||||
};
|
||||
|
||||
bool
|
||||
controller_init(struct controller *controller, sc_socket control_socket,
|
||||
struct sc_acksync *acksync);
|
||||
controller_init(struct controller *controller, sc_socket control_socket);
|
||||
|
||||
void
|
||||
controller_destroy(struct controller *controller);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "device_msg.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -35,11 +34,6 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
|
||||
msg->clipboard.text = text;
|
||||
return 5 + clipboard_len;
|
||||
}
|
||||
case DEVICE_MSG_TYPE_ACK_CLIPBOARD: {
|
||||
uint64_t sequence = buffer_read64be(&buf[1]);
|
||||
msg->ack_clipboard.sequence = sequence;
|
||||
return 9;
|
||||
}
|
||||
default:
|
||||
LOGW("Unknown device message type: %d", (int) msg->type);
|
||||
return -1; // error, we cannot recover
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
|
||||
enum device_msg_type {
|
||||
DEVICE_MSG_TYPE_CLIPBOARD,
|
||||
DEVICE_MSG_TYPE_ACK_CLIPBOARD,
|
||||
};
|
||||
|
||||
struct device_msg {
|
||||
@@ -22,9 +21,6 @@ struct device_msg {
|
||||
struct {
|
||||
char *text; // owned, to be freed by free()
|
||||
} clipboard;
|
||||
struct {
|
||||
uint64_t sequence;
|
||||
} ack_clipboard;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -278,8 +278,7 @@ push_mod_lock_state(struct sc_hid_keyboard *kb, uint16_t sdl_mod) {
|
||||
|
||||
static void
|
||||
sc_key_processor_process_key(struct sc_key_processor *kp,
|
||||
const SDL_KeyboardEvent *event,
|
||||
uint64_t ack_to_wait) {
|
||||
const SDL_KeyboardEvent *event) {
|
||||
if (event->repeat) {
|
||||
// In USB HID protocol, key repeat is handled by the host (Android), so
|
||||
// just ignore key repeat here.
|
||||
@@ -299,12 +298,16 @@ sc_key_processor_process_key(struct sc_key_processor *kp,
|
||||
}
|
||||
}
|
||||
|
||||
if (ack_to_wait) {
|
||||
SDL_Keycode keycode = event->keysym.sym;
|
||||
bool down = event->type == SDL_KEYDOWN;
|
||||
bool ctrl = event->keysym.mod & KMOD_CTRL;
|
||||
bool shift = event->keysym.mod & KMOD_SHIFT;
|
||||
if (ctrl && !shift && keycode == SDLK_v && down) {
|
||||
// Ctrl+v is pressed, so clipboard synchronization has been
|
||||
// requested. Wait until clipboard synchronization is acknowledged
|
||||
// by the server, otherwise it could paste the old clipboard
|
||||
// content.
|
||||
hid_event.ack_to_wait = ack_to_wait;
|
||||
// requested. Wait a bit so that the clipboard is set before
|
||||
// injecting Ctrl+v via HID, otherwise it would paste the old
|
||||
// clipboard content.
|
||||
hid_event.delay = SC_TICK_FROM_MS(5);
|
||||
}
|
||||
|
||||
if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) {
|
||||
@@ -345,10 +348,6 @@ sc_hid_keyboard_init(struct sc_hid_keyboard *kb, struct sc_aoa *aoa) {
|
||||
.process_text = sc_key_processor_process_text,
|
||||
};
|
||||
|
||||
// Clipboard synchronization is requested over the control socket, while HID
|
||||
// events are sent over AOA, so it must wait for clipboard synchronization
|
||||
// to be acknowledged by the device before injecting Ctrl+v.
|
||||
kb->key_processor.async_paste = true;
|
||||
kb->key_processor.ops = &ops;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -66,7 +66,6 @@ input_manager_init(struct input_manager *im, struct controller *controller,
|
||||
im->control = options->control;
|
||||
im->forward_all_clicks = options->forward_all_clicks;
|
||||
im->legacy_paste = options->legacy_paste;
|
||||
im->clipboard_autosync = options->clipboard_autosync;
|
||||
|
||||
const struct sc_shortcut_mods *shortcut_mods = &options->shortcut_mods;
|
||||
assert(shortcut_mods->count);
|
||||
@@ -83,8 +82,6 @@ input_manager_init(struct input_manager *im, struct controller *controller,
|
||||
im->last_keycode = SDLK_UNKNOWN;
|
||||
im->last_mod = 0;
|
||||
im->key_repeat = 0;
|
||||
|
||||
im->next_sequence = 1; // 0 is reserved for SC_SEQUENCE_INVALID
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -211,35 +208,35 @@ collapse_panels(struct controller *controller) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
set_device_clipboard(struct controller *controller, bool paste,
|
||||
uint64_t sequence) {
|
||||
static void
|
||||
set_device_clipboard(struct controller *controller, bool paste) {
|
||||
char *text = SDL_GetClipboardText();
|
||||
if (!text) {
|
||||
LOGW("Could not get clipboard text: %s", SDL_GetError());
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
if (!*text) {
|
||||
// empty text
|
||||
SDL_free(text);
|
||||
return;
|
||||
}
|
||||
|
||||
char *text_dup = strdup(text);
|
||||
SDL_free(text);
|
||||
if (!text_dup) {
|
||||
LOGW("Could not strdup input text");
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
struct control_msg msg;
|
||||
msg.type = CONTROL_MSG_TYPE_SET_CLIPBOARD;
|
||||
msg.set_clipboard.sequence = sequence;
|
||||
msg.set_clipboard.text = text_dup;
|
||||
msg.set_clipboard.paste = paste;
|
||||
|
||||
if (!controller_push_msg(controller, &msg)) {
|
||||
free(text_dup);
|
||||
LOGW("Could not request 'set device clipboard'");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -465,10 +462,8 @@ input_manager_process_key(struct input_manager *im,
|
||||
// inject the text as input events
|
||||
clipboard_paste(controller);
|
||||
} else {
|
||||
// store the text in the device clipboard and paste,
|
||||
// without requesting an acknowledgment
|
||||
set_device_clipboard(controller, true,
|
||||
SC_SEQUENCE_INVALID);
|
||||
// store the text in the device clipboard and paste
|
||||
set_device_clipboard(controller, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -517,36 +512,18 @@ input_manager_process_key(struct input_manager *im,
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t ack_to_wait = SC_SEQUENCE_INVALID;
|
||||
bool is_ctrl_v = ctrl && !shift && keycode == SDLK_v && down && !repeat;
|
||||
if (im->clipboard_autosync && is_ctrl_v) {
|
||||
if (ctrl && !shift && keycode == SDLK_v && down && !repeat) {
|
||||
if (im->legacy_paste) {
|
||||
// inject the text as input events
|
||||
clipboard_paste(controller);
|
||||
return;
|
||||
}
|
||||
|
||||
// Request an acknowledgement only if necessary
|
||||
uint64_t sequence = im->kp->async_paste ? im->next_sequence
|
||||
: SC_SEQUENCE_INVALID;
|
||||
|
||||
// Synchronize the computer clipboard to the device clipboard before
|
||||
// sending Ctrl+v, to allow seamless copy-paste.
|
||||
bool ok = set_device_clipboard(controller, false, sequence);
|
||||
if (!ok) {
|
||||
LOGW("Clipboard could not be synchronized, Ctrl+v not injected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (im->kp->async_paste) {
|
||||
// The key processor must wait for this ack before injecting Ctrl+v
|
||||
ack_to_wait = sequence;
|
||||
// Increment only when the request succeeded
|
||||
++im->next_sequence;
|
||||
}
|
||||
set_device_clipboard(controller, false);
|
||||
}
|
||||
|
||||
im->kp->ops->process_key(im->kp, event, ack_to_wait);
|
||||
im->kp->ops->process_key(im->kp, event);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -24,7 +24,6 @@ struct input_manager {
|
||||
bool control;
|
||||
bool forward_all_clicks;
|
||||
bool legacy_paste;
|
||||
bool clipboard_autosync;
|
||||
|
||||
struct {
|
||||
unsigned data[SC_MAX_SHORTCUT_MODS];
|
||||
@@ -39,8 +38,6 @@ struct input_manager {
|
||||
unsigned key_repeat;
|
||||
SDL_Keycode last_keycode;
|
||||
uint16_t last_mod;
|
||||
|
||||
uint64_t next_sequence; // used for request acknowledgements
|
||||
};
|
||||
|
||||
void
|
||||
|
||||
@@ -188,13 +188,7 @@ convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to,
|
||||
|
||||
static void
|
||||
sc_key_processor_process_key(struct sc_key_processor *kp,
|
||||
const SDL_KeyboardEvent *event,
|
||||
uint64_t ack_to_wait) {
|
||||
// The device clipboard synchronization and the key event messages are
|
||||
// serialized, there is nothing special to do to ensure that the clipboard
|
||||
// is set before injecting Ctrl+v.
|
||||
(void) ack_to_wait;
|
||||
|
||||
const SDL_KeyboardEvent *event) {
|
||||
struct sc_keyboard_inject *ki = DOWNCAST(kp);
|
||||
|
||||
if (event->repeat) {
|
||||
@@ -256,7 +250,5 @@ sc_keyboard_inject_init(struct sc_keyboard_inject *ki,
|
||||
.process_text = sc_key_processor_process_text,
|
||||
};
|
||||
|
||||
// Key injection and clipboard synchronization are serialized
|
||||
ki->key_processor.async_paste = false;
|
||||
ki->key_processor.ops = &ops;
|
||||
}
|
||||
|
||||
@@ -53,5 +53,4 @@ const struct scrcpy_options scrcpy_options_default = {
|
||||
.forward_all_clicks = false,
|
||||
.legacy_paste = false,
|
||||
.power_off_on_close = false,
|
||||
.clipboard_autosync = true,
|
||||
};
|
||||
|
||||
@@ -108,7 +108,6 @@ struct scrcpy_options {
|
||||
bool forward_all_clicks;
|
||||
bool legacy_paste;
|
||||
bool power_off_on_close;
|
||||
bool clipboard_autosync;
|
||||
};
|
||||
|
||||
extern const struct scrcpy_options scrcpy_options_default;
|
||||
|
||||
@@ -7,16 +7,12 @@
|
||||
#include "util/log.h"
|
||||
|
||||
bool
|
||||
receiver_init(struct receiver *receiver, sc_socket control_socket,
|
||||
struct sc_acksync *acksync) {
|
||||
receiver_init(struct receiver *receiver, sc_socket control_socket) {
|
||||
bool ok = sc_mutex_init(&receiver->mutex);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
receiver->control_socket = control_socket;
|
||||
receiver->acksync = acksync;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -26,7 +22,7 @@ receiver_destroy(struct receiver *receiver) {
|
||||
}
|
||||
|
||||
static void
|
||||
process_msg(struct receiver *receiver, struct device_msg *msg) {
|
||||
process_msg(struct device_msg *msg) {
|
||||
switch (msg->type) {
|
||||
case DEVICE_MSG_TYPE_CLIPBOARD: {
|
||||
char *current = SDL_GetClipboardText();
|
||||
@@ -41,17 +37,11 @@ process_msg(struct receiver *receiver, struct device_msg *msg) {
|
||||
SDL_SetClipboardText(msg->clipboard.text);
|
||||
break;
|
||||
}
|
||||
case DEVICE_MSG_TYPE_ACK_CLIPBOARD:
|
||||
assert(receiver->acksync);
|
||||
LOGD("Ack device clipboard sequence=%" PRIu64_,
|
||||
msg->ack_clipboard.sequence);
|
||||
sc_acksync_ack(receiver->acksync, msg->ack_clipboard.sequence);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
process_msgs(struct receiver *receiver, const unsigned char *buf, size_t len) {
|
||||
process_msgs(const unsigned char *buf, size_t len) {
|
||||
size_t head = 0;
|
||||
for (;;) {
|
||||
struct device_msg msg;
|
||||
@@ -63,7 +53,7 @@ process_msgs(struct receiver *receiver, const unsigned char *buf, size_t len) {
|
||||
return head;
|
||||
}
|
||||
|
||||
process_msg(receiver, &msg);
|
||||
process_msg(&msg);
|
||||
device_msg_destroy(&msg);
|
||||
|
||||
head += r;
|
||||
@@ -91,7 +81,7 @@ run_receiver(void *data) {
|
||||
}
|
||||
|
||||
head += r;
|
||||
ssize_t consumed = process_msgs(receiver, buf, head);
|
||||
ssize_t consumed = process_msgs(buf, head);
|
||||
if (consumed == -1) {
|
||||
// an error occurred
|
||||
break;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "util/acksync.h"
|
||||
#include "util/net.h"
|
||||
#include "util/thread.h"
|
||||
|
||||
@@ -15,13 +14,10 @@ struct receiver {
|
||||
sc_socket control_socket;
|
||||
sc_thread thread;
|
||||
sc_mutex mutex;
|
||||
|
||||
struct sc_acksync *acksync;
|
||||
};
|
||||
|
||||
bool
|
||||
receiver_init(struct receiver *receiver, sc_socket control_socket,
|
||||
struct sc_acksync *acksync);
|
||||
receiver_init(struct receiver *receiver, sc_socket control_socket);
|
||||
|
||||
void
|
||||
receiver_destroy(struct receiver *receiver);
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "screen.h"
|
||||
#include "server.h"
|
||||
#include "stream.h"
|
||||
#include "util/acksync.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net.h"
|
||||
#ifdef HAVE_V4L2
|
||||
@@ -47,8 +46,6 @@ struct scrcpy {
|
||||
struct file_handler file_handler;
|
||||
#ifdef HAVE_AOA_HID
|
||||
struct sc_aoa aoa;
|
||||
// sequence/ack helper to synchronize clipboard and Ctrl+v via HID
|
||||
struct sc_acksync acksync;
|
||||
#endif
|
||||
union {
|
||||
struct sc_keyboard_inject keyboard_inject;
|
||||
@@ -343,8 +340,6 @@ scrcpy(struct scrcpy_options *options) {
|
||||
bool controller_started = false;
|
||||
bool screen_initialized = false;
|
||||
|
||||
struct sc_acksync *acksync = NULL;
|
||||
|
||||
struct sc_server_params params = {
|
||||
.serial = options->serial,
|
||||
.log_level = options->log_level,
|
||||
@@ -364,7 +359,6 @@ scrcpy(struct scrcpy_options *options) {
|
||||
.encoder_name = options->encoder_name,
|
||||
.force_adb_forward = options->force_adb_forward,
|
||||
.power_off_on_close = options->power_off_on_close,
|
||||
.clipboard_autosync = options->clipboard_autosync,
|
||||
};
|
||||
|
||||
static const struct sc_server_callbacks cbs = {
|
||||
@@ -451,18 +445,7 @@ scrcpy(struct scrcpy_options *options) {
|
||||
}
|
||||
|
||||
if (options->control) {
|
||||
#ifdef HAVE_AOA_HID
|
||||
if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID) {
|
||||
bool ok = sc_acksync_init(&s->acksync);
|
||||
if (!ok) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
acksync = &s->acksync;
|
||||
}
|
||||
#endif
|
||||
if (!controller_init(&s->controller, s->server.control_socket,
|
||||
acksync)) {
|
||||
if (!controller_init(&s->controller, s->server.control_socket)) {
|
||||
goto end;
|
||||
}
|
||||
controller_initialized = true;
|
||||
@@ -538,7 +521,7 @@ scrcpy(struct scrcpy_options *options) {
|
||||
#ifdef HAVE_AOA_HID
|
||||
bool aoa_hid_ok = false;
|
||||
|
||||
bool ok = sc_aoa_init(&s->aoa, serial, acksync);
|
||||
bool ok = sc_aoa_init(&s->aoa, serial);
|
||||
if (!ok) {
|
||||
goto aoa_hid_end;
|
||||
}
|
||||
@@ -603,9 +586,6 @@ end:
|
||||
sc_hid_keyboard_destroy(&s->keyboard_hid);
|
||||
sc_aoa_stop(&s->aoa);
|
||||
}
|
||||
if (acksync) {
|
||||
sc_acksync_destroy(acksync);
|
||||
}
|
||||
#endif
|
||||
if (controller_started) {
|
||||
controller_stop(&s->controller);
|
||||
|
||||
@@ -186,7 +186,6 @@ execute_server(struct sc_server *server,
|
||||
params->codec_options ? params->codec_options : "-",
|
||||
params->encoder_name ? params->encoder_name : "-",
|
||||
params->power_off_on_close ? "true" : "false",
|
||||
params->clipboard_autosync ? "true" : "false",
|
||||
};
|
||||
#ifdef SERVER_DEBUGGER
|
||||
LOGI("Server debugger waiting for a client on device port "
|
||||
|
||||
@@ -41,7 +41,6 @@ struct sc_server_params {
|
||||
bool stay_awake;
|
||||
bool force_adb_forward;
|
||||
bool power_off_on_close;
|
||||
bool clipboard_autosync;
|
||||
};
|
||||
|
||||
struct sc_server {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// <https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873>
|
||||
#define _WIN32_WINNT 0x0600 // For extended process API
|
||||
|
||||
#include "util/process.h"
|
||||
|
||||
#include <processthreadsapi.h>
|
||||
|
||||
@@ -14,31 +14,12 @@
|
||||
* Component able to process and inject keys should implement this trait.
|
||||
*/
|
||||
struct sc_key_processor {
|
||||
/**
|
||||
* Set by the implementation to indicate that it must explicitly wait for
|
||||
* the clipboard to be set on the device before injecting Ctrl+v to avoid
|
||||
* race conditions. If it is set, the input_manager will pass a valid
|
||||
* ack_to_wait to process_key() in case of clipboard synchronization
|
||||
* resulting of the key event.
|
||||
*/
|
||||
bool async_paste;
|
||||
|
||||
const struct sc_key_processor_ops *ops;
|
||||
};
|
||||
|
||||
struct sc_key_processor_ops {
|
||||
|
||||
/**
|
||||
* Process the keyboard event
|
||||
*
|
||||
* The `sequence` number (if different from `SC_SEQUENCE_INVALID`) indicates
|
||||
* the acknowledgement number to wait for before injecting this event.
|
||||
* This allows to ensure that the device clipboard is set before injecting
|
||||
* Ctrl+v on the device.
|
||||
*/
|
||||
void
|
||||
(*process_key)(struct sc_key_processor *kp, const SDL_KeyboardEvent *event,
|
||||
uint64_t ack_to_wait);
|
||||
(*process_key)(struct sc_key_processor *kp, const SDL_KeyboardEvent *event);
|
||||
|
||||
void
|
||||
(*process_text)(struct sc_key_processor *kp,
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
#include "acksync.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include "util/log.h"
|
||||
|
||||
bool
|
||||
sc_acksync_init(struct sc_acksync *as) {
|
||||
bool ok = sc_mutex_init(&as->mutex);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = sc_cond_init(&as->cond);
|
||||
if (!ok) {
|
||||
sc_mutex_destroy(&as->mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
as->stopped = false;
|
||||
as->ack = SC_SEQUENCE_INVALID;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
sc_acksync_destroy(struct sc_acksync *as) {
|
||||
sc_cond_destroy(&as->cond);
|
||||
sc_mutex_destroy(&as->mutex);
|
||||
}
|
||||
|
||||
void
|
||||
sc_acksync_ack(struct sc_acksync *as, uint64_t sequence) {
|
||||
sc_mutex_lock(&as->mutex);
|
||||
|
||||
// Acknowledgements must be monotonic
|
||||
assert(sequence >= as->ack);
|
||||
|
||||
as->ack = sequence;
|
||||
sc_cond_signal(&as->cond);
|
||||
|
||||
sc_mutex_unlock(&as->mutex);
|
||||
}
|
||||
|
||||
enum sc_acksync_wait_result
|
||||
sc_acksync_wait(struct sc_acksync *as, uint64_t ack, sc_tick deadline) {
|
||||
sc_mutex_lock(&as->mutex);
|
||||
|
||||
bool timed_out = false;
|
||||
while (!as->stopped && as->ack < ack && !timed_out) {
|
||||
timed_out = !sc_cond_timedwait(&as->cond, &as->mutex, deadline);
|
||||
}
|
||||
|
||||
enum sc_acksync_wait_result ret;
|
||||
if (as->stopped) {
|
||||
ret = SC_ACKSYNC_WAIT_INTR;
|
||||
} else if (as->ack >= ack) {
|
||||
ret = SC_ACKSYNC_WAIT_OK;
|
||||
} else {
|
||||
assert(timed_out);
|
||||
ret = SC_ACKSYNC_WAIT_TIMEOUT;
|
||||
}
|
||||
sc_mutex_unlock(&as->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupt any `sc_acksync_wait()`
|
||||
*/
|
||||
void
|
||||
sc_acksync_interrupt(struct sc_acksync *as) {
|
||||
sc_mutex_lock(&as->mutex);
|
||||
as->stopped = true;
|
||||
sc_cond_signal(&as->cond);
|
||||
sc_mutex_unlock(&as->mutex);
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
#ifndef SC_ACK_SYNC_H
|
||||
#define SC_ACK_SYNC_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "thread.h"
|
||||
|
||||
#define SC_SEQUENCE_INVALID 0
|
||||
|
||||
/**
|
||||
* Helper to wait for acknowledgments
|
||||
*
|
||||
* In practice, it is used to wait for device clipboard acknowledgement from the
|
||||
* server before injecting Ctrl+v via AOA HID, in order to avoid pasting the
|
||||
* content of the old device clipboard (if Ctrl+v was injected before the
|
||||
* clipboard content was actually set).
|
||||
*/
|
||||
struct sc_acksync {
|
||||
sc_mutex mutex;
|
||||
sc_cond cond;
|
||||
|
||||
bool stopped;
|
||||
|
||||
// Last acked value, initially SC_SEQUENCE_INVALID
|
||||
uint64_t ack;
|
||||
};
|
||||
|
||||
enum sc_acksync_wait_result {
|
||||
// Acknowledgment received
|
||||
SC_ACKSYNC_WAIT_OK,
|
||||
|
||||
// Timeout expired
|
||||
SC_ACKSYNC_WAIT_TIMEOUT,
|
||||
|
||||
// Interrupted from another thread by sc_acksync_interrupt()
|
||||
SC_ACKSYNC_WAIT_INTR,
|
||||
};
|
||||
|
||||
bool
|
||||
sc_acksync_init(struct sc_acksync *as);
|
||||
|
||||
void
|
||||
sc_acksync_destroy(struct sc_acksync *as);
|
||||
|
||||
/**
|
||||
* Acknowledge `sequence`
|
||||
*
|
||||
* The `sequence` must be greater than (or equal to) any previous acknowledged
|
||||
* sequence.
|
||||
*/
|
||||
void
|
||||
sc_acksync_ack(struct sc_acksync *as, uint64_t sequence);
|
||||
|
||||
/**
|
||||
* Wait for acknowledgment of sequence `ack` (or higher)
|
||||
*/
|
||||
enum sc_acksync_wait_result
|
||||
sc_acksync_wait(struct sc_acksync *as, uint64_t ack, sc_tick deadline);
|
||||
|
||||
/**
|
||||
* Interrupt any `sc_acksync_wait()`
|
||||
*/
|
||||
void
|
||||
sc_acksync_interrupt(struct sc_acksync *as);
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
// For inet_pton() on Windows
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#define WINVER 0x0600
|
||||
|
||||
#include "net.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -78,7 +78,7 @@ static void test_serialize_inject_touch_event(void) {
|
||||
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||
.inject_touch_event = {
|
||||
.action = AMOTION_EVENT_ACTION_DOWN,
|
||||
.pointer_id = UINT64_C(0x1234567887654321),
|
||||
.pointer_id = 0x1234567887654321L,
|
||||
.position = {
|
||||
.point = {
|
||||
.x = 100,
|
||||
@@ -226,7 +226,6 @@ static void test_serialize_set_clipboard(void) {
|
||||
struct control_msg msg = {
|
||||
.type = CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||
.set_clipboard = {
|
||||
.sequence = UINT64_C(0x0102030405060708),
|
||||
.paste = true,
|
||||
.text = "hello, world!",
|
||||
},
|
||||
@@ -234,11 +233,10 @@ static void test_serialize_set_clipboard(void) {
|
||||
|
||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = control_msg_serialize(&msg, buf);
|
||||
assert(size == 27);
|
||||
assert(size == 19);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
||||
1, // paste
|
||||
0x00, 0x00, 0x00, 0x0d, // text length
|
||||
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text
|
||||
|
||||
@@ -47,26 +47,11 @@ static void test_deserialize_clipboard_big(void) {
|
||||
device_msg_destroy(&msg);
|
||||
}
|
||||
|
||||
static void test_deserialize_ack_set_clipboard(void) {
|
||||
const unsigned char input[] = {
|
||||
DEVICE_MSG_TYPE_ACK_CLIPBOARD,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
||||
};
|
||||
|
||||
struct device_msg msg;
|
||||
ssize_t r = device_msg_deserialize(input, sizeof(input), &msg);
|
||||
assert(r == 9);
|
||||
|
||||
assert(msg.type == DEVICE_MSG_TYPE_ACK_CLIPBOARD);
|
||||
assert(msg.ack_clipboard.sequence == UINT64_C(0x0102030405060708));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
test_deserialize_clipboard();
|
||||
test_deserialize_clipboard_big();
|
||||
test_deserialize_ack_set_clipboard();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ public final class ControlMessage {
|
||||
public static final int TYPE_SET_SCREEN_POWER_MODE = 10;
|
||||
public static final int TYPE_ROTATE_DEVICE = 11;
|
||||
|
||||
public static final long SEQUENCE_INVALID = 0;
|
||||
|
||||
private int type;
|
||||
private String text;
|
||||
private int metaState; // KeyEvent.META_*
|
||||
@@ -33,7 +31,6 @@ public final class ControlMessage {
|
||||
private int vScroll;
|
||||
private boolean paste;
|
||||
private int repeat;
|
||||
private long sequence;
|
||||
|
||||
private ControlMessage() {
|
||||
}
|
||||
@@ -82,10 +79,9 @@ public final class ControlMessage {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static ControlMessage createSetClipboard(long sequence, String text, boolean paste) {
|
||||
public static ControlMessage createSetClipboard(String text, boolean paste) {
|
||||
ControlMessage msg = new ControlMessage();
|
||||
msg.type = TYPE_SET_CLIPBOARD;
|
||||
msg.sequence = sequence;
|
||||
msg.text = text;
|
||||
msg.paste = paste;
|
||||
return msg;
|
||||
@@ -158,8 +154,4 @@ public final class ControlMessage {
|
||||
public int getRepeat() {
|
||||
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 BACK_OR_SCREEN_ON_LENGTH = 1;
|
||||
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
|
||||
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 9;
|
||||
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1;
|
||||
|
||||
private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k
|
||||
|
||||
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 CLIPBOARD_TEXT_MAX_LENGTH = MESSAGE_MAX_SIZE - 6; // type: 1 byte; paste flag: 1 byte; length: 4 bytes
|
||||
public static final int INJECT_TEXT_MAX_LENGTH = 300;
|
||||
|
||||
private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE];
|
||||
@@ -166,13 +166,12 @@ public class ControlMessageReader {
|
||||
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
long sequence = buffer.getLong();
|
||||
boolean paste = buffer.get() != 0;
|
||||
String text = parseString();
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
return ControlMessage.createSetClipboard(sequence, text, paste);
|
||||
return ControlMessage.createSetClipboard(text, paste);
|
||||
}
|
||||
|
||||
private ControlMessage parseSetScreenPowerMode() {
|
||||
|
||||
@@ -120,12 +120,7 @@ public class Controller {
|
||||
}
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||
long sequence = msg.getSequence();
|
||||
setClipboard(msg.getText(), msg.getPaste());
|
||||
if (sequence != ControlMessage.SEQUENCE_INVALID) {
|
||||
// Acknowledgement requested
|
||||
sender.pushAckClipboard(sequence);
|
||||
}
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
||||
if (device.supportsInputEvents()) {
|
||||
|
||||
@@ -82,8 +82,8 @@ public final class Device {
|
||||
}
|
||||
}, displayId);
|
||||
|
||||
if (options.getControl() && options.getClipboardAutosync()) {
|
||||
// If control and autosync are enabled, synchronize Android clipboard to the computer automatically
|
||||
if (options.getControl()) {
|
||||
// If control is enabled, synchronize Android clipboard to the computer automatically
|
||||
ClipboardManager clipboardManager = SERVICE_MANAGER.getClipboardManager();
|
||||
if (clipboardManager != null) {
|
||||
clipboardManager.addPrimaryClipChangedListener(new IOnPrimaryClipChangedListener.Stub() {
|
||||
|
||||
@@ -3,13 +3,9 @@ package com.genymobile.scrcpy;
|
||||
public final class DeviceMessage {
|
||||
|
||||
public static final int TYPE_CLIPBOARD = 0;
|
||||
public static final int TYPE_ACK_CLIPBOARD = 1;
|
||||
|
||||
public static final long SEQUENCE_INVALID = ControlMessage.SEQUENCE_INVALID;
|
||||
|
||||
private int type;
|
||||
private String text;
|
||||
private long sequence;
|
||||
|
||||
private DeviceMessage() {
|
||||
}
|
||||
@@ -21,13 +17,6 @@ public final class DeviceMessage {
|
||||
return event;
|
||||
}
|
||||
|
||||
public static DeviceMessage createAckClipboard(long sequence) {
|
||||
DeviceMessage event = new DeviceMessage();
|
||||
event.type = TYPE_ACK_CLIPBOARD;
|
||||
event.sequence = sequence;
|
||||
return event;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
@@ -35,8 +24,4 @@ public final class DeviceMessage {
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public long getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ public final class DeviceMessageSender {
|
||||
|
||||
private String clipboardText;
|
||||
|
||||
private long ack;
|
||||
|
||||
public DeviceMessageSender(DesktopConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
@@ -19,34 +17,18 @@ public final class DeviceMessageSender {
|
||||
notify();
|
||||
}
|
||||
|
||||
public synchronized void pushAckClipboard(long sequence) {
|
||||
ack = sequence;
|
||||
notify();
|
||||
}
|
||||
|
||||
public void loop() throws IOException, InterruptedException {
|
||||
while (true) {
|
||||
String text;
|
||||
long sequence;
|
||||
synchronized (this) {
|
||||
while (ack == DeviceMessage.SEQUENCE_INVALID && clipboardText == null) {
|
||||
while (clipboardText == null) {
|
||||
wait();
|
||||
}
|
||||
text = clipboardText;
|
||||
clipboardText = null;
|
||||
|
||||
sequence = ack;
|
||||
ack = DeviceMessage.SEQUENCE_INVALID;
|
||||
}
|
||||
|
||||
if (sequence != DeviceMessage.SEQUENCE_INVALID) {
|
||||
DeviceMessage event = DeviceMessage.createAckClipboard(sequence);
|
||||
connection.sendDeviceMessage(event);
|
||||
}
|
||||
if (text != null) {
|
||||
DeviceMessage event = DeviceMessage.createClipboard(text);
|
||||
connection.sendDeviceMessage(event);
|
||||
}
|
||||
DeviceMessage event = DeviceMessage.createClipboard(text);
|
||||
connection.sendDeviceMessage(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class DeviceMessageWriter {
|
||||
|
||||
public void writeTo(DeviceMessage msg, OutputStream output) throws IOException {
|
||||
buffer.clear();
|
||||
buffer.put((byte) msg.getType());
|
||||
buffer.put((byte) DeviceMessage.TYPE_CLIPBOARD);
|
||||
switch (msg.getType()) {
|
||||
case DeviceMessage.TYPE_CLIPBOARD:
|
||||
String text = msg.getText();
|
||||
@@ -25,10 +25,6 @@ public class DeviceMessageWriter {
|
||||
buffer.put(raw, 0, len);
|
||||
output.write(rawBuffer, 0, buffer.position());
|
||||
break;
|
||||
case DeviceMessage.TYPE_ACK_CLIPBOARD:
|
||||
buffer.putLong(msg.getSequence());
|
||||
output.write(rawBuffer, 0, buffer.position());
|
||||
break;
|
||||
default:
|
||||
Ln.w("Unknown device message: " + msg.getType());
|
||||
break;
|
||||
|
||||
@@ -18,7 +18,6 @@ public class Options {
|
||||
private String codecOptions;
|
||||
private String encoderName;
|
||||
private boolean powerOffScreenOnClose;
|
||||
private boolean clipboardAutosync;
|
||||
|
||||
public Ln.Level getLogLevel() {
|
||||
return logLevel;
|
||||
@@ -139,12 +138,4 @@ public class Options {
|
||||
public boolean getPowerOffScreenOnClose() {
|
||||
return this.powerOffScreenOnClose;
|
||||
}
|
||||
|
||||
public boolean getClipboardAutosync() {
|
||||
return clipboardAutosync;
|
||||
}
|
||||
|
||||
public void setClipboardAutosync(boolean clipboardAutosync) {
|
||||
this.clipboardAutosync = clipboardAutosync;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ public final class Server {
|
||||
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
||||
}
|
||||
|
||||
final int expectedParameters = 17;
|
||||
final int expectedParameters = 16;
|
||||
if (args.length != expectedParameters) {
|
||||
throw new IllegalArgumentException("Expecting " + expectedParameters + " parameters");
|
||||
}
|
||||
@@ -213,9 +213,6 @@ public final class Server {
|
||||
boolean powerOffScreenOnClose = Boolean.parseBoolean(args[15]);
|
||||
options.setPowerOffScreenOnClose(powerOffScreenOnClose);
|
||||
|
||||
boolean clipboardAutosync = Boolean.parseBoolean(args[16]);
|
||||
options.setClipboardAutosync(clipboardAutosync);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
@@ -235,7 +235,6 @@ public class ControlMessageReaderTest {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
|
||||
dos.writeLong(0x0102030405060708L); // sequence
|
||||
dos.writeByte(1); // paste
|
||||
byte[] text = "testé".getBytes(StandardCharsets.UTF_8);
|
||||
dos.writeInt(text.length);
|
||||
@@ -247,7 +246,6 @@ public class ControlMessageReaderTest {
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
|
||||
Assert.assertEquals(0x0102030405060708L, event.getSequence());
|
||||
Assert.assertEquals("testé", event.getText());
|
||||
Assert.assertTrue(event.getPaste());
|
||||
}
|
||||
@@ -261,7 +259,6 @@ public class ControlMessageReaderTest {
|
||||
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
|
||||
|
||||
byte[] rawText = new byte[ControlMessageReader.CLIPBOARD_TEXT_MAX_LENGTH];
|
||||
dos.writeLong(0x0807060504030201L); // sequence
|
||||
dos.writeByte(1); // paste
|
||||
Arrays.fill(rawText, (byte) 'a');
|
||||
String text = new String(rawText, 0, rawText.length);
|
||||
@@ -275,7 +272,6 @@ public class ControlMessageReaderTest {
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
|
||||
Assert.assertEquals(0x0807060504030201L, event.getSequence());
|
||||
Assert.assertEquals(text, event.getText());
|
||||
Assert.assertTrue(event.getPaste());
|
||||
}
|
||||
|
||||
@@ -32,24 +32,4 @@ public class DeviceMessageWriterTest {
|
||||
|
||||
Assert.assertArrayEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializeAckSetClipboard() throws IOException {
|
||||
DeviceMessageWriter writer = new DeviceMessageWriter();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(DeviceMessage.TYPE_ACK_CLIPBOARD);
|
||||
dos.writeLong(0x0102030405060708L);
|
||||
|
||||
byte[] expected = bos.toByteArray();
|
||||
|
||||
DeviceMessage msg = DeviceMessage.createAckClipboard(0x0102030405060708L);
|
||||
bos = new ByteArrayOutputStream();
|
||||
writer.writeTo(msg, bos);
|
||||
|
||||
byte[] actual = bos.toByteArray();
|
||||
|
||||
Assert.assertArrayEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user