Extract mouse HID handling

Split the mouse implementation using AOA and the code handling HID
events, so that HID events can be reused for another protocol (UHID).
This commit is contained in:
Romain Vimont 2024-01-25 23:04:09 +01:00
parent c2784379f2
commit 61e59ca735
8 changed files with 169 additions and 118 deletions

View file

@ -32,6 +32,7 @@ src = [
'src/server.c',
'src/version.c',
'src/hid/hid_keyboard.c',
'src/hid/hid_mouse.c',
'src/trait/frame_source.c',
'src/trait/packet_source.c',
'src/util/acksync.c',
@ -90,7 +91,7 @@ if usb_support
src += [
'src/usb/aoa_hid.c',
'src/usb/keyboard_aoa.c',
'src/usb/hid_mouse.c',
'src/usb/mouse_aoa.c',
'src/usb/scrcpy_otg.c',
'src/usb/screen_otg.c',
'src/usb/usb.c',

View file

@ -1,15 +1,5 @@
#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,
// 1 byte for wheel motion
#define HID_MOUSE_EVENT_SIZE 4
@ -24,7 +14,7 @@
* <https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf>
* §4 Generic Desktop Page (0x01) (p26)
*/
static const unsigned char mouse_report_desc[] = {
const uint8_t SC_HID_MOUSE_REPORT_DESC[] = {
// Usage Page (Generic Desktop)
0x05, 0x01,
// Usage (Mouse)
@ -90,6 +80,9 @@ static const unsigned char mouse_report_desc[] = {
0xC0,
};
const size_t SC_HID_MOUSE_REPORT_DESC_LEN =
sizeof(SC_HID_MOUSE_REPORT_DESC);
/**
* A mouse HID event is 4 bytes long:
*
@ -138,9 +131,9 @@ sc_hid_mouse_event_init(struct sc_hid_event *hid_event) {
// callers
}
static unsigned char
buttons_state_to_hid_buttons(uint8_t buttons_state) {
unsigned char c = 0;
static uint8_t
sc_hid_buttons_from_buttons_state(uint8_t buttons_state) {
uint8_t c = 0;
if (buttons_state & SC_MOUSE_BUTTON_LEFT) {
c |= 1 << 0;
}
@ -159,55 +152,36 @@ buttons_state_to_hid_buttons(uint8_t buttons_state) {
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);
void
sc_hid_mouse_event_from_motion(struct sc_hid_event *hid_event,
const struct sc_mouse_motion_event *event) {
sc_hid_mouse_event_init(hid_event);
struct sc_hid_event hid_event;
sc_hid_mouse_event_init(&hid_event);
unsigned char *data = hid_event.data;
data[0] = buttons_state_to_hid_buttons(event->buttons_state);
uint8_t *data = hid_event->data;
data[0] = sc_hid_buttons_from_buttons_state(event->buttons_state);
data[1] = CLAMP(event->xrel, -127, 127);
data[2] = CLAMP(event->yrel, -127, 127);
data[3] = 0; // wheel coordinates only used for scrolling
if (!sc_aoa_push_hid_event(mouse->aoa, HID_MOUSE_ACCESSORY_ID,
&hid_event)) {
LOGW("Could not request HID event (mouse motion)");
}
}
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);
void
sc_hid_mouse_event_from_click(struct sc_hid_event *hid_event,
const struct sc_mouse_click_event *event) {
sc_hid_mouse_event_init(hid_event);
struct sc_hid_event hid_event;
sc_hid_mouse_event_init(&hid_event);
unsigned char *data = hid_event.data;
data[0] = buttons_state_to_hid_buttons(event->buttons_state);
uint8_t *data = hid_event->data;
data[0] = sc_hid_buttons_from_buttons_state(event->buttons_state);
data[1] = 0; // no x motion
data[2] = 0; // no y motion
data[3] = 0; // wheel coordinates only used for scrolling
if (!sc_aoa_push_hid_event(mouse->aoa, HID_MOUSE_ACCESSORY_ID,
&hid_event)) {
LOGW("Could not request HID event (mouse click)");
}
}
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);
void
sc_hid_mouse_event_from_scroll(struct sc_hid_event *hid_event,
const struct sc_mouse_scroll_event *event) {
sc_hid_mouse_event_init(hid_event);
struct sc_hid_event hid_event;
sc_hid_mouse_event_init(&hid_event);
unsigned char *data = hid_event.data;
uint8_t *data = hid_event->data;
data[0] = 0; // buttons state irrelevant (and unknown)
data[1] = 0; // no x motion
data[2] = 0; // no y motion
@ -215,43 +189,4 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
// are possible
data[3] = CLAMP(event->vscroll, -127, 127);
// Horizontal scrolling ignored
if (!sc_aoa_push_hid_event(mouse->aoa, HID_MOUSE_ACCESSORY_ID,
&hid_event)) {
LOGW("Could not request HID event (mouse scroll)");
}
}
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 mouse");
}
}

26
app/src/hid/hid_mouse.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef SC_HID_MOUSE_H
#define SC_HID_MOUSE_H
#endif
#include "common.h"
#include <stdbool.h>
#include "hid/hid_event.h"
#include "input_events.h"
extern const uint8_t SC_HID_MOUSE_REPORT_DESC[];
extern const size_t SC_HID_MOUSE_REPORT_DESC_LEN;
void
sc_hid_mouse_event_from_motion(struct sc_hid_event *hid_event,
const struct sc_mouse_motion_event *event);
void
sc_hid_mouse_event_from_click(struct sc_hid_event *hid_event,
const struct sc_mouse_click_event *event);
void
sc_hid_mouse_event_from_scroll(struct sc_hid_event *hid_event,
const struct sc_mouse_scroll_event *event);

View file

@ -28,7 +28,7 @@
#ifdef HAVE_USB
# include "usb/aoa_hid.h"
# include "usb/keyboard_aoa.h"
# include "usb/hid_mouse.h"
# include "usb/mouse_aoa.h"
# include "usb/usb.h"
#endif
#include "util/acksync.h"
@ -71,7 +71,7 @@ struct scrcpy {
union {
struct sc_mouse_inject mouse_inject;
#ifdef HAVE_USB
struct sc_hid_mouse mouse_hid;
struct sc_mouse_aoa mouse_aoa;
#endif
};
struct sc_timeout timeout;
@ -331,7 +331,7 @@ scrcpy(struct scrcpy_options *options) {
#ifdef HAVE_USB
bool aoa_hid_initialized = false;
bool keyboard_aoa_initialized = false;
bool hid_mouse_initialized = false;
bool mouse_aoa_initialized = false;
#endif
bool controller_initialized = false;
bool controller_started = false;
@ -545,9 +545,9 @@ scrcpy(struct scrcpy_options *options) {
#ifdef HAVE_USB
bool use_keyboard_aoa =
options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AOA;
bool use_aoa_mouse =
bool use_mouse_aoa =
options->mouse_input_mode == SC_MOUSE_INPUT_MODE_AOA;
if (use_keyboard_aoa || use_aoa_mouse) {
if (use_keyboard_aoa || use_mouse_aoa) {
bool ok = sc_acksync_init(&s->acksync);
if (!ok) {
goto end;
@ -599,16 +599,16 @@ scrcpy(struct scrcpy_options *options) {
}
}
if (use_aoa_mouse) {
if (sc_hid_mouse_init(&s->mouse_hid, &s->aoa)) {
hid_mouse_initialized = true;
mp = &s->mouse_hid.mouse_processor;
if (use_mouse_aoa) {
if (sc_mouse_aoa_init(&s->mouse_aoa, &s->aoa)) {
mouse_aoa_initialized = true;
mp = &s->mouse_aoa.mouse_processor;
} else {
LOGE("Could not initialized HID mouse");
}
}
bool need_aoa = keyboard_aoa_initialized || hid_mouse_initialized;
bool need_aoa = keyboard_aoa_initialized || mouse_aoa_initialized;
if (!need_aoa || !sc_aoa_start(&s->aoa)) {
sc_acksync_destroy(&s->acksync);
@ -628,9 +628,9 @@ aoa_hid_end:
sc_keyboard_aoa_destroy(&s->keyboard_aoa);
keyboard_aoa_initialized = false;
}
if (hid_mouse_initialized) {
sc_hid_mouse_destroy(&s->mouse_hid);
hid_mouse_initialized = false;
if (mouse_aoa_initialized) {
sc_mouse_aoa_destroy(&s->mouse_aoa);
mouse_aoa_initialized = false;
}
}
@ -639,7 +639,7 @@ aoa_hid_end:
options->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_SDK;
}
if (use_aoa_mouse && !hid_mouse_initialized) {
if (use_mouse_aoa && !mouse_aoa_initialized) {
LOGE("Fallback to --keyboard=sdk (--keyboard=aoa ignored)");
options->mouse_input_mode = SC_MOUSE_INPUT_MODE_SDK;
}
@ -816,8 +816,8 @@ end:
if (keyboard_aoa_initialized) {
sc_keyboard_aoa_destroy(&s->keyboard_aoa);
}
if (hid_mouse_initialized) {
sc_hid_mouse_destroy(&s->mouse_hid);
if (mouse_aoa_initialized) {
sc_mouse_aoa_destroy(&s->mouse_aoa);
}
sc_aoa_stop(&s->aoa);
sc_usb_stop(&s->usb);

89
app/src/usb/mouse_aoa.c Normal file
View file

@ -0,0 +1,89 @@
#include "mouse_aoa.h"
#include <assert.h>
#include "hid/hid_mouse.h"
#include "input_events.h"
#include "util/log.h"
/** Downcast mouse processor to mouse_aoa */
#define DOWNCAST(MP) container_of(MP, struct sc_mouse_aoa, mouse_processor)
#define HID_MOUSE_ACCESSORY_ID 2
static void
sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
const struct sc_mouse_motion_event *event) {
struct sc_mouse_aoa *mouse = DOWNCAST(mp);
struct sc_hid_event hid_event;
sc_hid_mouse_event_from_motion(&hid_event, event);
if (!sc_aoa_push_hid_event(mouse->aoa, HID_MOUSE_ACCESSORY_ID,
&hid_event)) {
LOGW("Could not request HID event (mouse motion)");
}
}
static void
sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
const struct sc_mouse_click_event *event) {
struct sc_mouse_aoa *mouse = DOWNCAST(mp);
struct sc_hid_event hid_event;
sc_hid_mouse_event_from_click(&hid_event, event);
if (!sc_aoa_push_hid_event(mouse->aoa, HID_MOUSE_ACCESSORY_ID,
&hid_event)) {
LOGW("Could not request HID event (mouse click)");
}
}
static void
sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
const struct sc_mouse_scroll_event *event) {
struct sc_mouse_aoa *mouse = DOWNCAST(mp);
struct sc_hid_event hid_event;
sc_hid_mouse_event_from_scroll(&hid_event, event);
if (!sc_aoa_push_hid_event(mouse->aoa, HID_MOUSE_ACCESSORY_ID,
&hid_event)) {
LOGW("Could not request HID event (mouse scroll)");
}
}
bool
sc_mouse_aoa_init(struct sc_mouse_aoa *mouse, struct sc_aoa *aoa) {
mouse->aoa = aoa;
bool ok = sc_aoa_setup_hid(aoa, HID_MOUSE_ACCESSORY_ID,
SC_HID_MOUSE_REPORT_DESC,
SC_HID_MOUSE_REPORT_DESC_LEN);
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_mouse_aoa_destroy(struct sc_mouse_aoa *mouse) {
bool ok = sc_aoa_unregister_hid(mouse->aoa, HID_MOUSE_ACCESSORY_ID);
if (!ok) {
LOGW("Could not unregister HID mouse");
}
}

View file

@ -1,5 +1,5 @@
#ifndef SC_HID_MOUSE_H
#define SC_HID_MOUSE_H
#ifndef SC_MOUSE_AOA_H
#define SC_MOUSE_AOA_H
#include "common.h"
@ -8,16 +8,16 @@
#include "aoa_hid.h"
#include "trait/mouse_processor.h"
struct sc_hid_mouse {
struct sc_mouse_aoa {
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);
sc_mouse_aoa_init(struct sc_mouse_aoa *mouse, struct sc_aoa *aoa);
void
sc_hid_mouse_destroy(struct sc_hid_mouse *mouse);
sc_mouse_aoa_destroy(struct sc_mouse_aoa *mouse);
#endif

View file

@ -11,7 +11,7 @@ struct scrcpy_otg {
struct sc_usb usb;
struct sc_aoa aoa;
struct sc_keyboard_aoa keyboard;
struct sc_hid_mouse mouse;
struct sc_mouse_aoa mouse;
struct sc_screen_otg screen_otg;
};
@ -74,7 +74,7 @@ scrcpy_otg(struct scrcpy_options *options) {
enum scrcpy_exit_code ret = SCRCPY_EXIT_FAILURE;
struct sc_keyboard_aoa *keyboard = NULL;
struct sc_hid_mouse *mouse = NULL;
struct sc_mouse_aoa *mouse = NULL;
bool usb_device_initialized = false;
bool usb_connected = false;
bool aoa_started = false;
@ -142,7 +142,7 @@ scrcpy_otg(struct scrcpy_options *options) {
}
if (enable_mouse) {
ok = sc_hid_mouse_init(&s->mouse, &s->aoa);
ok = sc_mouse_aoa_init(&s->mouse, &s->aoa);
if (!ok) {
goto end;
}
@ -191,7 +191,7 @@ end:
sc_usb_stop(&s->usb);
if (mouse) {
sc_hid_mouse_destroy(&s->mouse);
sc_mouse_aoa_destroy(&s->mouse);
}
if (keyboard) {
sc_keyboard_aoa_destroy(&s->keyboard);

View file

@ -7,11 +7,11 @@
#include <SDL2/SDL.h>
#include "keyboard_aoa.h"
#include "hid_mouse.h"
#include "mouse_aoa.h"
struct sc_screen_otg {
struct sc_keyboard_aoa *keyboard;
struct sc_hid_mouse *mouse;
struct sc_mouse_aoa *mouse;
SDL_Window *window;
SDL_Renderer *renderer;
@ -23,7 +23,7 @@ struct sc_screen_otg {
struct sc_screen_otg_params {
struct sc_keyboard_aoa *keyboard;
struct sc_hid_mouse *mouse;
struct sc_mouse_aoa *mouse;
const char *window_title;
bool always_on_top;