mirror of
https://github.com/Genymobile/scrcpy.git
synced 2026-03-23 12:34:28 +01:00
Compare commits
34 Commits
gamepad.dr
...
gamepad.dr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ade819cef | ||
|
|
7828bb2dbd | ||
|
|
b32406681b | ||
|
|
b266fdb229 | ||
|
|
1487bddfa2 | ||
|
|
519969d3e0 | ||
|
|
f6a40ecfa9 | ||
|
|
97352bc21d | ||
|
|
1c326c9330 | ||
|
|
9be3a68ac6 | ||
|
|
a293bf368e | ||
|
|
0ad8ca2141 | ||
|
|
0c432bc854 | ||
|
|
a436a9ec34 | ||
|
|
3180218b9a | ||
|
|
3ae38a5c54 | ||
|
|
b633614d36 | ||
|
|
5841650aa0 | ||
|
|
9c382e8169 | ||
|
|
037009b11c | ||
|
|
9c5876cc15 | ||
|
|
ced31229c8 | ||
|
|
d5f7a5e704 | ||
|
|
80dc95c215 | ||
|
|
b04d8eb162 | ||
|
|
698e4d1bae | ||
|
|
c3a4b17842 | ||
|
|
59d80afab7 | ||
|
|
cb79d97f5d | ||
|
|
f355672ab2 | ||
|
|
154507c009 | ||
|
|
a3405ab62e | ||
|
|
cdafbec7e3 | ||
|
|
698faae1ad |
@@ -175,10 +175,6 @@ Start in fullscreen.
|
||||
.B \-\-force\-adb\-forward
|
||||
Do not attempt to use "adb reverse" to connect to the device.
|
||||
|
||||
.TP
|
||||
.B \-G
|
||||
Same as \fB\-\-gamepad=uhid\fR, or \fB\-\-keyboard=aoa\fR if \fB\-\-otg\fR is set.
|
||||
|
||||
.TP
|
||||
.BI "\-\-gamepad " mode
|
||||
Select how to send gamepad inputs to the device.
|
||||
@@ -196,7 +192,7 @@ Print this help.
|
||||
|
||||
.TP
|
||||
.B \-K
|
||||
Same as \fB\-\-keyboard=uhid\fR, or \fB\-\-keyboard=aoa\fR if \fB\-\-otg\fR is set.
|
||||
Same as \fB\-\-keyboard=uhid\fR.
|
||||
|
||||
.TP
|
||||
.BI "\-\-keyboard " mode
|
||||
@@ -261,7 +257,7 @@ Default is 0 (unlimited).
|
||||
|
||||
.TP
|
||||
.B \-M
|
||||
Same as \fB\-\-mouse=uhid\fR, or \fB\-\-mouse=aoa\fR if \fB\-\-otg\fR is set.
|
||||
Same as \fB\-\-mouse=uhid\fR.
|
||||
|
||||
.TP
|
||||
.BI "\-\-max\-fps " value
|
||||
|
||||
@@ -375,7 +375,7 @@ static const struct sc_option options[] = {
|
||||
},
|
||||
{
|
||||
.shortopt = 'G',
|
||||
.text = "Same as --gamepad=uhid, or --gamepad=aoa if --otg is set.",
|
||||
.text = "Same as --gamepad=uhid.",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_GAMEPAD,
|
||||
@@ -397,7 +397,7 @@ static const struct sc_option options[] = {
|
||||
},
|
||||
{
|
||||
.shortopt = 'K',
|
||||
.text = "Same as --keyboard=uhid, or --keyboard=aoa if --otg is set.",
|
||||
.text = "Same as --keyboard=uhid.",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_KEYBOARD,
|
||||
@@ -493,7 +493,7 @@ static const struct sc_option options[] = {
|
||||
},
|
||||
{
|
||||
.shortopt = 'M',
|
||||
.text = "Same as --mouse=uhid, or --mouse=aoa if --otg is set.",
|
||||
.text = "Same as --mouse=uhid.",
|
||||
},
|
||||
{
|
||||
.longopt_id = OPT_MAX_FPS,
|
||||
@@ -2264,7 +2264,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
args->help = true;
|
||||
break;
|
||||
case 'K':
|
||||
opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_UHID_OR_AOA;
|
||||
opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_UHID;
|
||||
break;
|
||||
case OPT_KEYBOARD:
|
||||
if (!parse_keyboard(optarg, &opts->keyboard_input_mode)) {
|
||||
@@ -2286,7 +2286,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_UHID_OR_AOA;
|
||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_UHID;
|
||||
break;
|
||||
case OPT_MOUSE:
|
||||
if (!parse_mouse(optarg, &opts->mouse_input_mode)) {
|
||||
@@ -2671,7 +2671,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
opts->audio_dup = true;
|
||||
break;
|
||||
case 'G':
|
||||
opts->gamepad_input_mode = SC_GAMEPAD_INPUT_MODE_UHID_OR_AOA;
|
||||
opts->gamepad_input_mode = SC_GAMEPAD_INPUT_MODE_UHID;
|
||||
break;
|
||||
case OPT_GAMEPAD:
|
||||
if (!parse_gamepad(optarg, &opts->gamepad_input_mode)) {
|
||||
@@ -2795,12 +2795,7 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
if (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AUTO) {
|
||||
opts->keyboard_input_mode = otg ? SC_KEYBOARD_INPUT_MODE_AOA
|
||||
: SC_KEYBOARD_INPUT_MODE_SDK;
|
||||
} else if (opts->keyboard_input_mode
|
||||
== SC_KEYBOARD_INPUT_MODE_UHID_OR_AOA) {
|
||||
opts->keyboard_input_mode = otg ? SC_KEYBOARD_INPUT_MODE_AOA
|
||||
: SC_KEYBOARD_INPUT_MODE_UHID;
|
||||
}
|
||||
|
||||
if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_AUTO) {
|
||||
if (otg) {
|
||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_AOA;
|
||||
@@ -2810,24 +2805,19 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[],
|
||||
} else {
|
||||
opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_SDK;
|
||||
}
|
||||
} else if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_UHID_OR_AOA) {
|
||||
opts->mouse_input_mode = otg ? SC_MOUSE_INPUT_MODE_AOA
|
||||
: SC_MOUSE_INPUT_MODE_SDK;
|
||||
} else if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_SDK
|
||||
&& !opts->video_playback) {
|
||||
LOGE("SDK mouse mode requires video playback. Try --mouse=uhid.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opts->gamepad_input_mode == SC_GAMEPAD_INPUT_MODE_AUTO) {
|
||||
// UHID does not work on all devices (with old Android
|
||||
// versions), so it cannot be enabled by default
|
||||
opts->gamepad_input_mode = otg ? SC_GAMEPAD_INPUT_MODE_AOA
|
||||
: SC_GAMEPAD_INPUT_MODE_DISABLED;
|
||||
} else if (opts->gamepad_input_mode
|
||||
== SC_GAMEPAD_INPUT_MODE_UHID_OR_AOA) {
|
||||
opts->gamepad_input_mode = otg ? SC_GAMEPAD_INPUT_MODE_AOA
|
||||
: SC_GAMEPAD_INPUT_MODE_UHID;
|
||||
if (otg) {
|
||||
opts->gamepad_input_mode = SC_GAMEPAD_INPUT_MODE_AOA;
|
||||
} else {
|
||||
// UHID does not work on all devices (with old Android
|
||||
// versions), so it cannot be enabled by default
|
||||
opts->gamepad_input_mode = SC_GAMEPAD_INPUT_MODE_DISABLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "events.h"
|
||||
|
||||
#include "util/log.h"
|
||||
#include "util/thread.h"
|
||||
|
||||
bool
|
||||
sc_push_event_impl(uint32_t type, const char *name) {
|
||||
@@ -33,34 +32,9 @@ sc_post_to_main_thread(sc_runnable_fn run, void *userdata) {
|
||||
// ret == 0: event was filtered
|
||||
// ret == 1: success
|
||||
if (ret != 1) {
|
||||
if (ret == 0) {
|
||||
// if ret == 0, this is expected on exit, log in debug mode
|
||||
LOGD("Could not post runnable to main thread (filtered)");
|
||||
} else {
|
||||
assert(ret < 0);
|
||||
LOGW("Coud not post to main thread: %s", SDL_GetError());
|
||||
}
|
||||
LOGW("Coud not post to main thread: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int SDLCALL
|
||||
task_event_filter(void *userdata, SDL_Event *event) {
|
||||
(void) userdata;
|
||||
|
||||
if (event->type == SC_EVENT_RUN_ON_MAIN_THREAD) {
|
||||
// Reject this event type from now on
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
sc_reject_new_runnables(void) {
|
||||
assert(sc_thread_get_id() == SC_MAIN_THREAD_ID);
|
||||
|
||||
SDL_SetEventFilter(task_event_filter, NULL);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SC_EVENTS_H
|
||||
#define SC_EVENTS_H
|
||||
#ifndef SC_EVENTS
|
||||
#define SC_EVENTS
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -32,7 +32,4 @@ typedef void (*sc_runnable_fn)(void *userdata);
|
||||
bool
|
||||
sc_post_to_main_thread(sc_runnable_fn run, void *userdata);
|
||||
|
||||
void
|
||||
sc_reject_new_runnables(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -76,8 +76,8 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
|
||||
0x09, 0xC4,
|
||||
// Logical Minimum (0)
|
||||
0x15, 0x00,
|
||||
// Logical Maximum (32767)
|
||||
0x26, 0xFF, 0x7F,
|
||||
// Logical Maximum (65535)
|
||||
0x27, 0xFF, 0xFF, 0x00, 0x00,
|
||||
// Report Size (16)
|
||||
0x75, 0x10,
|
||||
// Report Count (2)
|
||||
@@ -89,19 +89,26 @@ static const uint8_t SC_HID_GAMEPAD_REPORT_DESC[] = {
|
||||
0x05, 0x09,
|
||||
// Usage Minimum (1)
|
||||
0x19, 0x01,
|
||||
// Usage Maximum (16)
|
||||
0x29, 0x0F,
|
||||
// Usage Maximum (15)
|
||||
0x29, 0x0E,
|
||||
// Logical Minimum (0)
|
||||
0x15, 0x00,
|
||||
// Logical Maximum (1)
|
||||
0x25, 0x01,
|
||||
// Report Count (16)
|
||||
0x95, 0x10,
|
||||
// Report Count (15)
|
||||
0x95, 0x0F,
|
||||
// Report Size (1)
|
||||
0x75, 0x01,
|
||||
// Input (Data, Variable, Absolute): 16 buttons bits
|
||||
// Input (Data, Variable, Absolute): 15 buttons bits
|
||||
0x81, 0x02,
|
||||
|
||||
// Report Count (1)
|
||||
0x95, 0x01,
|
||||
// Report Size (1)
|
||||
0x75, 0x01,
|
||||
// Input (Constant): 1-bit padding
|
||||
0x81, 0x01,
|
||||
|
||||
// Usage Page (Generic Desktop)
|
||||
0x05, 0x01,
|
||||
// Usage (Hat switch)
|
||||
@@ -313,13 +320,14 @@ sc_hid_gamepad_event_from_slot(uint16_t hid_id,
|
||||
hid_input->size = SC_HID_GAMEPAD_EVENT_SIZE;
|
||||
|
||||
uint8_t *data = hid_input->data;
|
||||
// Values must be written in little-endian
|
||||
sc_write16le(data, slot->axis_left_x);
|
||||
sc_write16le(data + 2, slot->axis_left_y);
|
||||
sc_write16le(data + 4, slot->axis_right_x);
|
||||
sc_write16le(data + 6, slot->axis_right_y);
|
||||
sc_write16le(data + 8, slot->axis_left_trigger);
|
||||
sc_write16le(data + 10, slot->axis_right_trigger);
|
||||
// Buttons are individual bits in the report descriptor, so the resulting
|
||||
// u16 must be written in little-endian
|
||||
sc_write16be(data, slot->axis_left_x);
|
||||
sc_write16be(data + 2, slot->axis_left_y);
|
||||
sc_write16be(data + 4, slot->axis_right_x);
|
||||
sc_write16be(data + 6, slot->axis_right_y);
|
||||
sc_write16be(data + 8, slot->axis_left_trigger);
|
||||
sc_write16be(data + 10, slot->axis_right_trigger);
|
||||
sc_write16le(data + 12, slot->buttons & SC_HID_BUTTONS_MASK);
|
||||
data[14] = sc_hid_gamepad_get_dpad_value(slot->buttons);
|
||||
}
|
||||
@@ -398,7 +406,6 @@ sc_hid_gamepad_generate_input_from_button(struct sc_hid_gamepad *hid,
|
||||
|
||||
uint16_t hid_id = sc_hid_gamepad_slot_get_id(slot_idx);
|
||||
sc_hid_gamepad_event_from_slot(hid_id, slot, hid_input);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -418,28 +425,26 @@ sc_hid_gamepad_generate_input_from_axis(struct sc_hid_gamepad *hid,
|
||||
|
||||
struct sc_hid_gamepad_slot *slot = &hid->slots[slot_idx];
|
||||
|
||||
// [-32768 to 32767] -> [0 to 65535]
|
||||
#define AXIS_RESCALE(V) (uint16_t) (((int32_t) V) + 0x8000)
|
||||
// [-32768 to 32767] -> [0 to 65535]
|
||||
uint16_t value = ((int32_t) event->value) + 0x8000;
|
||||
switch (event->axis) {
|
||||
case SC_GAMEPAD_AXIS_LEFTX:
|
||||
slot->axis_left_x = AXIS_RESCALE(event->value);
|
||||
slot->axis_left_x = value;
|
||||
break;
|
||||
case SC_GAMEPAD_AXIS_LEFTY:
|
||||
slot->axis_left_y = AXIS_RESCALE(event->value);
|
||||
slot->axis_left_y = value;
|
||||
break;
|
||||
case SC_GAMEPAD_AXIS_RIGHTX:
|
||||
slot->axis_right_x = AXIS_RESCALE(event->value);
|
||||
slot->axis_right_x = value;
|
||||
break;
|
||||
case SC_GAMEPAD_AXIS_RIGHTY:
|
||||
slot->axis_right_y = AXIS_RESCALE(event->value);
|
||||
slot->axis_right_y = value;
|
||||
break;
|
||||
case SC_GAMEPAD_AXIS_LEFT_TRIGGER:
|
||||
// Trigger is always positive between 0 and 32767
|
||||
slot->axis_left_trigger = MAX(0, event->value);
|
||||
slot->axis_left_trigger = value;
|
||||
break;
|
||||
case SC_GAMEPAD_AXIS_RIGHT_TRIGGER:
|
||||
// Trigger is always positive between 0 and 32767
|
||||
slot->axis_right_trigger = MAX(0, event->value);
|
||||
slot->axis_right_trigger = value;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
@@ -447,6 +452,5 @@ sc_hid_gamepad_generate_input_from_axis(struct sc_hid_gamepad *hid,
|
||||
|
||||
uint16_t hid_id = sc_hid_gamepad_slot_get_id(slot_idx);
|
||||
sc_hid_gamepad_event_from_slot(hid_id, slot, hid_input);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -142,7 +142,6 @@ enum sc_lock_video_orientation {
|
||||
|
||||
enum sc_keyboard_input_mode {
|
||||
SC_KEYBOARD_INPUT_MODE_AUTO,
|
||||
SC_KEYBOARD_INPUT_MODE_UHID_OR_AOA, // normal vs otg mode
|
||||
SC_KEYBOARD_INPUT_MODE_DISABLED,
|
||||
SC_KEYBOARD_INPUT_MODE_SDK,
|
||||
SC_KEYBOARD_INPUT_MODE_UHID,
|
||||
@@ -151,7 +150,6 @@ enum sc_keyboard_input_mode {
|
||||
|
||||
enum sc_mouse_input_mode {
|
||||
SC_MOUSE_INPUT_MODE_AUTO,
|
||||
SC_MOUSE_INPUT_MODE_UHID_OR_AOA, // normal vs otg mode
|
||||
SC_MOUSE_INPUT_MODE_DISABLED,
|
||||
SC_MOUSE_INPUT_MODE_SDK,
|
||||
SC_MOUSE_INPUT_MODE_UHID,
|
||||
@@ -160,7 +158,6 @@ enum sc_mouse_input_mode {
|
||||
|
||||
enum sc_gamepad_input_mode {
|
||||
SC_GAMEPAD_INPUT_MODE_AUTO,
|
||||
SC_GAMEPAD_INPUT_MODE_UHID_OR_AOA, // normal vs otg mode
|
||||
SC_GAMEPAD_INPUT_MODE_DISABLED,
|
||||
SC_GAMEPAD_INPUT_MODE_UHID,
|
||||
SC_GAMEPAD_INPUT_MODE_AOA,
|
||||
|
||||
@@ -200,21 +200,6 @@ event_loop(struct scrcpy *s) {
|
||||
return SCRCPY_EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static void
|
||||
terminate_event_loop(void) {
|
||||
sc_reject_new_runnables();
|
||||
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
if (event.type == SC_EVENT_RUN_ON_MAIN_THREAD) {
|
||||
// Make sure all posted runnables are run, to avoid memory leaks
|
||||
sc_runnable_fn run = event.user.data1;
|
||||
void *userdata = event.user.data2;
|
||||
run(userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return true on success, false on error
|
||||
static bool
|
||||
await_for_server(bool *connected) {
|
||||
@@ -903,7 +888,6 @@ aoa_complete:
|
||||
}
|
||||
|
||||
ret = event_loop(s);
|
||||
terminate_event_loop();
|
||||
LOGD("quit...");
|
||||
|
||||
if (options->video_playback) {
|
||||
|
||||
@@ -83,10 +83,7 @@ sc_gamepad_processor_process_gamepad_axis(struct sc_gamepad_processor *gp,
|
||||
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
|
||||
|
||||
struct sc_hid_input hid_input;
|
||||
if (!sc_hid_gamepad_generate_input_from_axis(&gamepad->hid, &hid_input,
|
||||
event)) {
|
||||
return;
|
||||
}
|
||||
sc_hid_gamepad_generate_input_from_axis(&gamepad->hid, &hid_input, event);
|
||||
|
||||
sc_gamepad_uhid_send_input(gamepad, &hid_input, "gamepad axis");
|
||||
}
|
||||
@@ -97,10 +94,7 @@ sc_gamepad_processor_process_gamepad_button(struct sc_gamepad_processor *gp,
|
||||
struct sc_gamepad_uhid *gamepad = DOWNCAST(gp);
|
||||
|
||||
struct sc_hid_input hid_input;
|
||||
if (!sc_hid_gamepad_generate_input_from_button(&gamepad->hid, &hid_input,
|
||||
event)) {
|
||||
return;
|
||||
}
|
||||
sc_hid_gamepad_generate_input_from_button(&gamepad->hid, &hid_input, event);
|
||||
|
||||
sc_gamepad_uhid_send_input(gamepad, &hid_input, "gamepad button");
|
||||
|
||||
|
||||
@@ -38,9 +38,7 @@ sc_keyboard_uhid_synchronize_mod(struct sc_keyboard_uhid *kb) {
|
||||
kb->device_mod = mod;
|
||||
|
||||
struct sc_hid_input hid_input;
|
||||
if (!sc_hid_keyboard_generate_input_from_mods(&hid_input, diff)) {
|
||||
return;
|
||||
}
|
||||
sc_hid_keyboard_generate_input_from_mods(&hid_input, diff);
|
||||
|
||||
LOGV("HID keyboard state synchronized");
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@ event_loop(struct scrcpy_otg *s) {
|
||||
case SDL_QUIT:
|
||||
LOGD("User requested to quit");
|
||||
return SCRCPY_EXIT_SUCCESS;
|
||||
case SC_EVENT_RUN_ON_MAIN_THREAD:
|
||||
sc_runnable_fn run = event.user.data1;
|
||||
void *userdata = event.user.data2;
|
||||
run(userdata);
|
||||
break;
|
||||
default:
|
||||
sc_screen_otg_handle_event(&s->screen_otg, &event);
|
||||
break;
|
||||
|
||||
@@ -3,22 +3,31 @@ package com.genymobile.scrcpy.control;
|
||||
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;
|
||||
private final DeviceMessageWriter writer;
|
||||
private final ControlMessageReader reader = new ControlMessageReader();
|
||||
private final DeviceMessageWriter writer = new DeviceMessageWriter();
|
||||
|
||||
public ControlChannel(LocalSocket controlSocket) throws IOException {
|
||||
reader = new ControlMessageReader(controlSocket.getInputStream());
|
||||
writer = new DeviceMessageWriter(controlSocket.getOutputStream());
|
||||
this.inputStream = controlSocket.getInputStream();
|
||||
this.outputStream = controlSocket.getOutputStream();
|
||||
}
|
||||
|
||||
public ControlMessage recv() throws IOException {
|
||||
return reader.read();
|
||||
ControlMessage msg = reader.next();
|
||||
while (msg == null) {
|
||||
reader.readFrom(inputStream);
|
||||
msg = reader.next();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void send(DeviceMessage msg) throws IOException {
|
||||
writer.write(msg);
|
||||
writer.writeTo(msg, outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,159 +1,271 @@
|
||||
package com.genymobile.scrcpy.control;
|
||||
|
||||
import com.genymobile.scrcpy.util.Binary;
|
||||
import com.genymobile.scrcpy.util.Ln;
|
||||
import com.genymobile.scrcpy.device.Position;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class ControlMessageReader {
|
||||
|
||||
static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13;
|
||||
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 31;
|
||||
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 GET_CLIPBOARD_LENGTH = 1;
|
||||
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 9;
|
||||
static final int UHID_CREATE_FIXED_PAYLOAD_LENGTH = 4;
|
||||
static final int UHID_INPUT_FIXED_PAYLOAD_LENGTH = 4;
|
||||
static final int UHID_DESTROY_PAYLOAD_LENGTH = 2;
|
||||
|
||||
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 INJECT_TEXT_MAX_LENGTH = 300;
|
||||
|
||||
private final DataInputStream dis;
|
||||
private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE];
|
||||
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
|
||||
|
||||
public ControlMessageReader(InputStream rawInputStream) {
|
||||
dis = new DataInputStream(new BufferedInputStream(rawInputStream));
|
||||
public ControlMessageReader() {
|
||||
// invariant: the buffer is always in "get" mode
|
||||
buffer.limit(0);
|
||||
}
|
||||
|
||||
public ControlMessage read() throws IOException {
|
||||
int type = dis.readUnsignedByte();
|
||||
public boolean isFull() {
|
||||
return buffer.remaining() == rawBuffer.length;
|
||||
}
|
||||
|
||||
public void readFrom(InputStream input) throws IOException {
|
||||
if (isFull()) {
|
||||
throw new IllegalStateException("Buffer full, call next() to consume");
|
||||
}
|
||||
buffer.compact();
|
||||
int head = buffer.position();
|
||||
int r = input.read(rawBuffer, head, rawBuffer.length - head);
|
||||
if (r == -1) {
|
||||
throw new EOFException("Controller socket closed");
|
||||
}
|
||||
buffer.position(head + r);
|
||||
buffer.flip();
|
||||
}
|
||||
|
||||
public ControlMessage next() {
|
||||
if (!buffer.hasRemaining()) {
|
||||
return null;
|
||||
}
|
||||
int savedPosition = buffer.position();
|
||||
|
||||
int type = buffer.get();
|
||||
ControlMessage msg;
|
||||
switch (type) {
|
||||
case ControlMessage.TYPE_INJECT_KEYCODE:
|
||||
return parseInjectKeycode();
|
||||
msg = parseInjectKeycode();
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_TEXT:
|
||||
return parseInjectText();
|
||||
msg = parseInjectText();
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_TOUCH_EVENT:
|
||||
return parseInjectTouchEvent();
|
||||
msg = parseInjectTouchEvent();
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
|
||||
return parseInjectScrollEvent();
|
||||
msg = parseInjectScrollEvent();
|
||||
break;
|
||||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||
return parseBackOrScreenOnEvent();
|
||||
msg = parseBackOrScreenOnEvent();
|
||||
break;
|
||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||
return parseGetClipboard();
|
||||
msg = parseGetClipboard();
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||
return parseSetClipboard();
|
||||
msg = parseSetClipboard();
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_SCREEN_POWER_MODE:
|
||||
return parseSetScreenPowerMode();
|
||||
msg = parseSetScreenPowerMode();
|
||||
break;
|
||||
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||
case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL:
|
||||
case ControlMessage.TYPE_COLLAPSE_PANELS:
|
||||
case ControlMessage.TYPE_ROTATE_DEVICE:
|
||||
case ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS:
|
||||
return ControlMessage.createEmpty(type);
|
||||
msg = ControlMessage.createEmpty(type);
|
||||
break;
|
||||
case ControlMessage.TYPE_UHID_CREATE:
|
||||
return parseUhidCreate();
|
||||
msg = parseUhidCreate();
|
||||
break;
|
||||
case ControlMessage.TYPE_UHID_INPUT:
|
||||
return parseUhidInput();
|
||||
msg = parseUhidInput();
|
||||
break;
|
||||
case ControlMessage.TYPE_UHID_DESTROY:
|
||||
return parseUhidDestroy();
|
||||
msg = parseUhidDestroy();
|
||||
break;
|
||||
default:
|
||||
throw new ControlProtocolException("Unknown event type: " + type);
|
||||
Ln.w("Unknown event type: " + type);
|
||||
msg = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg == null) {
|
||||
// failure, reset savedPosition
|
||||
buffer.position(savedPosition);
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
private ControlMessage parseInjectKeycode() throws IOException {
|
||||
int action = dis.readUnsignedByte();
|
||||
int keycode = dis.readInt();
|
||||
int repeat = dis.readInt();
|
||||
int metaState = dis.readInt();
|
||||
private ControlMessage parseInjectKeycode() {
|
||||
if (buffer.remaining() < INJECT_KEYCODE_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int action = Binary.toUnsigned(buffer.get());
|
||||
int keycode = buffer.getInt();
|
||||
int repeat = buffer.getInt();
|
||||
int metaState = buffer.getInt();
|
||||
return ControlMessage.createInjectKeycode(action, keycode, repeat, metaState);
|
||||
}
|
||||
|
||||
private int parseBufferLength(int sizeBytes) throws IOException {
|
||||
private int parseBufferLength(int sizeBytes) {
|
||||
assert sizeBytes > 0 && sizeBytes <= 4;
|
||||
if (buffer.remaining() < sizeBytes) {
|
||||
return -1;
|
||||
}
|
||||
int value = 0;
|
||||
for (int i = 0; i < sizeBytes; ++i) {
|
||||
value = (value << 8) | dis.readUnsignedByte();
|
||||
value = (value << 8) | (buffer.get() & 0xFF);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String parseString() throws IOException {
|
||||
byte[] data = parseByteArray(4);
|
||||
return new String(data, StandardCharsets.UTF_8);
|
||||
private String parseString() {
|
||||
int len = parseBufferLength(4);
|
||||
if (len == -1 || buffer.remaining() < len) {
|
||||
return null;
|
||||
}
|
||||
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 byte[] parseByteArray(int sizeBytes) throws IOException {
|
||||
private byte[] parseByteArray(int sizeBytes) {
|
||||
int len = parseBufferLength(sizeBytes);
|
||||
if (len == -1 || buffer.remaining() < len) {
|
||||
return null;
|
||||
}
|
||||
byte[] data = new byte[len];
|
||||
dis.readFully(data);
|
||||
buffer.get(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private ControlMessage parseInjectText() throws IOException {
|
||||
private ControlMessage parseInjectText() {
|
||||
String text = parseString();
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
return ControlMessage.createInjectText(text);
|
||||
}
|
||||
|
||||
private ControlMessage parseInjectTouchEvent() throws IOException {
|
||||
int action = dis.readUnsignedByte();
|
||||
long pointerId = dis.readLong();
|
||||
Position position = parsePosition();
|
||||
float pressure = Binary.u16FixedPointToFloat(dis.readShort());
|
||||
int actionButton = dis.readInt();
|
||||
int buttons = dis.readInt();
|
||||
private ControlMessage parseInjectTouchEvent() {
|
||||
if (buffer.remaining() < INJECT_TOUCH_EVENT_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int action = Binary.toUnsigned(buffer.get());
|
||||
long pointerId = buffer.getLong();
|
||||
Position position = readPosition(buffer);
|
||||
float pressure = Binary.u16FixedPointToFloat(buffer.getShort());
|
||||
int actionButton = buffer.getInt();
|
||||
int buttons = buffer.getInt();
|
||||
return ControlMessage.createInjectTouchEvent(action, pointerId, position, pressure, actionButton, buttons);
|
||||
}
|
||||
|
||||
private ControlMessage parseInjectScrollEvent() throws IOException {
|
||||
Position position = parsePosition();
|
||||
float hScroll = Binary.i16FixedPointToFloat(dis.readShort());
|
||||
float vScroll = Binary.i16FixedPointToFloat(dis.readShort());
|
||||
int buttons = dis.readInt();
|
||||
private ControlMessage parseInjectScrollEvent() {
|
||||
if (buffer.remaining() < INJECT_SCROLL_EVENT_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
Position position = readPosition(buffer);
|
||||
float hScroll = Binary.i16FixedPointToFloat(buffer.getShort());
|
||||
float vScroll = Binary.i16FixedPointToFloat(buffer.getShort());
|
||||
int buttons = buffer.getInt();
|
||||
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll, buttons);
|
||||
}
|
||||
|
||||
private ControlMessage parseBackOrScreenOnEvent() throws IOException {
|
||||
int action = dis.readUnsignedByte();
|
||||
private ControlMessage parseBackOrScreenOnEvent() {
|
||||
if (buffer.remaining() < BACK_OR_SCREEN_ON_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int action = Binary.toUnsigned(buffer.get());
|
||||
return ControlMessage.createBackOrScreenOn(action);
|
||||
}
|
||||
|
||||
private ControlMessage parseGetClipboard() throws IOException {
|
||||
int copyKey = dis.readUnsignedByte();
|
||||
private ControlMessage parseGetClipboard() {
|
||||
if (buffer.remaining() < GET_CLIPBOARD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int copyKey = Binary.toUnsigned(buffer.get());
|
||||
return ControlMessage.createGetClipboard(copyKey);
|
||||
}
|
||||
|
||||
private ControlMessage parseSetClipboard() throws IOException {
|
||||
long sequence = dis.readLong();
|
||||
boolean paste = dis.readByte() != 0;
|
||||
private ControlMessage parseSetClipboard() {
|
||||
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);
|
||||
}
|
||||
|
||||
private ControlMessage parseSetScreenPowerMode() throws IOException {
|
||||
int mode = dis.readUnsignedByte();
|
||||
private ControlMessage parseSetScreenPowerMode() {
|
||||
if (buffer.remaining() < SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int mode = buffer.get();
|
||||
return ControlMessage.createSetScreenPowerMode(mode);
|
||||
}
|
||||
|
||||
private ControlMessage parseUhidCreate() throws IOException {
|
||||
int id = dis.readUnsignedShort();
|
||||
private ControlMessage parseUhidCreate() {
|
||||
if (buffer.remaining() < UHID_CREATE_FIXED_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int id = buffer.getShort();
|
||||
byte[] data = parseByteArray(2);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return ControlMessage.createUhidCreate(id, data);
|
||||
}
|
||||
|
||||
private ControlMessage parseUhidInput() throws IOException {
|
||||
int id = dis.readUnsignedShort();
|
||||
private ControlMessage parseUhidInput() {
|
||||
if (buffer.remaining() < UHID_INPUT_FIXED_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int id = buffer.getShort();
|
||||
byte[] data = parseByteArray(2);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
return ControlMessage.createUhidInput(id, data);
|
||||
}
|
||||
|
||||
private ControlMessage parseUhidDestroy() throws IOException {
|
||||
int id = dis.readUnsignedShort();
|
||||
private ControlMessage parseUhidDestroy() {
|
||||
if (buffer.remaining() < UHID_DESTROY_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int id = buffer.getShort();
|
||||
return ControlMessage.createUhidDestroy(id);
|
||||
}
|
||||
|
||||
private Position parsePosition() throws IOException {
|
||||
int x = dis.readInt();
|
||||
int y = dis.readInt();
|
||||
int screenWidth = dis.readUnsignedShort();
|
||||
int screenHeight = dis.readUnsignedShort();
|
||||
private static Position readPosition(ByteBuffer buffer) {
|
||||
int x = buffer.getInt();
|
||||
int y = buffer.getInt();
|
||||
int screenWidth = Binary.toUnsigned(buffer.getShort());
|
||||
int screenHeight = Binary.toUnsigned(buffer.getShort());
|
||||
return new Position(x, y, screenWidth, screenHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package com.genymobile.scrcpy.control;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ControlProtocolException extends IOException {
|
||||
public ControlProtocolException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.genymobile.scrcpy.control;
|
||||
|
||||
import com.genymobile.scrcpy.util.Ln;
|
||||
import com.genymobile.scrcpy.util.StringUtils;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class DeviceMessageWriter {
|
||||
@@ -13,35 +13,35 @@ public class DeviceMessageWriter {
|
||||
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 DataOutputStream dos;
|
||||
private final byte[] rawBuffer = new byte[MESSAGE_MAX_SIZE];
|
||||
private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer);
|
||||
|
||||
public DeviceMessageWriter(OutputStream rawOutputStream) {
|
||||
dos = new DataOutputStream(new BufferedOutputStream(rawOutputStream));
|
||||
}
|
||||
|
||||
public void write(DeviceMessage msg) throws IOException {
|
||||
int type = msg.getType();
|
||||
dos.writeByte(type);
|
||||
switch (type) {
|
||||
public void writeTo(DeviceMessage msg, OutputStream output) throws IOException {
|
||||
buffer.clear();
|
||||
buffer.put((byte) msg.getType());
|
||||
switch (msg.getType()) {
|
||||
case DeviceMessage.TYPE_CLIPBOARD:
|
||||
String text = msg.getText();
|
||||
byte[] raw = text.getBytes(StandardCharsets.UTF_8);
|
||||
int len = StringUtils.getUtf8TruncationIndex(raw, CLIPBOARD_TEXT_MAX_LENGTH);
|
||||
dos.writeInt(len);
|
||||
dos.write(raw, 0, len);
|
||||
buffer.putInt(len);
|
||||
buffer.put(raw, 0, len);
|
||||
output.write(rawBuffer, 0, buffer.position());
|
||||
break;
|
||||
case DeviceMessage.TYPE_ACK_CLIPBOARD:
|
||||
dos.writeLong(msg.getSequence());
|
||||
buffer.putLong(msg.getSequence());
|
||||
output.write(rawBuffer, 0, buffer.position());
|
||||
break;
|
||||
case DeviceMessage.TYPE_UHID_OUTPUT:
|
||||
dos.writeShort(msg.getId());
|
||||
buffer.putShort((short) msg.getId());
|
||||
byte[] data = msg.getData();
|
||||
dos.writeShort(data.length);
|
||||
dos.write(data);
|
||||
buffer.putShort((short) data.length);
|
||||
buffer.put(data);
|
||||
output.write(rawBuffer, 0, buffer.position());
|
||||
break;
|
||||
default:
|
||||
throw new ControlProtocolException("Unknown event type: " + type);
|
||||
Ln.w("Unknown device message: " + msg.getType());
|
||||
break;
|
||||
}
|
||||
dos.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import org.junit.Test;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
@@ -19,6 +18,8 @@ public class ControlMessageReaderTest {
|
||||
|
||||
@Test
|
||||
public void testParseKeycodeEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_INJECT_KEYCODE);
|
||||
@@ -28,21 +29,23 @@ public class ControlMessageReaderTest {
|
||||
dos.writeInt(KeyEvent.META_CTRL_ON);
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
// The message type (1 byte) does not count
|
||||
Assert.assertEquals(ControlMessageReader.INJECT_KEYCODE_PAYLOAD_LENGTH, packet.length - 1);
|
||||
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
|
||||
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
|
||||
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
|
||||
Assert.assertEquals(5, event.getRepeat());
|
||||
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTextEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_INJECT_TEXT);
|
||||
@@ -51,18 +54,17 @@ public class ControlMessageReaderTest {
|
||||
dos.write(text);
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_TEXT, event.getType());
|
||||
Assert.assertEquals("testé", event.getText());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseLongTextEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_INJECT_TEXT);
|
||||
@@ -72,18 +74,17 @@ public class ControlMessageReaderTest {
|
||||
dos.write(text);
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_TEXT, event.getType());
|
||||
Assert.assertEquals(new String(text, StandardCharsets.US_ASCII), event.getText());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseTouchEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_INJECT_TOUCH_EVENT);
|
||||
@@ -99,10 +100,12 @@ public class ControlMessageReaderTest {
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
// The message type (1 byte) does not count
|
||||
Assert.assertEquals(ControlMessageReader.INJECT_TOUCH_EVENT_PAYLOAD_LENGTH, packet.length - 1);
|
||||
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_TOUCH_EVENT, event.getType());
|
||||
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
|
||||
Assert.assertEquals(-42, event.getPointerId());
|
||||
@@ -113,12 +116,12 @@ public class ControlMessageReaderTest {
|
||||
Assert.assertEquals(1f, event.getPressure(), 0f); // must be exact
|
||||
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getActionButton());
|
||||
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getButtons());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseScrollEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_INJECT_SCROLL_EVENT);
|
||||
@@ -129,12 +132,15 @@ public class ControlMessageReaderTest {
|
||||
dos.writeShort(0); // 0.0f encoded as i16
|
||||
dos.writeShort(0x8000); // -1.0f encoded as i16
|
||||
dos.writeInt(1);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
// The message type (1 byte) does not count
|
||||
Assert.assertEquals(ControlMessageReader.INJECT_SCROLL_EVENT_PAYLOAD_LENGTH, packet.length - 1);
|
||||
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_SCROLL_EVENT, event.getType());
|
||||
Assert.assertEquals(260, event.getPosition().getPoint().getX());
|
||||
Assert.assertEquals(1026, event.getPosition().getPoint().getY());
|
||||
@@ -143,96 +149,96 @@ public class ControlMessageReaderTest {
|
||||
Assert.assertEquals(0f, event.getHScroll(), 0f);
|
||||
Assert.assertEquals(-1f, event.getVScroll(), 0f);
|
||||
Assert.assertEquals(1, event.getButtons());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseBackOrScreenOnEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_BACK_OR_SCREEN_ON);
|
||||
dos.writeByte(KeyEvent.ACTION_UP);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_BACK_OR_SCREEN_ON, event.getType());
|
||||
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseExpandNotificationPanelEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL, event.getType());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseExpandSettingsPanelEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_EXPAND_SETTINGS_PANEL);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_EXPAND_SETTINGS_PANEL, event.getType());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseCollapsePanelsEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_COLLAPSE_PANELS);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_COLLAPSE_PANELS, event.getType());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseGetClipboardEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_GET_CLIPBOARD);
|
||||
dos.writeByte(ControlMessage.COPY_KEY_COPY);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_GET_CLIPBOARD, event.getType());
|
||||
Assert.assertEquals(ControlMessage.COPY_KEY_COPY, event.getCopyKey());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseSetClipboardEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
|
||||
@@ -241,22 +247,22 @@ public class ControlMessageReaderTest {
|
||||
byte[] text = "testé".getBytes(StandardCharsets.UTF_8);
|
||||
dos.writeInt(text.length);
|
||||
dos.write(text);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
|
||||
Assert.assertEquals(0x0102030405060708L, event.getSequence());
|
||||
Assert.assertEquals("testé", event.getText());
|
||||
Assert.assertTrue(event.getPaste());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseBigSetClipboardEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_SET_CLIPBOARD);
|
||||
@@ -272,54 +278,56 @@ public class ControlMessageReaderTest {
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_SET_CLIPBOARD, event.getType());
|
||||
Assert.assertEquals(0x0807060504030201L, event.getSequence());
|
||||
Assert.assertEquals(text, event.getText());
|
||||
Assert.assertTrue(event.getPaste());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseSetScreenPowerMode() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_SET_SCREEN_POWER_MODE);
|
||||
dos.writeByte(Device.POWER_MODE_NORMAL);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
// The message type (1 byte) does not count
|
||||
Assert.assertEquals(ControlMessageReader.SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH, packet.length - 1);
|
||||
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_SET_SCREEN_POWER_MODE, event.getType());
|
||||
Assert.assertEquals(Device.POWER_MODE_NORMAL, event.getAction());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseRotateDevice() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_ROTATE_DEVICE);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_ROTATE_DEVICE, event.getType());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseUhidCreate() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_UHID_CREATE);
|
||||
@@ -327,21 +335,21 @@ public class ControlMessageReaderTest {
|
||||
byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
dos.writeShort(data.length); // size
|
||||
dos.write(data);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_UHID_CREATE, event.getType());
|
||||
Assert.assertEquals(42, event.getId());
|
||||
Assert.assertArrayEquals(data, event.getData());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseUhidInput() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_UHID_INPUT);
|
||||
@@ -349,55 +357,55 @@ public class ControlMessageReaderTest {
|
||||
byte[] data = {1, 2, 3, 4, 5};
|
||||
dos.writeShort(data.length); // size
|
||||
dos.write(data);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_UHID_INPUT, event.getType());
|
||||
Assert.assertEquals(42, event.getId());
|
||||
Assert.assertArrayEquals(data, event.getData());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseUhidDestroy() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_UHID_DESTROY);
|
||||
dos.writeShort(42); // id
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_UHID_DESTROY, event.getType());
|
||||
Assert.assertEquals(42, event.getId());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseOpenHardKeyboardSettings() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
Assert.assertEquals(ControlMessage.TYPE_OPEN_HARD_KEYBOARD_SETTINGS, event.getType());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiEvents() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
|
||||
@@ -414,29 +422,27 @@ public class ControlMessageReaderTest {
|
||||
dos.writeInt(KeyEvent.META_CTRL_ON);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
ControlMessage event = reader.next();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
|
||||
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
|
||||
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
|
||||
Assert.assertEquals(0, event.getRepeat());
|
||||
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
|
||||
|
||||
event = reader.read();
|
||||
event = reader.next();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
|
||||
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
|
||||
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getKeycode());
|
||||
Assert.assertEquals(1, event.getRepeat());
|
||||
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
|
||||
|
||||
Assert.assertEquals(-1, bis.read()); // EOS
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPartialEvents() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
|
||||
@@ -450,21 +456,31 @@ public class ControlMessageReaderTest {
|
||||
dos.writeByte(MotionEvent.ACTION_DOWN);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(packet);
|
||||
ControlMessageReader reader = new ControlMessageReader(bis);
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
|
||||
ControlMessage event = reader.read();
|
||||
ControlMessage event = reader.next();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
|
||||
Assert.assertEquals(KeyEvent.ACTION_UP, event.getAction());
|
||||
Assert.assertEquals(KeyEvent.KEYCODE_ENTER, event.getKeycode());
|
||||
Assert.assertEquals(4, event.getRepeat());
|
||||
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
|
||||
|
||||
try {
|
||||
event = reader.read();
|
||||
Assert.fail("Reader did not reach EOF");
|
||||
} catch (EOFException e) {
|
||||
// expected
|
||||
}
|
||||
event = reader.next();
|
||||
Assert.assertNull(event); // the event is not complete
|
||||
|
||||
bos.reset();
|
||||
dos.writeInt(MotionEvent.BUTTON_PRIMARY);
|
||||
dos.writeInt(5); // repeat
|
||||
dos.writeInt(KeyEvent.META_CTRL_ON);
|
||||
packet = bos.toByteArray();
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
|
||||
// the event is now complete
|
||||
event = reader.next();
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_KEYCODE, event.getType());
|
||||
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
|
||||
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getKeycode());
|
||||
Assert.assertEquals(5, event.getRepeat());
|
||||
Assert.assertEquals(KeyEvent.META_CTRL_ON, event.getMetaState());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ public class DeviceMessageWriterTest {
|
||||
|
||||
@Test
|
||||
public void testSerializeClipboard() throws IOException {
|
||||
DeviceMessageWriter writer = new DeviceMessageWriter();
|
||||
|
||||
String text = "aéûoç";
|
||||
byte[] data = text.getBytes(StandardCharsets.UTF_8);
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
@@ -19,13 +21,12 @@ public class DeviceMessageWriterTest {
|
||||
dos.writeByte(DeviceMessage.TYPE_CLIPBOARD);
|
||||
dos.writeInt(data.length);
|
||||
dos.write(data);
|
||||
|
||||
byte[] expected = bos.toByteArray();
|
||||
|
||||
bos = new ByteArrayOutputStream();
|
||||
DeviceMessageWriter writer = new DeviceMessageWriter(bos);
|
||||
|
||||
DeviceMessage msg = DeviceMessage.createClipboard(text);
|
||||
writer.write(msg);
|
||||
bos = new ByteArrayOutputStream();
|
||||
writer.writeTo(msg, bos);
|
||||
|
||||
byte[] actual = bos.toByteArray();
|
||||
|
||||
@@ -34,17 +35,18 @@ public class DeviceMessageWriterTest {
|
||||
|
||||
@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();
|
||||
|
||||
bos = new ByteArrayOutputStream();
|
||||
DeviceMessageWriter writer = new DeviceMessageWriter(bos);
|
||||
|
||||
DeviceMessage msg = DeviceMessage.createAckClipboard(0x0102030405060708L);
|
||||
writer.write(msg);
|
||||
bos = new ByteArrayOutputStream();
|
||||
writer.writeTo(msg, bos);
|
||||
|
||||
byte[] actual = bos.toByteArray();
|
||||
|
||||
@@ -53,6 +55,8 @@ public class DeviceMessageWriterTest {
|
||||
|
||||
@Test
|
||||
public void testSerializeUhidOutput() throws IOException {
|
||||
DeviceMessageWriter writer = new DeviceMessageWriter();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(DeviceMessage.TYPE_UHID_OUTPUT);
|
||||
@@ -60,13 +64,12 @@ public class DeviceMessageWriterTest {
|
||||
byte[] data = {1, 2, 3, 4, 5};
|
||||
dos.writeShort(data.length);
|
||||
dos.write(data);
|
||||
|
||||
byte[] expected = bos.toByteArray();
|
||||
|
||||
bos = new ByteArrayOutputStream();
|
||||
DeviceMessageWriter writer = new DeviceMessageWriter(bos);
|
||||
|
||||
DeviceMessage msg = DeviceMessage.createUhidOutput(42, data);
|
||||
writer.write(msg);
|
||||
bos = new ByteArrayOutputStream();
|
||||
writer.writeTo(msg, bos);
|
||||
|
||||
byte[] actual = bos.toByteArray();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user