Support USB HID over AoAv2 mode for keyboard input

This provides a better input experience via
simulate physical keyboard, it converts
SDL_KeyboardEvent to proper HID events and send it
via HID over AoAv2.

This is a rewriting and bugfix of the origin code
from [@amosbird](https://github.com/amosbird).

Make sdl_keymod_to_hid_modifiers() more readable

Support MOD keys in HID mode

Enable Ctrl+V on HID mode

Support to send media events from hid_keyboard

Use existing --serial to replace --usb

Use explict option for input mode

Move HID keyboard setup code into functions

Send HID events in separated thread

Let libusb handle max package size

Fix HID keyboard report desc
This commit is contained in:
Alynx Zhou
2021-09-10 18:57:35 +08:00
committed by Romain Vimont
parent a52779ae6b
commit 874a4967a4
11 changed files with 928 additions and 13 deletions

View File

@@ -18,6 +18,9 @@
#include "events.h"
#include "file_handler.h"
#include "input_manager.h"
#ifdef HAVE_AOA_HID
# include "hid_keyboard.h"
#endif
#include "keyboard_inject.h"
#include "mouse_inject.h"
#include "recorder.h"
@@ -42,7 +45,15 @@ struct scrcpy {
#endif
struct controller controller;
struct file_handler file_handler;
struct sc_keyboard_inject keyboard_inject;
#ifdef HAVE_AOA_HID
struct aoa aoa;
#endif
union {
struct sc_keyboard_inject keyboard_inject;
#ifdef HAVE_AOA_HID
struct hid_keyboard keyboard_hid;
#endif
};
struct sc_mouse_inject mouse_inject;
struct input_manager input_manager;
};
@@ -244,7 +255,7 @@ stream_on_eos(struct stream *stream, void *userdata) {
}
bool
scrcpy(const struct scrcpy_options *options) {
scrcpy(struct scrcpy_options *options) {
static struct scrcpy scrcpy;
struct scrcpy *s = &scrcpy;
@@ -261,6 +272,9 @@ scrcpy(const struct scrcpy_options *options) {
bool v4l2_sink_initialized = false;
#endif
bool stream_started = false;
#ifdef HAVE_AOA_HID
bool aoa_hid_initialized = false;
#endif
bool controller_initialized = false;
bool controller_started = false;
bool screen_initialized = false;
@@ -420,8 +434,51 @@ scrcpy(const struct scrcpy_options *options) {
struct sc_mouse_processor *mp = NULL;
if (options->control) {
sc_keyboard_inject_init(&s->keyboard_inject, &s->controller, options);
kp = &s->keyboard_inject.key_processor;
if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID) {
#ifdef HAVE_AOA_HID
bool aoa_hid_ok = false;
if (!aoa_init(&s->aoa, options->serial)) {
goto aoa_hid_end;
}
if (!aoa_start(&s->aoa)) {
aoa_destroy(&s->aoa);
goto aoa_hid_end;
}
if (!hid_keyboard_init(&s->keyboard_hid, &s->aoa)) {
aoa_join(&s->aoa);
aoa_stop(&s->aoa);
aoa_destroy(&s->aoa);
goto aoa_hid_end;
}
aoa_hid_ok = true;
kp = &s->keyboard_hid.key_processor;
aoa_hid_initialized = true;
aoa_hid_end:
if (!aoa_hid_ok) {
LOGE("Failed to enable HID over AOA, "
"fallback to default keyboard injection method "
"(-K/--keyboard-hid ignored)");
options->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_INJECT;
}
#else
LOGE("HID over AOA is not supported on this platform, "
"fallback to default keyboard injection method "
"(-K/--keyboard-hid ignored)");
options->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_INJECT;
#endif
}
// keyboard_input_mode may have been reset if HID mode failed
if (options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_INJECT) {
sc_keyboard_inject_init(&s->keyboard_inject, &s->controller,
options);
kp = &s->keyboard_inject.key_processor;
}
sc_mouse_inject_init(&s->mouse_inject, &s->controller, &s->screen);
mp = &s->mouse_inject.mouse_processor;
@@ -440,6 +497,12 @@ scrcpy(const struct scrcpy_options *options) {
end:
// The stream is not stopped explicitly, because it will stop by itself on
// end-of-stream
#ifdef HAVE_AOA_HID
if (aoa_hid_initialized) {
hid_keyboard_destroy(&s->keyboard_hid);
aoa_stop(&s->aoa);
}
#endif
if (controller_started) {
controller_stop(&s->controller);
}
@@ -467,6 +530,13 @@ end:
}
#endif
#ifdef HAVE_AOA_HID
if (aoa_hid_initialized) {
aoa_join(&s->aoa);
aoa_destroy(&s->aoa);
}
#endif
// Destroy the screen only after the stream is guaranteed to be finished,
// because otherwise the screen could receive new frames after destruction
if (screen_initialized) {