Compare commits

..

1 Commits

Author SHA1 Message Date
ef24690eee Fix reference to FAQ in README
PR #3065 <https://github.com/Genymobile/scrcpy/pull/3065>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2022-03-06 22:44:26 +01:00
31 changed files with 94 additions and 205 deletions

View File

@ -448,9 +448,6 @@ scrcpy --serial 0123456789abcdef
scrcpy -s 0123456789abcdef # short version scrcpy -s 0123456789abcdef # short version
``` ```
The serial may also be provided via the environment variable `ANDROID_SERIAL`
(also used by `adb`).
If the device is connected over TCP/IP: If the device is connected over TCP/IP:
```bash ```bash
@ -1108,7 +1105,7 @@ See [BUILD].
## Common issues ## Common issues
See the [FAQ].md). See the [FAQ].
[FAQ]: FAQ.md [FAQ]: FAQ.md

View File

@ -355,12 +355,6 @@ Set the initial window height.
Default is 0 (automatic). Default is 0 (automatic).
.SH EXIT STATUS
.B scrcpy
will exit with code 0 on normal program termination. If an initial
connection cannot be established, the exit code 1 will be returned. If the
device disconnects while a session is active, exit code 2 will be returned.
.SH SHORTCUTS .SH SHORTCUTS
In the following list, MOD is the shortcut modifier. By default, it's (left) In the following list, MOD is the shortcut modifier. By default, it's (left)
@ -477,10 +471,6 @@ Push file to device (see \fB\-\-push\-target\fR)
.B ADB .B ADB
Path to adb. Path to adb.
.TP
.B ANDROID_SERIAL
Device serial to use if no selector (-s, -d, -e or --tcpip=<addr>) is specified.
.TP .TP
.B SCRCPY_ICON_PATH .B SCRCPY_ICON_PATH
Path to the program icon. Path to the program icon.

View File

@ -473,12 +473,9 @@ sc_adb_accept_device(const struct sc_adb_device *device,
} }
return !strcmp(selector->serial, device->serial); return !strcmp(selector->serial, device->serial);
case SC_ADB_DEVICE_SELECT_USB: case SC_ADB_DEVICE_SELECT_USB:
return sc_adb_device_get_type(device->serial) == return !sc_adb_is_serial_tcpip(device->serial);
SC_ADB_DEVICE_TYPE_USB;
case SC_ADB_DEVICE_SELECT_TCPIP: case SC_ADB_DEVICE_SELECT_TCPIP:
// Both emulators and TCP/IP devices are selected via -e return sc_adb_is_serial_tcpip(device->serial);
return sc_adb_device_get_type(device->serial) !=
SC_ADB_DEVICE_TYPE_USB;
default: default:
assert(!"Missing SC_ADB_DEVICE_SELECT_* handling"); assert(!"Missing SC_ADB_DEVICE_SELECT_* handling");
break; break;
@ -512,10 +509,8 @@ sc_adb_devices_log(enum sc_log_level level, struct sc_adb_device *devices,
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
struct sc_adb_device *d = &devices[i]; struct sc_adb_device *d = &devices[i];
const char *selection = d->selected ? "-->" : " "; const char *selection = d->selected ? "-->" : " ";
bool is_usb = const char *type = sc_adb_is_serial_tcpip(d->serial) ? "(tcpip)"
sc_adb_device_get_type(d->serial) == SC_ADB_DEVICE_TYPE_USB; : " (usb)";
const char *type = is_usb ? " (usb)"
: "(tcpip)";
LOG(level, " %s %s %-20s %16s %s", LOG(level, " %s %s %-20s %16s %s",
selection, type, d->serial, d->state, d->model ? d->model : ""); selection, type, d->serial, d->state, d->model ? d->model : "");
} }
@ -536,8 +531,6 @@ sc_adb_device_check_state(struct sc_adb_device *device,
LOGE("A popup should open on the device to request authorization."); LOGE("A popup should open on the device to request authorization.");
LOGE("Check the FAQ: " LOGE("Check the FAQ: "
"<https://github.com/Genymobile/scrcpy/blob/master/FAQ.md>"); "<https://github.com/Genymobile/scrcpy/blob/master/FAQ.md>");
} else {
LOGE("Device could not be connected (state=%s)", state);
} }
return false; return false;
@ -712,3 +705,8 @@ sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags) {
return sc_adb_parse_device_ip_from_output(buf); return sc_adb_parse_device_ip_from_output(buf);
} }
bool
sc_adb_is_serial_tcpip(const char *serial) {
return strchr(serial, ':');
}

View File

@ -114,4 +114,13 @@ sc_adb_getprop(struct sc_intr *intr, const char *serial, const char *prop,
char * char *
sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags); sc_adb_get_device_ip(struct sc_intr *intr, const char *serial, unsigned flags);
/**
* Indicate if the serial represents an IP address
*
* In practice, it just returns true if and only if it contains a ':', which is
* sufficient to distinguish an ip:port from a real USB serial.
*/
bool
sc_adb_is_serial_tcpip(const char *serial);
#endif #endif

View File

@ -1,7 +1,6 @@
#include "adb_device.h" #include "adb_device.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
void void
sc_adb_device_destroy(struct sc_adb_device *device) { sc_adb_device_destroy(struct sc_adb_device *device) {
@ -26,18 +25,3 @@ sc_adb_devices_destroy(struct sc_vec_adb_devices *devices) {
sc_vector_destroy(devices); sc_vector_destroy(devices);
} }
enum sc_adb_device_type
sc_adb_device_get_type(const char *serial) {
// Starts with "emulator-"
if (!strncmp(serial, "emulator-", sizeof("emulator-") - 1)) {
return SC_ADB_DEVICE_TYPE_EMULATOR;
}
// If the serial contains a ':', then it is a TCP/IP device (it is
// sufficient to distinguish an ip:port from a real USB serial)
if (strchr(serial, ':')) {
return SC_ADB_DEVICE_TYPE_TCPIP;
}
return SC_ADB_DEVICE_TYPE_USB;
}

View File

@ -15,12 +15,6 @@ struct sc_adb_device {
bool selected; bool selected;
}; };
enum sc_adb_device_type {
SC_ADB_DEVICE_TYPE_USB,
SC_ADB_DEVICE_TYPE_TCPIP,
SC_ADB_DEVICE_TYPE_EMULATOR,
};
struct sc_vec_adb_devices SC_VECTOR(struct sc_adb_device); struct sc_vec_adb_devices SC_VECTOR(struct sc_adb_device);
void void
@ -41,10 +35,4 @@ sc_adb_device_move(struct sc_adb_device *dst, struct sc_adb_device *src);
void void
sc_adb_devices_destroy(struct sc_vec_adb_devices *devices); sc_adb_devices_destroy(struct sc_vec_adb_devices *devices);
/**
* Deduce the device type from the serial
*/
enum sc_adb_device_type
sc_adb_device_get_type(const char *serial);
#endif #endif

View File

@ -80,11 +80,6 @@ struct sc_envvar {
const char *text; const char *text;
}; };
struct sc_exit_status {
unsigned value;
const char *text;
};
struct sc_getopt_adapter { struct sc_getopt_adapter {
char *optstring; char *optstring;
struct option *longopts; struct option *longopts;
@ -660,11 +655,6 @@ static const struct sc_envvar envvars[] = {
.name = "ADB", .name = "ADB",
.text = "Path to adb executable", .text = "Path to adb executable",
}, },
{
.name = "ANDROID_SERIAL",
.text = "Device serial to use if no selector (-s, -d, -e or "
"--tcpip=<addr>) is specified",
},
{ {
.name = "SCRCPY_ICON_PATH", .name = "SCRCPY_ICON_PATH",
.text = "Path to the program icon", .text = "Path to the program icon",
@ -672,22 +662,7 @@ static const struct sc_envvar envvars[] = {
{ {
.name = "SCRCPY_SERVER_PATH", .name = "SCRCPY_SERVER_PATH",
.text = "Path to the server binary", .text = "Path to the server binary",
}, }
};
static const struct sc_exit_status exit_statuses[] = {
{
.value = 0,
.text = "Normal program termination",
},
{
.value = 1,
.text = "Start failure",
},
{
.value = 2,
.text = "Device disconnected while running",
},
}; };
static char * static char *
@ -926,25 +901,6 @@ print_envvar(const struct sc_envvar *envvar, unsigned cols) {
free(text); free(text);
} }
static void
print_exit_status(const struct sc_exit_status *status, unsigned cols) {
assert(cols > 8); // sc_str_wrap_lines() requires indent < columns
assert(status->text);
// The text starts at 9: 4 ident spaces, 3 chars for numeric value, 2 spaces
char *text = sc_str_wrap_lines(status->text, cols, 9);
if (!text) {
printf("<ERROR>\n");
return;
}
assert(strlen(text) >= 9); // Contains at least the initial identation
// text + 9 to remove the initial indentation
printf(" %3d %s\n", status->value, text + 9);
free(text);
}
void void
scrcpy_print_usage(const char *arg0) { scrcpy_print_usage(const char *arg0) {
#define SC_TERM_COLS_DEFAULT 80 #define SC_TERM_COLS_DEFAULT 80
@ -983,11 +939,6 @@ scrcpy_print_usage(const char *arg0) {
for (size_t i = 0; i < ARRAY_LEN(envvars); ++i) { for (size_t i = 0; i < ARRAY_LEN(envvars); ++i) {
print_envvar(&envvars[i], cols); print_envvar(&envvars[i], cols);
} }
printf("\nExit status:\n\n");
for (size_t i = 0; i < ARRAY_LEN(exit_statuses); ++i) {
print_exit_status(&exit_statuses[i], cols);
}
} }
static bool static bool

View File

@ -1,5 +1,5 @@
#ifndef SC_COMMON_H #ifndef COMMON_H
#define SC_COMMON_H #define COMMON_H
#include "config.h" #include "config.h"
#include "compat.h" #include "compat.h"

View File

@ -1,5 +1,5 @@
#ifndef SC_COMPAT_H #ifndef COMPAT_H
#define SC_COMPAT_H #define COMPAT_H
#include "config.h" #include "config.h"

View File

@ -1,5 +1,5 @@
#ifndef SC_CONTROLMSG_H #ifndef CONTROLMSG_H
#define SC_CONTROLMSG_H #define CONTROLMSG_H
#include "common.h" #include "common.h"

View File

@ -1,5 +1,5 @@
#ifndef SC_CONTROLLER_H #ifndef CONTROLLER_H
#define SC_CONTROLLER_H #define CONTROLLER_H
#include "common.h" #include "common.h"

View File

@ -1,5 +1,5 @@
#ifndef SC_DEVICEMSG_H #ifndef DEVICEMSG_H
#define SC_DEVICEMSG_H #define DEVICEMSG_H
#include "common.h" #include "common.h"

View File

@ -1,5 +1,5 @@
#ifndef SC_FPSCOUNTER_H #ifndef FPSCOUNTER_H
#define SC_FPSCOUNTER_H #define FPSCOUNTER_H
#include "common.h" #include "common.h"

View File

@ -1,5 +1,5 @@
#ifndef SC_ICON_H #ifndef ICON_H
#define SC_ICON_H #define ICON_H
#include "common.h" #include "common.h"

View File

@ -1,5 +1,5 @@
#ifndef SC_INPUTMANAGER_H #ifndef INPUTMANAGER_H
#define SC_INPUTMANAGER_H #define INPUTMANAGER_H
#include "common.h" #include "common.h"

View File

@ -40,19 +40,19 @@ main(int argc, char *argv[]) {
#endif #endif
if (!scrcpy_parse_args(&args, argc, argv)) { if (!scrcpy_parse_args(&args, argc, argv)) {
return SCRCPY_EXIT_FAILURE; return 1;
} }
sc_set_log_level(args.opts.log_level); sc_set_log_level(args.opts.log_level);
if (args.help) { if (args.help) {
scrcpy_print_usage(argv[0]); scrcpy_print_usage(argv[0]);
return SCRCPY_EXIT_SUCCESS; return 0;
} }
if (args.version) { if (args.version) {
scrcpy_print_version(); scrcpy_print_version();
return SCRCPY_EXIT_SUCCESS; return 0;
} }
#ifdef SCRCPY_LAVF_REQUIRES_REGISTER_ALL #ifdef SCRCPY_LAVF_REQUIRES_REGISTER_ALL
@ -66,17 +66,17 @@ main(int argc, char *argv[]) {
#endif #endif
if (avformat_network_init()) { if (avformat_network_init()) {
return SCRCPY_EXIT_FAILURE; return 1;
} }
#ifdef HAVE_USB #ifdef HAVE_USB
enum scrcpy_exit_code ret = args.opts.otg ? scrcpy_otg(&args.opts) bool ok = args.opts.otg ? scrcpy_otg(&args.opts)
: scrcpy(&args.opts); : scrcpy(&args.opts);
#else #else
enum scrcpy_exit_code ret = scrcpy(&args.opts); bool ok = scrcpy(&args.opts);
#endif #endif
avformat_network_deinit(); // ignore failure avformat_network_deinit(); // ignore failure
return ret; return ok ? 0 : 1;
} }

View File

@ -28,7 +28,7 @@ sc_opengl_init(struct sc_opengl *gl) {
sizeof(OPENGL_ES_PREFIX) - 1); sizeof(OPENGL_ES_PREFIX) - 1);
if (gl->is_opengles) { if (gl->is_opengles) {
/* skip the prefix */ /* skip the prefix */
version += sizeof(OPENGL_ES_PREFIX) - 1; version += sizeof(PREFIX) - 1;
} }
int r = sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor); int r = sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor);

View File

@ -1,5 +1,5 @@
#ifndef SC_RECEIVER_H #ifndef RECEIVER_H
#define SC_RECEIVER_H #define RECEIVER_H
#include "common.h" #include "common.h"

View File

@ -149,41 +149,38 @@ sdl_configure(bool display, bool disable_screensaver) {
} }
} }
static enum scrcpy_exit_code static bool
event_loop(struct scrcpy *s) { event_loop(struct scrcpy *s) {
SDL_Event event; SDL_Event event;
while (SDL_WaitEvent(&event)) { while (SDL_WaitEvent(&event)) {
switch (event.type) { switch (event.type) {
case EVENT_STREAM_STOPPED: case EVENT_STREAM_STOPPED:
LOGW("Device disconnected"); LOGW("Device disconnected");
return SCRCPY_EXIT_DISCONNECTED; return false;
case SDL_QUIT: case SDL_QUIT:
LOGD("User requested to quit"); LOGD("User requested to quit");
return SCRCPY_EXIT_SUCCESS; return true;
default: default:
sc_screen_handle_event(&s->screen, &event); sc_screen_handle_event(&s->screen, &event);
break; break;
} }
} }
return SCRCPY_EXIT_FAILURE; return false;
} }
// Return true on success, false on error
static bool static bool
await_for_server(bool *connected) { await_for_server(void) {
SDL_Event event; SDL_Event event;
while (SDL_WaitEvent(&event)) { while (SDL_WaitEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_QUIT: case SDL_QUIT:
LOGD("User requested to quit"); LOGD("User requested to quit");
*connected = false; return false;
return true;
case EVENT_SERVER_CONNECTION_FAILED: case EVENT_SERVER_CONNECTION_FAILED:
LOGE("Server connection failed"); LOGE("Server connection failed");
return false; return false;
case EVENT_SERVER_CONNECTED: case EVENT_SERVER_CONNECTED:
LOGD("Server connected"); LOGD("Server connected");
*connected = true;
return true; return true;
default: default:
break; break;
@ -265,7 +262,7 @@ sc_server_on_disconnected(struct sc_server *server, void *userdata) {
// event // event
} }
enum scrcpy_exit_code bool
scrcpy(struct scrcpy_options *options) { scrcpy(struct scrcpy_options *options) {
static struct scrcpy scrcpy; static struct scrcpy scrcpy;
struct scrcpy *s = &scrcpy; struct scrcpy *s = &scrcpy;
@ -273,12 +270,12 @@ scrcpy(struct scrcpy_options *options) {
// Minimal SDL initialization // Minimal SDL initialization
if (SDL_Init(SDL_INIT_EVENTS)) { if (SDL_Init(SDL_INIT_EVENTS)) {
LOGE("Could not initialize SDL: %s", SDL_GetError()); LOGE("Could not initialize SDL: %s", SDL_GetError());
return SCRCPY_EXIT_FAILURE; return false;
} }
atexit(SDL_Quit); atexit(SDL_Quit);
enum scrcpy_exit_code ret = SCRCPY_EXIT_FAILURE; bool ret = false;
bool server_started = false; bool server_started = false;
bool file_pusher_initialized = false; bool file_pusher_initialized = false;
@ -332,7 +329,7 @@ scrcpy(struct scrcpy_options *options) {
.on_disconnected = sc_server_on_disconnected, .on_disconnected = sc_server_on_disconnected,
}; };
if (!sc_server_init(&s->server, &params, &cbs, NULL)) { if (!sc_server_init(&s->server, &params, &cbs, NULL)) {
return SCRCPY_EXIT_FAILURE; return false;
} }
if (!sc_server_start(&s->server)) { if (!sc_server_start(&s->server)) {
@ -354,14 +351,7 @@ scrcpy(struct scrcpy_options *options) {
sdl_configure(options->display, options->disable_screensaver); sdl_configure(options->display, options->disable_screensaver);
// Await for server without blocking Ctrl+C handling // Await for server without blocking Ctrl+C handling
bool connected; if (!await_for_server()) {
if (!await_for_server(&connected)) {
goto end;
}
if (!connected) {
// This is not an error, user requested to quit
ret = SCRCPY_EXIT_SUCCESS;
goto end; goto end;
} }

View File

@ -6,18 +6,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "options.h" #include "options.h"
enum scrcpy_exit_code { bool
// Normal program termination
SCRCPY_EXIT_SUCCESS,
// No connection could be established
SCRCPY_EXIT_FAILURE,
// Device was disconnected while running
SCRCPY_EXIT_DISCONNECTED,
};
enum scrcpy_exit_code
scrcpy(struct scrcpy_options *options); scrcpy(struct scrcpy_options *options);
#endif #endif

View File

@ -649,8 +649,7 @@ sc_server_configure_tcpip_known_address(struct sc_server *server,
static bool static bool
sc_server_configure_tcpip_unknown_address(struct sc_server *server, sc_server_configure_tcpip_unknown_address(struct sc_server *server,
const char *serial) { const char *serial) {
bool is_already_tcpip = bool is_already_tcpip = sc_adb_is_serial_tcpip(serial);
sc_adb_device_get_type(serial) == SC_ADB_DEVICE_TYPE_TCPIP;
if (is_already_tcpip) { if (is_already_tcpip) {
// Nothing to do // Nothing to do
LOGI("Device already connected via TCP/IP: %s", serial); LOGI("Device already connected via TCP/IP: %s", serial);
@ -708,15 +707,7 @@ run_server(void *data) {
} else if (params->select_tcpip) { } else if (params->select_tcpip) {
selector.type = SC_ADB_DEVICE_SELECT_TCPIP; selector.type = SC_ADB_DEVICE_SELECT_TCPIP;
} else { } else {
// No explicit selection, check $ANDROID_SERIAL selector.type = SC_ADB_DEVICE_SELECT_ALL;
const char *env_serial = getenv("ANDROID_SERIAL");
if (env_serial) {
LOGI("Using ANDROID_SERIAL: %s", env_serial);
selector.type = SC_ADB_DEVICE_SELECT_SERIAL;
selector.serial = env_serial;
} else {
selector.type = SC_ADB_DEVICE_SELECT_ALL;
}
} }
struct sc_adb_device device; struct sc_adb_device device;
ok = sc_adb_select_device(&server->intr, &selector, 0, &device); ok = sc_adb_select_device(&server->intr, &selector, 0, &device);

View File

@ -340,7 +340,7 @@ push_mod_lock_state(struct sc_hid_keyboard *kb, uint16_t mods_state) {
if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (mod lock state)"); LOGW("Could request HID event");
return false; return false;
} }
@ -382,7 +382,7 @@ sc_key_processor_process_key(struct sc_key_processor *kp,
if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(kb->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (key)"); LOGW("Could request HID event");
} }
} }
} }

View File

@ -181,7 +181,7 @@ sc_mouse_processor_process_mouse_motion(struct sc_mouse_processor *mp,
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (mouse motion)"); LOGW("Could request HID event");
} }
} }
@ -203,7 +203,7 @@ sc_mouse_processor_process_mouse_click(struct sc_mouse_processor *mp,
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (mouse click)"); LOGW("Could request HID event");
} }
} }
@ -228,7 +228,7 @@ sc_mouse_processor_process_mouse_scroll(struct sc_mouse_processor *mp,
if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) { if (!sc_aoa_push_hid_event(mouse->aoa, &hid_event)) {
sc_hid_event_destroy(&hid_event); sc_hid_event_destroy(&hid_event);
LOGW("Could not request HID event (mouse scroll)"); LOGW("Could request HID event");
} }
} }

View File

@ -29,26 +29,26 @@ sc_usb_on_disconnected(struct sc_usb *usb, void *userdata) {
} }
} }
static enum scrcpy_exit_code static bool
event_loop(struct scrcpy_otg *s) { event_loop(struct scrcpy_otg *s) {
SDL_Event event; SDL_Event event;
while (SDL_WaitEvent(&event)) { while (SDL_WaitEvent(&event)) {
switch (event.type) { switch (event.type) {
case EVENT_USB_DEVICE_DISCONNECTED: case EVENT_USB_DEVICE_DISCONNECTED:
LOGW("Device disconnected"); LOGW("Device disconnected");
return SCRCPY_EXIT_DISCONNECTED; return false;
case SDL_QUIT: case SDL_QUIT:
LOGD("User requested to quit"); LOGD("User requested to quit");
return SCRCPY_EXIT_SUCCESS; return true;
default: default:
sc_screen_otg_handle_event(&s->screen_otg, &event); sc_screen_otg_handle_event(&s->screen_otg, &event);
break; break;
} }
} }
return SCRCPY_EXIT_FAILURE; return false;
} }
enum scrcpy_exit_code bool
scrcpy_otg(struct scrcpy_options *options) { scrcpy_otg(struct scrcpy_options *options) {
static struct scrcpy_otg scrcpy_otg; static struct scrcpy_otg scrcpy_otg;
struct scrcpy_otg *s = &scrcpy_otg; struct scrcpy_otg *s = &scrcpy_otg;
@ -67,7 +67,7 @@ scrcpy_otg(struct scrcpy_options *options) {
LOGW("Could not enable mouse focus clickthrough"); LOGW("Could not enable mouse focus clickthrough");
} }
enum scrcpy_exit_code ret = SCRCPY_EXIT_FAILURE; bool ret = false;
struct sc_hid_keyboard *keyboard = NULL; struct sc_hid_keyboard *keyboard = NULL;
struct sc_hid_mouse *mouse = NULL; struct sc_hid_mouse *mouse = NULL;
@ -90,7 +90,7 @@ scrcpy_otg(struct scrcpy_options *options) {
}; };
bool ok = sc_usb_init(&s->usb); bool ok = sc_usb_init(&s->usb);
if (!ok) { if (!ok) {
return SCRCPY_EXIT_FAILURE; return false;
} }
struct sc_usb_device usb_device; struct sc_usb_device usb_device;

View File

@ -3,10 +3,10 @@
#include "common.h" #include "common.h"
#include <stdbool.h>
#include "options.h" #include "options.h"
#include "scrcpy.h"
enum scrcpy_exit_code bool
scrcpy_otg(struct scrcpy_options *options); scrcpy_otg(struct scrcpy_options *options);
#endif #endif

View File

@ -15,7 +15,6 @@ read_string(libusb_device_handle *handle, uint8_t desc_index) {
(unsigned char *) buffer, (unsigned char *) buffer,
sizeof(buffer)); sizeof(buffer));
if (result < 0) { if (result < 0) {
LOGD("Read string: libusb error: %s", libusb_strerror(result));
return NULL; return NULL;
} }

View File

@ -1,6 +1,6 @@
// generic circular buffer (bounded queue) implementation // generic circular buffer (bounded queue) implementation
#ifndef SC_CBUF_H #ifndef CBUF_H
#define SC_CBUF_H #define CBUF_H
#include "common.h" #include "common.h"

View File

@ -1,5 +1,5 @@
#ifndef SC_NET_H #ifndef NET_H
#define SC_NET_H #define NET_H
#include "common.h" #include "common.h"

2
run
View File

@ -20,6 +20,6 @@ then
exit 1 exit 1
fi fi
SCRCPY_ICON_PATH="app/data/icon.png" \ SCRCPY_ICON_PATH="data/icon.png" \
SCRCPY_SERVER_PATH="$BUILDDIR/server/scrcpy-server" \ SCRCPY_SERVER_PATH="$BUILDDIR/server/scrcpy-server" \
"$BUILDDIR/app/scrcpy" "$@" "$BUILDDIR/app/scrcpy" "$@"

View File

@ -14,18 +14,24 @@ public final class InputManager {
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1; public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1;
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2;
private final android.hardware.input.InputManager manager; private final IInterface manager;
private Method injectInputEventMethod; private Method injectInputEventMethod;
private boolean alternativeInjectInputEventMethod;
private static Method setDisplayIdMethod; private static Method setDisplayIdMethod;
public InputManager(android.hardware.input.InputManager manager) { public InputManager(IInterface manager) {
this.manager = manager; this.manager = manager;
} }
private Method getInjectInputEventMethod() throws NoSuchMethodException { private Method getInjectInputEventMethod() throws NoSuchMethodException {
if (injectInputEventMethod == null) { if (injectInputEventMethod == null) {
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class); try {
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class);
} catch (NoSuchMethodException e) {
injectInputEventMethod = manager.getClass().getMethod("injectInputEvent", InputEvent.class, int.class, int.class);
alternativeInjectInputEventMethod = true;
}
} }
return injectInputEventMethod; return injectInputEventMethod;
} }
@ -33,6 +39,10 @@ public final class InputManager {
public boolean injectInputEvent(InputEvent inputEvent, int mode) { public boolean injectInputEvent(InputEvent inputEvent, int mode) {
try { try {
Method method = getInjectInputEventMethod(); Method method = getInjectInputEventMethod();
if (alternativeInjectInputEventMethod) {
// See <https://github.com/Genymobile/scrcpy/issues/2250>
return (boolean) method.invoke(manager, inputEvent, mode, 0);
}
return (boolean) method.invoke(manager, inputEvent, mode); return (boolean) method.invoke(manager, inputEvent, mode);
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
Ln.e("Could not invoke method", e); Ln.e("Could not invoke method", e);

View File

@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
import android.os.IBinder; import android.os.IBinder;
import android.os.IInterface; import android.os.IInterface;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@SuppressLint("PrivateApi,DiscouragedPrivateApi") @SuppressLint("PrivateApi,DiscouragedPrivateApi")
@ -57,13 +56,7 @@ public final class ServiceManager {
public InputManager getInputManager() { public InputManager getInputManager() {
if (inputManager == null) { if (inputManager == null) {
try { inputManager = new InputManager(getService("input", "android.hardware.input.IInputManager"));
Method getInstanceMethod = android.hardware.input.InputManager.class.getDeclaredMethod("getInstance");
android.hardware.input.InputManager im = (android.hardware.input.InputManager) getInstanceMethod.invoke(null);
inputManager = new InputManager(im);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new AssertionError(e);
}
} }
return inputManager; return inputManager;
} }