Compare commits

..

8 Commits

Author SHA1 Message Date
b26ad41da7 wip 2021-12-29 01:21:40 +01:00
bc84a130a4 wip 2021-12-29 00:37:49 +01:00
3c663e1c0f wip 2021-12-28 23:46:24 +01:00
05ef36545c wip 2021-12-28 23:46:24 +01:00
ac32280a43 wip 2021-12-28 23:46:24 +01:00
93c49ae446 wip 2021-12-28 23:46:24 +01:00
15d40b6d16 input_events 2021-12-28 23:46:24 +01:00
c520d9f0e7 Rename SC_MOD_* to SC_SHORTCUT_MOD_*
This will avoid conflicts with new SC_MOD_* constants.
2021-12-28 23:46:24 +01:00
15 changed files with 418 additions and 543 deletions

View File

@ -14,6 +14,7 @@ src = [
'src/file_handler.c',
'src/fps_counter.c',
'src/frame_buffer.c',
'src/input_events.c',
'src/input_manager.c',
'src/keyboard_inject.c',
'src/mouse_inject.c',
@ -77,7 +78,6 @@ if aoa_hid_support
src += [
'src/aoa_hid.c',
'src/hid_keyboard.c',
'src/hid_mouse.c',
]
endif

View File

@ -7,7 +7,6 @@
#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0]))
#define MIN(X,Y) (X) < (Y) ? (X) : (Y)
#define MAX(X,Y) (X) > (Y) ? (X) : (Y)
#define CLAMP(V,X,Y) MIN( MAX((V),(X)), (Y) )
#define container_of(ptr, type, member) \
((type *) (((char *) (ptr)) - offsetof(type, member)))

View File

@ -387,6 +387,15 @@ sc_key_processor_process_key(struct sc_key_processor *kp,
}
}
static void
sc_key_processor_process_text(struct sc_key_processor *kp,
const struct sc_text_event *event) {
(void) kp;
(void) event;
// Never forward text input via HID (all the keys are injected separately)
}
bool
sc_hid_keyboard_init(struct sc_hid_keyboard *kb, struct sc_aoa *aoa) {
kb->aoa = aoa;
@ -406,9 +415,7 @@ sc_hid_keyboard_init(struct sc_hid_keyboard *kb, struct sc_aoa *aoa) {
static const struct sc_key_processor_ops ops = {
.process_key = sc_key_processor_process_key,
// Never forward text input via HID (all the keys are injected
// separately)
.process_text = NULL,
.process_text = sc_key_processor_process_text,
};
// Clipboard synchronization is requested over the control socket, while HID

View File

@ -1,258 +0,0 @@
#include "hid_mouse.h"
#include <assert.h>
#include "input_events.h"
#include "util/log.h"
/** Downcast mouse processor to hid_mouse */
#define DOWNCAST(MP) container_of(MP, struct sc_hid_mouse, mouse_processor)
#define HID_MOUSE_ACCESSORY_ID 2
// 1 byte for buttons + padding, 1 byte for X position, 1 byte for Y position
#define HID_MOUSE_EVENT_SIZE 4
/**
* Mouse descriptor from the specification:
* <https://www.usb.org/sites/default/files/hid1_11.pdf>
*
* Appendix E (p71): §E.10 Report Descriptor (Mouse)
*
* The usage tags (like Wheel) are listed in "HID Usage Tables":
* <https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf>
* §4 Generic Desktop Page (0x01) (p26)
*/
static const unsigned char mouse_report_desc[] = {
// Usage Page (Generic Desktop)
0x05, 0x01,
// Usage (Mouse)
0x09, 0x02,
// Collection (Application)
0xA1, 0x01,
// Usage (Pointer)
0x09, 0x01,
// Collection (Physical)
0xA1, 0x00,
// Usage Page (Buttons)
0x05, 0x09,
// Usage Minimum (1)
0x19, 0x01,
// Usage Maximum (3)
0x29, 0x03,
// Logical Minimum (0)
0x15, 0x00,
// Logical Maximum (1)
0x25, 0x01,
// Report Count (3)
0x95, 0x03,
// Report Size (1)
0x75, 0x01,
// Input (Data, Variable, Absolute): 3 buttons bits
0x81, 0x02,
// Report Count (1)
0x95, 0x01,
// Report Size (5)
0x75, 0x05,
// Input (Constant): 5 bits padding
0x81, 0x01,
// Usage Page (Generic Desktop)
0x05, 0x01,
// Usage (X)
0x09, 0x30,
// Usage (Y)
0x09, 0x31,
// Usage (Wheel)
0x09, 0x38,
// Local Minimum (-127)
0x15, 0x81,
// Local Maximum (127)
0x25, 0x7F,
// Report Size (8)
0x75, 0x08,
// Report Count (3)
0x95, 0x03,
// Input (Data, Variable, Relative): 3 position bytes (X, Y, Wheel)
0x81, 0x06,
// End Collection
0xC0,
// End Collection
0xC0,
};
/**
* A mouse HID event is 3 bytes long:
*
* - byte 0: buttons state
* - byte 1: relative x motion (signed byte from -127 to 127)
* - byte 2: relative y motion (signed byte from -127 to 127)
*
* 7 6 5 4 3 2 1 0
* +---------------+
* byte 0: |0 0 0 0 0 . . .| buttons state
* +---------------+
* ^ ^ ^
* | | `- left button
* | `--- right button
* `----- middle button
*
* +---------------+
* byte 1: |. . . . . . . .| relative x motion
* +---------------+
* byte 2: |. . . . . . . .| relative y motion
* +---------------+
* byte 3: |. . . . . . . .| wheel motion (-1, 0 or 1)
* +---------------+
*
* As an example, here is the report for a motion of (x=5, y=-4) with left
* button pressed:
*
* +---------------+
* |0 0 0 0 0 0 0 1| left button pressed
* +---------------+
* |0 0 0 0 0 1 0 1| horizontal motion (x = 5)
* +---------------+
* |1 1 1 1 1 1 0 0| relative y motion (y = -4)
* +---------------+
* |0 0 0 0 0 0 0 0| wheel motion
* +---------------+
*/
static bool
sc_hid_mouse_event_init(struct sc_hid_event *hid_event) {
unsigned char *buffer = calloc(1, HID_MOUSE_EVENT_SIZE);
if (!buffer) {
LOG_OOM();
return false;
}
sc_hid_event_init(hid_event, HID_MOUSE_ACCESSORY_ID, buffer,
HID_MOUSE_EVENT_SIZE);
return true;
}
static unsigned char
buttons_state_to_hid_buttons(uint8_t buttons_state) {
unsigned char c = 0;
if (buttons_state & SC_MOUSE_BUTTON_LEFT) {
c |= 1 << 0;
}
if (buttons_state & SC_MOUSE_BUTTON_RIGHT) {
c |= 1 << 1;
}
if (buttons_state & SC_MOUSE_BUTTON_MIDDLE) {
c |= 1 << 2;
}
// TODO buttons 4 and 5?
return c;
}
static void
sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
const struct sc_mouse_motion_event *event) {
struct sc_hid_mouse *mouse = DOWNCAST(mp);
struct sc_hid_event hid_event;
if (!sc_hid_mouse_event_init(&hid_event)) {
return;
}
unsigned char *buffer = hid_event.buffer;
buffer[0] = buttons_state_to_hid_buttons(event->buttons_state);
buffer[1] = CLAMP(event->xrel, -127, 127);
buffer[2] = CLAMP(event->yrel, -127, 127);
buffer[3] = 0; // wheel coordinates only used for scrolling
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event);
LOGW("Could request HID event");
}
}
static void
sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
const struct sc_mouse_click_event *event) {
struct sc_hid_mouse *mouse = DOWNCAST(mp);
struct sc_hid_event hid_event;
if (!sc_hid_mouse_event_init(&hid_event)) {
return;
}
unsigned char *buffer = hid_event.buffer;
buffer[0] = buttons_state_to_hid_buttons(event->buttons_state);
buffer[1] = 0; // no x motion
buffer[2] = 0; // no y motion
buffer[3] = 0; // wheel coordinates only used for scrolling
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event);
LOGW("Could request HID event");
}
}
static void
sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
const struct sc_mouse_scroll_event *event) {
struct sc_hid_mouse *mouse = DOWNCAST(mp);
struct sc_hid_event hid_event;
if (!sc_hid_mouse_event_init(&hid_event)) {
return;
}
unsigned char *buffer = hid_event.buffer;
buffer[0] = 0; // buttons state irrelevant (and unknown)
buffer[1] = 0; // no x motion
buffer[2] = 0; // no y motion
// In practice, vscroll is always -1, 0 or 1, but in theory other values
// are possible
buffer[3] = CLAMP(event->vscroll, -127, 127);
// Horizontal scrolling ignored
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event);
LOGW("Could request HID event");
}
}
bool
sc_hid_mouse_init(struct sc_hid_mouse *mouse, struct sc_aoa *aoa) {
mouse->aoa = aoa;
bool ok = sc_aoa_setup_hid(aoa, HID_MOUSE_ACCESSORY_ID, mouse_report_desc,
ARRAY_LEN(mouse_report_desc));
if (!ok) {
LOGW("Register HID mouse failed");
return false;
}
static const struct sc_mouse_processor_ops ops = {
.process_mouse_motion = sc_mouse_processor_process_mouse_motion,
.process_mouse_click = sc_mouse_processor_process_mouse_click,
.process_mouse_scroll = sc_mouse_processor_process_mouse_scroll,
// Touch events not supported (coordinates are not relative)
.process_touch = NULL,
};
mouse->mouse_processor.ops = &ops;
return true;
}
void
sc_hid_mouse_destroy(struct sc_hid_mouse *mouse) {
bool ok = sc_aoa_unregister_hid(mouse->aoa, HID_MOUSE_ACCESSORY_ID);
if (!ok) {
LOGW("Could not unregister HID");
}
}

View File

@ -1,23 +0,0 @@
#ifndef HID_MOUSE_H
#define HID_MOUSE_H
#include "common.h"
#include <stdbool.h>
#include "aoa_hid.h"
#include "trait/mouse_processor.h"
struct sc_hid_mouse {
struct sc_mouse_processor mouse_processor; // mouse processor trait
struct sc_aoa *aoa;
};
bool
sc_hid_mouse_init(struct sc_hid_mouse *mouse, struct sc_aoa *aoa);
void
sc_hid_mouse_destroy(struct sc_hid_mouse *mouse);
#endif

76
app/src/input_events.c Normal file
View File

@ -0,0 +1,76 @@
#include <input_events.h>
static inline uint16_t
sc_mods_state_from_sdl(uint16_t mods_state) {
return mods_state;
}
static inline enum sc_keycode
sc_keycode_from_sdl(SDL_Keycode keycode) {
return (enum sc_keycode) keycode;
}
static inline enum sc_scancode
sc_scancode_from_sdl(SDL_Scancode scancode) {
return (enum sc_scancode) scancode;
}
static inline enum sc_action
sc_action_from_sdl_keyboard_type(uint32_t type) {
assert(type == SDL_KEYDOWN || type == SDL_KEYUP);
if (type == SDL_KEYDOWN) {
return SC_ACTION_DOWN;
}
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_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;
}
void
sc_key_event_from_sdl(struct sc_key_event *event,
const SDL_KeyboardEvent *sdl) {
event->action = sc_action_from_sdl_keyboard_type(sdl->type);
event->keycode = sc_keycode_from_sdl(sdl->keysym.sym);
event->scancode = sc_scancode_from_sdl(sdl->keysym.scancode);
event->repeat = sdl->repeat;
event->mods_state = sc_mods_state_from_sdl(sdl->keysym.mod);
}
void
sc_text_event_from_sdl(struct sc_text_event *event,
const SDL_TextInputEvent *sdl) {
event->text = sdl->text;
}
void
sc_mouse_click_event_from_sdl(struct sc_mouse_click_event *event,
const SDL_MouseButtonEvent *sdl,
const SDL_Window *window,
struct sc_size screen_size) {
event->action = sc_action_from_sdl_mousebutton_type(sdl->type);
event->button = sc_mouse_button_from_sdl(sdl->button);
event->position.screen_size = screen_size;
}

View File

@ -10,37 +10,9 @@
#include "coords.h"
/* The representation of input events in scrcpy is very close to the SDL API,
* for simplicity.
*
* This scrcpy input events API is designed to be consumed by input event
* processors (sc_key_processor and sc_mouse_processor, see app/src/trait/).
*
* One major semantic difference between SDL input events and scrcpy input
* events is their frame of reference (for mouse and touch events): SDL events
* coordinates are expressed in SDL window coordinates (the visible UI), while
* scrcpy events are expressed in device frame coordinates.
*
* In particular, the window may be visually scaled or rotated (with --rotation
* or MOD+Left/Right), but this does not impact scrcpy input events (contrary
* to SDL input events). This allows to abstract these display details from the
* input event processors (and to make them independent from the "screen").
*
* For many enums below, the values are purposely the same as the SDL
* constants (though not all SDL values are represented), so that the
/* The values are purposely the same as the SDL constants, so that the
* implementation to convert from the SDL version to the scrcpy version is
* straightforward.
*
* In practice, there are 3 levels of input events:
* 1. SDL input events (as received from SDL)
* 2. scrcpy input events (this API)
* 3. the key/mouse processors input events (Android API or HID events)
*
* An input event is first received (1), then (if accepted) converted to an
* scrcpy input event (2), then submitted to the relevant key/mouse processor,
* which (if accepted) is converted to an Android event (to be sent to the
* server) or to an HID event (to be sent over USB/AOA directly).
*/
* straightforward */
enum sc_mod {
SC_MOD_LSHIFT = KMOD_LSHIFT,
@ -58,8 +30,8 @@ enum sc_mod {
};
enum sc_action {
SC_ACTION_DOWN, // key or button pressed
SC_ACTION_UP, // key or button released
SC_ACTION_DOWN = 1, // key or button pressed
SC_ACTION_UP = 2, // key or button released
};
enum sc_keycode {
@ -370,6 +342,32 @@ struct sc_mouse_motion_event {
uint8_t buttons_state; // bitwise-OR of sc_mouse_button values
};
//enum sc_mouse_event_type {
// SC_MOUSE_EVENT_TYPE_CLICK,
// SC_MOUSE_EVENT_TYPE_MOVE,
// SC_MOUSE_EVENT_TYPE_SCROLL,
//};
//
//struct sc_mouse_event {
// enum sc_mouse_event_type type;
// struct sc_position position;
// uint8_t buttons_state; // bitwise-OR of sc_mouse_button values
// union {
// struct {
// enum sc_action action;
// enum sc_mouse_button button;
// } click;
// struct {
// int32_t xrel;
// int32_t yrel;
// } move;
// struct {
// int32_t h;
// int32_t v;
// } scroll;
// };
//};
struct sc_touch_event {
struct sc_position position;
enum sc_touch_action action;
@ -377,4 +375,30 @@ struct sc_touch_event {
float pressure;
};
//void
//sc_key_event_from_sdl(struct sc_key_event *event, const SDL_KeyboardEvent *sdl);
//
//void
//sc_text_event_from_sdl(struct sc_text_event *event,
// const SDL_TextInputEvent *sdl);
//
//void
//sc_mouse_click_event_from_sdl(struct sc_mouse_click_event *event,
// const SDL_MouseButtonEvent *sdl,
// const SDL_Window *window,
// struct sc_size screen_size);
//
//void
//sc_mouse_wheel_event_from_sdl(struct sc_mouse_wheel_event *event,
// const SDL_MouseWheelEvent *sdl);
//
//void
//sc_mouse_motion_event_from_sdl(struct sc_mouse_motion_event *event,
// const SDL_MouseMotionEvent *sdl);
//
//void
//sc_touch_event_from_sdl(struct sc_touch_event *event,
// const SDL_TouchFingerEvent *sdl);
#endif

View File

@ -63,21 +63,36 @@ sc_mouse_button_from_sdl(uint8_t button) {
}
static inline uint8_t
sc_mouse_buttons_state_from_sdl(uint32_t buttons_state,
bool forward_all_clicks) {
sc_mouse_buttons_state_from_sdl(uint32_t buttons_state) {
assert(buttons_state < 0x100); // fits in uint8_t
uint8_t mask = SC_MOUSE_BUTTON_LEFT;
if (forward_all_clicks) {
mask |= SC_MOUSE_BUTTON_RIGHT
| SC_MOUSE_BUTTON_MIDDLE
| SC_MOUSE_BUTTON_X1
| SC_MOUSE_BUTTON_X2;
}
return buttons_state & mask;
return buttons_state;
}
//void
//sc_key_event_from_sdl(struct sc_key_event *event,
// const SDL_KeyboardEvent *sdl) {
// event->action = sc_action_from_sdl_keyboard_type(sdl->type);
// event->keycode = sc_keycode_from_sdl(sdl->keysym.sym);
// event->scancode = sc_scancode_from_sdl(sdl->keysym.scancode);
// event->repeat = sdl->repeat;
// event->mods_state = sc_mods_state_from_sdl(sdl->keysym.mod);
//}
//
//void
//sc_text_event_from_sdl(struct sc_text_event *event,
// const SDL_TextInputEvent *sdl) {
// event->text = sdl->text;
//}
//
//void
//sc_mouse_click_event_from_sdl(struct sc_mouse_click_event *event,
// const SDL_MouseButtonEvent *sdl,
// struct sc_size screen_size) {
// event->action = sc_action_from_sdl_mousebutton_type(sdl->type);
// event->button = sc_mouse_button_from_sdl(sdl->button);
// event->position.screen_size = screen_size;
//}
#define SC_SDL_SHORTCUT_MODS_MASK (KMOD_CTRL | KMOD_ALT | KMOD_GUI)
static inline uint16_t
@ -159,72 +174,85 @@ input_manager_init(struct input_manager *im, struct controller *controller,
static void
send_keycode(struct controller *controller, enum android_keycode keycode,
enum sc_action action, const char *name) {
int actions, const char *name) {
// send DOWN event
struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
msg.inject_keycode.action = action == SC_ACTION_DOWN
? AKEY_EVENT_ACTION_DOWN
: AKEY_EVENT_ACTION_UP;
msg.inject_keycode.keycode = keycode;
msg.inject_keycode.metastate = 0;
msg.inject_keycode.repeat = 0;
if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request 'inject %s'", name);
return;
if (actions & SC_ACTION_DOWN) {
msg.inject_keycode.action = AKEY_EVENT_ACTION_DOWN;
if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request 'inject %s (DOWN)'", name);
return;
}
}
if (actions & SC_ACTION_UP) {
msg.inject_keycode.action = AKEY_EVENT_ACTION_UP;
if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request 'inject %s (UP)'", name);
}
}
}
static inline void
action_home(struct controller *controller, enum sc_action action) {
send_keycode(controller, AKEYCODE_HOME, action, "HOME");
action_home(struct controller *controller, int actions) {
send_keycode(controller, AKEYCODE_HOME, actions, "HOME");
}
static inline void
action_back(struct controller *controller, enum sc_action action) {
send_keycode(controller, AKEYCODE_BACK, action, "BACK");
action_back(struct controller *controller, int actions) {
send_keycode(controller, AKEYCODE_BACK, actions, "BACK");
}
static inline void
action_app_switch(struct controller *controller, enum sc_action action) {
send_keycode(controller, AKEYCODE_APP_SWITCH, action, "APP_SWITCH");
action_app_switch(struct controller *controller, int actions) {
send_keycode(controller, AKEYCODE_APP_SWITCH, actions, "APP_SWITCH");
}
static inline void
action_power(struct controller *controller, enum sc_action action) {
send_keycode(controller, AKEYCODE_POWER, action, "POWER");
action_power(struct controller *controller, int actions) {
send_keycode(controller, AKEYCODE_POWER, actions, "POWER");
}
static inline void
action_volume_up(struct controller *controller, enum sc_action action) {
send_keycode(controller, AKEYCODE_VOLUME_UP, action, "VOLUME_UP");
action_volume_up(struct controller *controller, int actions) {
send_keycode(controller, AKEYCODE_VOLUME_UP, actions, "VOLUME_UP");
}
static inline void
action_volume_down(struct controller *controller, enum sc_action action) {
send_keycode(controller, AKEYCODE_VOLUME_DOWN, action, "VOLUME_DOWN");
action_volume_down(struct controller *controller, int actions) {
send_keycode(controller, AKEYCODE_VOLUME_DOWN, actions, "VOLUME_DOWN");
}
static inline void
action_menu(struct controller *controller, enum sc_action action) {
send_keycode(controller, AKEYCODE_MENU, action, "MENU");
action_menu(struct controller *controller, int actions) {
send_keycode(controller, AKEYCODE_MENU, actions, "MENU");
}
// turn the screen on if it was off, press BACK otherwise
// If the screen is off, it is turned on only on ACTION_DOWN
static void
press_back_or_turn_screen_on(struct controller *controller,
enum sc_action action) {
press_back_or_turn_screen_on(struct controller *controller, int actions) {
struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON;
msg.back_or_screen_on.action = action == SC_ACTION_DOWN
? AKEY_EVENT_ACTION_DOWN
: AKEY_EVENT_ACTION_UP;
if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request 'press back or turn screen on'");
return;
if (actions & SC_ACTION_DOWN) {
msg.back_or_screen_on.action = AKEY_EVENT_ACTION_DOWN;
if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request 'press back or turn screen on'");
return;
}
}
if (actions & SC_ACTION_UP) {
msg.back_or_screen_on.action = AKEY_EVENT_ACTION_UP;
if (!controller_push_msg(controller, &msg)) {
LOGW("Could not request 'press back or turn screen on'");
}
}
}
@ -386,11 +414,6 @@ rotate_client_right(struct screen *screen) {
static void
input_manager_process_text_input(struct input_manager *im,
const SDL_TextInputEvent *event) {
if (!im->kp->ops->process_text) {
// The key processor does not support text input
return;
}
if (is_shortcut_mod(im, SDL_GetModState())) {
// A shortcut must never generate text events
return;
@ -627,22 +650,20 @@ input_manager_process_key(struct input_manager *im,
.mods_state = sc_mods_state_from_sdl(event->keysym.mod),
};
assert(im->kp->ops->process_key);
im->kp->ops->process_key(im->kp, &evt, ack_to_wait);
}
static void
input_manager_process_mouse_motion(struct input_manager *im,
const SDL_MouseMotionEvent *event) {
uint32_t mask = SDL_BUTTON_LMASK;
if (im->forward_all_clicks) {
mask |= SDL_BUTTON_MMASK | SDL_BUTTON_RMASK;
}
//if (!(event->state & mask)) {
// // do not send motion events when no click is pressed
// return;
//}
if (!(event->state & mask)) {
// do not send motion events when no click is pressed
return;
}
if (event->which == SDL_TOUCH_MOUSEID) {
// simulated from touch events, so it's a duplicate
return;
@ -656,13 +677,10 @@ input_manager_process_mouse_motion(struct input_manager *im,
},
.xrel = event->xrel,
.yrel = event->yrel,
.buttons_state =
sc_mouse_buttons_state_from_sdl(event->state,
im->forward_all_clicks),
.buttons_state = sc_mouse_buttons_state_from_sdl(event->state),
};
assert(im->mp->ops->process_mouse_motion);
im->mp->ops->process_mouse_motion(im->mp, &evt);
im->mp->ops->process_mouse_motion(im->mp, event);
if (im->vfinger_down) {
struct sc_point mouse =
@ -676,11 +694,6 @@ input_manager_process_mouse_motion(struct input_manager *im,
static void
input_manager_process_touch(struct input_manager *im,
const SDL_TouchFingerEvent *event) {
if (!im->mp->ops->process_touch) {
// The mouse processor does not support touch events
return;
}
int dw;
int dh;
SDL_GL_GetDrawableSize(im->screen->window, &dw, &dh);
@ -699,7 +712,7 @@ input_manager_process_touch(struct input_manager *im,
.pressure = event->pressure,
};
im->mp->ops->process_touch(im->mp, &evt);
im->mp->ops->process_touch(im->mp, event);
}
static void
@ -769,13 +782,10 @@ input_manager_process_mouse_button(struct input_manager *im,
},
.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->forward_all_clicks),
.buttons_state = sc_mouse_buttons_state_from_sdl(sdl_buttons_state),
};
assert(im->mp->ops->process_mouse_click);
im->mp->ops->process_mouse_click(im->mp, &evt);
im->mp->ops->process_mouse_button(im->mp, event);
// Pinch-to-zoom simulation.
//
@ -806,11 +816,6 @@ input_manager_process_mouse_button(struct input_manager *im,
static void
input_manager_process_mouse_wheel(struct input_manager *im,
const SDL_MouseWheelEvent *event) {
if (!im->mp->ops->process_mouse_scroll) {
// The mouse processor does not support scroll events
return;
}
// mouse_x and mouse_y are expressed in pixels relative to the window
int mouse_x;
int mouse_y;
@ -826,7 +831,7 @@ input_manager_process_mouse_wheel(struct input_manager *im,
.vscroll = event->y,
};
im->mp->ops->process_mouse_scroll(im->mp, &evt);
im->mp->ops->process_mouse_wheel(im->mp, event);
}
bool

View File

@ -12,13 +12,20 @@
/** Downcast key processor to sc_keyboard_inject */
#define DOWNCAST(KP) container_of(KP, struct sc_keyboard_inject, key_processor)
static enum android_keyevent_action
convert_keycode_action(enum sc_action action) {
if (action == SC_ACTION_DOWN) {
return AKEY_EVENT_ACTION_DOWN;
static bool
convert_keycode_action(enum sc_action from, enum android_keyevent_action *to) {
static const struct sc_intmap_entry actions[] = {
{SC_ACTION_DOWN, AKEY_EVENT_ACTION_DOWN},
{SC_ACTION_UP, AKEY_EVENT_ACTION_UP},
};
const struct sc_intmap_entry *entry = SC_INTMAP_FIND_ENTRY(actions, from);
if (entry) {
*to = entry->value;
return true;
}
assert(action == SC_ACTION_UP);
return AKEY_EVENT_ACTION_UP;
return false;
}
static bool
@ -250,12 +257,15 @@ convert_input_key(const struct sc_key_event *event, struct control_msg *msg,
enum sc_key_inject_mode key_inject_mode, uint32_t repeat) {
msg->type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
if (!convert_keycode_action(event->action, &msg->inject_keycode.action)) {
return false;
}
if (!convert_keycode(event->keycode, &msg->inject_keycode.keycode,
event->mods_state, key_inject_mode)) {
return false;
}
msg->inject_keycode.action = convert_keycode_action(event->action);
msg->inject_keycode.repeat = repeat;
msg->inject_keycode.metastate = convert_meta_state(event->mods_state);

View File

@ -1,11 +1,11 @@
#include "mouse_inject.h"
#include <assert.h>
#include <SDL2/SDL_events.h>
#include "android/input.h"
#include "control_msg.h"
#include "controller.h"
#include "input_events.h"
#include "util/intmap.h"
#include "util/log.h"
@ -15,138 +15,209 @@
static enum android_motionevent_buttons
convert_mouse_buttons(uint32_t state) {
enum android_motionevent_buttons buttons = 0;
if (state & SC_MOUSE_BUTTON_LEFT) {
if (state & SDL_BUTTON_LMASK) {
buttons |= AMOTION_EVENT_BUTTON_PRIMARY;
}
if (state & SC_MOUSE_BUTTON_RIGHT) {
if (state & SDL_BUTTON_RMASK) {
buttons |= AMOTION_EVENT_BUTTON_SECONDARY;
}
if (state & SC_MOUSE_BUTTON_MIDDLE) {
if (state & SDL_BUTTON_MMASK) {
buttons |= AMOTION_EVENT_BUTTON_TERTIARY;
}
if (state & SC_MOUSE_BUTTON_X1) {
if (state & SDL_BUTTON_X1MASK) {
buttons |= AMOTION_EVENT_BUTTON_BACK;
}
if (state & SC_MOUSE_BUTTON_X2) {
if (state & SDL_BUTTON_X2MASK) {
buttons |= AMOTION_EVENT_BUTTON_FORWARD;
}
return buttons;
}
static enum android_motionevent_action
convert_mouse_action(enum sc_action action) {
if (action == SC_ACTION_DOWN) {
return AMOTION_EVENT_ACTION_DOWN;
static bool
convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) {
static const struct sc_intmap_entry actions[] = {
{SDL_MOUSEBUTTONDOWN, AMOTION_EVENT_ACTION_DOWN},
{SDL_MOUSEBUTTONUP, AMOTION_EVENT_ACTION_UP},
};
const struct sc_intmap_entry *entry = SC_INTMAP_FIND_ENTRY(actions, from);
if (entry) {
*to = entry->value;
return true;
}
assert(action == SC_ACTION_UP);
return AMOTION_EVENT_ACTION_UP;
return false;
}
static enum android_motionevent_action
convert_touch_action(enum sc_touch_action action) {
switch (action) {
case SC_TOUCH_ACTION_MOVE:
return AMOTION_EVENT_ACTION_MOVE;
case SC_TOUCH_ACTION_DOWN:
return AMOTION_EVENT_ACTION_DOWN;
default:
assert(action == SC_TOUCH_ACTION_UP);
return AMOTION_EVENT_ACTION_UP;
static bool
convert_touch_action(SDL_EventType from, enum android_motionevent_action *to) {
static const struct sc_intmap_entry actions[] = {
{SDL_FINGERMOTION, AMOTION_EVENT_ACTION_MOVE},
{SDL_FINGERDOWN, AMOTION_EVENT_ACTION_DOWN},
{SDL_FINGERUP, AMOTION_EVENT_ACTION_UP},
};
const struct sc_intmap_entry *entry = SC_INTMAP_FIND_ENTRY(actions, from);
if (entry) {
*to = entry->value;
return true;
}
return false;
}
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 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;
}
static void
sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
const struct sc_mouse_motion_event *event) {
const SDL_MouseMotionEvent *event) {
struct sc_mouse_inject *mi = DOWNCAST(mp);
struct control_msg msg = {
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
.inject_touch_event = {
.action = AMOTION_EVENT_ACTION_MOVE,
.pointer_id = POINTER_ID_MOUSE,
.position = event->position,
.pressure = 1.f,
.buttons = convert_mouse_buttons(event->buttons_state),
},
};
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_mouse_click(struct sc_mouse_processor *mp,
const struct sc_mouse_click_event *event) {
struct sc_mouse_inject *mi = DOWNCAST(mp);
struct control_msg msg = {
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
.inject_touch_event = {
.action = convert_mouse_action(event->action),
.pointer_id = POINTER_ID_MOUSE,
.position = event->position,
.pressure = event->action == SC_ACTION_DOWN ? 1.f : 0.f,
.buttons = convert_mouse_buttons(event->buttons_state),
},
};
if (!controller_push_msg(mi->controller, &msg)) {
LOGW("Could not request 'inject mouse click event'");
}
}
static void
sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
const struct sc_mouse_scroll_event *event) {
struct sc_mouse_inject *mi = DOWNCAST(mp);
struct control_msg msg = {
.type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
.inject_scroll_event = {
.position = event->position,
.hscroll = event->hscroll,
.vscroll = event->vscroll,
},
};
if (!controller_push_msg(mi->controller, &msg)) {
LOGW("Could not request 'inject mouse scroll event'");
}
}
static void
sc_mouse_processor_process_touch(struct sc_mouse_processor *mp,
const struct sc_touch_event *event) {
const SDL_TouchFingerEvent *event) {
struct sc_mouse_inject *mi = DOWNCAST(mp);
struct control_msg msg = {
.type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT,
.inject_touch_event = {
.action = convert_touch_action(event->action),
.pointer_id = event->pointer_id,
.position = event->position,
.pressure = event->pressure,
.buttons = 0,
},
};
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'");
}
}
}
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) {
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_mouse_click = sc_mouse_processor_process_mouse_click,
.process_mouse_scroll = sc_mouse_processor_process_mouse_scroll,
.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;

View File

@ -13,9 +13,11 @@ 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);
sc_mouse_inject_init(struct sc_mouse_inject *mi, struct controller *controller,
struct screen *screen);
#endif

View File

@ -20,7 +20,6 @@
#include "input_manager.h"
#ifdef HAVE_AOA_HID
# include "hid_keyboard.h"
# include "hid_mouse.h"
#endif
#include "keyboard_inject.h"
#include "mouse_inject.h"
@ -57,12 +56,7 @@ struct scrcpy {
struct sc_hid_keyboard keyboard_hid;
#endif
};
union {
struct sc_mouse_inject mouse_inject;
#ifdef HAVE_AOA_HID
struct sc_hid_mouse mouse_hid;
#endif
};
struct sc_mouse_inject mouse_inject;
struct input_manager input_manager;
};
@ -587,9 +581,8 @@ aoa_hid_end:
kp = &s->keyboard_inject.key_processor;
}
//sc_mouse_inject_init(&s->mouse_inject, &s->controller);
sc_hid_mouse_init(&s->mouse_hid, &s->aoa);
mp = &s->mouse_hid.mouse_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, mp,

View File

@ -485,10 +485,6 @@ screen_init(struct screen *screen, const struct screen_params *params) {
SDL_AddEventWatch(event_watcher, screen);
#endif
if (SDL_SetRelativeMouseMode(true)) {
LOGE("Could not set relative mouse mode: %s", SDL_GetError());
}
static const struct sc_frame_sink_ops ops = {
.open = screen_frame_sink_open,
.close = screen_frame_sink_close,

View File

@ -29,24 +29,17 @@ struct sc_key_processor {
struct sc_key_processor_ops {
/**
* Process a keyboard event
* Process the keyboard event
*
* The `sequence` number (if different from `SC_SEQUENCE_INVALID`) indicates
* the acknowledgement number to wait for before injecting this event.
* This allows to ensure that the device clipboard is set before injecting
* Ctrl+v on the device.
*
* This function is mandatory.
*/
void
(*process_key)(struct sc_key_processor *kp,
const struct sc_key_event *event, uint64_t ack_to_wait);
/**
* Process an input text
*
* This function is optional.
*/
void
(*process_text)(struct sc_key_processor *kp,
const struct sc_text_event *event);

View File

@ -6,7 +6,7 @@
#include <assert.h>
#include <stdbool.h>
#include "input_events.h"
#include <SDL2/SDL_events.h>
/**
* Mouse processor trait.
@ -19,41 +19,21 @@ struct sc_mouse_processor {
};
struct sc_mouse_processor_ops {
/**
* Process a mouse motion event
*
* This function is mandatory.
*/
void
(*process_mouse_motion)(struct sc_mouse_processor *mp,
const struct sc_mouse_motion_event *event);
const SDL_MouseMotionEvent *event);
/**
* Process a mouse click event
*
* This function is mandatory.
*/
void
(*process_mouse_click)(struct sc_mouse_processor *mp,
const struct sc_mouse_click_event *event);
/**
* Process a mouse scroll event
*
* This function is optional.
*/
void
(*process_mouse_scroll)(struct sc_mouse_processor *mp,
const struct sc_mouse_scroll_event *event);
/**
* Process a touch event
*
* This function is optional.
*/
void
(*process_touch)(struct sc_mouse_processor *mp,
const struct sc_touch_event *event);
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