Compare commits
6 Commits
logical_si
...
finger.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b1c3d7280 | ||
|
|
2ec96d7d36 | ||
|
|
b419388100 | ||
|
|
ce863aed12 | ||
|
|
3002f6bc0f | ||
|
|
bdf2644664 |
@@ -49,6 +49,11 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
||||
CONTROL_MSG_TEXT_MAX_LENGTH, &buf[1]);
|
||||
return 1 + len;
|
||||
}
|
||||
case CONTROL_MSG_TYPE_INJECT_MOUSE_EVENT:
|
||||
buf[1] = msg->inject_mouse_event.action;
|
||||
buffer_write32be(&buf[2], msg->inject_mouse_event.buttons);
|
||||
write_position(&buf[6], &msg->inject_mouse_event.position);
|
||||
return 18;
|
||||
case CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT:
|
||||
buf[1] = msg->inject_touch_event.action;
|
||||
buffer_write64be(&buf[2], msg->inject_touch_event.pointer_id);
|
||||
@@ -56,8 +61,7 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
||||
uint16_t pressure =
|
||||
to_fixed_point_16(msg->inject_touch_event.pressure);
|
||||
buffer_write16be(&buf[22], pressure);
|
||||
buffer_write32be(&buf[24], msg->inject_touch_event.buttons);
|
||||
return 28;
|
||||
return 24;
|
||||
case CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
|
||||
write_position(&buf[1], &msg->inject_scroll_event.position);
|
||||
buffer_write32be(&buf[13],
|
||||
|
||||
@@ -15,11 +15,10 @@
|
||||
#define CONTROL_MSG_SERIALIZED_MAX_SIZE \
|
||||
(3 + CONTROL_MSG_CLIPBOARD_TEXT_MAX_LENGTH)
|
||||
|
||||
#define POINTER_ID_MOUSE UINT64_C(-1);
|
||||
|
||||
enum control_msg_type {
|
||||
CONTROL_MSG_TYPE_INJECT_KEYCODE,
|
||||
CONTROL_MSG_TYPE_INJECT_TEXT,
|
||||
CONTROL_MSG_TYPE_INJECT_MOUSE_EVENT,
|
||||
CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||
CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||
CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON,
|
||||
@@ -50,6 +49,10 @@ struct control_msg {
|
||||
struct {
|
||||
enum android_motionevent_action action;
|
||||
enum android_motionevent_buttons buttons;
|
||||
struct position position;
|
||||
} inject_mouse_event;
|
||||
struct {
|
||||
enum android_motionevent_action action;
|
||||
uint64_t pointer_id;
|
||||
struct position position;
|
||||
float pressure;
|
||||
|
||||
@@ -128,6 +128,15 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) {
|
||||
switch (from) {
|
||||
MAP(SDL_MOUSEBUTTONDOWN, AMOTION_EVENT_ACTION_DOWN);
|
||||
MAP(SDL_MOUSEBUTTONUP, AMOTION_EVENT_ACTION_UP);
|
||||
FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static enum android_motionevent_buttons
|
||||
convert_mouse_buttons(uint32_t state) {
|
||||
enum android_motionevent_buttons buttons = 0;
|
||||
@@ -167,61 +176,33 @@ convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) {
|
||||
switch (from) {
|
||||
MAP(SDL_MOUSEBUTTONDOWN, AMOTION_EVENT_ACTION_DOWN);
|
||||
MAP(SDL_MOUSEBUTTONUP, AMOTION_EVENT_ACTION_UP);
|
||||
FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
map_coords(int32_t *x, int32_t *y, const SDL_Rect *rect,
|
||||
struct size frame_size) {
|
||||
*x = (*x - rect->x) * frame_size.width / rect->w;
|
||||
*y = (*y - rect->y) * frame_size.height / rect->h;
|
||||
}
|
||||
|
||||
bool
|
||||
convert_mouse_button(const SDL_MouseButtonEvent *from, const SDL_Rect *rect,
|
||||
struct size frame_size, struct control_msg *to) {
|
||||
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
|
||||
convert_mouse_button(const SDL_MouseButtonEvent *from, struct size screen_size,
|
||||
struct control_msg *to) {
|
||||
to->type = CONTROL_MSG_TYPE_INJECT_MOUSE_EVENT;
|
||||
|
||||
if (!convert_mouse_action(from->type, &to->inject_touch_event.action)) {
|
||||
if (!convert_mouse_action(from->type, &to->inject_mouse_event.action)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t x = from->x;
|
||||
int32_t y = from->y;
|
||||
map_coords(&x, &y, rect, frame_size);
|
||||
|
||||
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
||||
to->inject_touch_event.position.screen_size = frame_size;
|
||||
to->inject_touch_event.position.point.x = x;
|
||||
to->inject_touch_event.position.point.y = y;
|
||||
to->inject_touch_event.pressure = 1.f;
|
||||
to->inject_touch_event.buttons =
|
||||
to->inject_mouse_event.buttons =
|
||||
convert_mouse_buttons(SDL_BUTTON(from->button));
|
||||
to->inject_mouse_event.position.screen_size = screen_size;
|
||||
to->inject_mouse_event.position.point.x = from->x;
|
||||
to->inject_mouse_event.position.point.y = from->y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
convert_mouse_motion(const SDL_MouseMotionEvent *from, const SDL_Rect *rect,
|
||||
struct size frame_size, struct control_msg *to) {
|
||||
int32_t x = from->x;
|
||||
int32_t y = from->y;
|
||||
map_coords(&x, &y, rect, frame_size);
|
||||
|
||||
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
|
||||
to->inject_touch_event.action = AMOTION_EVENT_ACTION_MOVE;
|
||||
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
|
||||
to->inject_touch_event.position.screen_size = frame_size;
|
||||
to->inject_touch_event.position.point.x = x;
|
||||
to->inject_touch_event.position.point.y = y;
|
||||
to->inject_touch_event.pressure = 1.f;
|
||||
to->inject_touch_event.buttons = convert_mouse_buttons(from->state);
|
||||
convert_mouse_motion(const SDL_MouseMotionEvent *from, struct size screen_size,
|
||||
struct control_msg *to) {
|
||||
to->type = CONTROL_MSG_TYPE_INJECT_MOUSE_EVENT;
|
||||
to->inject_mouse_event.action = AMOTION_EVENT_ACTION_MOVE;
|
||||
to->inject_mouse_event.buttons = convert_mouse_buttons(from->state);
|
||||
to->inject_mouse_event.position.screen_size = screen_size;
|
||||
to->inject_mouse_event.position.point.x = from->x;
|
||||
to->inject_mouse_event.position.point.y = from->y;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -251,7 +232,6 @@ convert_touch(const SDL_TouchFingerEvent *from, struct size screen_size,
|
||||
to->inject_touch_event.position.point.x = from->x * screen_size.width;
|
||||
to->inject_touch_event.position.point.y = from->y * screen_size.height;
|
||||
to->inject_touch_event.pressure = from->pressure;
|
||||
to->inject_touch_event.buttons = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -260,7 +240,6 @@ convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct position position,
|
||||
struct control_msg *to) {
|
||||
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
|
||||
|
||||
// TODO map coords
|
||||
to->inject_scroll_event.position = position;
|
||||
|
||||
int mul = from->direction == SDL_MOUSEWHEEL_NORMAL ? 1 : -1;
|
||||
|
||||
@@ -21,14 +21,14 @@ bool
|
||||
convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to);
|
||||
|
||||
bool
|
||||
convert_mouse_button(const SDL_MouseButtonEvent *from, const SDL_Rect *rect,
|
||||
struct size frame_size, struct control_msg *to);
|
||||
convert_mouse_button(const SDL_MouseButtonEvent *from, struct size screen_size,
|
||||
struct control_msg *to);
|
||||
|
||||
// the video size may be different from the real device size, so we need the
|
||||
// size to which the absolute position apply, to scale it accordingly
|
||||
bool
|
||||
convert_mouse_motion(const SDL_MouseMotionEvent *from, const SDL_Rect *rect,
|
||||
struct size frame_size, struct control_msg *to);
|
||||
convert_mouse_motion(const SDL_MouseMotionEvent *from, struct size screen_size,
|
||||
struct control_msg *to);
|
||||
|
||||
bool
|
||||
convert_touch(const SDL_TouchFingerEvent *from, struct size screen_size,
|
||||
|
||||
@@ -394,7 +394,7 @@ input_manager_process_mouse_motion(struct input_manager *input_manager,
|
||||
return;
|
||||
}
|
||||
struct control_msg msg;
|
||||
if (convert_mouse_motion(event, &input_manager->screen->rect, input_manager->screen->frame_size, &msg)) {
|
||||
if (convert_mouse_motion(event, input_manager->screen->frame_size, &msg)) {
|
||||
if (!controller_push_msg(input_manager->controller, &msg)) {
|
||||
LOGW("Could not request 'inject mouse motion event'");
|
||||
}
|
||||
@@ -453,7 +453,7 @@ input_manager_process_mouse_button(struct input_manager *input_manager,
|
||||
}
|
||||
|
||||
struct control_msg msg;
|
||||
if (convert_mouse_button(event, &input_manager->screen->rect, input_manager->screen->frame_size, &msg)) {
|
||||
if (convert_mouse_button(event, input_manager->screen->frame_size, &msg)) {
|
||||
if (!controller_push_msg(input_manager->controller, &msg)) {
|
||||
LOGW("Could not request 'inject mouse button event'");
|
||||
}
|
||||
|
||||
@@ -145,10 +145,8 @@ handle_event(SDL_Event *event, bool control) {
|
||||
case SDL_WINDOWEVENT:
|
||||
switch (event->window.event) {
|
||||
case SDL_WINDOWEVENT_EXPOSED:
|
||||
screen_render(&screen);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
screen_resized(&screen);
|
||||
screen_render(&screen);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -122,32 +122,6 @@ get_initial_optimal_size(struct size frame_size) {
|
||||
return get_optimal_size(frame_size, frame_size);
|
||||
}
|
||||
|
||||
static void
|
||||
update_frame_rect(struct screen *screen) {
|
||||
struct size window_size = get_window_size(screen);
|
||||
|
||||
// 32 bits because we need to multiply two 16 bits values
|
||||
uint32_t ww = window_size.width;
|
||||
uint32_t wh = window_size.height;
|
||||
uint32_t fw = screen->frame_size.width;
|
||||
uint32_t fh = screen->frame_size.height;
|
||||
|
||||
SDL_Rect *rect = &screen->rect;
|
||||
|
||||
bool keep_width = fw * wh > fh * ww;
|
||||
if (keep_width) {
|
||||
rect->x = 0;
|
||||
rect->w = ww;
|
||||
rect->h = ww * fh / fw;
|
||||
rect->y = (wh - rect->h) / 2;
|
||||
} else {
|
||||
rect->y = 0;
|
||||
rect->h = wh;
|
||||
rect->w = wh * fw / fh;
|
||||
rect->x = (ww - rect->w) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
screen_init(struct screen *screen) {
|
||||
*screen = (struct screen) SCREEN_INITIALIZER;
|
||||
@@ -196,6 +170,13 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SDL_RenderSetLogicalSize(screen->renderer, frame_size.width,
|
||||
frame_size.height)) {
|
||||
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
||||
screen_destroy(screen);
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_Surface *icon = read_xpm(icon_xpm);
|
||||
if (icon) {
|
||||
SDL_SetWindowIcon(screen->window, icon);
|
||||
@@ -239,6 +220,12 @@ static bool
|
||||
prepare_for_frame(struct screen *screen, struct size new_frame_size) {
|
||||
if (screen->frame_size.width != new_frame_size.width
|
||||
|| screen->frame_size.height != new_frame_size.height) {
|
||||
if (SDL_RenderSetLogicalSize(screen->renderer, new_frame_size.width,
|
||||
new_frame_size.height)) {
|
||||
LOGE("Could not set renderer logical size: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
// frame dimension changed, destroy texture
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
|
||||
@@ -284,7 +271,6 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
|
||||
mutex_unlock(vb->mutex);
|
||||
return false;
|
||||
}
|
||||
update_frame_rect(screen);
|
||||
update_texture(screen, frame);
|
||||
mutex_unlock(vb->mutex);
|
||||
|
||||
@@ -292,16 +278,10 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
screen_resized(struct screen *screen) {
|
||||
update_frame_rect(screen);
|
||||
screen_render(screen);
|
||||
}
|
||||
|
||||
void
|
||||
screen_render(struct screen *screen) {
|
||||
SDL_RenderClear(screen->renderer);
|
||||
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &screen->rect);
|
||||
SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL);
|
||||
SDL_RenderPresent(screen->renderer);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ struct screen {
|
||||
struct size frame_size;
|
||||
//used only in fullscreen mode to know the windowed window size
|
||||
struct size windowed_window_size;
|
||||
struct SDL_Rect rect; // frame location and size inside the window
|
||||
bool has_frame;
|
||||
bool fullscreen;
|
||||
bool no_window;
|
||||
@@ -35,15 +34,9 @@ struct screen {
|
||||
.width = 0, \
|
||||
.height = 0, \
|
||||
}, \
|
||||
.rect = { \
|
||||
.x = 0, \
|
||||
.y = 0, \
|
||||
.w = 0, \
|
||||
.h = 0, \
|
||||
}, \
|
||||
.has_frame = false, \
|
||||
.fullscreen = false, \
|
||||
.no_window = false, \
|
||||
.has_frame = false, \
|
||||
.fullscreen = false, \
|
||||
.no_window = false, \
|
||||
}
|
||||
|
||||
// initialize default values
|
||||
@@ -67,9 +60,6 @@ screen_destroy(struct screen *screen);
|
||||
bool
|
||||
screen_update_frame(struct screen *screen, struct video_buffer *vb);
|
||||
|
||||
void
|
||||
screen_resized(struct screen *screen);
|
||||
|
||||
// render the texture to the renderer
|
||||
void
|
||||
screen_render(struct screen *screen);
|
||||
|
||||
@@ -67,6 +67,39 @@ static void test_serialize_inject_text_long(void) {
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
}
|
||||
|
||||
static void test_serialize_inject_mouse_event(void) {
|
||||
struct control_msg msg = {
|
||||
.type = CONTROL_MSG_TYPE_INJECT_MOUSE_EVENT,
|
||||
.inject_mouse_event = {
|
||||
.action = AMOTION_EVENT_ACTION_DOWN,
|
||||
.buttons = AMOTION_EVENT_BUTTON_PRIMARY,
|
||||
.position = {
|
||||
.point = {
|
||||
.x = 260,
|
||||
.y = 1026,
|
||||
},
|
||||
.screen_size = {
|
||||
.width = 1080,
|
||||
.height = 1920,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
|
||||
int size = control_msg_serialize(&msg, buf);
|
||||
assert(size == 18);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
CONTROL_MSG_TYPE_INJECT_MOUSE_EVENT,
|
||||
0x00, // AKEY_EVENT_ACTION_DOWN
|
||||
0x00, 0x00, 0x00, 0x01, // AMOTION_EVENT_BUTTON_PRIMARY
|
||||
0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x04, 0x02, // 260 1026
|
||||
0x04, 0x38, 0x07, 0x80, // 1080 1920
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
}
|
||||
#include <stdio.h>
|
||||
static void test_serialize_inject_touch_event(void) {
|
||||
struct control_msg msg = {
|
||||
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||
@@ -84,13 +117,12 @@ static void test_serialize_inject_touch_event(void) {
|
||||
},
|
||||
},
|
||||
.pressure = 1.0f,
|
||||
.buttons = AMOTION_EVENT_BUTTON_PRIMARY,
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[CONTROL_MSG_SERIALIZED_MAX_SIZE];
|
||||
int size = control_msg_serialize(&msg, buf);
|
||||
assert(size == 28);
|
||||
assert(size == 24);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
|
||||
@@ -99,7 +131,6 @@ static void test_serialize_inject_touch_event(void) {
|
||||
0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xc8, // 100 200
|
||||
0x04, 0x38, 0x07, 0x80, // 1080 1920
|
||||
0xff, 0xff, // pressure
|
||||
0x00, 0x00, 0x00, 0x01 // AMOTION_EVENT_BUTTON_PRIMARY
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
}
|
||||
@@ -240,6 +271,7 @@ int main(void) {
|
||||
test_serialize_inject_keycode();
|
||||
test_serialize_inject_text();
|
||||
test_serialize_inject_text_long();
|
||||
test_serialize_inject_mouse_event();
|
||||
test_serialize_inject_touch_event();
|
||||
test_serialize_inject_scroll_event();
|
||||
test_serialize_back_or_screen_on();
|
||||
|
||||
@@ -7,14 +7,15 @@ public final class ControlMessage {
|
||||
|
||||
public static final int TYPE_INJECT_KEYCODE = 0;
|
||||
public static final int TYPE_INJECT_TEXT = 1;
|
||||
public static final int TYPE_INJECT_TOUCH_EVENT = 2;
|
||||
public static final int TYPE_INJECT_SCROLL_EVENT = 3;
|
||||
public static final int TYPE_BACK_OR_SCREEN_ON = 4;
|
||||
public static final int TYPE_EXPAND_NOTIFICATION_PANEL = 5;
|
||||
public static final int TYPE_COLLAPSE_NOTIFICATION_PANEL = 6;
|
||||
public static final int TYPE_GET_CLIPBOARD = 7;
|
||||
public static final int TYPE_SET_CLIPBOARD = 8;
|
||||
public static final int TYPE_SET_SCREEN_POWER_MODE = 9;
|
||||
public static final int TYPE_INJECT_MOUSE_EVENT = 2;
|
||||
public static final int TYPE_INJECT_TOUCH_EVENT = 3;
|
||||
public static final int TYPE_INJECT_SCROLL_EVENT = 4;
|
||||
public static final int TYPE_BACK_OR_SCREEN_ON = 5;
|
||||
public static final int TYPE_EXPAND_NOTIFICATION_PANEL = 6;
|
||||
public static final int TYPE_COLLAPSE_NOTIFICATION_PANEL = 7;
|
||||
public static final int TYPE_GET_CLIPBOARD = 8;
|
||||
public static final int TYPE_SET_CLIPBOARD = 9;
|
||||
public static final int TYPE_SET_SCREEN_POWER_MODE = 10;
|
||||
|
||||
private int type;
|
||||
private String text;
|
||||
@@ -47,15 +48,22 @@ public final class ControlMessage {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static ControlMessage createInjectTouchEvent(int action, long pointerId, Position position, float pressure,
|
||||
int buttons) {
|
||||
public static ControlMessage createInjectMouseEvent(int action, int buttons, Position position) {
|
||||
ControlMessage msg = new ControlMessage();
|
||||
msg.type = TYPE_INJECT_MOUSE_EVENT;
|
||||
msg.action = action;
|
||||
msg.buttons = buttons;
|
||||
msg.position = position;
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static ControlMessage createInjectTouchEvent(int action, long pointerId, Position position, float pressure) {
|
||||
ControlMessage msg = new ControlMessage();
|
||||
msg.type = TYPE_INJECT_TOUCH_EVENT;
|
||||
msg.action = action;
|
||||
msg.pointerId = pointerId;
|
||||
msg.pressure = pressure;
|
||||
msg.position = position;
|
||||
msg.buttons = buttons;
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,9 @@ public class ControlMessageReader {
|
||||
case ControlMessage.TYPE_INJECT_TEXT:
|
||||
msg = parseInjectText();
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_MOUSE_EVENT:
|
||||
msg = parseInjectMouseEvent();
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_TOUCH_EVENT:
|
||||
msg = parseInjectTouchEvent();
|
||||
break;
|
||||
@@ -121,6 +124,16 @@ public class ControlMessageReader {
|
||||
return ControlMessage.createInjectText(text);
|
||||
}
|
||||
|
||||
private ControlMessage parseInjectMouseEvent() {
|
||||
if (buffer.remaining() < INJECT_MOUSE_EVENT_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int action = toUnsigned(buffer.get());
|
||||
int buttons = buffer.getInt();
|
||||
Position position = readPosition(buffer);
|
||||
return ControlMessage.createInjectMouseEvent(action, buttons, position);
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:MagicNumber")
|
||||
private ControlMessage parseInjectTouchEvent() {
|
||||
if (buffer.remaining() < INJECT_TOUCH_EVENT_PAYLOAD_LENGTH) {
|
||||
@@ -133,8 +146,7 @@ public class ControlMessageReader {
|
||||
int pressureInt = toUnsigned(buffer.getShort());
|
||||
// convert it to a float between 0 and 1 (0x1p16f is 2^16 as float)
|
||||
float pressure = pressureInt == 0xffff ? 1f : (pressureInt / 0x1p16f);
|
||||
int buttons = buffer.getInt();
|
||||
return ControlMessage.createInjectTouchEvent(action, pointerId, position, pressure, buttons);
|
||||
return ControlMessage.createInjectTouchEvent(action, pointerId, position, pressure);
|
||||
}
|
||||
|
||||
private ControlMessage parseInjectScrollEvent() {
|
||||
|
||||
@@ -19,21 +19,37 @@ public class Controller {
|
||||
|
||||
private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
|
||||
|
||||
private long lastMouseDown;
|
||||
private final MotionEvent.PointerProperties[] mousePointerProperties = {new MotionEvent.PointerProperties()};
|
||||
private final MotionEvent.PointerCoords[] mousePointerCoords = {new MotionEvent.PointerCoords()};
|
||||
|
||||
private long lastTouchDown;
|
||||
private final PointersState pointersState = new PointersState();
|
||||
private final MotionEvent.PointerProperties[] pointerProperties =
|
||||
private final MotionEvent.PointerProperties[] touchPointerProperties =
|
||||
new MotionEvent.PointerProperties[PointersState.MAX_POINTERS];
|
||||
private final MotionEvent.PointerCoords[] pointerCoords =
|
||||
private final MotionEvent.PointerCoords[] touchPointerCoords =
|
||||
new MotionEvent.PointerCoords[PointersState.MAX_POINTERS];
|
||||
|
||||
public Controller(Device device, DesktopConnection connection) {
|
||||
this.device = device;
|
||||
this.connection = connection;
|
||||
initPointers();
|
||||
initMousePointer();
|
||||
initTouchPointers();
|
||||
sender = new DeviceMessageSender(connection);
|
||||
}
|
||||
|
||||
private void initPointers() {
|
||||
private void initMousePointer() {
|
||||
MotionEvent.PointerProperties props = mousePointerProperties[0];
|
||||
props.id = 0;
|
||||
props.toolType = MotionEvent.TOOL_TYPE_FINGER;
|
||||
|
||||
MotionEvent.PointerCoords coords = mousePointerCoords[0];
|
||||
coords.orientation = 0;
|
||||
coords.pressure = 1;
|
||||
coords.size = 1;
|
||||
}
|
||||
|
||||
private void initTouchPointers() {
|
||||
for (int i = 0; i < PointersState.MAX_POINTERS; ++i) {
|
||||
MotionEvent.PointerProperties props = new MotionEvent.PointerProperties();
|
||||
props.toolType = MotionEvent.TOOL_TYPE_FINGER;
|
||||
@@ -42,11 +58,23 @@ public class Controller {
|
||||
coords.orientation = 0;
|
||||
coords.size = 1;
|
||||
|
||||
pointerProperties[i] = props;
|
||||
pointerCoords[i] = coords;
|
||||
touchPointerProperties[i] = props;
|
||||
touchPointerCoords[i] = coords;
|
||||
}
|
||||
}
|
||||
|
||||
private void setMousePointerCoords(Point point) {
|
||||
MotionEvent.PointerCoords coords = mousePointerCoords[0];
|
||||
coords.x = point.getX();
|
||||
coords.y = point.getY();
|
||||
}
|
||||
|
||||
private void setScroll(int hScroll, int vScroll) {
|
||||
MotionEvent.PointerCoords coords = mousePointerCoords[0];
|
||||
coords.setAxisValue(MotionEvent.AXIS_HSCROLL, hScroll);
|
||||
coords.setAxisValue(MotionEvent.AXIS_VSCROLL, vScroll);
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:MagicNumber")
|
||||
public void control() throws IOException {
|
||||
// on start, power on the device
|
||||
@@ -81,8 +109,11 @@ public class Controller {
|
||||
case ControlMessage.TYPE_INJECT_TEXT:
|
||||
injectText(msg.getText());
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_MOUSE_EVENT:
|
||||
injectMouse(msg.getAction(), msg.getButtons(), msg.getPosition());
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_TOUCH_EVENT:
|
||||
injectTouch(msg.getAction(), msg.getPointerId(), msg.getPosition(), msg.getPressure(), 0);
|
||||
injectTouch(msg.getAction(), msg.getPointerId(), msg.getPosition(), msg.getPressure());
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
|
||||
injectScroll(msg.getPosition(), msg.getHScroll(), msg.getVScroll());
|
||||
@@ -142,7 +173,23 @@ public class Controller {
|
||||
return successCount;
|
||||
}
|
||||
|
||||
private boolean injectTouch(int action, long pointerId, Position position, float pressure, int buttons) {
|
||||
private boolean injectMouse(int action, int buttons, Position position) {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
lastMouseDown = now;
|
||||
}
|
||||
Point point = device.getPhysicalPoint(position);
|
||||
if (point == null) {
|
||||
// ignore event
|
||||
return false;
|
||||
}
|
||||
setMousePointerCoords(point);
|
||||
MotionEvent event = MotionEvent.obtain(lastMouseDown, now, action, 1, mousePointerProperties,
|
||||
mousePointerCoords, 0, buttons, 1f, 1f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
|
||||
return injectEvent(event);
|
||||
}
|
||||
|
||||
private boolean injectTouch(int action, long pointerId, Position position, float pressure) {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
|
||||
Point point = device.getPhysicalPoint(position);
|
||||
@@ -161,7 +208,7 @@ public class Controller {
|
||||
pointer.setPressure(pressure);
|
||||
pointer.setUp(action == MotionEvent.ACTION_UP);
|
||||
|
||||
int pointerCount = pointersState.update(pointerProperties, pointerCoords);
|
||||
int pointerCount = pointersState.update(touchPointerProperties, touchPointerCoords);
|
||||
|
||||
if (pointerCount == 1) {
|
||||
if (action == MotionEvent.ACTION_DOWN) {
|
||||
@@ -176,8 +223,8 @@ public class Controller {
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, pointerProperties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
|
||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, touchPointerProperties,
|
||||
touchPointerCoords, 0, 0, 1f, 1f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
|
||||
return injectEvent(event);
|
||||
}
|
||||
|
||||
@@ -188,18 +235,10 @@ public class Controller {
|
||||
// ignore event
|
||||
return false;
|
||||
}
|
||||
|
||||
MotionEvent.PointerProperties props = pointerProperties[0];
|
||||
props.id = 0;
|
||||
|
||||
MotionEvent.PointerCoords coords = pointerCoords[0];
|
||||
coords.x = point.getX();
|
||||
coords.y = point.getY();
|
||||
coords.setAxisValue(MotionEvent.AXIS_HSCROLL, hScroll);
|
||||
coords.setAxisValue(MotionEvent.AXIS_VSCROLL, vScroll);
|
||||
|
||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties,
|
||||
pointerCoords, 0, 0, 1f, 1f, 0, 0, InputDevice.SOURCE_MOUSE, 0);
|
||||
setMousePointerCoords(point);
|
||||
setScroll(hScroll, vScroll);
|
||||
MotionEvent event = MotionEvent.obtain(lastMouseDown, now, MotionEvent.ACTION_SCROLL, 1,
|
||||
mousePointerProperties, mousePointerCoords, 0, 0, 1f, 1f, 0, 0, InputDevice.SOURCE_MOUSE, 0);
|
||||
return injectEvent(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,11 +161,7 @@ public final class Device {
|
||||
* @param mode one of the {@code SCREEN_POWER_MODE_*} constants
|
||||
*/
|
||||
public void setScreenPowerMode(int mode) {
|
||||
IBinder d = SurfaceControl.getBuiltInDisplay();
|
||||
if (d == null) {
|
||||
Ln.e("Could not get built-in display");
|
||||
return;
|
||||
}
|
||||
IBinder d = SurfaceControl.getBuiltInDisplay(0);
|
||||
SurfaceControl.setDisplayPowerMode(d, mode);
|
||||
Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on"));
|
||||
}
|
||||
|
||||
@@ -1,102 +1,44 @@
|
||||
package com.genymobile.scrcpy.wrappers;
|
||||
|
||||
import com.genymobile.scrcpy.Ln;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.os.Build;
|
||||
import android.os.IInterface;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ClipboardManager {
|
||||
|
||||
private static final String PACKAGE_NAME = "com.android.shell";
|
||||
private static final int USER_ID = 0;
|
||||
|
||||
private final IInterface manager;
|
||||
private Method getPrimaryClipMethod;
|
||||
private Method setPrimaryClipMethod;
|
||||
private final Method getPrimaryClipMethod;
|
||||
private final Method setPrimaryClipMethod;
|
||||
|
||||
public ClipboardManager(IInterface manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
private Method getGetPrimaryClipMethod() {
|
||||
if (getPrimaryClipMethod == null) {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class);
|
||||
} else {
|
||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("Could not find method", e);
|
||||
}
|
||||
}
|
||||
return getPrimaryClipMethod;
|
||||
}
|
||||
|
||||
private Method getSetPrimaryClipMethod() {
|
||||
if (setPrimaryClipMethod == null) {
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class);
|
||||
} else {
|
||||
setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class,
|
||||
String.class, int.class);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("Could not find method", e);
|
||||
}
|
||||
}
|
||||
return setPrimaryClipMethod;
|
||||
}
|
||||
|
||||
private static ClipData getPrimaryClip(Method method, IInterface manager) throws InvocationTargetException,
|
||||
IllegalAccessException {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
return (ClipData) method.invoke(manager, PACKAGE_NAME);
|
||||
}
|
||||
return (ClipData) method.invoke(manager, PACKAGE_NAME, USER_ID);
|
||||
}
|
||||
|
||||
private static void setPrimaryClip(Method method, IInterface manager, ClipData clipData) throws InvocationTargetException,
|
||||
IllegalAccessException {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
method.invoke(manager, clipData, PACKAGE_NAME);
|
||||
} else {
|
||||
method.invoke(manager, clipData, PACKAGE_NAME, USER_ID);
|
||||
try {
|
||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class);
|
||||
setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public CharSequence getText() {
|
||||
Method method = getGetPrimaryClipMethod();
|
||||
if (method == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
ClipData clipData = getPrimaryClip(method, manager);
|
||||
ClipData clipData = (ClipData) getPrimaryClipMethod.invoke(manager, "com.android.shell");
|
||||
if (clipData == null || clipData.getItemCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
return clipData.getItemAt(0).getText();
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
Ln.e("Could not invoke " + method.getName(), e);
|
||||
return null;
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setText(CharSequence text) {
|
||||
Method method = getSetPrimaryClipMethod();
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
ClipData clipData = ClipData.newPlainText(null, text);
|
||||
try {
|
||||
setPrimaryClip(method, manager, clipData);
|
||||
setPrimaryClipMethod.invoke(manager, clipData, "com.android.shell");
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
Ln.e("Could not invoke " + method.getName(), e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.genymobile.scrcpy.wrappers;
|
||||
|
||||
import com.genymobile.scrcpy.Ln;
|
||||
|
||||
import android.os.IInterface;
|
||||
import android.view.InputEvent;
|
||||
|
||||
@@ -15,33 +13,22 @@ public final class InputManager {
|
||||
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2;
|
||||
|
||||
private final IInterface manager;
|
||||
private Method injectInputEventMethod;
|
||||
private final Method injectInputEventMethod;
|
||||
|
||||
public InputManager(IInterface manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
private Method getInjectInputEventMethod() {
|
||||
if (injectInputEventMethod == null) {
|
||||
try {
|
||||
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("Could not find method", e);
|
||||
}
|
||||
try {
|
||||
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return injectInputEventMethod;
|
||||
}
|
||||
|
||||
public boolean injectInputEvent(InputEvent inputEvent, int mode) {
|
||||
Method method = getInjectInputEventMethod();
|
||||
if (method == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return (Boolean) method.invoke(manager, inputEvent, mode);
|
||||
return (Boolean) injectInputEventMethod.invoke(manager, inputEvent, mode);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
Ln.e("Could not invoke " + method.getName(), e);
|
||||
return false;
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.genymobile.scrcpy.wrappers;
|
||||
|
||||
import com.genymobile.scrcpy.Ln;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.os.IInterface;
|
||||
@@ -11,35 +9,24 @@ import java.lang.reflect.Method;
|
||||
|
||||
public final class PowerManager {
|
||||
private final IInterface manager;
|
||||
private Method isScreenOnMethod;
|
||||
private final Method isScreenOnMethod;
|
||||
|
||||
public PowerManager(IInterface manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
private Method getIsScreenOnMethod() {
|
||||
if (isScreenOnMethod == null) {
|
||||
try {
|
||||
@SuppressLint("ObsoleteSdkInt") // we may lower minSdkVersion in the future
|
||||
String methodName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH ? "isInteractive" : "isScreenOn";
|
||||
isScreenOnMethod = manager.getClass().getMethod(methodName);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("Could not find method", e);
|
||||
}
|
||||
try {
|
||||
@SuppressLint("ObsoleteSdkInt") // we may lower minSdkVersion in the future
|
||||
String methodName = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH ? "isInteractive" : "isScreenOn";
|
||||
isScreenOnMethod = manager.getClass().getMethod(methodName);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
return isScreenOnMethod;
|
||||
}
|
||||
|
||||
public boolean isScreenOn() {
|
||||
Method method = getIsScreenOnMethod();
|
||||
if (method == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return (Boolean) method.invoke(manager);
|
||||
return (Boolean) isScreenOnMethod.invoke(manager);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
Ln.e("Could not invoke " + method.getName(), e);
|
||||
return false;
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,49 +17,35 @@ public class StatusBarManager {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
private Method getExpandNotificationsPanelMethod() {
|
||||
public void expandNotificationsPanel() {
|
||||
if (expandNotificationsPanelMethod == null) {
|
||||
try {
|
||||
expandNotificationsPanelMethod = manager.getClass().getMethod("expandNotificationsPanel");
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("Could not find method", e);
|
||||
Ln.e("ServiceBarManager.expandNotificationsPanel() is not available on this device");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return expandNotificationsPanelMethod;
|
||||
}
|
||||
|
||||
private Method getCollapsePanelsMethod() {
|
||||
if (collapsePanelsMethod == null) {
|
||||
try {
|
||||
collapsePanelsMethod = manager.getClass().getMethod("collapsePanels");
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("Could not find method", e);
|
||||
}
|
||||
}
|
||||
return collapsePanelsMethod;
|
||||
}
|
||||
|
||||
public void expandNotificationsPanel() {
|
||||
Method method = getExpandNotificationsPanelMethod();
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
method.invoke(manager);
|
||||
expandNotificationsPanelMethod.invoke(manager);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
Ln.e("Could not invoke " + method.getName(), e);
|
||||
Ln.e("Could not invoke ServiceBarManager.expandNotificationsPanel()", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void collapsePanels() {
|
||||
Method method = getCollapsePanelsMethod();
|
||||
if (method == null) {
|
||||
return;
|
||||
if (collapsePanelsMethod == null) {
|
||||
try {
|
||||
collapsePanelsMethod = manager.getClass().getMethod("collapsePanels");
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("ServiceBarManager.collapsePanels() is not available on this device");
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
method.invoke(manager);
|
||||
collapsePanelsMethod.invoke(manager);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
Ln.e("Could not invoke " + method.getName(), e);
|
||||
Ln.e("Could not invoke ServiceBarManager.collapsePanels()", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
package com.genymobile.scrcpy.wrappers;
|
||||
|
||||
import com.genymobile.scrcpy.Ln;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@SuppressLint("PrivateApi")
|
||||
public final class SurfaceControl {
|
||||
|
||||
@@ -28,9 +23,6 @@ public final class SurfaceControl {
|
||||
}
|
||||
}
|
||||
|
||||
private static Method getBuiltInDisplayMethod;
|
||||
private static Method setDisplayPowerModeMethod;
|
||||
|
||||
private SurfaceControl() {
|
||||
// only static methods
|
||||
}
|
||||
@@ -84,62 +76,24 @@ public final class SurfaceControl {
|
||||
}
|
||||
}
|
||||
|
||||
private static Method getGetBuiltInDisplayMethod() {
|
||||
if (getBuiltInDisplayMethod == null) {
|
||||
try {
|
||||
// the method signature has changed in Android Q
|
||||
// <https://github.com/Genymobile/scrcpy/issues/586>
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
getBuiltInDisplayMethod = CLASS.getMethod("getBuiltInDisplay", int.class);
|
||||
} else {
|
||||
getBuiltInDisplayMethod = CLASS.getMethod("getInternalDisplayToken");
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("Could not find method", e);
|
||||
}
|
||||
}
|
||||
return getBuiltInDisplayMethod;
|
||||
}
|
||||
|
||||
public static IBinder getBuiltInDisplay() {
|
||||
Method method = getGetBuiltInDisplayMethod();
|
||||
if (method == null) {
|
||||
return null;
|
||||
}
|
||||
public static IBinder getBuiltInDisplay(int builtInDisplayId) {
|
||||
try {
|
||||
// the method signature has changed in Android Q
|
||||
// <https://github.com/Genymobile/scrcpy/issues/586>
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
// call getBuiltInDisplay(0)
|
||||
return (IBinder) method.invoke(null, 0);
|
||||
return (IBinder) CLASS.getMethod("getBuiltInDisplay", int.class).invoke(null, builtInDisplayId);
|
||||
}
|
||||
|
||||
// call getInternalDisplayToken()
|
||||
return (IBinder) method.invoke(null);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
Ln.e("Could not invoke " + method.getName(), e);
|
||||
return null;
|
||||
return (IBinder) CLASS.getMethod("getPhysicalDisplayToken", long.class).invoke(null, builtInDisplayId);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Method getSetDisplayPowerModeMethod() {
|
||||
if (setDisplayPowerModeMethod == null) {
|
||||
try {
|
||||
setDisplayPowerModeMethod = CLASS.getMethod("setDisplayPowerMode", IBinder.class, int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Ln.e("Could not find method", e);
|
||||
}
|
||||
}
|
||||
return setDisplayPowerModeMethod;
|
||||
}
|
||||
|
||||
public static void setDisplayPowerMode(IBinder displayToken, int mode) {
|
||||
Method method = getSetDisplayPowerModeMethod();
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
method.invoke(null, displayToken, mode);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
Ln.e("Could not invoke " + method.getName(), e);
|
||||
CLASS.getMethod("setDisplayPowerMode", IBinder.class, int.class).invoke(null, displayToken, mode);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,35 @@ public class ControlMessageReaderTest {
|
||||
Assert.assertEquals(new String(text, StandardCharsets.US_ASCII), event.getText());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("checkstyle:MagicNumber")
|
||||
public void testParseMouseEvent() throws IOException {
|
||||
ControlMessageReader reader = new ControlMessageReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_INJECT_MOUSE_EVENT);
|
||||
dos.writeByte(MotionEvent.ACTION_DOWN);
|
||||
dos.writeInt(MotionEvent.BUTTON_PRIMARY);
|
||||
dos.writeInt(100);
|
||||
dos.writeInt(200);
|
||||
dos.writeShort(1080);
|
||||
dos.writeShort(1920);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlMessage event = reader.next();
|
||||
|
||||
Assert.assertEquals(ControlMessage.TYPE_INJECT_MOUSE_EVENT, event.getType());
|
||||
Assert.assertEquals(MotionEvent.ACTION_DOWN, event.getAction());
|
||||
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getButtons());
|
||||
Assert.assertEquals(100, event.getPosition().getPoint().getX());
|
||||
Assert.assertEquals(200, event.getPosition().getPoint().getY());
|
||||
Assert.assertEquals(1080, event.getPosition().getScreenSize().getWidth());
|
||||
Assert.assertEquals(1920, event.getPosition().getScreenSize().getHeight());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("checkstyle:MagicNumber")
|
||||
public void testParseTouchEvent() throws IOException {
|
||||
@@ -91,7 +120,6 @@ public class ControlMessageReaderTest {
|
||||
dos.writeShort(1080);
|
||||
dos.writeShort(1920);
|
||||
dos.writeShort(0xffff); // pressure
|
||||
dos.writeInt(MotionEvent.BUTTON_PRIMARY);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
@@ -106,7 +134,6 @@ public class ControlMessageReaderTest {
|
||||
Assert.assertEquals(1080, event.getPosition().getScreenSize().getWidth());
|
||||
Assert.assertEquals(1920, event.getPosition().getScreenSize().getHeight());
|
||||
Assert.assertEquals(1f, event.getPressure(), 0f); // must be exact
|
||||
Assert.assertEquals(MotionEvent.BUTTON_PRIMARY, event.getButtons());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user