Use scrcpy input events for mouse processors

Pass scrcpy input events instead of SDL input events to mouse
processors.

These events represent exactly what mouse processors need, abstracted
from any visual orientation and scaling applied on the SDL window.

This makes the mouse processors independent of the "screen" instance,
and the implementation source code independent of the SDL API.
This commit is contained in:
Romain Vimont 2021-12-29 16:24:20 +01:00
parent b4b638e8fe
commit 9460bdd87b
5 changed files with 169 additions and 104 deletions

View file

@ -30,6 +30,44 @@ sc_action_from_sdl_keyboard_type(uint32_t type) {
return SC_ACTION_UP; return SC_ACTION_UP;
} }
static inline enum sc_action
sc_action_from_sdl_mousebutton_type(uint32_t type) {
assert(type == SDL_MOUSEBUTTONDOWN || type == SDL_MOUSEBUTTONUP);
if (type == SDL_MOUSEBUTTONDOWN) {
return SC_ACTION_DOWN;
}
return SC_ACTION_UP;
}
static inline enum sc_touch_action
sc_touch_action_from_sdl(uint32_t type) {
assert(type == SDL_FINGERMOTION || type == SDL_FINGERDOWN ||
type == SDL_FINGERUP);
if (type == SDL_FINGERMOTION) {
return SC_TOUCH_ACTION_MOVE;
}
if (type == SDL_FINGERDOWN) {
return SC_TOUCH_ACTION_DOWN;
}
return SC_TOUCH_ACTION_UP;
}
static inline enum sc_mouse_button
sc_mouse_button_from_sdl(uint8_t button) {
if (button >= SDL_BUTTON_LEFT && button <= SDL_BUTTON_X2) {
// SC_MOUSE_BUTTON_* constants are initialized from SDL_BUTTON(index)
return SDL_BUTTON(button);
}
return SC_MOUSE_BUTTON_UNKNOWN;
}
static inline uint8_t
sc_mouse_buttons_state_from_sdl(uint32_t buttons_state) {
assert(buttons_state < 0x100); // fits in uint8_t
return buttons_state;
}
#define SC_SDL_SHORTCUT_MODS_MASK (KMOD_CTRL | KMOD_ALT | KMOD_GUI) #define SC_SDL_SHORTCUT_MODS_MASK (KMOD_CTRL | KMOD_ALT | KMOD_GUI)
static inline uint16_t static inline uint16_t
@ -591,7 +629,16 @@ input_manager_process_mouse_motion(struct input_manager *im,
return; return;
} }
im->mp->ops->process_mouse_motion(im->mp, event); struct sc_mouse_motion_event evt = {
.position = {
.screen_size = im->screen->frame_size,
.point = screen_convert_window_to_frame_coords(im->screen,
event->x, event->y),
},
.buttons_state = sc_mouse_buttons_state_from_sdl(event->state),
};
im->mp->ops->process_mouse_motion(im->mp, &evt);
if (im->vfinger_down) { if (im->vfinger_down) {
struct sc_point mouse = struct sc_point mouse =
@ -605,7 +652,25 @@ input_manager_process_mouse_motion(struct input_manager *im,
static void static void
input_manager_process_touch(struct input_manager *im, input_manager_process_touch(struct input_manager *im,
const SDL_TouchFingerEvent *event) { const SDL_TouchFingerEvent *event) {
im->mp->ops->process_touch(im->mp, event); int dw;
int dh;
SDL_GL_GetDrawableSize(im->screen->window, &dw, &dh);
// SDL touch event coordinates are normalized in the range [0; 1]
int32_t x = event->x * dw;
int32_t y = event->y * dh;
struct sc_touch_event evt = {
.position = {
.screen_size = im->screen->frame_size,
.point = screen_convert_drawable_to_frame_coords(im->screen, x, y),
},
.action = sc_touch_action_from_sdl(event->type),
.pointer_id = event->fingerId,
.pressure = event->pressure,
};
im->mp->ops->process_touch(im->mp, &evt);
} }
static void static void
@ -665,7 +730,20 @@ input_manager_process_mouse_button(struct input_manager *im,
return; return;
} }
im->mp->ops->process_mouse_button(im->mp, event); uint32_t sdl_buttons_state = SDL_GetMouseState(NULL, NULL);
struct sc_mouse_click_event evt = {
.position = {
.screen_size = im->screen->frame_size,
.point = screen_convert_window_to_frame_coords(im->screen, event->x,
event->y),
},
.action = sc_action_from_sdl_mousebutton_type(event->type),
.button = sc_mouse_button_from_sdl(event->button),
.buttons_state = sc_mouse_buttons_state_from_sdl(sdl_buttons_state),
};
im->mp->ops->process_mouse_click(im->mp, &evt);
// Pinch-to-zoom simulation. // Pinch-to-zoom simulation.
// //
@ -696,7 +774,22 @@ input_manager_process_mouse_button(struct input_manager *im,
static void static void
input_manager_process_mouse_wheel(struct input_manager *im, input_manager_process_mouse_wheel(struct input_manager *im,
const SDL_MouseWheelEvent *event) { const SDL_MouseWheelEvent *event) {
im->mp->ops->process_mouse_wheel(im->mp, event); // mouse_x and mouse_y are expressed in pixels relative to the window
int mouse_x;
int mouse_y;
SDL_GetMouseState(&mouse_x, &mouse_y);
struct sc_mouse_scroll_event evt = {
.position = {
.screen_size = im->screen->frame_size,
.point = screen_convert_window_to_frame_coords(im->screen,
mouse_x, mouse_y),
},
.hscroll = event->x,
.vscroll = event->y,
};
im->mp->ops->process_mouse_scroll(im->mp, &evt);
} }
bool bool

View file

@ -1,11 +1,11 @@
#include "mouse_inject.h" #include "mouse_inject.h"
#include <assert.h> #include <assert.h>
#include <SDL2/SDL_events.h>
#include "android/input.h" #include "android/input.h"
#include "control_msg.h" #include "control_msg.h"
#include "controller.h" #include "controller.h"
#include "input_events.h"
#include "util/intmap.h" #include "util/intmap.h"
#include "util/log.h" #include "util/log.h"
@ -15,29 +15,29 @@
static enum android_motionevent_buttons static enum android_motionevent_buttons
convert_mouse_buttons(uint32_t state) { convert_mouse_buttons(uint32_t state) {
enum android_motionevent_buttons buttons = 0; enum android_motionevent_buttons buttons = 0;
if (state & SDL_BUTTON_LMASK) { if (state & SC_MOUSE_BUTTON_LEFT) {
buttons |= AMOTION_EVENT_BUTTON_PRIMARY; buttons |= AMOTION_EVENT_BUTTON_PRIMARY;
} }
if (state & SDL_BUTTON_RMASK) { if (state & SC_MOUSE_BUTTON_RIGHT) {
buttons |= AMOTION_EVENT_BUTTON_SECONDARY; buttons |= AMOTION_EVENT_BUTTON_SECONDARY;
} }
if (state & SDL_BUTTON_MMASK) { if (state & SC_MOUSE_BUTTON_MIDDLE) {
buttons |= AMOTION_EVENT_BUTTON_TERTIARY; buttons |= AMOTION_EVENT_BUTTON_TERTIARY;
} }
if (state & SDL_BUTTON_X1MASK) { if (state & SC_MOUSE_BUTTON_X1) {
buttons |= AMOTION_EVENT_BUTTON_BACK; buttons |= AMOTION_EVENT_BUTTON_BACK;
} }
if (state & SDL_BUTTON_X2MASK) { if (state & SC_MOUSE_BUTTON_X2) {
buttons |= AMOTION_EVENT_BUTTON_FORWARD; buttons |= AMOTION_EVENT_BUTTON_FORWARD;
} }
return buttons; return buttons;
} }
static bool static bool
convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) { convert_mouse_action(enum sc_action from, enum android_motionevent_action *to) {
static const struct sc_intmap_entry actions[] = { static const struct sc_intmap_entry actions[] = {
{SDL_MOUSEBUTTONDOWN, AMOTION_EVENT_ACTION_DOWN}, {SC_ACTION_DOWN, AMOTION_EVENT_ACTION_DOWN},
{SDL_MOUSEBUTTONUP, AMOTION_EVENT_ACTION_UP}, {SC_ACTION_UP, AMOTION_EVENT_ACTION_UP},
}; };
const struct sc_intmap_entry *entry = SC_INTMAP_FIND_ENTRY(actions, from); const struct sc_intmap_entry *entry = SC_INTMAP_FIND_ENTRY(actions, from);
@ -50,11 +50,12 @@ convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) {
} }
static bool static bool
convert_touch_action(SDL_EventType from, enum android_motionevent_action *to) { convert_touch_action(enum sc_touch_action from,
enum android_motionevent_action *to) {
static const struct sc_intmap_entry actions[] = { static const struct sc_intmap_entry actions[] = {
{SDL_FINGERMOTION, AMOTION_EVENT_ACTION_MOVE}, {SC_TOUCH_ACTION_MOVE, AMOTION_EVENT_ACTION_MOVE},
{SDL_FINGERDOWN, AMOTION_EVENT_ACTION_DOWN}, {SC_TOUCH_ACTION_DOWN, AMOTION_EVENT_ACTION_DOWN},
{SDL_FINGERUP, AMOTION_EVENT_ACTION_UP}, {SC_TOUCH_ACTION_UP, AMOTION_EVENT_ACTION_UP},
}; };
const struct sc_intmap_entry *entry = SC_INTMAP_FIND_ENTRY(actions, from); const struct sc_intmap_entry *entry = SC_INTMAP_FIND_ENTRY(actions, from);
@ -67,99 +68,73 @@ convert_touch_action(SDL_EventType from, enum android_motionevent_action *to) {
} }
static bool static bool
convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen, convert_mouse_motion(const struct sc_mouse_motion_event *event,
struct control_msg *to) { struct control_msg *msg) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT; msg->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
to->inject_touch_event.action = AMOTION_EVENT_ACTION_MOVE; msg->inject_touch_event.action = AMOTION_EVENT_ACTION_MOVE;
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE; msg->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
to->inject_touch_event.position.screen_size = screen->frame_size; msg->inject_touch_event.position = event->position;
to->inject_touch_event.position.point = msg->inject_touch_event.pressure = 1.f;
screen_convert_window_to_frame_coords(screen, from->x, from->y); msg->inject_touch_event.buttons =
to->inject_touch_event.pressure = 1.f; convert_mouse_buttons(event->buttons_state);
to->inject_touch_event.buttons = convert_mouse_buttons(from->state);
return true; return true;
} }
static bool static bool
convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen, convert_touch(const struct sc_touch_event *event,
struct control_msg *to) { struct control_msg *msg) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT; msg->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
if (!convert_touch_action(from->type, &to->inject_touch_event.action)) { if (!convert_touch_action(event->action, &msg->inject_touch_event.action)) {
return false; return false;
} }
to->inject_touch_event.pointer_id = from->fingerId; msg->inject_touch_event.pointer_id = event->pointer_id;
to->inject_touch_event.position.screen_size = screen->frame_size; msg->inject_touch_event.position = event->position;
msg->inject_touch_event.pressure = event->pressure;
msg->inject_touch_event.buttons = 0;
int dw;
int dh;
SDL_GL_GetDrawableSize(screen->window, &dw, &dh);
// SDL touch event coordinates are normalized in the range [0; 1]
int32_t x = from->x * dw;
int32_t y = from->y * dh;
to->inject_touch_event.position.point =
screen_convert_drawable_to_frame_coords(screen, x, y);
to->inject_touch_event.pressure = from->pressure;
to->inject_touch_event.buttons = 0;
return true; return true;
} }
static bool static bool
convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen, convert_mouse_click(const struct sc_mouse_click_event *event,
struct control_msg *to) { struct control_msg *msg) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT; msg->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
if (!convert_mouse_action(from->type, &to->inject_touch_event.action)) { if (!convert_mouse_action(event->action, &msg->inject_touch_event.action)) {
return false; return false;
} }
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE; msg->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
to->inject_touch_event.position.screen_size = screen->frame_size; msg->inject_touch_event.position = event->position;
to->inject_touch_event.position.point = msg->inject_touch_event.pressure = event->action == SC_ACTION_DOWN
screen_convert_window_to_frame_coords(screen, from->x, from->y); ? 1.f : 0.f;
to->inject_touch_event.pressure = msg->inject_touch_event.buttons =
from->type == SDL_MOUSEBUTTONDOWN ? 1.f : 0.f; convert_mouse_buttons(event->buttons_state);
to->inject_touch_event.buttons =
convert_mouse_buttons(SDL_BUTTON(from->button));
return true; return true;
} }
static bool static bool
convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen, convert_mouse_scroll(const struct sc_mouse_scroll_event *event,
struct control_msg *to) { struct control_msg *msg) {
msg->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
// mouse_x and mouse_y are expressed in pixels relative to the window msg->inject_scroll_event.position = event->position;
int mouse_x; msg->inject_scroll_event.hscroll = event->hscroll;
int mouse_y; msg->inject_scroll_event.vscroll = event->vscroll;
SDL_GetMouseState(&mouse_x, &mouse_y);
struct sc_position position = {
.screen_size = screen->frame_size,
.point = screen_convert_window_to_frame_coords(screen,
mouse_x, mouse_y),
};
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
to->inject_scroll_event.position = position;
to->inject_scroll_event.hscroll = from->x;
to->inject_scroll_event.vscroll = from->y;
return true; return true;
} }
static void static void
sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp, sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
const SDL_MouseMotionEvent *event) { const struct sc_mouse_motion_event *event) {
struct sc_mouse_inject *mi = DOWNCAST(mp); struct sc_mouse_inject *mi = DOWNCAST(mp);
struct control_msg msg; struct control_msg msg;
if (!convert_mouse_motion(event, mi->screen, &msg)) { if (!convert_mouse_motion(event, &msg)) {
return; return;
} }
@ -170,11 +145,11 @@ sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
static void static void
sc_mouse_processor_process_touch(struct sc_mouse_processor *mp, sc_mouse_processor_process_touch(struct sc_mouse_processor *mp,
const SDL_TouchFingerEvent *event) { const struct sc_touch_event *event) {
struct sc_mouse_inject *mi = DOWNCAST(mp); struct sc_mouse_inject *mi = DOWNCAST(mp);
struct control_msg msg; struct control_msg msg;
if (convert_touch(event, mi->screen, &msg)) { if (convert_touch(event, &msg)) {
if (!controller_push_msg(mi->controller, &msg)) { if (!controller_push_msg(mi->controller, &msg)) {
LOGW("Could not request 'inject touch event'"); LOGW("Could not request 'inject touch event'");
} }
@ -182,42 +157,41 @@ sc_mouse_processor_process_touch(struct sc_mouse_processor *mp,
} }
static void static void
sc_mouse_processor_process_mouse_button(struct sc_mouse_processor *mp, sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
const SDL_MouseButtonEvent *event) { const struct sc_mouse_click_event *event) {
struct sc_mouse_inject *mi = DOWNCAST(mp); struct sc_mouse_inject *mi = DOWNCAST(mp);
struct control_msg msg; struct control_msg msg;
if (convert_mouse_button(event, mi->screen, &msg)) { if (convert_mouse_click(event, &msg)) {
if (!controller_push_msg(mi->controller, &msg)) { if (!controller_push_msg(mi->controller, &msg)) {
LOGW("Could not request 'inject mouse button event'"); LOGW("Could not request 'inject mouse click event'");
} }
} }
} }
static void static void
sc_mouse_processor_process_mouse_wheel(struct sc_mouse_processor *mp, sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
const SDL_MouseWheelEvent *event) { const struct sc_mouse_scroll_event *event) {
struct sc_mouse_inject *mi = DOWNCAST(mp); struct sc_mouse_inject *mi = DOWNCAST(mp);
struct control_msg msg; struct control_msg msg;
if (convert_mouse_wheel(event, mi->screen, &msg)) { if (convert_mouse_scroll(event, &msg)) {
if (!controller_push_msg(mi->controller, &msg)) { if (!controller_push_msg(mi->controller, &msg)) {
LOGW("Could not request 'inject mouse wheel event'"); LOGW("Could not request 'inject mouse scroll event'");
} }
} }
} }
void void
sc_mouse_inject_init(struct sc_mouse_inject *mi, struct controller *controller, sc_mouse_inject_init(struct sc_mouse_inject *mi,
struct screen *screen) { struct controller *controller) {
mi->controller = controller; mi->controller = controller;
mi->screen = screen;
static const struct sc_mouse_processor_ops ops = { static const struct sc_mouse_processor_ops ops = {
.process_mouse_motion = sc_mouse_processor_process_mouse_motion, .process_mouse_motion = sc_mouse_processor_process_mouse_motion,
.process_touch = sc_mouse_processor_process_touch, .process_touch = sc_mouse_processor_process_touch,
.process_mouse_button = sc_mouse_processor_process_mouse_button, .process_mouse_click = sc_mouse_processor_process_mouse_click,
.process_mouse_wheel = sc_mouse_processor_process_mouse_wheel, .process_mouse_scroll = sc_mouse_processor_process_mouse_scroll,
}; };
mi->mouse_processor.ops = &ops; mi->mouse_processor.ops = &ops;

View file

@ -13,11 +13,9 @@ struct sc_mouse_inject {
struct sc_mouse_processor mouse_processor; // mouse processor trait struct sc_mouse_processor mouse_processor; // mouse processor trait
struct controller *controller; struct controller *controller;
struct screen *screen;
}; };
void void
sc_mouse_inject_init(struct sc_mouse_inject *mi, struct controller *controller, sc_mouse_inject_init(struct sc_mouse_inject *mi, struct controller *controller);
struct screen *screen);
#endif #endif

View file

@ -578,7 +578,7 @@ aoa_hid_end:
kp = &s->keyboard_inject.key_processor; kp = &s->keyboard_inject.key_processor;
} }
sc_mouse_inject_init(&s->mouse_inject, &s->controller, &s->screen); sc_mouse_inject_init(&s->mouse_inject, &s->controller);
mp = &s->mouse_inject.mouse_processor; mp = &s->mouse_inject.mouse_processor;
} }

View file

@ -6,7 +6,7 @@
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <SDL2/SDL_events.h> #include "input_events.h"
/** /**
* Mouse processor trait. * Mouse processor trait.
@ -21,19 +21,19 @@ struct sc_mouse_processor {
struct sc_mouse_processor_ops { struct sc_mouse_processor_ops {
void void
(*process_mouse_motion)(struct sc_mouse_processor *mp, (*process_mouse_motion)(struct sc_mouse_processor *mp,
const SDL_MouseMotionEvent *event); const struct sc_mouse_motion_event *event);
void void
(*process_touch)(struct sc_mouse_processor *mp, (*process_touch)(struct sc_mouse_processor *mp,
const SDL_TouchFingerEvent *event); const struct sc_touch_event *event);
void void
(*process_mouse_button)(struct sc_mouse_processor *mp, (*process_mouse_click)(struct sc_mouse_processor *mp,
const SDL_MouseButtonEvent *event); const struct sc_mouse_click_event *event);
void void
(*process_mouse_wheel)(struct sc_mouse_processor *mp, (*process_mouse_scroll)(struct sc_mouse_processor *mp,
const SDL_MouseWheelEvent *event); const struct sc_mouse_scroll_event *event);
}; };
#endif #endif