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 a7fe9ad779).

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 <https://github.com/Genymobile/scrcpy/issues/357>.
This commit is contained in:
Romain Vimont 2018-11-27 08:54:31 +01:00
parent 7830859c21
commit fefb9816a9
4 changed files with 29 additions and 40 deletions

View file

@ -13,8 +13,8 @@ struct size {
};
struct point {
Uint16 x;
Uint16 y;
Sint32 x;
Sint32 y;
};
struct position {

View file

@ -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;

View file

@ -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)) {

View file

@ -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);