Compare commits
8 Commits
hidmouse.1
...
input_even
Author | SHA1 | Date | |
---|---|---|---|
b26ad41da7 | |||
bc84a130a4 | |||
3c663e1c0f | |||
05ef36545c | |||
ac32280a43 | |||
93c49ae446 | |||
15d40b6d16 | |||
c520d9f0e7 |
@ -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
|
||||
|
||||
|
@ -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)))
|
||||
|
@ -119,8 +119,7 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) {
|
||||
(uint32_t) msg->inject_scroll_event.hscroll);
|
||||
buffer_write32be(&buf[17],
|
||||
(uint32_t) msg->inject_scroll_event.vscroll);
|
||||
buffer_write32be(&buf[21], msg->inject_scroll_event.buttons);
|
||||
return 25;
|
||||
return 21;
|
||||
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
||||
buf[1] = msg->inject_keycode.action;
|
||||
return 2;
|
||||
@ -193,12 +192,11 @@ control_msg_log(const struct control_msg *msg) {
|
||||
}
|
||||
case CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT:
|
||||
LOG_CMSG("scroll position=%" PRIi32 ",%" PRIi32 " hscroll=%" PRIi32
|
||||
" vscroll=%" PRIi32 " buttons=%06lx",
|
||||
" vscroll=%" PRIi32,
|
||||
msg->inject_scroll_event.position.point.x,
|
||||
msg->inject_scroll_event.position.point.y,
|
||||
msg->inject_scroll_event.hscroll,
|
||||
msg->inject_scroll_event.vscroll,
|
||||
(long) msg->inject_scroll_event.buttons);
|
||||
msg->inject_scroll_event.vscroll);
|
||||
break;
|
||||
case CONTROL_MSG_TYPE_BACK_OR_SCREEN_ON:
|
||||
LOG_CMSG("back-or-screen-on %s",
|
||||
|
@ -70,7 +70,6 @@ struct control_msg {
|
||||
struct sc_position position;
|
||||
int32_t hscroll;
|
||||
int32_t vscroll;
|
||||
enum android_motionevent_buttons buttons;
|
||||
} inject_scroll_event;
|
||||
struct {
|
||||
enum android_keyevent_action action; // action for the BACK key
|
||||
|
@ -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
|
||||
|
@ -1,267 +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 (5)
|
||||
0x29, 0x05,
|
||||
// Logical Minimum (0)
|
||||
0x15, 0x00,
|
||||
// Logical Maximum (1)
|
||||
0x25, 0x01,
|
||||
// Report Count (5)
|
||||
0x95, 0x05,
|
||||
// Report Size (1)
|
||||
0x75, 0x01,
|
||||
// Input (Data, Variable, Absolute): 5 buttons bits
|
||||
0x81, 0x02,
|
||||
|
||||
// Report Count (1)
|
||||
0x95, 0x01,
|
||||
// Report Size (3)
|
||||
0x75, 0x03,
|
||||
// Input (Constant): 3 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 . . . . .| buttons state
|
||||
* +---------------+
|
||||
* ^ ^ ^ ^ ^
|
||||
* | | | | `- left button
|
||||
* | | | `--- right button
|
||||
* | | `----- middle button
|
||||
* | `------- button 4
|
||||
* `--------- button 5
|
||||
*
|
||||
* +---------------+
|
||||
* 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;
|
||||
}
|
||||
if (buttons_state & SC_MOUSE_BUTTON_X1) {
|
||||
c |= 1 << 3;
|
||||
}
|
||||
if (buttons_state & SC_MOUSE_BUTTON_X2) {
|
||||
c |= 1 << 4;
|
||||
}
|
||||
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;
|
||||
|
||||
mouse->mouse_processor.relative_mode = true;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
@ -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
76
app/src/input_events.c
Normal 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;
|
||||
}
|
@ -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 {
|
||||
@ -361,7 +333,6 @@ struct sc_mouse_scroll_event {
|
||||
struct sc_position position;
|
||||
int32_t hscroll;
|
||||
int32_t vscroll;
|
||||
uint8_t buttons_state; // bitwise-OR of sc_mouse_button values
|
||||
};
|
||||
|
||||
struct sc_mouse_motion_event {
|
||||
@ -371,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;
|
||||
@ -378,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
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include <SDL2/SDL_keycode.h>
|
||||
|
||||
#include "input_events.h"
|
||||
#include "screen.h"
|
||||
#include "util/log.h"
|
||||
|
||||
static inline uint16_t
|
||||
@ -64,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
|
||||
@ -122,22 +136,24 @@ is_shortcut_mod(struct input_manager *im, uint16_t sdl_mod) {
|
||||
}
|
||||
|
||||
void
|
||||
input_manager_init(struct input_manager *im,
|
||||
const struct input_manager_params *params) {
|
||||
assert(!params->control || (params->kp && params->kp->ops));
|
||||
assert(!params->control || (params->mp && params->mp->ops));
|
||||
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 = params->controller;
|
||||
im->screen = params->screen;
|
||||
im->kp = params->kp;
|
||||
im->mp = params->mp;
|
||||
im->controller = controller;
|
||||
im->screen = screen;
|
||||
im->kp = kp;
|
||||
im->mp = mp;
|
||||
|
||||
im->control = params->control;
|
||||
im->forward_all_clicks = params->forward_all_clicks;
|
||||
im->legacy_paste = params->legacy_paste;
|
||||
im->clipboard_autosync = params->clipboard_autosync;
|
||||
im->control = options->control;
|
||||
im->forward_all_clicks = options->forward_all_clicks;
|
||||
im->legacy_paste = options->legacy_paste;
|
||||
im->clipboard_autosync = options->clipboard_autosync;
|
||||
|
||||
const struct sc_shortcut_mods *shortcut_mods = params->shortcut_mods;
|
||||
const struct sc_shortcut_mods *shortcut_mods = &options->shortcut_mods;
|
||||
assert(shortcut_mods->count);
|
||||
assert(shortcut_mods->count < SC_MAX_SHORTCUT_MODS);
|
||||
for (unsigned i = 0; i < shortcut_mods->count; ++i) {
|
||||
@ -158,72 +174,85 @@ input_manager_init(struct input_manager *im,
|
||||
|
||||
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'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,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;
|
||||
@ -626,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;
|
||||
@ -655,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 =
|
||||
@ -675,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);
|
||||
@ -698,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
|
||||
@ -768,19 +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);
|
||||
|
||||
if (im->mp->relative_mode) {
|
||||
assert(!im->vfinger_down); // vfinger must not be used in relative mode
|
||||
// No pinch-to-zoom simulation
|
||||
return;
|
||||
}
|
||||
im->mp->ops->process_mouse_button(im->mp, event);
|
||||
|
||||
// Pinch-to-zoom simulation.
|
||||
//
|
||||
@ -811,15 +816,10 @@ 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;
|
||||
uint32_t buttons = SDL_GetMouseState(&mouse_x, &mouse_y);
|
||||
SDL_GetMouseState(&mouse_x, &mouse_y);
|
||||
|
||||
struct sc_mouse_scroll_event evt = {
|
||||
.position = {
|
||||
@ -829,11 +829,9 @@ input_manager_process_mouse_wheel(struct input_manager *im,
|
||||
},
|
||||
.hscroll = event->x,
|
||||
.vscroll = event->y,
|
||||
.buttons_state =
|
||||
sc_mouse_buttons_state_from_sdl(buttons, im->forward_all_clicks),
|
||||
};
|
||||
|
||||
im->mp->ops->process_mouse_scroll(im->mp, &evt);
|
||||
im->mp->ops->process_mouse_wheel(im->mp, event);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -10,11 +10,10 @@
|
||||
#include "controller.h"
|
||||
#include "fps_counter.h"
|
||||
#include "options.h"
|
||||
#include "screen.h"
|
||||
#include "trait/key_processor.h"
|
||||
#include "trait/mouse_processor.h"
|
||||
|
||||
struct screen; // forward declaration to avoid cycle
|
||||
|
||||
struct input_manager {
|
||||
struct controller *controller;
|
||||
struct screen *screen;
|
||||
@ -44,22 +43,11 @@ struct input_manager {
|
||||
uint64_t next_sequence; // used for request acknowledgements
|
||||
};
|
||||
|
||||
struct input_manager_params {
|
||||
struct controller *controller;
|
||||
struct screen *screen;
|
||||
struct sc_key_processor *kp;
|
||||
struct sc_mouse_processor *mp;
|
||||
|
||||
bool control;
|
||||
bool forward_all_clicks;
|
||||
bool legacy_paste;
|
||||
bool clipboard_autosync;
|
||||
const struct sc_shortcut_mods *shortcut_mods;
|
||||
};
|
||||
|
||||
void
|
||||
input_manager_init(struct input_manager *im,
|
||||
const struct input_manager_params *params);
|
||||
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
|
||||
input_manager_handle_event(struct input_manager *im, SDL_Event *event);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,142 +15,210 @@
|
||||
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,
|
||||
.buttons = convert_mouse_buttons(event->buttons_state),
|
||||
},
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
mi->mouse_processor.relative_mode = false;
|
||||
}
|
||||
|
@ -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
|
||||
|
131
app/src/scrcpy.c
131
app/src/scrcpy.c
@ -17,9 +17,9 @@
|
||||
#include "decoder.h"
|
||||
#include "events.h"
|
||||
#include "file_handler.h"
|
||||
#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"
|
||||
@ -56,12 +56,8 @@ 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;
|
||||
};
|
||||
|
||||
static inline void
|
||||
@ -193,6 +189,11 @@ handle_event(struct scrcpy *s, const struct scrcpy_options *options,
|
||||
}
|
||||
|
||||
bool consumed = screen_handle_event(&s->screen, event);
|
||||
if (consumed) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
consumed = input_manager_handle_event(&s->input_manager, event);
|
||||
(void) consumed;
|
||||
|
||||
end:
|
||||
@ -449,9 +450,6 @@ scrcpy(struct scrcpy_options *options) {
|
||||
stream_add_sink(&s->stream, &rec->packet_sink);
|
||||
}
|
||||
|
||||
struct sc_key_processor *kp = NULL;
|
||||
struct sc_mouse_processor *mp = NULL;
|
||||
|
||||
if (options->control) {
|
||||
#ifdef HAVE_AOA_HID
|
||||
if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID) {
|
||||
@ -483,7 +481,59 @@ scrcpy(struct scrcpy_options *options) {
|
||||
LOGW("Could not request 'set screen power mode'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options->display) {
|
||||
const char *window_title =
|
||||
options->window_title ? options->window_title : info->device_name;
|
||||
|
||||
struct screen_params screen_params = {
|
||||
.window_title = window_title,
|
||||
.frame_size = info->frame_size,
|
||||
.always_on_top = options->always_on_top,
|
||||
.window_x = options->window_x,
|
||||
.window_y = options->window_y,
|
||||
.window_width = options->window_width,
|
||||
.window_height = options->window_height,
|
||||
.window_borderless = options->window_borderless,
|
||||
.rotation = options->rotation,
|
||||
.mipmaps = options->mipmaps,
|
||||
.fullscreen = options->fullscreen,
|
||||
.buffering_time = options->display_buffer,
|
||||
};
|
||||
|
||||
if (!screen_init(&s->screen, &screen_params)) {
|
||||
goto end;
|
||||
}
|
||||
screen_initialized = true;
|
||||
|
||||
decoder_add_sink(&s->decoder, &s->screen.frame_sink);
|
||||
}
|
||||
|
||||
#ifdef HAVE_V4L2
|
||||
if (options->v4l2_device) {
|
||||
if (!sc_v4l2_sink_init(&s->v4l2_sink, options->v4l2_device,
|
||||
info->frame_size, options->v4l2_buffer)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
decoder_add_sink(&s->decoder, &s->v4l2_sink.frame_sink);
|
||||
|
||||
v4l2_sink_initialized = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// now we consumed the header values, the socket receives the video stream
|
||||
// start the stream
|
||||
if (!stream_start(&s->stream)) {
|
||||
goto end;
|
||||
}
|
||||
stream_started = true;
|
||||
|
||||
struct sc_key_processor *kp = NULL;
|
||||
struct sc_mouse_processor *mp = NULL;
|
||||
|
||||
if (options->control) {
|
||||
if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID) {
|
||||
#ifdef HAVE_AOA_HID
|
||||
bool aoa_hid_ok = false;
|
||||
@ -531,65 +581,12 @@ 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;
|
||||
}
|
||||
|
||||
if (options->display) {
|
||||
const char *window_title =
|
||||
options->window_title ? options->window_title : info->device_name;
|
||||
|
||||
struct screen_params screen_params = {
|
||||
.controller = &s->controller,
|
||||
.kp = kp,
|
||||
.mp = mp,
|
||||
.control = options->control,
|
||||
.forward_all_clicks = options->forward_all_clicks,
|
||||
.legacy_paste = options->legacy_paste,
|
||||
.clipboard_autosync = options->clipboard_autosync,
|
||||
.shortcut_mods = &options->shortcut_mods,
|
||||
.window_title = window_title,
|
||||
.frame_size = info->frame_size,
|
||||
.always_on_top = options->always_on_top,
|
||||
.window_x = options->window_x,
|
||||
.window_y = options->window_y,
|
||||
.window_width = options->window_width,
|
||||
.window_height = options->window_height,
|
||||
.window_borderless = options->window_borderless,
|
||||
.rotation = options->rotation,
|
||||
.mipmaps = options->mipmaps,
|
||||
.fullscreen = options->fullscreen,
|
||||
.buffering_time = options->display_buffer,
|
||||
};
|
||||
|
||||
if (!screen_init(&s->screen, &screen_params)) {
|
||||
goto end;
|
||||
}
|
||||
screen_initialized = true;
|
||||
|
||||
decoder_add_sink(&s->decoder, &s->screen.frame_sink);
|
||||
}
|
||||
|
||||
#ifdef HAVE_V4L2
|
||||
if (options->v4l2_device) {
|
||||
if (!sc_v4l2_sink_init(&s->v4l2_sink, options->v4l2_device,
|
||||
info->frame_size, options->v4l2_buffer)) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
decoder_add_sink(&s->decoder, &s->v4l2_sink.frame_sink);
|
||||
|
||||
v4l2_sink_initialized = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// now we consumed the header values, the socket receives the video stream
|
||||
// start the stream
|
||||
if (!stream_start(&s->stream)) {
|
||||
goto end;
|
||||
}
|
||||
stream_started = true;
|
||||
input_manager_init(&s->input_manager, &s->controller, &s->screen, kp, mp,
|
||||
options);
|
||||
|
||||
ret = event_loop(s, options);
|
||||
LOGD("quit...");
|
||||
|
@ -156,17 +156,6 @@ get_initial_optimal_size(struct sc_size content_size, uint16_t req_width,
|
||||
return window_size;
|
||||
}
|
||||
|
||||
static inline void
|
||||
screen_capture_mouse(struct screen *screen, bool capture) {
|
||||
if (SDL_SetRelativeMouseMode(capture)) {
|
||||
LOGE("Could not set relative mouse mode to %s: %s",
|
||||
capture ? "true" : "false", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
screen->mouse_captured = capture;
|
||||
}
|
||||
|
||||
static void
|
||||
screen_update_content_rect(struct screen *screen) {
|
||||
int dw;
|
||||
@ -365,8 +354,6 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
||||
screen->fullscreen = false;
|
||||
screen->maximized = false;
|
||||
screen->event_failed = false;
|
||||
screen->mouse_captured = false;
|
||||
screen->mouse_capture_key_pressed = 0;
|
||||
|
||||
static const struct sc_video_buffer_callbacks cbs = {
|
||||
.on_new_frame = sc_video_buffer_on_new_frame,
|
||||
@ -483,20 +470,6 @@ screen_init(struct screen *screen, const struct screen_params *params) {
|
||||
goto error_destroy_texture;
|
||||
}
|
||||
|
||||
struct input_manager_params im_params = {
|
||||
.controller = params->controller,
|
||||
.screen = screen,
|
||||
.kp = params->kp,
|
||||
.mp = params->mp,
|
||||
.control = params->control,
|
||||
.forward_all_clicks = params->forward_all_clicks,
|
||||
.legacy_paste = params->legacy_paste,
|
||||
.clipboard_autosync = params->clipboard_autosync,
|
||||
.shortcut_mods = params->shortcut_mods,
|
||||
};
|
||||
|
||||
input_manager_init(&screen->im, &im_params);
|
||||
|
||||
// Reset the window size to trigger a SIZE_CHANGED event, to workaround
|
||||
// HiDPI issues with some SDL renderers when several displays having
|
||||
// different HiDPI scaling are connected
|
||||
@ -754,11 +727,6 @@ screen_resize_to_pixel_perfect(struct screen *screen) {
|
||||
content_size.height);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
screen_is_mouse_capture_key(SDL_Keycode key) {
|
||||
return key == SDLK_LALT || key == SDLK_LGUI || key == SDLK_RGUI;
|
||||
}
|
||||
|
||||
bool
|
||||
screen_handle_event(struct screen *screen, SDL_Event *event) {
|
||||
switch (event->type) {
|
||||
@ -801,71 +769,11 @@ screen_handle_event(struct screen *screen, SDL_Event *event) {
|
||||
apply_pending_resize(screen);
|
||||
screen_render(screen, true);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
if (screen->im.mp->relative_mode) {
|
||||
screen_capture_mouse(screen, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
case SDL_KEYDOWN:
|
||||
if (screen->im.mp->relative_mode) {
|
||||
SDL_Keycode key = event->key.keysym.sym;
|
||||
if (screen_is_mouse_capture_key(key)) {
|
||||
if (!screen->mouse_capture_key_pressed) {
|
||||
screen->mouse_capture_key_pressed = key;
|
||||
return true;
|
||||
} else {
|
||||
// Another mouse capture key has been pressed, cancel
|
||||
// mouse (un)capture
|
||||
screen->mouse_capture_key_pressed = 0;
|
||||
// Do not return, the event must be forwarded to the
|
||||
// input manager
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
if (screen->im.mp->relative_mode) {
|
||||
SDL_Keycode key = event->key.keysym.sym;
|
||||
SDL_Keycode cap = screen->mouse_capture_key_pressed;
|
||||
screen->mouse_capture_key_pressed = 0;
|
||||
if (key == cap) {
|
||||
// A mouse capture key has been pressed then released:
|
||||
// toggle the capture mouse mode
|
||||
screen_capture_mouse(screen, !screen->mouse_captured);
|
||||
return true;
|
||||
}
|
||||
// Do not return, the event must be forwarded to the input
|
||||
// manager
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
case SDL_MOUSEMOTION:
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (screen->im.mp->relative_mode && !screen->mouse_captured) {
|
||||
// Do not forward to input manager, the mouse will be captured
|
||||
// on SDL_MOUSEBUTTONUP
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SDL_FINGERMOTION:
|
||||
case SDL_FINGERDOWN:
|
||||
case SDL_FINGERUP:
|
||||
if (screen->im.mp->relative_mode) {
|
||||
// Touch events are not compatible with relative mode
|
||||
// (coordinates are not relative)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (screen->im.mp->relative_mode && !screen->mouse_captured) {
|
||||
screen_capture_mouse(screen, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return input_manager_handle_event(&screen->im, event);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sc_point
|
||||
|
@ -7,14 +7,10 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include "controller.h"
|
||||
#include "coords.h"
|
||||
#include "fps_counter.h"
|
||||
#include "input_manager.h"
|
||||
#include "opengl.h"
|
||||
#include "trait/key_processor.h"
|
||||
#include "trait/frame_sink.h"
|
||||
#include "trait/mouse_processor.h"
|
||||
#include "video_buffer.h"
|
||||
|
||||
struct screen {
|
||||
@ -24,7 +20,6 @@ struct screen {
|
||||
bool open; // track the open/close state to assert correct behavior
|
||||
#endif
|
||||
|
||||
struct input_manager im;
|
||||
struct sc_video_buffer vb;
|
||||
struct fps_counter fps_counter;
|
||||
|
||||
@ -51,25 +46,10 @@ struct screen {
|
||||
|
||||
bool event_failed; // in case SDL_PushEvent() returned an error
|
||||
|
||||
bool mouse_captured; // only relevant in relative mouse mode
|
||||
// To enable/disable mouse capture, a mouse capture key (LALT, LGUI or
|
||||
// RGUI) must be pressed. This variable tracks the pressed capture key.
|
||||
SDL_Keycode mouse_capture_key_pressed;
|
||||
|
||||
AVFrame *frame;
|
||||
};
|
||||
|
||||
struct screen_params {
|
||||
struct controller *controller;
|
||||
struct sc_key_processor *kp;
|
||||
struct sc_mouse_processor *mp;
|
||||
|
||||
bool control;
|
||||
bool forward_all_clicks;
|
||||
bool legacy_paste;
|
||||
bool clipboard_autosync;
|
||||
const struct sc_shortcut_mods *shortcut_mods;
|
||||
|
||||
const char *window_title;
|
||||
struct sc_size frame_size;
|
||||
bool always_on_top;
|
||||
|
@ -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);
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "input_events.h"
|
||||
#include <SDL2/SDL_events.h>
|
||||
|
||||
/**
|
||||
* Mouse processor trait.
|
||||
@ -16,51 +16,24 @@
|
||||
*/
|
||||
struct sc_mouse_processor {
|
||||
const struct sc_mouse_processor_ops *ops;
|
||||
|
||||
/**
|
||||
* If set, the mouse processor works in relative mode (the absolute
|
||||
* position is irrelevant). In particular, it indicates that the mouse
|
||||
* pointer must be "captured" by the UI.
|
||||
*/
|
||||
bool relative_mode;
|
||||
};
|
||||
|
||||
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
|
||||
|
@ -11,7 +11,6 @@ static void test_get_ip_single_line() {
|
||||
char *ip = sc_adb_parse_device_ip_from_output(ip_route, sizeof(ip_route));
|
||||
assert(ip);
|
||||
assert(!strcmp(ip, "192.168.12.34"));
|
||||
free(ip);
|
||||
}
|
||||
|
||||
static void test_get_ip_single_line_without_eol() {
|
||||
@ -21,7 +20,6 @@ static void test_get_ip_single_line_without_eol() {
|
||||
char *ip = sc_adb_parse_device_ip_from_output(ip_route, sizeof(ip_route));
|
||||
assert(ip);
|
||||
assert(!strcmp(ip, "192.168.12.34"));
|
||||
free(ip);
|
||||
}
|
||||
|
||||
static void test_get_ip_single_line_with_trailing_space() {
|
||||
@ -31,7 +29,6 @@ static void test_get_ip_single_line_with_trailing_space() {
|
||||
char *ip = sc_adb_parse_device_ip_from_output(ip_route, sizeof(ip_route));
|
||||
assert(ip);
|
||||
assert(!strcmp(ip, "192.168.12.34"));
|
||||
free(ip);
|
||||
}
|
||||
|
||||
static void test_get_ip_multiline_first_ok() {
|
||||
@ -43,7 +40,6 @@ static void test_get_ip_multiline_first_ok() {
|
||||
char *ip = sc_adb_parse_device_ip_from_output(ip_route, sizeof(ip_route));
|
||||
assert(ip);
|
||||
assert(!strcmp(ip, "192.168.1.2"));
|
||||
free(ip);
|
||||
}
|
||||
|
||||
static void test_get_ip_multiline_second_ok() {
|
||||
@ -55,7 +51,6 @@ static void test_get_ip_multiline_second_ok() {
|
||||
char *ip = sc_adb_parse_device_ip_from_output(ip_route, sizeof(ip_route));
|
||||
assert(ip);
|
||||
assert(!strcmp(ip, "192.168.1.3"));
|
||||
free(ip);
|
||||
}
|
||||
|
||||
static void test_get_ip_no_wlan() {
|
||||
|
@ -126,13 +126,12 @@ static void test_serialize_inject_scroll_event(void) {
|
||||
},
|
||||
.hscroll = 1,
|
||||
.vscroll = -1,
|
||||
.buttons = 1,
|
||||
},
|
||||
};
|
||||
|
||||
unsigned char buf[CONTROL_MSG_MAX_SIZE];
|
||||
size_t size = control_msg_serialize(&msg, buf);
|
||||
assert(size == 25);
|
||||
assert(size == 21);
|
||||
|
||||
const unsigned char expected[] = {
|
||||
CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT,
|
||||
@ -140,7 +139,6 @@ static void test_serialize_inject_scroll_event(void) {
|
||||
0x04, 0x38, 0x07, 0x80, // 1080 1920
|
||||
0x00, 0x00, 0x00, 0x01, // 1
|
||||
0xFF, 0xFF, 0xFF, 0xFF, // -1
|
||||
0x00, 0x00, 0x00, 0x01, // 1
|
||||
};
|
||||
assert(!memcmp(buf, expected, sizeof(expected)));
|
||||
}
|
||||
|
@ -71,13 +71,12 @@ public final class ControlMessage {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static ControlMessage createInjectScrollEvent(Position position, int hScroll, int vScroll, int buttons) {
|
||||
public static ControlMessage createInjectScrollEvent(Position position, int hScroll, int vScroll) {
|
||||
ControlMessage msg = new ControlMessage();
|
||||
msg.type = TYPE_INJECT_SCROLL_EVENT;
|
||||
msg.position = position;
|
||||
msg.hScroll = hScroll;
|
||||
msg.vScroll = vScroll;
|
||||
msg.buttons = buttons;
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ public class ControlMessageReader {
|
||||
|
||||
static final int INJECT_KEYCODE_PAYLOAD_LENGTH = 13;
|
||||
static final int INJECT_TOUCH_EVENT_PAYLOAD_LENGTH = 27;
|
||||
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 24;
|
||||
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
|
||||
static final int BACK_OR_SCREEN_ON_LENGTH = 1;
|
||||
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
|
||||
static final int GET_CLIPBOARD_LENGTH = 1;
|
||||
@ -154,8 +154,7 @@ public class ControlMessageReader {
|
||||
Position position = readPosition(buffer);
|
||||
int hScroll = buffer.getInt();
|
||||
int vScroll = buffer.getInt();
|
||||
int buttons = buffer.getInt();
|
||||
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll, buttons);
|
||||
return ControlMessage.createInjectScrollEvent(position, hScroll, vScroll);
|
||||
}
|
||||
|
||||
private ControlMessage parseBackOrScreenOnEvent() {
|
||||
|
@ -98,7 +98,7 @@ public class Controller {
|
||||
break;
|
||||
case ControlMessage.TYPE_INJECT_SCROLL_EVENT:
|
||||
if (device.supportsInputEvents()) {
|
||||
injectScroll(msg.getPosition(), msg.getHScroll(), msg.getVScroll(), msg.getButtons());
|
||||
injectScroll(msg.getPosition(), msg.getHScroll(), msg.getVScroll());
|
||||
}
|
||||
break;
|
||||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||
@ -221,7 +221,7 @@ public class Controller {
|
||||
return device.injectEvent(event, Device.INJECT_MODE_ASYNC);
|
||||
}
|
||||
|
||||
private boolean injectScroll(Position position, int hScroll, int vScroll, int buttons) {
|
||||
private boolean injectScroll(Position position, int hScroll, int vScroll) {
|
||||
long now = SystemClock.uptimeMillis();
|
||||
Point point = device.getPhysicalPoint(position);
|
||||
if (point == null) {
|
||||
@ -239,7 +239,7 @@ public class Controller {
|
||||
coords.setAxisValue(MotionEvent.AXIS_VSCROLL, vScroll);
|
||||
|
||||
MotionEvent event = MotionEvent
|
||||
.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0,
|
||||
.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, 0, 1f, 1f, DEFAULT_DEVICE_ID, 0,
|
||||
InputDevice.SOURCE_MOUSE, 0);
|
||||
return device.injectEvent(event, Device.INJECT_MODE_ASYNC);
|
||||
}
|
||||
|
@ -128,7 +128,6 @@ public class ControlMessageReaderTest {
|
||||
dos.writeShort(1920);
|
||||
dos.writeInt(1);
|
||||
dos.writeInt(-1);
|
||||
dos.writeInt(1);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
@ -145,7 +144,6 @@ public class ControlMessageReaderTest {
|
||||
Assert.assertEquals(1920, event.getPosition().getScreenSize().getHeight());
|
||||
Assert.assertEquals(1, event.getHScroll());
|
||||
Assert.assertEquals(-1, event.getVScroll());
|
||||
Assert.assertEquals(1, event.getButtons());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Reference in New Issue
Block a user