Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc7b60e619 | ||
|
|
1e4ee547b5 | ||
|
|
488d22d4e2 | ||
|
|
00d292b2f5 | ||
|
|
245999aec4 | ||
|
|
d91c5dcfd5 | ||
|
|
d202d7b205 | ||
|
|
08c0c64af6 | ||
|
|
a00a8763d6 | ||
|
|
8f314c74b0 | ||
|
|
6e1069a822 | ||
|
|
c4323df976 | ||
|
|
8ff07e0c88 | ||
|
|
e4efd75766 | ||
|
|
0e4a6f462b | ||
|
|
8b73c90427 | ||
|
|
ef91ab2841 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,5 +1,8 @@
|
||||
build/
|
||||
/dist/
|
||||
/build-*/
|
||||
/build_*/
|
||||
/release-*/
|
||||
.idea/
|
||||
.gradle/
|
||||
/x/
|
||||
|
||||
6
BUILD.md
6
BUILD.md
@@ -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:
|
||||
|
||||
23
README.md
23
README.md
@@ -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
|
||||
|
||||
@@ -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',
|
||||
]],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user