diff --git a/README.md b/README.md index c1ffbe373d..f812e47968 100644 --- a/README.md +++ b/README.md @@ -207,19 +207,6 @@ scrcpy --crop 1224:1440:0:0 # 1224x1440 at offset (0,0) If `--max-size` is also specified, resizing is applied after cropping. -#### USB HID over AoAv2 - -Scrcpy can simulate a USB physical keyboard on Android to provide better input -experience, to use this feature you need to find your Android device's USB ID. -Then run it with `--usb` argument. - -```bash -scrcpy --usb 04e8:6861 -``` - -USB ID can be found via lsusb. It will fallback to inject mode if HID over AoAv2 -failed to set up. - #### Lock video orientation diff --git a/app/scrcpy.1 b/app/scrcpy.1 index a99723ea38..1b69a0650f 100644 --- a/app/scrcpy.1 +++ b/app/scrcpy.1 @@ -106,12 +106,6 @@ Limit both the width and height of the video to \fIvalue\fR. The other dimension Default is 0 (unlimited). -.TP -.BI "\-u, \-\-usb " vid:pid -Specify the USB ID of Android device to simulate a physical keyboard via HID over AoAv2, provide better input experience than inject mode. - -The USB ID of Android device can be found via lsusb. - .TP .B \-n, \-\-no\-control Disable device control (mirror the device in read\-only). diff --git a/app/src/adb.c b/app/src/adb.c index 5bb9df300d..262b00a5b0 100644 --- a/app/src/adb.c +++ b/app/src/adb.c @@ -224,3 +224,10 @@ adb_install(const char *serial, const char *local) { return proc; } + +process_t +adb_get_serialno(const char *serial) { + const char *const adb_cmd[] = {"get-serialno"}; + process_t proc = adb_execute(serial, adb_cmd, ARRAY_LEN(adb_cmd)); + return proc; +} diff --git a/app/src/adb.h b/app/src/adb.h index e27f34fa30..7cf8068bdd 100644 --- a/app/src/adb.h +++ b/app/src/adb.h @@ -31,4 +31,7 @@ adb_push(const char *serial, const char *local, const char *remote); process_t adb_install(const char *serial, const char *local); +process_t +adb_get_serialno(const char *serial); + #endif diff --git a/app/src/aoa_hid.c b/app/src/aoa_hid.c index 96a63327de..5f65ca2940 100644 --- a/app/src/aoa_hid.c +++ b/app/src/aoa_hid.c @@ -9,23 +9,58 @@ #define DEFAULT_TIMEOUT 1000 -inline static void print_libusb_error(enum libusb_error errcode) { +// 128 seems to be enough for serial. +#define SERIAL_BUFFER_SIZE 128 + +inline static void log_libusb_error(enum libusb_error errcode) { LOGW("libusb error: %s", libusb_strerror(errcode)); } -libusb_device *aoa_find_usb_device(uint16_t vid, uint16_t pid) { +inline static int +get_usb_serial(libusb_device *device, char *buffer, int size) { + libusb_device_handle *handle; + int result = libusb_open(device, &handle); + if (result < 0) { + log_libusb_error((enum libusb_error)result); + return result; + } + + struct libusb_device_descriptor desc; + libusb_get_device_descriptor(device, &desc); + if (!desc.iSerialNumber) { + libusb_close(handle); + LOGW("USB device %04x:%04x has no serial number", + desc.idVendor, desc.idProduct); + return 1; + } + + result = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, + (unsigned char *)buffer, size); + if (result < 0) { + log_libusb_error((enum libusb_error)result); + libusb_close(handle); + return result; + } + + libusb_close(handle); + buffer[SERIAL_BUFFER_SIZE - 1] = '\0'; + return 0; +} + +libusb_device *aoa_find_usb_device(const char *serial) { libusb_device **list; libusb_device *result = NULL; ssize_t count = libusb_get_device_list(NULL, &list); if (count < 0) { - print_libusb_error((enum libusb_error)count); + log_libusb_error((enum libusb_error)count); return NULL; } + + char buffer[SERIAL_BUFFER_SIZE]; for (ssize_t i = 0; i < count; ++i) { libusb_device *device = list[i]; - struct libusb_device_descriptor desc; - libusb_get_device_descriptor(device, &desc); - if (vid == desc.idVendor && pid == desc.idProduct) { + int error = get_usb_serial(device, buffer, SERIAL_BUFFER_SIZE); + if (!error && !strcmp(buffer, serial)) { result = libusb_ref_device(device); break; } @@ -37,7 +72,7 @@ libusb_device *aoa_find_usb_device(uint16_t vid, uint16_t pid) { int aoa_open_usb_handle(libusb_device *device, libusb_device_handle **handle) { int result = libusb_open(device, handle); if (result < 0) { - print_libusb_error((enum libusb_error)result); + log_libusb_error((enum libusb_error)result); return result; } return 0; @@ -56,7 +91,7 @@ int aoa_register_hid(libusb_device_handle *handle, uint16_t report_desc_size) { int result = libusb_control_transfer(handle, request_type, request, value, index, buffer, length, DEFAULT_TIMEOUT); if (result < 0) { - print_libusb_error((enum libusb_error)result); + log_libusb_error((enum libusb_error)result); return result; } return 0; @@ -75,7 +110,7 @@ int aoa_unregister_hid(libusb_device_handle *handle) { int result = libusb_control_transfer(handle, request_type, request, value, index, buffer, length, DEFAULT_TIMEOUT); if (result < 0) { - print_libusb_error((enum libusb_error)result); + log_libusb_error((enum libusb_error)result); return result; } return 0; @@ -111,7 +146,7 @@ aoa_set_hid_report_desc(libusb_device_handle *handle, value, offset, buffer + offset, packet_length, DEFAULT_TIMEOUT); offset += packet_length; if (result < 0) { - print_libusb_error((enum libusb_error)result); + log_libusb_error((enum libusb_error)result); return result; } } @@ -134,7 +169,7 @@ aoa_send_hid_event(libusb_device_handle *handle, int result = libusb_control_transfer(handle, request_type, request, value, index, buffer, length, DEFAULT_TIMEOUT); if (result < 0) { - print_libusb_error((enum libusb_error)result); + log_libusb_error((enum libusb_error)result); return result; } return 0; diff --git a/app/src/aoa_hid.h b/app/src/aoa_hid.h index 244b1ba22a..8b17d913df 100644 --- a/app/src/aoa_hid.h +++ b/app/src/aoa_hid.h @@ -15,7 +15,7 @@ struct hid_event { uint16_t size; }; -libusb_device *aoa_find_usb_device(uint16_t vid, uint16_t pid); +libusb_device *aoa_find_usb_device(const char *serial); int aoa_open_usb_handle(libusb_device *device, libusb_device_handle **handle); int aoa_register_hid(libusb_device_handle *handle, uint16_t report_desc_size); int aoa_unregister_hid(libusb_device_handle *handle); diff --git a/app/src/cli.c b/app/src/cli.c index fbad6d6ec9..d22096cafa 100644 --- a/app/src/cli.c +++ b/app/src/cli.c @@ -105,12 +105,6 @@ scrcpy_print_usage(const char *arg0) { " is preserved.\n" " Default is 0 (unlimited).\n" "\n" - " -u, --usb vid:pid\n" - " Specify the USB ID of Android device to simulate a physical\n" - " keyboard via HID over AoAv2, provide better input experience\n" - " than inject mode.\n" - " The USB ID of Android device can be found via lsusb.\n" - "\n" " -n, --no-control\n" " Disable device control (mirror the device in read-only).\n" "\n" @@ -537,29 +531,6 @@ parse_display_id(const char *s, uint32_t *display_id) { return true; } -static bool -parse_usb_id(char *s, uint16_t *vid, uint16_t *pid) { - if (strlen(s) == 0) { - LOGE("USB ID parameter is empty"); - return false; - } - uint32_t v; - uint32_t p; - int result = sscanf(s, "%x:%x", &v, &p); - if (result != 2) { - LOGE("Invalid USB ID: %s", s); - return false; - } - if ((v & ~0xffff) || (p & ~0xffff)) { - LOGE("USB ID out of range: %s", s); - return false; - } - - *vid = (uint16_t)v; - *pid = (uint16_t)p; - return true; -} - static bool parse_log_level(const char *s, enum sc_log_level *log_level) { if (!strcmp(s, "verbose")) { @@ -772,7 +743,6 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { OPT_LOCK_VIDEO_ORIENTATION}, {"max-fps", required_argument, NULL, OPT_MAX_FPS}, {"max-size", required_argument, NULL, 'm'}, - {"usb", required_argument, NULL, 'u'}, {"no-control", no_argument, NULL, 'n'}, {"no-display", no_argument, NULL, 'N'}, {"no-key-repeat", no_argument, NULL, OPT_NO_KEY_REPEAT}, @@ -814,7 +784,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { optind = 0; // reset to start from the first argument in tests int c; - while ((c = getopt_long(argc, argv, "b:c:fF:hm:u:nNp:r:s:StTvV:w", + while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTvV:w", long_options, NULL)) != -1) { switch (c) { case 'b': @@ -857,12 +827,6 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) { return false; } break; - case 'u': - if (!parse_usb_id(optarg, &opts->usb_vid, &opts->usb_pid)) { - return false; - } - opts->use_hid_over_aoa = true; - break; case OPT_LOCK_VIDEO_ORIENTATION: if (!parse_lock_video_orientation(optarg, &opts->lock_video_orientation)) { diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index ed859f1956..393c1ccaa5 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -419,14 +419,13 @@ scrcpy(const struct scrcpy_options *options) { libusb_device_handle *usb_handle = NULL; libusb_device *usb_device = NULL; - if (options->use_hid_over_aoa) { + if (options->serial) { + LOGD("USB serial provided, starting in HID over AoAv2 mode"); s->input_manager.use_hid_over_aoa = true; libusb_init(NULL); - usb_device = aoa_find_usb_device(options->usb_vid, - options->usb_pid); + usb_device = aoa_find_usb_device(options->serial); if (!usb_device) { - LOGW("USB device %04x:%04x not found", options->usb_vid, - options->usb_pid); + LOGW("USB device of serial %s not found", options->serial); LOGW("Fallback to inject mode"); s->input_manager.use_hid_over_aoa = false; } @@ -467,6 +466,7 @@ scrcpy(const struct scrcpy_options *options) { // Finally successfully set up HID over AoAv2. if (s->input_manager.use_hid_over_aoa) { + LOGD("Successfully set up HID over AoAv2 mode"); s->input_manager.usb_handle = usb_handle; } diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index 1d1e3c9b00..8b76fb25a2 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -80,11 +80,8 @@ struct scrcpy_options { uint16_t window_width; uint16_t window_height; uint32_t display_id; - uint16_t usb_vid; - uint16_t usb_pid; sc_tick display_buffer; sc_tick v4l2_buffer; - bool use_hid_over_aoa; bool show_touches; bool fullscreen; bool always_on_top; @@ -135,7 +132,6 @@ struct scrcpy_options { .display_id = 0, \ .display_buffer = 0, \ .v4l2_buffer = 0, \ - .use_hid_over_aoa = false, \ .show_touches = false, \ .fullscreen = false, \ .always_on_top = false, \