From fefb9816a99e6f8fa59befcfb70ba87112f90a8d Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Tue, 27 Nov 2018 08:54:31 +0100 Subject: [PATCH] Handle mouse events outside device screen Mouse events position were unsigned (so negative values could not be handled properly). To avoid issues with negative values, mouse events outside the device screen were ignored (commit a7fe9ad779057f7a2698fc1769dce3c3786993ee). But as a consequence, drag&drop were "broken" if the "drop" occurred outside the device screen. Instead, use signed 32-bits to store the position, and forward events outside the device screen. Fixes . --- app/src/common.h | 4 +- app/src/control_event.c | 16 +++---- app/src/input_manager.c | 45 +++++++------------ .../genymobile/scrcpy/ControlEventReader.java | 4 +- 4 files changed, 29 insertions(+), 40 deletions(-) diff --git a/app/src/common.h b/app/src/common.h index 9f5f9c6e..d3d000f9 100644 --- a/app/src/common.h +++ b/app/src/common.h @@ -13,8 +13,8 @@ struct size { }; struct point { - Uint16 x; - Uint16 y; + Sint32 x; + Sint32 y; }; struct position { diff --git a/app/src/control_event.c b/app/src/control_event.c index ace78dbf..34b71fb0 100644 --- a/app/src/control_event.c +++ b/app/src/control_event.c @@ -8,10 +8,10 @@ #include "log.h" static void write_position(Uint8 *buf, const struct position *position) { - buffer_write16be(&buf[0], position->point.x); - buffer_write16be(&buf[2], position->point.y); - buffer_write16be(&buf[4], position->screen_size.width); - buffer_write16be(&buf[6], position->screen_size.height); + buffer_write32be(&buf[0], position->point.x); + buffer_write32be(&buf[4], position->point.y); + buffer_write16be(&buf[8], position->screen_size.width); + buffer_write16be(&buf[10], position->screen_size.height); } int control_event_serialize(const struct control_event *event, unsigned char *buf) { @@ -37,12 +37,12 @@ int control_event_serialize(const struct control_event *event, unsigned char *bu buf[1] = event->mouse_event.action; buffer_write32be(&buf[2], event->mouse_event.buttons); write_position(&buf[6], &event->mouse_event.position); - return 14; + return 18; case CONTROL_EVENT_TYPE_SCROLL: write_position(&buf[1], &event->scroll_event.position); - buffer_write32be(&buf[9], (Uint32) event->scroll_event.hscroll); - buffer_write32be(&buf[13], (Uint32) event->scroll_event.vscroll); - return 17; + buffer_write32be(&buf[13], (Uint32) event->scroll_event.hscroll); + buffer_write32be(&buf[17], (Uint32) event->scroll_event.vscroll); + return 21; case CONTROL_EVENT_TYPE_COMMAND: buf[1] = event->command_event.action; return 2; diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 7a3a4ad1..e2a238d8 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -18,9 +18,15 @@ static void convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int *y = (int) (*y / scale_y) - viewport.y; } -static void get_mouse_point(struct screen *screen, int *x, int *y) { - SDL_GetMouseState(x, y); - convert_to_renderer_coordinates(screen->renderer, x, y); +static struct point get_mouse_point(struct screen *screen) { + int x; + int y; + SDL_GetMouseState(&x, &y); + convert_to_renderer_coordinates(screen->renderer, &x, &y); + return (struct point) { + .x = x, + .y = y, + }; } static const int ACTION_DOWN = 1; @@ -273,9 +279,6 @@ static SDL_bool is_outside_device_screen(struct input_manager *input_manager, void input_manager_process_mouse_button(struct input_manager *input_manager, const SDL_MouseButtonEvent *event) { - SDL_bool outside_device_screen = is_outside_device_screen(input_manager, - event->x, - event->y); if (event->type == SDL_MOUSEBUTTONDOWN) { if (event->button == SDL_BUTTON_RIGHT) { press_back_or_turn_screen_on(input_manager->controller); @@ -286,19 +289,18 @@ void input_manager_process_mouse_button(struct input_manager *input_manager, return; } // double-click on black borders resize to fit the device screen - if (event->button == SDL_BUTTON_LEFT && event->clicks == 2 - && outside_device_screen) { - screen_resize_to_fit(input_manager->screen); + if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) { + SDL_bool outside= is_outside_device_screen(input_manager, + event->x, + event->y); + if (outside) { + screen_resize_to_fit(input_manager->screen); + } return; } // otherwise, send the click event to the device } - if (outside_device_screen) { - // ignore - return; - } - struct control_event control_event; if (mouse_button_from_sdl_to_android(event, input_manager->screen->frame_size, &control_event)) { if (!controller_push_event(input_manager->controller, &control_event)) { @@ -309,22 +311,9 @@ void input_manager_process_mouse_button(struct input_manager *input_manager, void input_manager_process_mouse_wheel(struct input_manager *input_manager, const SDL_MouseWheelEvent *event) { - int x; - int y; - get_mouse_point(input_manager->screen, &x, &y); - if (is_outside_device_screen(input_manager, x, y)) { - // ignore - return; - } - - SDL_assert_release(x >= 0 && x < 0x10000 && y >= 0 && y < 0x10000); - struct position position = { .screen_size = input_manager->screen->frame_size, - .point = { - .x = (Uint16) x, - .y = (Uint16) y, - }, + .point = get_mouse_point(input_manager->screen), }; struct control_event control_event; if (mouse_wheel_from_sdl_to_android(event, position, &control_event)) { diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java b/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java index 83088b10..e47ca309 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java @@ -132,8 +132,8 @@ public class ControlEventReader { } private static Position readPosition(ByteBuffer buffer) { - int x = toUnsigned(buffer.getShort()); - int y = toUnsigned(buffer.getShort()); + int x = buffer.getInt(); + int y = buffer.getInt(); int screenWidth = toUnsigned(buffer.getShort()); int screenHeight = toUnsigned(buffer.getShort()); return new Position(x, y, screenWidth, screenHeight);