From 24efeace4b961ec7371d7ae7b107a59cc076d411 Mon Sep 17 00:00:00 2001 From: Simon Chan <1330321+yume-chan@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:17:35 +0800 Subject: [PATCH] Expose named input modes (wip) Replace: - -K/--hid-keyboard by --keyboard-input-mode - -M/--hid-mouse by --mouse-input-mode Each supports 3 possible values (for now): - disable - inject - aoa Signed-off-by: Romain Vimont --- app/data/bash-completion/scrcpy | 6 +- app/data/zsh-completion/_scrcpy | 2 +- app/src/cli.c | 157 ++++++++++++++++++++++++++++---- app/src/options.c | 4 +- app/src/options.h | 8 +- app/src/scrcpy.c | 22 ++--- app/src/usb/scrcpy_otg.c | 23 ++++- 7 files changed, 184 insertions(+), 38 deletions(-) diff --git a/app/data/bash-completion/scrcpy b/app/data/bash-completion/scrcpy index 78aa539d..138e040d 100644 --- a/app/data/bash-completion/scrcpy +++ b/app/data/bash-completion/scrcpy @@ -27,8 +27,8 @@ _scrcpy() { --force-adb-forward --forward-all-clicks -h --help + --keyboard-input-mode= --kill-adb-on-close - -K --hid-keyboard --legacy-paste --list-camera-sizes --list-cameras @@ -115,6 +115,10 @@ _scrcpy() { COMPREPLY=($(compgen -W 'front back external' -- "$cur")) return ;; + --keyboard-input-mode) + COMPREPLY=($(compgen -W 'inject aoa' -- "$cur")) + return + ;; --orientation|--display-orientation) COMPREPLY=($(compgen -W '0 90 180 270 flip0 flip90 flip180 flip270' -- "$cur")) return diff --git a/app/data/zsh-completion/_scrcpy b/app/data/zsh-completion/_scrcpy index 3c7ca217..7ffbd31a 100644 --- a/app/data/zsh-completion/_scrcpy +++ b/app/data/zsh-completion/_scrcpy @@ -34,8 +34,8 @@ arguments=( '--force-adb-forward[Do not attempt to use \"adb reverse\" to connect to the device]' '--forward-all-clicks[Forward clicks to device]' {-h,--help}'[Print the help]' + '--keyboard-input-mode=[Set the keyboard input mode]:mode:(inject aoa)' '--kill-adb-on-close[Kill adb when scrcpy terminates]' - {-K,--hid-keyboard}'[Simulate a physical keyboard by using HID over AOAv2]' '--legacy-paste[Inject computer clipboard text as a sequence of key events on Ctrl+v]' '--list-camera-sizes[List the valid camera capture sizes]' '--list-cameras[List cameras available on the device]' diff --git a/app/src/cli.c b/app/src/cli.c index f7d7e390..1f8bc304 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -93,6 +93,8 @@ enum { OPT_DISPLAY_ORIENTATION, OPT_RECORD_ORIENTATION, OPT_ORIENTATION, + OPT_KEYBOARD_INPUT_MODE, + OPT_MOUSE_INPUT_MODE, }; struct sc_option { @@ -359,14 +361,19 @@ static const struct sc_option options[] = { .text = "Print this help.", }, { - .longopt_id = OPT_KILL_ADB_ON_CLOSE, - .longopt = "kill-adb-on-close", - .text = "Kill adb when scrcpy terminates.", - }, - { - .shortopt = 'K', - .longopt = "hid-keyboard", - .text = "Simulate a physical keyboard by using HID over AOAv2.\n" + .longopt_id = OPT_KEYBOARD_INPUT_MODE, + .longopt = "keyboard-input-mode", + .argdesc = "value", + .text = "Select how to send keyboard inputs to the device.\n" + "Possible values are \"disable\", \"inject\" and \"aoa\".\n" + "\n" + "\"disable\" does not send keyboard inputs to the device.\n" + "\n" + "\"inject\" uses the Android system API to deliver keyboard\n" + "events to applications.\n" + "\n" + "\"aoa\" simulates a physical keyboard using the AOAv2\n" + "protocol. It may only work over USB.\n" "It provides a better experience for IME users, and allows to " "generate non-ASCII characters, contrary to the default " "injection method.\n" @@ -378,7 +385,19 @@ static const struct sc_option options[] = { "android.settings.HARD_KEYBOARD_SETTINGS`.\n" "However, the option is only available when the HID keyboard " "is enabled (or a physical keyboard is connected).\n" - "Also see --hid-mouse.", + "Also see --mouse-input-mode and --otg." + "\n" + "Default is \"inject\" (or \"aoa\" if --otg is set).", + }, + { + .longopt_id = OPT_KILL_ADB_ON_CLOSE, + .longopt = "kill-adb-on-close", + .text = "Kill adb when scrcpy terminates.", + }, + { + // deprecated + .shortopt = 'K', + .longopt = "hid-keyboard", }, { .longopt_id = OPT_LEGACY_PASTE, @@ -440,7 +459,7 @@ static const struct sc_option options[] = { "LAlt, LSuper or RSuper toggle the capture mode, to give " "control of the mouse back to the computer.\n" "It may only work over USB.\n" - "Also see --hid-keyboard.", + "Also see --keyboard-input-mode and --otg.", }, { .longopt_id = OPT_MAX_FPS, @@ -449,6 +468,26 @@ static const struct sc_option options[] = { .text = "Limit the frame rate of screen capture (officially supported " "since Android 10, but may work on earlier versions).", }, + { + .longopt_id = OPT_MOUSE_INPUT_MODE, + .longopt = "mouse-input-mode", + .argdesc = "value", + .text = "Select how to send mouse inputs to the device.\n" + "Possible values are \"disable\", \"inject\" and \"aoa\".\n" + "\n" + "\"disable\" does not send mouse inputs to the device.\n" + "\n" + "\"inject\" uses the Android system API to deliver mouse\n" + "events to applications.\n" + "\n" + "\"aoa\" simulates a physical mouse using the AOAv2\n" + "protocol. It may only work over USB.\n" + "In this mode, the computer mouse is captured to control the " + "device directly (relative mouse mode).\n" + "LAlt, LSuper or RSuper toggle the capture mode, to give " + "control of the mouse back to the computer.\n" + "Also see --keyboard-input-mode and --otg.", + }, { .shortopt = 'n', .longopt = "no-control", @@ -543,10 +582,11 @@ static const struct sc_option options[] = { "mirroring is disabled.\n" "LAlt, LSuper or RSuper toggle the mouse capture mode, to give " "control of the mouse back to the computer.\n" - "If any of --hid-keyboard or --hid-mouse is set, only enable " - "keyboard or mouse respectively, otherwise enable both.\n" + "Keyboard and mouse may be disabled separately using\n" + "--keyboard-input-mode=disable and\n" + "--mouse-input-mode=disable.\n" "It may only work over USB.\n" - "See --hid-keyboard and --hid-mouse.", + "See --keyboard-input-mode and --mouse-input-mode.", }, { .shortopt = 'p', @@ -1902,6 +1942,61 @@ parse_camera_fps(const char *s, uint16_t *camera_fps) { return true; } +static bool +parse_keyboard_input_mode(const char *optarg, + enum sc_keyboard_input_mode *mode) { + if (!strcmp(optarg, "disable")) { + *mode = SC_KEYBOARD_INPUT_MODE_DISABLED; + return true; + } + + if (!strcmp(optarg, "inject")) { + *mode = SC_KEYBOARD_INPUT_MODE_INJECT; + return true; + } + + if (!strcmp(optarg, "aoa")) { +#ifdef HAVE_USB + *mode = SC_KEYBOARD_INPUT_MODE_AOA; + return true; +#else + LOGE("--keyboard-input-mode=aoa is disabled."); + return false; +#endif + } + + LOGE("Unsupported keyboard input mode: %s (expected disable, inject, aoa)", + optarg); + return false; +} + +static bool +parse_mouse_input_mode(const char *optarg, enum sc_mouse_input_mode *mode) { + if (!strcmp(optarg, "disable")) { + *mode = SC_MOUSE_INPUT_MODE_DISABLED; + return true; + } + + if (!strcmp(optarg, "inject")) { + *mode = SC_MOUSE_INPUT_MODE_INJECT; + return true; + } + + if (!strcmp(optarg, "aoa")) { +#ifdef HAVE_USB + *mode = SC_MOUSE_INPUT_MODE_AOA; + return true; +#else + LOGE("--mouse-input-mode=aoa is disabled."); + return false; +#endif + } + + LOGE("Unsupported mouse input mode: %s (expected disable, inject, aoa)", + optarg); + return false; +} + static bool parse_time_limit(const char *s, sc_tick *tick) { long value; @@ -1991,12 +2086,20 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[], break; case 'K': #ifdef HAVE_USB - opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_HID; + LOGW("-K/--hid-keyboard is deprecated, use " + "--keyboard-input-mode=aoa instead."); + opts->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_AOA; break; #else LOGE("HID over AOA (-K/--hid-keyboard) is disabled."); return false; #endif + case OPT_KEYBOARD_INPUT_MODE: + if (!parse_keyboard_input_mode(optarg, + &opts->keyboard_input_mode)) { + return false; + } + break; case OPT_MAX_FPS: if (!parse_max_fps(optarg, &opts->max_fps)) { return false; @@ -2009,12 +2112,19 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[], break; case 'M': #ifdef HAVE_USB - opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_HID; + LOGW("-M/--hid-mouse is deprecated, use --mouse-input-mode=aoa " + "instead."); + opts->mouse_input_mode = SC_MOUSE_INPUT_MODE_AOA; break; #else LOGE("HID over AOA (-M/--hid-mouse) is disabled."); return false; #endif + case OPT_MOUSE_INPUT_MODE: + if (!parse_mouse_input_mode(optarg, &opts->mouse_input_mode)) { + return false; + } + break; case OPT_LOCK_VIDEO_ORIENTATION: if (!parse_lock_video_orientation(optarg, &opts->lock_video_orientation)) { @@ -2461,6 +2571,15 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[], } #endif + if (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AUTO) { + opts->keyboard_input_mode = otg ? SC_KEYBOARD_INPUT_MODE_AOA + : SC_KEYBOARD_INPUT_MODE_INJECT; + } + if (opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_AUTO) { + opts->mouse_input_mode = otg ? SC_MOUSE_INPUT_MODE_AOA + : SC_MOUSE_INPUT_MODE_INJECT; + } + if ((opts->tunnel_host || opts->tunnel_port) && !opts->force_adb_forward) { LOGI("Tunnel host/port is set, " "--force-adb-forward automatically enabled."); @@ -2621,12 +2740,12 @@ parse_args_with_getopt(struct scrcpy_cli_args *args, int argc, char *argv[], } # ifdef _WIN32 - if (!otg && (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID - || opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_HID)) { + if (!otg && (opts->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AOA + || opts->mouse_input_mode == SC_MOUSE_INPUT_MODE_AOA)) { LOGE("On Windows, it is not possible to open a USB device already open " "by another process (like adb)."); - LOGE("Therefore, -K/--hid-keyboard and -M/--hid-mouse may only work in " - "OTG mode (--otg)."); + LOGE("Therefore, --keyboard-input-mode=aoa and --mouse-input-mode=aoa " + "may only work in OTG mode (--otg)."); return false; } # endif diff --git a/app/src/options.c b/app/src/options.c index a13df585..7a885aa5 100644 --- a/app/src/options.c +++ b/app/src/options.c @@ -21,8 +21,8 @@ const struct scrcpy_options scrcpy_options_default = { .video_source = SC_VIDEO_SOURCE_DISPLAY, .audio_source = SC_AUDIO_SOURCE_AUTO, .record_format = SC_RECORD_FORMAT_AUTO, - .keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_INJECT, - .mouse_input_mode = SC_MOUSE_INPUT_MODE_INJECT, + .keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_AUTO, + .mouse_input_mode = SC_MOUSE_INPUT_MODE_AUTO, .camera_facing = SC_CAMERA_FACING_ANY, .port_range = { .first = DEFAULT_LOCAL_PORT_RANGE_FIRST, diff --git a/app/src/options.h b/app/src/options.h index 11e64fa1..28c71c7d 100644 --- a/app/src/options.h +++ b/app/src/options.h @@ -140,13 +140,17 @@ enum sc_lock_video_orientation { }; enum sc_keyboard_input_mode { + SC_KEYBOARD_INPUT_MODE_AUTO, + SC_KEYBOARD_INPUT_MODE_DISABLED, SC_KEYBOARD_INPUT_MODE_INJECT, - SC_KEYBOARD_INPUT_MODE_HID, + SC_KEYBOARD_INPUT_MODE_AOA, }; enum sc_mouse_input_mode { + SC_MOUSE_INPUT_MODE_AUTO, + SC_MOUSE_INPUT_MODE_DISABLED, SC_MOUSE_INPUT_MODE_INJECT, - SC_MOUSE_INPUT_MODE_HID, + SC_MOUSE_INPUT_MODE_AOA, }; enum sc_key_inject_mode { diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index cf2e7e47..676b8724 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -543,11 +543,11 @@ scrcpy(struct scrcpy_options *options) { if (options->control) { #ifdef HAVE_USB - bool use_hid_keyboard = - options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID; - bool use_hid_mouse = - options->mouse_input_mode == SC_MOUSE_INPUT_MODE_HID; - if (use_hid_keyboard || use_hid_mouse) { + bool use_aoa_keyboard = + options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AOA; + bool use_aoa_mouse = + options->mouse_input_mode == SC_MOUSE_INPUT_MODE_AOA; + if (use_aoa_keyboard || use_aoa_mouse) { bool ok = sc_acksync_init(&s->acksync); if (!ok) { goto end; @@ -590,7 +590,7 @@ scrcpy(struct scrcpy_options *options) { goto aoa_hid_end; } - if (use_hid_keyboard) { + if (use_aoa_keyboard) { if (sc_hid_keyboard_init(&s->keyboard_hid, &s->aoa)) { hid_keyboard_initialized = true; kp = &s->keyboard_hid.key_processor; @@ -599,7 +599,7 @@ scrcpy(struct scrcpy_options *options) { } } - if (use_hid_mouse) { + if (use_aoa_mouse) { if (sc_hid_mouse_init(&s->mouse_hid, &s->aoa)) { hid_mouse_initialized = true; mp = &s->mouse_hid.mouse_processor; @@ -636,19 +636,19 @@ aoa_hid_end: if (use_hid_keyboard && !hid_keyboard_initialized) { LOGE("Fallback to default keyboard injection method " - "(-K/--hid-keyboard ignored)"); + "(--keyboard-input-mode=aoa ignored)"); options->keyboard_input_mode = SC_KEYBOARD_INPUT_MODE_INJECT; } if (use_hid_mouse && !hid_mouse_initialized) { LOGE("Fallback to default mouse injection method " - "(-M/--hid-mouse ignored)"); + "(--mouse-input-mode=aoa ignored)"); options->mouse_input_mode = SC_MOUSE_INPUT_MODE_INJECT; } } #else - assert(options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_HID); - assert(options->mouse_input_mode != SC_MOUSE_INPUT_MODE_HID); + assert(options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_AOA); + assert(options->mouse_input_mode != SC_MOUSE_INPUT_MODE_AOA); #endif // keyboard_input_mode may have been reset if HID mode failed diff --git a/app/src/usb/scrcpy_otg.c b/app/src/usb/scrcpy_otg.c index dfb0b9e9..774a4c71 100644 --- a/app/src/usb/scrcpy_otg.c +++ b/app/src/usb/scrcpy_otg.c @@ -53,6 +53,25 @@ scrcpy_otg(struct scrcpy_options *options) { static struct scrcpy_otg scrcpy_otg; struct scrcpy_otg *s = &scrcpy_otg; + bool enable_keyboard; + assert(options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_AUTO); + switch (options->keyboard_input_mode) { + case SC_KEYBOARD_INPUT_MODE_AOA: + enable_keyboard = true; + break; + case SC_KEYBOARD_INPUT_MODE_DISABLED: + enable_keyboard = false; + break; + default: + LOGE("In --otg mode, --keyboard-input-mode must be either aoa or " + "disable"); + goto end; + } + if (options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_AOA + && options->keyboard_input_mode != SC_KEYBOARD_INPUT_MODE_DISABLED) { + return SCRCPY_EXIT_FAILURE; + } + const char *serial = options->serial; if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1")) { @@ -118,9 +137,9 @@ scrcpy_otg(struct scrcpy_options *options) { aoa_initialized = true; bool enable_keyboard = - options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_HID; + options->keyboard_input_mode == SC_KEYBOARD_INPUT_MODE_AOA; bool enable_mouse = - options->mouse_input_mode == SC_MOUSE_INPUT_MODE_HID; + options->mouse_input_mode == SC_MOUSE_INPUT_MODE_AOA; // If neither --hid-keyboard or --hid-mouse is passed, enable both if (!enable_keyboard && !enable_mouse) {