mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-03-28 23:14:29 +01:00
Compare commits
6 Commits
audio_play
...
pr4698
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63dd07109f | ||
|
|
746eaea556 | ||
|
|
78a7e4f293 | ||
|
|
9858eff856 | ||
|
|
9e22f3bf1c | ||
|
|
25f1e703b7 |
@@ -87,7 +87,7 @@ write_position(uint8_t *buf, const struct sc_position *position) {
|
||||
|
||||
// write length (4 bytes) + string (non null-terminated)
|
||||
static size_t
|
||||
write_string(const char *utf8, size_t max_len, unsigned char *buf) {
|
||||
write_string(const char *utf8, size_t max_len, uint8_t *buf) {
|
||||
size_t len = sc_str_utf8_truncation_index(utf8, max_len);
|
||||
sc_write32be(buf, len);
|
||||
memcpy(&buf[4], utf8, len);
|
||||
@@ -95,7 +95,7 @@ write_string(const char *utf8, size_t max_len, unsigned char *buf) {
|
||||
}
|
||||
|
||||
size_t
|
||||
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf) {
|
||||
sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf) {
|
||||
buf[0] = msg->type;
|
||||
switch (msg->type) {
|
||||
case SC_CONTROL_MSG_TYPE_INJECT_KEYCODE:
|
||||
|
||||
@@ -98,7 +98,7 @@ struct sc_control_msg {
|
||||
// buf size must be at least CONTROL_MSG_MAX_SIZE
|
||||
// return the number of bytes written
|
||||
size_t
|
||||
sc_control_msg_serialize(const struct sc_control_msg *msg, unsigned char *buf);
|
||||
sc_control_msg_serialize(const struct sc_control_msg *msg, uint8_t *buf);
|
||||
|
||||
void
|
||||
sc_control_msg_log(const struct sc_control_msg *msg);
|
||||
|
||||
@@ -84,7 +84,7 @@ sc_controller_push_msg(struct sc_controller *controller,
|
||||
static bool
|
||||
process_msg(struct sc_controller *controller,
|
||||
const struct sc_control_msg *msg) {
|
||||
static unsigned char serialized_msg[SC_CONTROL_MSG_MAX_SIZE];
|
||||
static uint8_t serialized_msg[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t length = sc_control_msg_serialize(msg, serialized_msg);
|
||||
if (!length) {
|
||||
return false;
|
||||
|
||||
@@ -8,19 +8,22 @@
|
||||
#include "util/log.h"
|
||||
|
||||
ssize_t
|
||||
device_msg_deserialize(const unsigned char *buf, size_t len,
|
||||
struct device_msg *msg) {
|
||||
if (len < 5) {
|
||||
// at least type + empty string length
|
||||
return 0; // not available
|
||||
sc_device_msg_deserialize(const uint8_t *buf, size_t len,
|
||||
struct sc_device_msg *msg) {
|
||||
if (!len) {
|
||||
return 0; // no message
|
||||
}
|
||||
|
||||
msg->type = buf[0];
|
||||
switch (msg->type) {
|
||||
case DEVICE_MSG_TYPE_CLIPBOARD: {
|
||||
if (len < 5) {
|
||||
// at least type + empty string length
|
||||
return 0; // no complete message
|
||||
}
|
||||
size_t clipboard_len = sc_read32be(&buf[1]);
|
||||
if (clipboard_len > len - 5) {
|
||||
return 0; // not available
|
||||
return 0; // no complete message
|
||||
}
|
||||
char *text = malloc(clipboard_len + 1);
|
||||
if (!text) {
|
||||
@@ -36,6 +39,9 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
|
||||
return 5 + clipboard_len;
|
||||
}
|
||||
case DEVICE_MSG_TYPE_ACK_CLIPBOARD: {
|
||||
if (len < 9) {
|
||||
return 0; // no complete message
|
||||
}
|
||||
uint64_t sequence = sc_read64be(&buf[1]);
|
||||
msg->ack_clipboard.sequence = sequence;
|
||||
return 9;
|
||||
@@ -47,7 +53,7 @@ device_msg_deserialize(const unsigned char *buf, size_t len,
|
||||
}
|
||||
|
||||
void
|
||||
device_msg_destroy(struct device_msg *msg) {
|
||||
sc_device_msg_destroy(struct sc_device_msg *msg) {
|
||||
if (msg->type == DEVICE_MSG_TYPE_CLIPBOARD) {
|
||||
free(msg->clipboard.text);
|
||||
}
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
// type: 1 byte; length: 4 bytes
|
||||
#define DEVICE_MSG_TEXT_MAX_LENGTH (DEVICE_MSG_MAX_SIZE - 5)
|
||||
|
||||
enum device_msg_type {
|
||||
enum sc_device_msg_type {
|
||||
DEVICE_MSG_TYPE_CLIPBOARD,
|
||||
DEVICE_MSG_TYPE_ACK_CLIPBOARD,
|
||||
};
|
||||
|
||||
struct device_msg {
|
||||
enum device_msg_type type;
|
||||
struct sc_device_msg {
|
||||
enum sc_device_msg_type type;
|
||||
union {
|
||||
struct {
|
||||
char *text; // owned, to be freed by free()
|
||||
@@ -30,10 +30,10 @@ struct device_msg {
|
||||
|
||||
// return the number of bytes consumed (0 for no msg available, -1 on error)
|
||||
ssize_t
|
||||
device_msg_deserialize(const unsigned char *buf, size_t len,
|
||||
struct device_msg *msg);
|
||||
sc_device_msg_deserialize(const uint8_t *buf, size_t len,
|
||||
struct sc_device_msg *msg);
|
||||
|
||||
void
|
||||
device_msg_destroy(struct device_msg *msg);
|
||||
sc_device_msg_destroy(struct sc_device_msg *msg);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "receiver.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <SDL2/SDL_clipboard.h>
|
||||
|
||||
#include "device_msg.h"
|
||||
@@ -26,7 +27,7 @@ sc_receiver_destroy(struct sc_receiver *receiver) {
|
||||
}
|
||||
|
||||
static void
|
||||
process_msg(struct sc_receiver *receiver, struct device_msg *msg) {
|
||||
process_msg(struct sc_receiver *receiver, struct sc_device_msg *msg) {
|
||||
switch (msg->type) {
|
||||
case DEVICE_MSG_TYPE_CLIPBOARD: {
|
||||
char *current = SDL_GetClipboardText();
|
||||
@@ -51,11 +52,11 @@ process_msg(struct sc_receiver *receiver, struct device_msg *msg) {
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
process_msgs(struct sc_receiver *receiver, const unsigned char *buf, size_t len) {
|
||||
process_msgs(struct sc_receiver *receiver, const uint8_t *buf, size_t len) {
|
||||
size_t head = 0;
|
||||
for (;;) {
|
||||
struct device_msg msg;
|
||||
ssize_t r = device_msg_deserialize(&buf[head], len - head, &msg);
|
||||
struct sc_device_msg msg;
|
||||
ssize_t r = sc_device_msg_deserialize(&buf[head], len - head, &msg);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
@@ -64,7 +65,7 @@ process_msgs(struct sc_receiver *receiver, const unsigned char *buf, size_t len)
|
||||
}
|
||||
|
||||
process_msg(receiver, &msg);
|
||||
device_msg_destroy(&msg);
|
||||
sc_device_msg_destroy(&msg);
|
||||
|
||||
head += r;
|
||||
assert(head <= len);
|
||||
@@ -78,7 +79,7 @@ static int
|
||||
run_receiver(void *data) {
|
||||
struct sc_receiver *receiver = data;
|
||||
|
||||
static unsigned char buf[DEVICE_MSG_MAX_SIZE];
|
||||
static uint8_t buf[DEVICE_MSG_MAX_SIZE];
|
||||
size_t head = 0;
|
||||
|
||||
for (;;) {
|
||||
|
||||
@@ -498,7 +498,7 @@ sc_server_init(struct sc_server *server, const struct sc_server_params *params,
|
||||
static bool
|
||||
device_read_info(struct sc_intr *intr, sc_socket device_socket,
|
||||
struct sc_server_info *info) {
|
||||
unsigned char buf[SC_DEVICE_NAME_FIELD_LENGTH];
|
||||
uint8_t buf[SC_DEVICE_NAME_FIELD_LENGTH];
|
||||
ssize_t r = net_recv_all_intr(intr, device_socket, buf, sizeof(buf));
|
||||
if (r < SC_DEVICE_NAME_FIELD_LENGTH) {
|
||||
LOGE("Could not retrieve device information");
|
||||
|
||||
@@ -113,7 +113,7 @@ sc_aoa_register_hid(struct sc_aoa *aoa, uint16_t accessory_id,
|
||||
|
||||
static bool
|
||||
sc_aoa_set_hid_report_desc(struct sc_aoa *aoa, uint16_t accessory_id,
|
||||
const unsigned char *report_desc,
|
||||
const uint8_t *report_desc,
|
||||
uint16_t report_desc_size) {
|
||||
uint8_t request_type = LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR;
|
||||
uint8_t request = ACCESSORY_SET_HID_REPORT_DESC;
|
||||
@@ -150,7 +150,7 @@ sc_aoa_set_hid_report_desc(struct sc_aoa *aoa, uint16_t accessory_id,
|
||||
|
||||
bool
|
||||
sc_aoa_setup_hid(struct sc_aoa *aoa, uint16_t accessory_id,
|
||||
const unsigned char *report_desc, uint16_t report_desc_size) {
|
||||
const uint8_t *report_desc, uint16_t report_desc_size) {
|
||||
bool ok = sc_aoa_register_hid(aoa, accessory_id, report_desc_size);
|
||||
if (!ok) {
|
||||
return false;
|
||||
|
||||
@@ -57,7 +57,7 @@ sc_aoa_join(struct sc_aoa *aoa);
|
||||
|
||||
bool
|
||||
sc_aoa_setup_hid(struct sc_aoa *aoa, uint16_t accessory_id,
|
||||
const unsigned char *report_desc, uint16_t report_desc_size);
|
||||
const uint8_t *report_desc, uint16_t report_desc_size);
|
||||
|
||||
bool
|
||||
sc_aoa_unregister_hid(struct sc_aoa *aoa, uint16_t accessory_id);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "control_msg.h"
|
||||
@@ -16,11 +17,11 @@ static void test_serialize_inject_keycode(void) {
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 14);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
||||
0x01, // AKEY_EVENT_ACTION_UP
|
||||
0x00, 0x00, 0x00, 0x42, // AKEYCODE_ENTER
|
||||
@@ -38,11 +39,11 @@ static void test_serialize_inject_text(void) {
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 18);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_INJECT_TEXT,
|
||||
0x00, 0x00, 0x00, 0x0d, // text length
|
||||
'h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', // text
|
||||
@@ -58,11 +59,11 @@ static void test_serialize_inject_text_long(void) {
|
||||
text[SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH] = '\0';
|
||||
msg.inject_text.text = text;
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 5 + SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH);
|
||||
|
||||
unsigned char expected[5 + SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
|
||||
uint8_t expected[5 + SC_CONTROL_MSG_INJECT_TEXT_MAX_LENGTH];
|
||||
expected[0] = SC_CONTROL_MSG_TYPE_INJECT_TEXT;
|
||||
expected[1] = 0x00;
|
||||
expected[2] = 0x00;
|
||||
@@ -95,11 +96,11 @@ static void test_serialize_inject_touch_event(void) {
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 32);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||
0x00, // AKEY_EVENT_ACTION_DOWN
|
||||
0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21, // pointer id
|
||||
@@ -132,11 +133,11 @@ static void test_serialize_inject_scroll_event(void) {
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 21);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||
0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x02, // 260 1026
|
||||
0x04, 0x38, 0x07, 0x80, // 1080 1920
|
||||
@@ -155,11 +156,11 @@ static void test_serialize_back_or_screen_on(void) {
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 2);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||
0x01, // AKEY_EVENT_ACTION_UP
|
||||
};
|
||||
@@ -171,11 +172,11 @@ static void test_serialize_expand_notification_panel(void) {
|
||||
.type = SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 1);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL,
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
@@ -186,11 +187,11 @@ static void test_serialize_expand_settings_panel(void) {
|
||||
.type = SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 1);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_EXPAND_SETTINGS_PANEL,
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
@@ -201,11 +202,11 @@ static void test_serialize_collapse_panels(void) {
|
||||
.type = SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 1);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_COLLAPSE_PANELS,
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
@@ -219,11 +220,11 @@ static void test_serialize_get_clipboard(void) {
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 2);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_GET_CLIPBOARD,
|
||||
SC_COPY_KEY_COPY,
|
||||
};
|
||||
@@ -240,11 +241,11 @@ static void test_serialize_set_clipboard(void) {
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 27);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
||||
1, // paste
|
||||
@@ -269,11 +270,11 @@ static void test_serialize_set_clipboard_long(void) {
|
||||
text[SC_CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH] = '\0';
|
||||
msg.set_clipboard.text = text;
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == SC_CONTROL_MSG_MAX_SIZE);
|
||||
|
||||
unsigned char expected[SC_CONTROL_MSG_MAX_SIZE] = {
|
||||
uint8_t expected[SC_CONTROL_MSG_MAX_SIZE] = {
|
||||
SC_CONTROL_MSG_TYPE_SET_CLIPBOARD,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // sequence
|
||||
1, // paste
|
||||
@@ -296,11 +297,11 @@ static void test_serialize_set_screen_power_mode(void) {
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 2);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE,
|
||||
0x02, // SC_SCREEN_POWER_MODE_NORMAL
|
||||
};
|
||||
@@ -312,11 +313,11 @@ static void test_serialize_rotate_device(void) {
|
||||
.type = SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
||||
};
|
||||
|
||||
unsigned char buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
uint8_t buf[SC_CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = sc_control_msg_serialize(&msg, buf);
|
||||
assert(size == 1);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
const uint8_t expected[] = {
|
||||
SC_CONTROL_MSG_TYPE_ROTATE_DEVICE,
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "device_msg.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static void test_deserialize_clipboard(void) {
|
||||
const unsigned char input[] = {
|
||||
const uint8_t input[] = {
|
||||
DEVICE_MSG_TYPE_CLIPBOARD,
|
||||
0x00, 0x00, 0x00, 0x03, // text length
|
||||
0x41, 0x42, 0x43, // "ABC"
|
||||
};
|
||||
|
||||
struct device_msg msg;
|
||||
ssize_t r = device_msg_deserialize(input, sizeof(input), &msg);
|
||||
struct sc_device_msg msg;
|
||||
ssize_t r = sc_device_msg_deserialize(input, sizeof(input), &msg);
|
||||
assert(r == 8);
|
||||
|
||||
assert(msg.type == DEVICE_MSG_TYPE_CLIPBOARD);
|
||||
assert(msg.clipboard.text);
|
||||
assert(!strcmp("ABC", msg.clipboard.text));
|
||||
|
||||
device_msg_destroy(&msg);
|
||||
sc_device_msg_destroy(&msg);
|
||||
}
|
||||
|
||||
static void test_deserialize_clipboard_big(void) {
|
||||
unsigned char input[DEVICE_MSG_MAX_SIZE];
|
||||
uint8_t 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;
|
||||
@@ -35,8 +35,8 @@ static void test_deserialize_clipboard_big(void) {
|
||||
|
||||
memset(input + 5, 'a', DEVICE_MSG_TEXT_MAX_LENGTH);
|
||||
|
||||
struct device_msg msg;
|
||||
ssize_t r = device_msg_deserialize(input, sizeof(input), &msg);
|
||||
struct sc_device_msg msg;
|
||||
ssize_t r = sc_device_msg_deserialize(input, sizeof(input), &msg);
|
||||
assert(r == DEVICE_MSG_MAX_SIZE);
|
||||
|
||||
assert(msg.type == DEVICE_MSG_TYPE_CLIPBOARD);
|
||||
@@ -44,17 +44,17 @@ static void test_deserialize_clipboard_big(void) {
|
||||
assert(strlen(msg.clipboard.text) == DEVICE_MSG_TEXT_MAX_LENGTH);
|
||||
assert(msg.clipboard.text[0] == 'a');
|
||||
|
||||
device_msg_destroy(&msg);
|
||||
sc_device_msg_destroy(&msg);
|
||||
}
|
||||
|
||||
static void test_deserialize_ack_set_clipboard(void) {
|
||||
const unsigned char input[] = {
|
||||
const uint8_t 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);
|
||||
struct sc_device_msg msg;
|
||||
ssize_t r = sc_device_msg_deserialize(input, sizeof(input), &msg);
|
||||
assert(r == 9);
|
||||
|
||||
assert(msg.type == DEVICE_MSG_TYPE_ACK_CLIPBOARD);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.genymobile.scrcpy;
|
||||
|
||||
import android.net.LocalSocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public final class ControlChannel {
|
||||
private final InputStream inputStream;
|
||||
private final OutputStream outputStream;
|
||||
|
||||
private final ControlMessageReader reader = new ControlMessageReader();
|
||||
private final DeviceMessageWriter writer = new DeviceMessageWriter();
|
||||
|
||||
public ControlChannel(LocalSocket controlSocket) throws IOException {
|
||||
this.inputStream = controlSocket.getInputStream();
|
||||
this.outputStream = controlSocket.getOutputStream();
|
||||
}
|
||||
|
||||
public ControlMessage recv() throws IOException {
|
||||
ControlMessage msg = reader.next();
|
||||
while (msg == null) {
|
||||
reader.readFrom(inputStream);
|
||||
msg = reader.next();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void send(DeviceMessage msg) throws IOException {
|
||||
writer.writeTo(msg, outputStream);
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public class Controller implements AsyncProcessor {
|
||||
private Thread thread;
|
||||
|
||||
private final Device device;
|
||||
private final DesktopConnection connection;
|
||||
private final ControlChannel controlChannel;
|
||||
private final CleanUp cleanUp;
|
||||
private final DeviceMessageSender sender;
|
||||
private final boolean clipboardAutosync;
|
||||
@@ -42,14 +42,14 @@ public class Controller implements AsyncProcessor {
|
||||
|
||||
private boolean keepPowerModeOff;
|
||||
|
||||
public Controller(Device device, DesktopConnection connection, CleanUp cleanUp, boolean clipboardAutosync, boolean powerOn) {
|
||||
public Controller(Device device, ControlChannel controlChannel, CleanUp cleanUp, boolean clipboardAutosync, boolean powerOn) {
|
||||
this.device = device;
|
||||
this.connection = connection;
|
||||
this.controlChannel = controlChannel;
|
||||
this.cleanUp = cleanUp;
|
||||
this.clipboardAutosync = clipboardAutosync;
|
||||
this.powerOn = powerOn;
|
||||
initPointers();
|
||||
sender = new DeviceMessageSender(connection);
|
||||
sender = new DeviceMessageSender(controlChannel);
|
||||
}
|
||||
|
||||
private void initPointers() {
|
||||
@@ -123,7 +123,7 @@ public class Controller implements AsyncProcessor {
|
||||
}
|
||||
|
||||
private void handleEvent() throws IOException {
|
||||
ControlMessage msg = connection.receiveControlMessage();
|
||||
ControlMessage msg = controlChannel.recv();
|
||||
switch (msg.getType()) {
|
||||
case ControlMessage.TYPE_INJECT_KEYCODE:
|
||||
if (device.supportsInputEvents()) {
|
||||
@@ -180,7 +180,7 @@ public class Controller implements AsyncProcessor {
|
||||
}
|
||||
break;
|
||||
case ControlMessage.TYPE_ROTATE_DEVICE:
|
||||
Device.rotateDevice();
|
||||
device.rotateDevice();
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
|
||||
@@ -7,8 +7,6 @@ import android.net.LocalSocketAddress;
|
||||
import java.io.Closeable;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public final class DesktopConnection implements Closeable {
|
||||
@@ -24,25 +22,16 @@ public final class DesktopConnection implements Closeable {
|
||||
private final FileDescriptor audioFd;
|
||||
|
||||
private final LocalSocket controlSocket;
|
||||
private final InputStream controlInputStream;
|
||||
private final OutputStream controlOutputStream;
|
||||
|
||||
private final ControlMessageReader reader = new ControlMessageReader();
|
||||
private final DeviceMessageWriter writer = new DeviceMessageWriter();
|
||||
private final ControlChannel controlChannel;
|
||||
|
||||
private DesktopConnection(LocalSocket videoSocket, LocalSocket audioSocket, LocalSocket controlSocket) throws IOException {
|
||||
this.videoSocket = videoSocket;
|
||||
this.controlSocket = controlSocket;
|
||||
this.audioSocket = audioSocket;
|
||||
if (controlSocket != null) {
|
||||
controlInputStream = controlSocket.getInputStream();
|
||||
controlOutputStream = controlSocket.getOutputStream();
|
||||
} else {
|
||||
controlInputStream = null;
|
||||
controlOutputStream = null;
|
||||
}
|
||||
this.controlSocket = controlSocket;
|
||||
|
||||
videoFd = videoSocket != null ? videoSocket.getFileDescriptor() : null;
|
||||
audioFd = audioSocket != null ? audioSocket.getFileDescriptor() : null;
|
||||
controlChannel = controlSocket != null ? new ControlChannel(controlSocket) : null;
|
||||
}
|
||||
|
||||
private static LocalSocket connect(String abstractName) throws IOException {
|
||||
@@ -179,16 +168,7 @@ public final class DesktopConnection implements Closeable {
|
||||
return audioFd;
|
||||
}
|
||||
|
||||
public ControlMessage receiveControlMessage() throws IOException {
|
||||
ControlMessage msg = reader.next();
|
||||
while (msg == null) {
|
||||
reader.readFrom(controlInputStream);
|
||||
msg = reader.next();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void sendDeviceMessage(DeviceMessage msg) throws IOException {
|
||||
writer.writeTo(msg, controlOutputStream);
|
||||
public ControlChannel getControlChannel() {
|
||||
return controlChannel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,21 +359,30 @@ public final class Device {
|
||||
/**
|
||||
* Disable auto-rotation (if enabled), set the screen rotation and re-enable auto-rotation (if it was enabled).
|
||||
*/
|
||||
public static void rotateDevice() {
|
||||
public void rotateDevice() {
|
||||
WindowManager wm = ServiceManager.getWindowManager();
|
||||
|
||||
boolean accelerometerRotation = !wm.isRotationFrozen();
|
||||
boolean accelerometerRotation = !wm.isRotationFrozen(displayId);
|
||||
|
||||
int currentRotation = wm.getRotation();
|
||||
int currentRotation = getCurrentRotation(displayId);
|
||||
int newRotation = (currentRotation & 1) ^ 1; // 0->1, 1->0, 2->1, 3->0
|
||||
String newRotationString = newRotation == 0 ? "portrait" : "landscape";
|
||||
|
||||
Ln.i("Device rotation requested: " + newRotationString);
|
||||
wm.freezeRotation(newRotation);
|
||||
wm.freezeRotation(displayId, newRotation);
|
||||
|
||||
// restore auto-rotate if necessary
|
||||
if (accelerometerRotation) {
|
||||
wm.thawRotation();
|
||||
wm.thawRotation(displayId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getCurrentRotation(int displayId) {
|
||||
if (displayId == 0) {
|
||||
return ServiceManager.getWindowManager().getRotation();
|
||||
}
|
||||
|
||||
DisplayInfo displayInfo = ServiceManager.getDisplayManager().getDisplayInfo(displayId);
|
||||
return displayInfo.getRotation();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.io.IOException;
|
||||
|
||||
public final class DeviceMessageSender {
|
||||
|
||||
private final DesktopConnection connection;
|
||||
private final ControlChannel controlChannel;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
@@ -12,8 +12,8 @@ public final class DeviceMessageSender {
|
||||
|
||||
private long ack;
|
||||
|
||||
public DeviceMessageSender(DesktopConnection connection) {
|
||||
this.connection = connection;
|
||||
public DeviceMessageSender(ControlChannel controlChannel) {
|
||||
this.controlChannel = controlChannel;
|
||||
}
|
||||
|
||||
public synchronized void pushClipboardText(String text) {
|
||||
@@ -43,11 +43,11 @@ public final class DeviceMessageSender {
|
||||
|
||||
if (sequence != DeviceMessage.SEQUENCE_INVALID) {
|
||||
DeviceMessage event = DeviceMessage.createAckClipboard(sequence);
|
||||
connection.sendDeviceMessage(event);
|
||||
controlChannel.send(event);
|
||||
}
|
||||
if (text != null) {
|
||||
DeviceMessage event = DeviceMessage.createClipboard(text);
|
||||
connection.sendDeviceMessage(event);
|
||||
controlChannel.send(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,8 @@ public final class Server {
|
||||
}
|
||||
|
||||
if (control) {
|
||||
Controller controller = new Controller(device, connection, cleanUp, options.getClipboardAutosync(), options.getPowerOn());
|
||||
ControlChannel controlChannel = connection.getControlChannel();
|
||||
Controller controller = new Controller(device, controlChannel, cleanUp, options.getClipboardAutosync(), options.getPowerOn());
|
||||
device.setClipboardListener(text -> controller.getSender().pushClipboardText(text));
|
||||
asyncProcessors.add(controller);
|
||||
}
|
||||
|
||||
@@ -87,9 +87,15 @@ public final class ClipboardManager {
|
||||
setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class);
|
||||
setMethodVersion = 1;
|
||||
} catch (NoSuchMethodException e2) {
|
||||
setPrimaryClipMethod = manager.getClass()
|
||||
.getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class, int.class);
|
||||
setMethodVersion = 2;
|
||||
try {
|
||||
setPrimaryClipMethod = manager.getClass()
|
||||
.getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class, int.class);
|
||||
setMethodVersion = 2;
|
||||
} catch (NoSuchMethodException e3) {
|
||||
setPrimaryClipMethod = manager.getClass()
|
||||
.getMethod("setPrimaryClip", ClipData.class, String.class, String.class, int.class, int.class, boolean.class);
|
||||
setMethodVersion = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -132,9 +138,12 @@ public final class ClipboardManager {
|
||||
case 1:
|
||||
method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID);
|
||||
break;
|
||||
default:
|
||||
case 2:
|
||||
method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0);
|
||||
break;
|
||||
default:
|
||||
// The last boolean parameter is "userOperate"
|
||||
method.invoke(manager, clipData, FakeContext.PACKAGE_NAME, null, FakeContext.ROOT_UID, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,11 @@ public final class WindowManager {
|
||||
private final IInterface manager;
|
||||
private Method getRotationMethod;
|
||||
private Method freezeRotationMethod;
|
||||
private Method freezeDisplayRotationMethod;
|
||||
private Method isRotationFrozenMethod;
|
||||
private Method isDisplayRotationFrozenMethod;
|
||||
private Method thawRotationMethod;
|
||||
private Method thawDisplayRotationMethod;
|
||||
|
||||
static WindowManager create() {
|
||||
IInterface manager = ServiceManager.getService("window", "android.view.IWindowManager");
|
||||
@@ -47,6 +50,15 @@ public final class WindowManager {
|
||||
return freezeRotationMethod;
|
||||
}
|
||||
|
||||
// New method added by this commit:
|
||||
// <https://android.googlesource.com/platform/frameworks/base/+/90c9005e687aa0f63f1ac391adc1e8878ab31759%5E%21/>
|
||||
private Method getFreezeDisplayRotationMethod() throws NoSuchMethodException {
|
||||
if (freezeDisplayRotationMethod == null) {
|
||||
freezeDisplayRotationMethod = manager.getClass().getMethod("freezeDisplayRotation", int.class, int.class);
|
||||
}
|
||||
return freezeDisplayRotationMethod;
|
||||
}
|
||||
|
||||
private Method getIsRotationFrozenMethod() throws NoSuchMethodException {
|
||||
if (isRotationFrozenMethod == null) {
|
||||
isRotationFrozenMethod = manager.getClass().getMethod("isRotationFrozen");
|
||||
@@ -54,6 +66,15 @@ public final class WindowManager {
|
||||
return isRotationFrozenMethod;
|
||||
}
|
||||
|
||||
// New method added by this commit:
|
||||
// <https://android.googlesource.com/platform/frameworks/base/+/90c9005e687aa0f63f1ac391adc1e8878ab31759%5E%21/>
|
||||
private Method getIsDisplayRotationFrozenMethod() throws NoSuchMethodException {
|
||||
if (isDisplayRotationFrozenMethod == null) {
|
||||
isDisplayRotationFrozenMethod = manager.getClass().getMethod("isDisplayRotationFrozen", int.class);
|
||||
}
|
||||
return isDisplayRotationFrozenMethod;
|
||||
}
|
||||
|
||||
private Method getThawRotationMethod() throws NoSuchMethodException {
|
||||
if (thawRotationMethod == null) {
|
||||
thawRotationMethod = manager.getClass().getMethod("thawRotation");
|
||||
@@ -61,6 +82,15 @@ public final class WindowManager {
|
||||
return thawRotationMethod;
|
||||
}
|
||||
|
||||
// New method added by this commit:
|
||||
// <https://android.googlesource.com/platform/frameworks/base/+/90c9005e687aa0f63f1ac391adc1e8878ab31759%5E%21/>
|
||||
private Method getThawDisplayRotationMethod() throws NoSuchMethodException {
|
||||
if (thawDisplayRotationMethod == null) {
|
||||
thawDisplayRotationMethod = manager.getClass().getMethod("thawDisplayRotation", int.class);
|
||||
}
|
||||
return thawDisplayRotationMethod;
|
||||
}
|
||||
|
||||
public int getRotation() {
|
||||
try {
|
||||
Method method = getGetRotationMethod();
|
||||
@@ -71,29 +101,57 @@ public final class WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void freezeRotation(int rotation) {
|
||||
public void freezeRotation(int displayId, int rotation) {
|
||||
try {
|
||||
Method method = getFreezeRotationMethod();
|
||||
method.invoke(manager, rotation);
|
||||
try {
|
||||
Method method = getFreezeDisplayRotationMethod();
|
||||
method.invoke(manager, displayId, rotation);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
if (displayId == 0) {
|
||||
Method method = getFreezeRotationMethod();
|
||||
method.invoke(manager, rotation);
|
||||
} else {
|
||||
Ln.e("Could not invoke method", e);
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Ln.e("Could not invoke method", e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRotationFrozen() {
|
||||
public boolean isRotationFrozen(int displayId) {
|
||||
try {
|
||||
Method method = getIsRotationFrozenMethod();
|
||||
return (boolean) method.invoke(manager);
|
||||
try {
|
||||
Method method = getIsDisplayRotationFrozenMethod();
|
||||
return (boolean) method.invoke(manager, displayId);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
if (displayId == 0) {
|
||||
Method method = getIsRotationFrozenMethod();
|
||||
return (boolean) method.invoke(manager);
|
||||
} else {
|
||||
Ln.e("Could not invoke method", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Ln.e("Could not invoke method", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void thawRotation() {
|
||||
public void thawRotation(int displayId) {
|
||||
try {
|
||||
Method method = getThawRotationMethod();
|
||||
method.invoke(manager);
|
||||
try {
|
||||
Method method = getThawDisplayRotationMethod();
|
||||
method.invoke(manager, displayId);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
if (displayId == 0) {
|
||||
Method method = getThawRotationMethod();
|
||||
method.invoke(manager);
|
||||
} else {
|
||||
Ln.e("Could not invoke method", e);
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Ln.e("Could not invoke method", e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user