diff --git a/app/meson.build b/app/meson.build index 78060cff..46d3994f 100644 --- a/app/meson.build +++ b/app/meson.build @@ -8,13 +8,13 @@ src = [ 'src/controller.c', 'src/decoder.c', 'src/device_msg.c', - 'src/event_converter.c', 'src/icon.c', 'src/file_handler.c', 'src/fps_counter.c', 'src/frame_buffer.c', 'src/input_manager.c', 'src/keyboard_inject.c', + 'src/mouse_inject.c', 'src/opengl.c', 'src/receiver.c', 'src/recorder.c', diff --git a/app/src/event_converter.c b/app/src/event_converter.c deleted file mode 100644 index 71f9de16..00000000 --- a/app/src/event_converter.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "event_converter.h" - -#define MAP(FROM, TO) case FROM: *to = TO; return true -#define FAIL default: return false - -enum android_motionevent_buttons -convert_mouse_buttons(uint32_t state) { - enum android_motionevent_buttons buttons = 0; - if (state & SDL_BUTTON_LMASK) { - buttons |= AMOTION_EVENT_BUTTON_PRIMARY; - } - if (state & SDL_BUTTON_RMASK) { - buttons |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (state & SDL_BUTTON_MMASK) { - buttons |= AMOTION_EVENT_BUTTON_TERTIARY; - } - if (state & SDL_BUTTON_X1MASK) { - buttons |= AMOTION_EVENT_BUTTON_BACK; - } - if (state & SDL_BUTTON_X2MASK) { - buttons |= AMOTION_EVENT_BUTTON_FORWARD; - } - return buttons; -} - -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; - } -} - -bool -convert_touch_action(SDL_EventType from, enum android_motionevent_action *to) { - switch (from) { - MAP(SDL_FINGERMOTION, AMOTION_EVENT_ACTION_MOVE); - MAP(SDL_FINGERDOWN, AMOTION_EVENT_ACTION_DOWN); - MAP(SDL_FINGERUP, AMOTION_EVENT_ACTION_UP); - FAIL; - } -} diff --git a/app/src/event_converter.h b/app/src/event_converter.h deleted file mode 100644 index 71e8edec..00000000 --- a/app/src/event_converter.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CONVERT_H -#define CONVERT_H - -#include "common.h" - -#include -#include - -#include "control_msg.h" - -enum android_motionevent_buttons -convert_mouse_buttons(uint32_t state); - -bool -convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to); - -bool -convert_touch_action(SDL_EventType from, enum android_motionevent_action *to); - -#endif diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 764760cf..bba3c998 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -3,7 +3,6 @@ #include #include -#include "event_converter.h" #include "util/log.h" static const int ACTION_DOWN = 1; @@ -54,12 +53,15 @@ is_shortcut_mod(struct input_manager *im, uint16_t sdl_mod) { void input_manager_init(struct input_manager *im, struct controller *controller, struct screen *screen, struct sc_key_processor *kp, + struct sc_mouse_processor *mp, const struct scrcpy_options *options) { assert(!options->control || (kp && kp->ops)); + assert(!options->control || (mp && mp->ops)); im->controller = controller; im->screen = screen; im->kp = kp; + im->mp = mp; im->control = options->control; im->forward_all_clicks = options->forward_all_clicks; @@ -524,21 +526,6 @@ input_manager_process_key(struct input_manager *im, im->kp->ops->process_key(im->kp, event); } -static bool -convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen, - struct control_msg *to) { - 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 = screen->frame_size; - to->inject_touch_event.position.point = - screen_convert_window_to_frame_coords(screen, from->x, from->y); - to->inject_touch_event.pressure = 1.f; - to->inject_touch_event.buttons = convert_mouse_buttons(from->state); - - return true; -} - static void input_manager_process_mouse_motion(struct input_manager *im, const SDL_MouseMotionEvent *event) { @@ -554,79 +541,22 @@ input_manager_process_mouse_motion(struct input_manager *im, // simulated from touch events, so it's a duplicate return; } - struct control_msg msg; - if (!convert_mouse_motion(event, im->screen, &msg)) { - return; - } - if (!controller_push_msg(im->controller, &msg)) { - LOGW("Could not request 'inject mouse motion event'"); - } + im->mp->ops->process_mouse_motion(im->mp, event); if (im->vfinger_down) { - struct point mouse = msg.inject_touch_event.position.point; + struct point mouse = + screen_convert_window_to_frame_coords(im->screen, event->x, + event->y); struct point vfinger = inverse_point(mouse, im->screen->frame_size); simulate_virtual_finger(im, AMOTION_EVENT_ACTION_MOVE, vfinger); } } -static bool -convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen, - struct control_msg *to) { - to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT; - - if (!convert_touch_action(from->type, &to->inject_touch_event.action)) { - return false; - } - - to->inject_touch_event.pointer_id = from->fingerId; - to->inject_touch_event.position.screen_size = screen->frame_size; - - 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; -} - static void input_manager_process_touch(struct input_manager *im, const SDL_TouchFingerEvent *event) { - struct control_msg msg; - if (convert_touch(event, im->screen, &msg)) { - if (!controller_push_msg(im->controller, &msg)) { - LOGW("Could not request 'inject touch event'"); - } - } -} - -static bool -convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen, - struct control_msg *to) { - to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT; - - if (!convert_mouse_action(from->type, &to->inject_touch_event.action)) { - return false; - } - - to->inject_touch_event.pointer_id = POINTER_ID_MOUSE; - to->inject_touch_event.position.screen_size = screen->frame_size; - to->inject_touch_event.position.point = - screen_convert_window_to_frame_coords(screen, from->x, from->y); - to->inject_touch_event.pressure = - from->type == SDL_MOUSEBUTTONDOWN ? 1.f : 0.f; - to->inject_touch_event.buttons = - convert_mouse_buttons(SDL_BUTTON(from->button)); - - return true; + im->mp->ops->process_touch(im->mp, event); } static void @@ -686,15 +616,7 @@ input_manager_process_mouse_button(struct input_manager *im, return; } - struct control_msg msg; - if (!convert_mouse_button(event, im->screen, &msg)) { - return; - } - - if (!controller_push_msg(im->controller, &msg)) { - LOGW("Could not request 'inject mouse button event'"); - return; - } + im->mp->ops->process_mouse_button(im->mp, event); // Pinch-to-zoom simulation. // @@ -708,7 +630,9 @@ input_manager_process_mouse_button(struct input_manager *im, #define CTRL_PRESSED (SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL)) if ((down && !im->vfinger_down && CTRL_PRESSED) || (!down && im->vfinger_down)) { - struct point mouse = msg.inject_touch_event.position.point; + struct point mouse = + screen_convert_window_to_frame_coords(im->screen, event->x, + event->y); struct point vfinger = inverse_point(mouse, im->screen->frame_size); enum android_motionevent_action action = down ? AMOTION_EVENT_ACTION_DOWN @@ -720,39 +644,10 @@ input_manager_process_mouse_button(struct input_manager *im, } } -static bool -convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen, - struct control_msg *to) { - - // 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 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; -} - static void input_manager_process_mouse_wheel(struct input_manager *im, const SDL_MouseWheelEvent *event) { - struct control_msg msg; - if (convert_mouse_wheel(event, im->screen, &msg)) { - if (!controller_push_msg(im->controller, &msg)) { - LOGW("Could not request 'inject mouse wheel event'"); - } - } + im->mp->ops->process_mouse_wheel(im->mp, event); } bool diff --git a/app/src/input_manager.h b/app/src/input_manager.h index cdd32295..bd9d7a1b 100644 --- a/app/src/input_manager.h +++ b/app/src/input_manager.h @@ -12,12 +12,14 @@ #include "scrcpy.h" #include "screen.h" #include "trait/key_processor.h" +#include "trait/mouse_processor.h" struct input_manager { struct controller *controller; struct screen *screen; struct sc_key_processor *kp; + struct sc_mouse_processor *mp; bool control; bool forward_all_clicks; @@ -41,6 +43,7 @@ struct input_manager { void input_manager_init(struct input_manager *im, struct controller *controller, struct screen *screen, struct sc_key_processor *kp, + struct sc_mouse_processor *mp, const struct scrcpy_options *options); bool diff --git a/app/src/mouse_inject.c b/app/src/mouse_inject.c new file mode 100644 index 00000000..008da267 --- /dev/null +++ b/app/src/mouse_inject.c @@ -0,0 +1,211 @@ +#include "mouse_inject.h" + +#include +#include + +#include "android/input.h" +#include "control_msg.h" +#include "controller.h" +#include "util/log.h" + +/** Downcast mouse processor to sc_mouse_inject */ +#define DOWNCAST(MP) container_of(MP, struct sc_mouse_inject, mouse_processor) + +static enum android_motionevent_buttons +convert_mouse_buttons(uint32_t state) { + enum android_motionevent_buttons buttons = 0; + if (state & SDL_BUTTON_LMASK) { + buttons |= AMOTION_EVENT_BUTTON_PRIMARY; + } + if (state & SDL_BUTTON_RMASK) { + buttons |= AMOTION_EVENT_BUTTON_SECONDARY; + } + if (state & SDL_BUTTON_MMASK) { + buttons |= AMOTION_EVENT_BUTTON_TERTIARY; + } + if (state & SDL_BUTTON_X1MASK) { + buttons |= AMOTION_EVENT_BUTTON_BACK; + } + if (state & SDL_BUTTON_X2MASK) { + buttons |= AMOTION_EVENT_BUTTON_FORWARD; + } + return buttons; +} + +#define MAP(FROM, TO) case FROM: *to = TO; return true +#define FAIL default: return false +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 bool +convert_touch_action(SDL_EventType from, enum android_motionevent_action *to) { + switch (from) { + MAP(SDL_FINGERMOTION, AMOTION_EVENT_ACTION_MOVE); + MAP(SDL_FINGERDOWN, AMOTION_EVENT_ACTION_DOWN); + MAP(SDL_FINGERUP, AMOTION_EVENT_ACTION_UP); + FAIL; + } +} + +static bool +convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen, + struct control_msg *to) { + 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 = screen->frame_size; + to->inject_touch_event.position.point = + screen_convert_window_to_frame_coords(screen, from->x, from->y); + to->inject_touch_event.pressure = 1.f; + to->inject_touch_event.buttons = convert_mouse_buttons(from->state); + + return true; +} + +static bool +convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen, + struct control_msg *to) { + to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT; + + if (!convert_touch_action(from->type, &to->inject_touch_event.action)) { + return false; + } + + to->inject_touch_event.pointer_id = from->fingerId; + to->inject_touch_event.position.screen_size = screen->frame_size; + + 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; +} + +static bool +convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen, + struct control_msg *to) { + to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT; + + if (!convert_mouse_action(from->type, &to->inject_touch_event.action)) { + return false; + } + + to->inject_touch_event.pointer_id = POINTER_ID_MOUSE; + to->inject_touch_event.position.screen_size = screen->frame_size; + to->inject_touch_event.position.point = + screen_convert_window_to_frame_coords(screen, from->x, from->y); + to->inject_touch_event.pressure = + from->type == SDL_MOUSEBUTTONDOWN ? 1.f : 0.f; + to->inject_touch_event.buttons = + convert_mouse_buttons(SDL_BUTTON(from->button)); + + return true; +} + +static bool +convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen, + struct control_msg *to) { + + // 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 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; +} + +static void +sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp, + const SDL_MouseMotionEvent *event) { + struct sc_mouse_inject *mi = DOWNCAST(mp); + + struct control_msg msg; + if (!convert_mouse_motion(event, mi->screen, &msg)) { + return; + } + + if (!controller_push_msg(mi->controller, &msg)) { + LOGW("Could not request 'inject mouse motion event'"); + } +} + +static void +sc_mouse_processor_process_touch(struct sc_mouse_processor *mp, + const SDL_TouchFingerEvent *event) { + struct sc_mouse_inject *mi = DOWNCAST(mp); + + struct control_msg msg; + if (convert_touch(event, mi->screen, &msg)) { + if (!controller_push_msg(mi->controller, &msg)) { + LOGW("Could not request 'inject touch event'"); + } + } +} + +static void +sc_mouse_processor_process_mouse_button(struct sc_mouse_processor *mp, + const SDL_MouseButtonEvent *event) { + struct sc_mouse_inject *mi = DOWNCAST(mp); + + struct control_msg msg; + if (convert_mouse_button(event, mi->screen, &msg)) { + if (!controller_push_msg(mi->controller, &msg)) { + LOGW("Could not request 'inject mouse button event'"); + } + } +} + +static void +sc_mouse_processor_process_mouse_wheel(struct sc_mouse_processor *mp, + const SDL_MouseWheelEvent *event) { + struct sc_mouse_inject *mi = DOWNCAST(mp); + + struct control_msg msg; + if (convert_mouse_wheel(event, mi->screen, &msg)) { + if (!controller_push_msg(mi->controller, &msg)) { + LOGW("Could not request 'inject mouse wheel event'"); + } + } +} + +void +sc_mouse_inject_init(struct sc_mouse_inject *mi, struct controller *controller, + struct screen *screen) { + mi->controller = controller; + mi->screen = screen; + + static const struct sc_mouse_processor_ops ops = { + .process_mouse_motion = sc_mouse_processor_process_mouse_motion, + .process_touch = sc_mouse_processor_process_touch, + .process_mouse_button = sc_mouse_processor_process_mouse_button, + .process_mouse_wheel = sc_mouse_processor_process_mouse_wheel, + }; + + mi->mouse_processor.ops = &ops; +} diff --git a/app/src/mouse_inject.h b/app/src/mouse_inject.h new file mode 100644 index 00000000..d5220db9 --- /dev/null +++ b/app/src/mouse_inject.h @@ -0,0 +1,24 @@ +#ifndef SC_MOUSE_INJECT_H +#define SC_MOUSE_INJECT_H + +#include "common.h" + +#include + +#include "controller.h" +#include "scrcpy.h" +#include "screen.h" +#include "trait/mouse_processor.h" + +struct sc_mouse_inject { + struct sc_mouse_processor mouse_processor; // mouse processor trait + + struct controller *controller; + struct screen *screen; +}; + +void +sc_mouse_inject_init(struct sc_mouse_inject *mi, struct controller *controller, + struct screen *screen); + +#endif diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index def96bb7..50250e2c 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -19,6 +19,7 @@ #include "file_handler.h" #include "input_manager.h" #include "keyboard_inject.h" +#include "mouse_inject.h" #include "recorder.h" #include "screen.h" #include "server.h" @@ -41,6 +42,7 @@ struct scrcpy { struct controller controller; struct file_handler file_handler; struct sc_keyboard_inject keyboard_inject; + struct sc_mouse_inject mouse_inject; struct input_manager input_manager; }; @@ -414,13 +416,17 @@ scrcpy(const struct scrcpy_options *options) { stream_started = true; struct sc_key_processor *kp = NULL; + struct sc_mouse_processor *mp = NULL; if (options->control) { sc_keyboard_inject_init(&s->keyboard_inject, &s->controller, options); kp = &s->keyboard_inject.key_processor; + + sc_mouse_inject_init(&s->mouse_inject, &s->controller, &s->screen); + mp = &s->mouse_inject.mouse_processor; } - input_manager_init(&s->input_manager, &s->controller, &s->screen, kp, + input_manager_init(&s->input_manager, &s->controller, &s->screen, kp, mp, options); ret = event_loop(s, options); diff --git a/app/src/trait/mouse_processor.h b/app/src/trait/mouse_processor.h new file mode 100644 index 00000000..f3548574 --- /dev/null +++ b/app/src/trait/mouse_processor.h @@ -0,0 +1,39 @@ +#ifndef SC_MOUSE_PROCESSOR_H +#define SC_MOUSE_PROCESSOR_H + +#include "common.h" + +#include +#include + +#include + +/** + * Mouse processor trait. + * + * Component able to process and inject mouse events should implement this + * trait. + */ +struct sc_mouse_processor { + const struct sc_mouse_processor_ops *ops; +}; + +struct sc_mouse_processor_ops { + void + (*process_mouse_motion)(struct sc_mouse_processor *mp, + const SDL_MouseMotionEvent *event); + + void + (*process_touch)(struct sc_mouse_processor *mp, + const SDL_TouchFingerEvent *event); + + void + (*process_mouse_button)(struct sc_mouse_processor *mp, + const SDL_MouseButtonEvent *event); + + void + (*process_mouse_wheel)(struct sc_mouse_processor *mp, + const SDL_MouseWheelEvent *event); +}; + +#endif