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:
parent
7830859c21
commit
fefb9816a9
4 changed files with 29 additions and 40 deletions
|
@ -13,8 +13,8 @@ struct size {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct point {
|
struct point {
|
||||||
Uint16 x;
|
Sint32 x;
|
||||||
Uint16 y;
|
Sint32 y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct position {
|
struct position {
|
||||||
|
|
|
@ -8,10 +8,10 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
static void write_position(Uint8 *buf, const struct position *position) {
|
static void write_position(Uint8 *buf, const struct position *position) {
|
||||||
buffer_write16be(&buf[0], position->point.x);
|
buffer_write32be(&buf[0], position->point.x);
|
||||||
buffer_write16be(&buf[2], position->point.y);
|
buffer_write32be(&buf[4], position->point.y);
|
||||||
buffer_write16be(&buf[4], position->screen_size.width);
|
buffer_write16be(&buf[8], position->screen_size.width);
|
||||||
buffer_write16be(&buf[6], position->screen_size.height);
|
buffer_write16be(&buf[10], position->screen_size.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
int control_event_serialize(const struct control_event *event, unsigned char *buf) {
|
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;
|
buf[1] = event->mouse_event.action;
|
||||||
buffer_write32be(&buf[2], event->mouse_event.buttons);
|
buffer_write32be(&buf[2], event->mouse_event.buttons);
|
||||||
write_position(&buf[6], &event->mouse_event.position);
|
write_position(&buf[6], &event->mouse_event.position);
|
||||||
return 14;
|
return 18;
|
||||||
case CONTROL_EVENT_TYPE_SCROLL:
|
case CONTROL_EVENT_TYPE_SCROLL:
|
||||||
write_position(&buf[1], &event->scroll_event.position);
|
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.hscroll);
|
||||||
buffer_write32be(&buf[13], (Uint32) event->scroll_event.vscroll);
|
buffer_write32be(&buf[17], (Uint32) event->scroll_event.vscroll);
|
||||||
return 17;
|
return 21;
|
||||||
case CONTROL_EVENT_TYPE_COMMAND:
|
case CONTROL_EVENT_TYPE_COMMAND:
|
||||||
buf[1] = event->command_event.action;
|
buf[1] = event->command_event.action;
|
||||||
return 2;
|
return 2;
|
||||||
|
|
|
@ -18,9 +18,15 @@ static void convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int
|
||||||
*y = (int) (*y / scale_y) - viewport.y;
|
*y = (int) (*y / scale_y) - viewport.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_mouse_point(struct screen *screen, int *x, int *y) {
|
static struct point get_mouse_point(struct screen *screen) {
|
||||||
SDL_GetMouseState(x, y);
|
int x;
|
||||||
convert_to_renderer_coordinates(screen->renderer, x, y);
|
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;
|
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,
|
void input_manager_process_mouse_button(struct input_manager *input_manager,
|
||||||
const SDL_MouseButtonEvent *event) {
|
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->type == SDL_MOUSEBUTTONDOWN) {
|
||||||
if (event->button == SDL_BUTTON_RIGHT) {
|
if (event->button == SDL_BUTTON_RIGHT) {
|
||||||
press_back_or_turn_screen_on(input_manager->controller);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
// double-click on black borders resize to fit the device screen
|
// double-click on black borders resize to fit the device screen
|
||||||
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2
|
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
||||||
&& outside_device_screen) {
|
SDL_bool outside= is_outside_device_screen(input_manager,
|
||||||
|
event->x,
|
||||||
|
event->y);
|
||||||
|
if (outside) {
|
||||||
screen_resize_to_fit(input_manager->screen);
|
screen_resize_to_fit(input_manager->screen);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// otherwise, send the click event to the device
|
// otherwise, send the click event to the device
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outside_device_screen) {
|
|
||||||
// ignore
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct control_event control_event;
|
struct control_event control_event;
|
||||||
if (mouse_button_from_sdl_to_android(event, input_manager->screen->frame_size, &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)) {
|
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,
|
void input_manager_process_mouse_wheel(struct input_manager *input_manager,
|
||||||
const SDL_MouseWheelEvent *event) {
|
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 = {
|
struct position position = {
|
||||||
.screen_size = input_manager->screen->frame_size,
|
.screen_size = input_manager->screen->frame_size,
|
||||||
.point = {
|
.point = get_mouse_point(input_manager->screen),
|
||||||
.x = (Uint16) x,
|
|
||||||
.y = (Uint16) y,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
struct control_event control_event;
|
struct control_event control_event;
|
||||||
if (mouse_wheel_from_sdl_to_android(event, position, &control_event)) {
|
if (mouse_wheel_from_sdl_to_android(event, position, &control_event)) {
|
||||||
|
|
|
@ -132,8 +132,8 @@ public class ControlEventReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Position readPosition(ByteBuffer buffer) {
|
private static Position readPosition(ByteBuffer buffer) {
|
||||||
int x = toUnsigned(buffer.getShort());
|
int x = buffer.getInt();
|
||||||
int y = toUnsigned(buffer.getShort());
|
int y = buffer.getInt();
|
||||||
int screenWidth = toUnsigned(buffer.getShort());
|
int screenWidth = toUnsigned(buffer.getShort());
|
||||||
int screenHeight = toUnsigned(buffer.getShort());
|
int screenHeight = toUnsigned(buffer.getShort());
|
||||||
return new Position(x, y, screenWidth, screenHeight);
|
return new Position(x, y, screenWidth, screenHeight);
|
||||||
|
|
Loading…
Reference in a new issue