Compare commits

..

17 Commits

Author SHA1 Message Date
Ivan Keliukh
dc7b60e619 Add option for disabling screensaver
PR #1502 <https://github.com/Genymobile/scrcpy/pull/1502>
Fixes #1370 <https://github.com/Genymobile/scrcpy/issues/1370>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2020-06-18 21:35:28 +02:00
Romain Vimont
1e4ee547b5 Make message buffer static
Now that the message max size is 256k, do not put the buffer on the
stack.
2020-06-11 23:11:20 +02:00
Romain Vimont
488d22d4e2 Increase clipboard size from 4k to 256k
Beyond 256k, SDL_GetClipboardText() returns an empty string on my
computer.

Fixes #1117 <https://github.com/Genymobile/scrcpy/issues/1117>
2020-06-11 23:11:20 +02:00
Romain Vimont
00d292b2f5 Fix receiver on partial device messages
If a single device message was read in several chunks from the control
socket, the communication was broken.
2020-06-11 23:11:20 +02:00
Romain Vimont
245999aec4 Serialize text size on 4 bytes
This will allow to send text having a size greater than 65535 bytes.
2020-06-11 23:11:17 +02:00
Romain Vimont
d91c5dcfd5 Rename MSG_SERIALIZED_MAX_SIZE to MSG_MAX_SIZE
For simplicity and consistency with the server part.
2020-06-11 23:08:04 +02:00
Romain Vimont
d202d7b205 Add unit test for big clipboard device message
Test clipboard synchronization from the device to the computer.
2020-06-11 23:06:02 +02:00
Romain Vimont
08c0c64af6 Rename test names from "event" to "msg"
The meson test names had not been changed when "event" had been renamed
to "message".

Ref: 28980bbc90
2020-06-11 23:06:02 +02:00
Romain Vimont
a00a8763d6 Avoid additional copy on Java text parsing
Directly pass the buffer range to the String constructor.
2020-06-11 23:06:02 +02:00
Romain Vimont
8f314c74b0 Reorganize message size constants
Make the max clipboard text length depend on the max message size.
2020-06-11 22:58:54 +02:00
Romain Vimont
6e1069a822 Configure log level for application only
Do not expose internal SDL logs to users.

Fixes #1441 <https://github.com/Genymobile/scrcpy/issues/1441>
2020-06-02 18:27:23 +02:00
Romain Vimont
c4323df976 Fix incorrect log return value
The function must return a SDL_LogPriority, but returned an enum
sc_log_level.

(It was harmless because this specific return should never happen, as
asserted.)
2020-06-02 18:27:14 +02:00
Romain Vimont
8ff07e0c88 Git-ignore release directories 2020-06-02 18:25:22 +02:00
Romain Vimont
e4efd75766 Avoid repetition for some shortcuts
Keeping the key pressed generate "repeat" events. It does not make sense
to repeat the event for rotation or turn screen off.
2020-05-29 22:02:41 +02:00
Romain Vimont
0e4a6f462b Mention stay awake limitation
The "stay awake" feature only works when the device is plugged in.

Refs #1445 <https://github.com/Genymobile/scrcpy/issues/1445>
2020-05-28 23:07:28 +02:00
Romain Vimont
8b73c90427 Mention how to turn the screen on in README
Now that Ctrl+Shift+o has been reactivated, mention it in the "turn
screen off" section.
2020-05-27 19:32:02 +02:00
Romain Vimont
ef91ab2841 Update links to v1.14 in README and BUILD 2020-05-27 19:31:12 +02:00
22 changed files with 152 additions and 85 deletions

3
.gitignore vendored
View File

@@ -1,5 +1,8 @@
build/
/dist/
/build-*/
/build_*/
/release-*/
.idea/
.gradle/
/x/

View File

@@ -249,10 +249,10 @@ You can then [run](README.md#run) _scrcpy_.
## Prebuilt server
- [`scrcpy-server-v1.13`][direct-scrcpy-server]
_(SHA-256: 5fee64ca1ccdc2f38550f31f5353c66de3de30c2e929a964e30fa2d005d5f885)_
- [`scrcpy-server-v1.14`][direct-scrcpy-server]
_(SHA-256: 1d1b18a2b80e956771fd63b99b414d2d028713a8f12ddfa5a369709ad4295620)_
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.13/scrcpy-server-v1.13
[direct-scrcpy-server]: https://github.com/Genymobile/scrcpy/releases/download/v1.14/scrcpy-server-v1.14
Download the prebuilt server somewhere, and specify its path during the Meson
configuration:

View File

@@ -1,4 +1,4 @@
# scrcpy (v1.13)
# scrcpy (v1.14)
This application provides display and control of Android devices connected on
USB (or [over TCP/IP][article-tcpip]). It does not require any _root_ access.
@@ -69,10 +69,10 @@ hard).
For Windows, for simplicity, a prebuilt archive with all the dependencies
(including `adb`) is available:
- [`scrcpy-win64-v1.13.zip`][direct-win64]
_(SHA-256: 806aafc00d4db01513193addaa24f47858893ba5efe75770bfef6ae1ea987d27)_
- [`scrcpy-win64-v1.14.zip`][direct-win64]
_(SHA-256: 2be9139e46e29cf2f5f695848bb2b75a543b8f38be1133257dc5068252abc25f)_
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.13/scrcpy-win64-v1.13.zip
[direct-win64]: https://github.com/Genymobile/scrcpy/releases/download/v1.14/scrcpy-win64-v1.14.zip
It is also available in [Chocolatey]:
@@ -417,7 +417,7 @@ The secondary display may only be controlled if the device runs at least Android
#### Stay awake
To prevent the device to sleep after some delay:
To prevent the device to sleep after some delay when the device is plugged in:
```bash
scrcpy --stay-awake
@@ -439,7 +439,7 @@ scrcpy -S
Or by pressing `Ctrl`+`o` at any time.
To turn it back on, press `POWER` (or `Ctrl`+`p`).
To turn it back on, press `Ctrl`+`Shift`+`o` (or `POWER`, `Ctrl`+`p`).
It can be useful to also prevent the device to sleep:
@@ -479,6 +479,17 @@ scrcpy -t
Note that it only shows _physical_ touches (with the finger on the device).
#### Disable screensaver
By default, scrcpy does not prevent the screensaver to run on the computer.
To disable it:
```bash
scrcpy --disable-screensaver
```
### Input control
#### Rotate device screen

View File

@@ -164,12 +164,12 @@ if get_option('buildtype') == 'debug'
'src/cli.c',
'src/util/str_util.c',
]],
['test_control_event_serialize', [
['test_control_msg_serialize', [
'tests/test_control_msg_serialize.c',
'src/control_msg.c',
'src/util/str_util.c',
]],
['test_device_event_deserialize', [
['test_device_msg_deserialize', [
'tests/test_device_msg_deserialize.c',
'src/device_msg.c',
]],

View File

@@ -43,6 +43,10 @@ The values are expressed in the device natural orientation (typically, portrait
.B \-\-max\-size
value is computed on the cropped size.
.TP
.BI "\-\-disable-screensaver"
Disable screensaver while scrcpy is running.
.TP
.BI "\-\-display " id
Specify the display id to mirror.
@@ -167,7 +171,7 @@ Default is "info" for release builds, "debug" for debug builds.
.TP
.B \-w, \-\-stay-awake
Keep the device on while scrcpy is running.
Keep the device on while scrcpy is running, when the device is plugged in.
.TP
.B \-\-window\-borderless

View File

@@ -45,6 +45,9 @@ scrcpy_print_usage(const char *arg0) {
" (typically, portrait for a phone, landscape for a tablet).\n"
" Any --max-size value is computed on the cropped size.\n"
"\n"
" --disable-screensaver\n"
" Disable screensaver while scrcpy is running.\n"
"\n"
" --display id\n"
" Specify the display id to mirror.\n"
"\n"
@@ -159,7 +162,8 @@ scrcpy_print_usage(const char *arg0) {
#endif
"\n"
" -w, --stay-awake\n"
" Keep the device on while scrcpy is running.\n"
" Keep the device on while scrcpy is running, when the device\n"
" is plugged in.\n"
"\n"
" --window-borderless\n"
" Disable window decorations (display borderless window).\n"
@@ -525,6 +529,7 @@ guess_record_format(const char *filename) {
#define OPT_NO_MIPMAPS 1017
#define OPT_CODEC_OPTIONS 1018
#define OPT_FORCE_ADB_FORWARD 1019
#define OPT_DISABLE_SCREENSAVER 1020
bool
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
@@ -533,6 +538,8 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
{"bit-rate", required_argument, NULL, 'b'},
{"codec-options", required_argument, NULL, OPT_CODEC_OPTIONS},
{"crop", required_argument, NULL, OPT_CROP},
{"disable-screensaver", no_argument, NULL,
OPT_DISABLE_SCREENSAVER},
{"display", required_argument, NULL, OPT_DISPLAY_ID},
{"force-adb-forward", no_argument, NULL,
OPT_FORCE_ADB_FORWARD},
@@ -715,6 +722,9 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
case OPT_FORCE_ADB_FORWARD:
opts->force_adb_forward = true;
break;
case OPT_DISABLE_SCREENSAVER:
opts->disable_screensaver = true;
break;
default:
// getopt prints the error message on stderr
return false;

View File

@@ -20,9 +20,9 @@ write_position(uint8_t *buf, const struct position *position) {
static size_t
write_string(const char *utf8, size_t max_len, unsigned char *buf) {
size_t len = utf8_truncation_index(utf8, max_len);
buffer_write16be(buf, (uint16_t) len);
memcpy(&buf[2], utf8, len);
return 2 + len;
buffer_write32be(buf, len);
memcpy(&buf[4], utf8, len);
return 4 + len;
}
static uint16_t

View File

@@ -10,10 +10,11 @@
#include "android/keycodes.h"
#include "common.h"
#define CONTROL_MSG_MAX_SIZE (1 << 18) // 256k
#define CONTROL_MSG_INJECT_TEXT_MAX_LENGTH 300
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH 4092
#define CONTROL_MSG_SERIALIZED_MAX_SIZE \
(4 + CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH)
// type: 1 byte; paste flag: 1 byte; length: 4 bytes
#define CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH (CONTROL_MSG_MAX_SIZE - 6)
#define POINTER_ID_MOUSE UINT64_C(-1);
@@ -70,7 +71,7 @@ struct control_msg {
};
};
// buf size must be at least CONTROL_MSG_SERIALIZED_MAX_SIZE
// buf size must be at least CONTROL_MSG_MAX_SIZE
// return the number of bytes written
size_t
control_msg_serialize(const struct control_msg *msg, unsigned char *buf);

View File

@@ -60,7 +60,7 @@ controller_push_msg(struct controller *controller,
static bool
process_msg(struct controller *controller,
const struct control_msg *msg) {
unsigned char serialized_msg[CONTROL_MSG_SERIALIZED_MAX_SIZE];
static unsigned char serialized_msg[CONTROL_MSG_MAX_SIZE];
int length = control_msg_serialize(msg, serialized_msg);
if (!length) {
return false;

View File

@@ -9,7 +9,7 @@
ssize_t
device_msg_deserialize(const unsigned char *buf, size_t len,
struct device_msg *msg) {
if (len < 3) {
if (len < 5) {
// at least type + empty string length
return 0; // not available
}
@@ -17,8 +17,8 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
msg->type = buf[0];
switch (msg->type) {
case DEVICE_MSG_TYPE_CLIPBOARD: {
uint16_t clipboard_len = buffer_read16be(&buf[1]);
if (clipboard_len > len - 3) {
size_t clipboard_len = buffer_read32be(&buf[1]);
if (clipboard_len > len - 5) {
return 0; // not available
}
char *text = SDL_malloc(clipboard_len + 1);
@@ -27,12 +27,12 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
return -1;
}
if (clipboard_len) {
memcpy(text, &buf[3], clipboard_len);
memcpy(text, &buf[5], clipboard_len);
}
text[clipboard_len] = '\0';
msg->clipboard.text = text;
return 3 + clipboard_len;
return 5 + clipboard_len;
}
default:
LOGW("Unknown device message type: %d", (int) msg->type);

View File

@@ -7,8 +7,9 @@
#include "config.h"
#define DEVICE_MSG_TEXT_MAX_LENGTH 4093
#define DEVICE_MSG_SERIALIZED_MAX_SIZE (3 + DEVICE_MSG_TEXT_MAX_LENGTH)
#define DEVICE_MSG_MAX_SIZE (1 << 18) // 256k
// type: 1 byte; length: 4 bytes
#define DEVICE_MSG_TEXT_MAX_LENGTH (DEVICE_MSG_MAX_SIZE - 5)
enum device_msg_type {
DEVICE_MSG_TYPE_CLIPBOARD,

View File

@@ -321,7 +321,7 @@ input_manager_process_key(struct input_manager *im,
}
return;
case SDLK_o:
if (control && cmd && down) {
if (control && cmd && !repeat && down) {
enum screen_power_mode mode = shift
? SCREEN_POWER_MODE_NORMAL
: SCREEN_POWER_MODE_OFF;
@@ -341,12 +341,12 @@ input_manager_process_key(struct input_manager *im,
}
return;
case SDLK_LEFT:
if (cmd && !shift && down) {
if (cmd && !shift && !repeat && down) {
rotate_client_left(im->screen);
}
return;
case SDLK_RIGHT:
if (cmd && !shift && down) {
if (cmd && !shift && !repeat && down) {
rotate_client_right(im->screen);
}
return;

View File

@@ -42,7 +42,7 @@ convert_log_level_to_sdl(enum sc_log_level level) {
return SDL_LOG_PRIORITY_ERROR;
default:
assert(!"unexpected log level");
return SC_LOG_LEVEL_INFO;
return SDL_LOG_PRIORITY_INFO;
}
}
@@ -71,7 +71,7 @@ main(int argc, char *argv[]) {
}
SDL_LogPriority sdl_log = convert_log_level_to_sdl(args.opts.log_level);
SDL_LogSetAllPriority(sdl_log);
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, sdl_log);
if (args.help) {
scrcpy_print_usage(argv[0]);

View File

@@ -60,28 +60,29 @@ static int
run_receiver(void *data) {
struct receiver *receiver = data;
unsigned char buf[DEVICE_MSG_SERIALIZED_MAX_SIZE];
static unsigned char buf[DEVICE_MSG_MAX_SIZE];
size_t head = 0;
for (;;) {
assert(head < DEVICE_MSG_SERIALIZED_MAX_SIZE);
ssize_t r = net_recv(receiver->control_socket, buf,
DEVICE_MSG_SERIALIZED_MAX_SIZE - head);
assert(head < DEVICE_MSG_MAX_SIZE);
ssize_t r = net_recv(receiver->control_socket, buf + head,
DEVICE_MSG_MAX_SIZE - head);
if (r <= 0) {
LOGD("Receiver stopped");
break;
}
ssize_t consumed = process_msgs(buf, r);
head += r;
ssize_t consumed = process_msgs(buf, head);
if (consumed == -1) {
// an error occurred
break;
}
if (consumed) {
head -= consumed;
// shift the remaining data in the buffer
memmove(buf, &buf[consumed], r - consumed);
head = r - consumed;
memmove(buf, &buf[consumed], head);
}
}

View File

@@ -63,7 +63,8 @@ BOOL WINAPI windows_ctrl_handler(DWORD ctrl_type) {
// init SDL and set appropriate hints
static bool
sdl_init_and_configure(bool display, const char *render_driver) {
sdl_init_and_configure(bool display, const char *render_driver,
bool disable_screensaver) {
uint32_t flags = display ? SDL_INIT_VIDEO : SDL_INIT_EVENTS;
if (SDL_Init(flags)) {
LOGC("Could not initialize SDL: %s", SDL_GetError());
@@ -112,8 +113,13 @@ sdl_init_and_configure(bool display, const char *render_driver) {
LOGW("Could not disable minimize on focus loss");
}
// Do not disable the screensaver when scrcpy is running
SDL_EnableScreenSaver();
if (disable_screensaver) {
LOGD("Screensaver disabled");
SDL_DisableScreenSaver();
} else {
LOGD("Screensaver enabled");
SDL_EnableScreenSaver();
}
return true;
}
@@ -321,7 +327,8 @@ scrcpy(const struct scrcpy_options *options) {
bool controller_initialized = false;
bool controller_started = false;
if (!sdl_init_and_configure(options->display, options->render_driver)) {
if (!sdl_init_and_configure(options->display, options->render_driver,
options->disable_screensaver)) {
goto end;
}

View File

@@ -43,6 +43,7 @@ struct scrcpy_options {
bool mipmaps;
bool stay_awake;
bool force_adb_forward;
bool disable_screensaver;
};
#define SCRCPY_OPTIONS_DEFAULT { \
@@ -81,6 +82,7 @@ struct scrcpy_options {
.mipmaps = true, \
.stay_awake = false, \
.force_adb_forward = false, \
.disable_screensaver = false, \
}
bool

View File

@@ -13,7 +13,7 @@ static void test_serialize_inject_keycode(void) {
},
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 10);
@@ -34,13 +34,13 @@ static void test_serialize_inject_text(void) {
},
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 16);
assert(size == 18);
const unsigned char expected[] = {
CONTROL_MSG_TYPE_INJECT_TEXT,
0x00, 0x0d, // text length
0x00, 0x00, 0x00, 0x0d, // text length
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text
};
assert(!memcmp(buf, expected, sizeof(expected)));
@@ -54,15 +54,17 @@ static void test_serialize_inject_text_long(void) {
text[CONTROL_MSG_INJECT_TEXT_MAX_LENGTH] = '\0';
msg.inject_text.text = text;
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 3 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
assert(size == 5 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
unsigned char expected[3 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
unsigned char expected[5 + CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
expected[0] = CONTROL_MSG_TYPE_INJECT_TEXT;
expected[1] = 0x01;
expected[2] = 0x2c; // text length (16 bits)
memset(&expected[3], 'a', CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
expected[1] = 0x00;
expected[2] = 0x00;
expected[3] = 0x01;
expected[4] = 0x2c; // text length (32 bits)
memset(&expected[5], 'a', CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
assert(!memcmp(buf, expected, sizeof(expected)));
}
@@ -88,7 +90,7 @@ static void test_serialize_inject_touch_event(void) {
},
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 28);
@@ -123,7 +125,7 @@ static void test_serialize_inject_scroll_event(void) {
},
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 21);
@@ -142,7 +144,7 @@ static void test_serialize_back_or_screen_on(void) {
.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 1);
@@ -157,7 +159,7 @@ static void test_serialize_expand_notification_panel(void) {
.type = CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 1);
@@ -172,7 +174,7 @@ static void test_serialize_collapse_notification_panel(void) {
.type = CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL,
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 1);
@@ -187,7 +189,7 @@ static void test_serialize_get_clipboard(void) {
.type = CONTROL_MSG_TYPE_GET_CLIPBOARD,
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 1);
@@ -206,14 +208,14 @@ static void test_serialize_set_clipboard(void) {
},
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 17);
assert(size == 19);
const unsigned char expected[] = {
CONTROL_MSG_TYPE_SET_CLIPBOARD,
1, // paste
0x00, 0x0d, // text length
0x00, 0x00, 0x00, 0x0d, // text length
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text
};
assert(!memcmp(buf, expected, sizeof(expected)));
@@ -227,7 +229,7 @@ static void test_serialize_set_screen_power_mode(void) {
},
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 2);
@@ -243,7 +245,7 @@ static void test_serialize_rotate_device(void) {
.type = CONTROL_MSG_TYPE_ROTATE_DEVICE,
};
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
unsigned char buf[CONTROL_MSG_MAX_SIZE];
int size = control_msg_serialize(&msg, buf);
assert(size == 1);

View File

@@ -4,16 +4,17 @@
#include "device_msg.h"
#include <stdio.h>
static void test_deserialize_clipboard(void) {
const unsigned char input[] = {
DEVICE_MSG_TYPE_CLIPBOARD,
0x00, 0x03, // text length
0x00, 0x00, 0x00, 0x03, // text length
0x41, 0x42, 0x43, // "ABC"
};
struct device_msg msg;
ssize_t r = device_msg_deserialize(input, sizeof(input), &msg);
assert(r == 6);
assert(r == 8);
assert(msg.type == DEVICE_MSG_TYPE_CLIPBOARD);
assert(msg.clipboard.text);
@@ -22,7 +23,30 @@ static void test_deserialize_clipboard(void) {
device_msg_destroy(&msg);
}
static void test_deserialize_clipboard_big(void) {
unsigned char input[DEVICE_MSG_MAX_SIZE];
input[0] = DEVICE_MSG_TYPE_CLIPBOARD;
input[1] = (DEVICE_MSG_TEXT_MAX_LENGTH & 0xff000000u) >> 24;
input[2] = (DEVICE_MSG_TEXT_MAX_LENGTH & 0x00ff0000u) >> 16;
input[3] = (DEVICE_MSG_TEXT_MAX_LENGTH & 0x0000ff00u) >> 8;
input[4] = DEVICE_MSG_TEXT_MAX_LENGTH & 0x000000ffu;
memset(input + 5, 'a', DEVICE_MSG_TEXT_MAX_LENGTH);
struct device_msg msg;
ssize_t r = device_msg_deserialize(input, sizeof(input), &msg);
assert(r == DEVICE_MSG_MAX_SIZE);
assert(msg.type == DEVICE_MSG_TYPE_CLIPBOARD);
assert(msg.clipboard.text);
assert(strlen(msg.clipboard.text) == DEVICE_MSG_TEXT_MAX_LENGTH);
assert(msg.clipboard.text[0] == 'a');
device_msg_destroy(&msg);
}
int main(void) {
test_deserialize_clipboard();
test_deserialize_clipboard_big();
return 0;
}

View File

@@ -14,14 +14,13 @@ public class ControlMessageReader {
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 1;
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4092; // 4096 - 1 (type) - 1 (parse flag) - 2 (length)
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 INJECT_TEXT_MAX_LENGTH = 300;
private static final int RAW_BUFFER_SIZE = 4096;
private final byte[] rawBuffer = new byte[RAW_BUFFER_SIZE];
private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE];
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
private final byte[] textBuffer = new byte[CLIPBOARD_TEXT_MAX_LENGTH];
public ControlMessageReader() {
// invariant: the buffer is always in "get" mode
@@ -104,15 +103,17 @@ public class ControlMessageReader {
}
private String parseString() {
if (buffer.remaining() < 2) {
if (buffer.remaining() < 4) {
return null;
}
int len = toUnsigned(buffer.getShort());
int len = buffer.getInt();
if (buffer.remaining() < len) {
return null;
}
buffer.get(textBuffer, 0, len);
return new String(textBuffer, 0, len, StandardCharsets.UTF_8);
int position = buffer.position();
// Move the buffer position to consume the text
buffer.position(position + len);
return new String(rawBuffer, position, len, StandardCharsets.UTF_8);
}
private ControlMessage parseInjectText() {

View File

@@ -7,10 +7,10 @@ import java.nio.charset.StandardCharsets;
public class DeviceMessageWriter {
public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093;
private static final int MAX_EVENT_SIZE = CLIPBOARD_TEXT_MAX_LENGTH + 3;
private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k
public static final int CLIPBOARD_TEXT_MAX_LENGTH = MESSAGE_MAX_SIZE - 5; // type: 1 byte; length: 4 bytes
private final byte[] rawBuffer = new byte[MAX_EVENT_SIZE];
private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE];
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
public void writeTo(DeviceMessage msg, OutputStream output) throws IOException {
@@ -21,7 +21,7 @@ public class DeviceMessageWriter {
String text = msg.getText();
byte[] raw = text.getBytes(StandardCharsets.UTF_8);
int len = StringUtils.getUtf8TruncationIndex(raw, CLIPBOARD_TEXT_MAX_LENGTH);
buffer.putShort((short) len);
buffer.putInt(len);
buffer.put(raw, 0, len);
output.write(rawBuffer, 0, buffer.position());
break;

View File

@@ -48,7 +48,7 @@ public class ControlMessageReaderTest {
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(ControlMessage.TYPE_INJECT_TEXT);
byte[] text = "testé".getBytes(StandardCharsets.UTF_8);
dos.writeShort(text.length);
dos.writeInt(text.length);
dos.write(text);
byte[] packet = bos.toByteArray();
@@ -68,7 +68,7 @@ public class ControlMessageReaderTest {
dos.writeByte(ControlMessage.TYPE_INJECT_TEXT);
byte[] text = new byte[ControlMessageReader.INJECT_TEXT_MAX_LENGTH];
Arrays.fill(text, (byte) 'a');
dos.writeShort(text.length);
dos.writeInt(text.length);
dos.write(text);
byte[] packet = bos.toByteArray();
@@ -218,7 +218,7 @@ public class ControlMessageReaderTest {
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
dos.writeByte(1); // paste
byte[] text = "testé".getBytes(StandardCharsets.UTF_8);
dos.writeShort(text.length);
dos.writeInt(text.length);
dos.write(text);
byte[] packet = bos.toByteArray();
@@ -246,7 +246,7 @@ public class ControlMessageReaderTest {
Arrays.fill(rawText, (byte) 'a');
String text = new String(rawText, 0, rawText.length);
dos.writeShort(rawText.length);
dos.writeInt(rawText.length);
dos.write(rawText);
byte[] packet = bos.toByteArray();

View File

@@ -19,7 +19,7 @@ public class DeviceMessageWriterTest {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(DeviceMessage.TYPE_CLIPBOARD);
dos.writeShort(data.length);
dos.writeInt(data.length);
dos.write(data);
byte[] expected = bos.toByteArray();