Add option to mirror in read-only

Add an option to disable device control: -n/--no-control.
This commit is contained in:
Romain Vimont 2019-03-02 22:40:51 +01:00
parent 163cd36ccc
commit 8655ba7197
6 changed files with 92 additions and 32 deletions

View file

@ -247,6 +247,17 @@ _scrcpy_ window.
There is no visual feedback, a log is printed to the console.
### Read-only
To disable controls (everything which can interact with the device: input keys,
mouse events, drag&drop files):
```bash
scrcpy --no-control
scrcpy -n
```
### Forward audio
Audio is not forwarded by _scrcpy_.

View file

@ -202,6 +202,9 @@ input_manager_process_key(struct input_manager *input_manager,
return;
}
// false if the user requested not to interact with the device
SDL_bool control = input_manager->control;
// capture all Ctrl events
if (ctrl | meta) {
SDL_Keycode keycode = event->keysym.sym;
@ -210,36 +213,36 @@ input_manager_process_key(struct input_manager *input_manager,
SDL_bool shift = event->keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT);
switch (keycode) {
case SDLK_h:
if (ctrl && !meta && !shift && !repeat) {
if (control && ctrl && !meta && !shift && !repeat) {
action_home(input_manager->controller, action);
}
return;
case SDLK_b: // fall-through
case SDLK_BACKSPACE:
if (ctrl && !meta && !shift && !repeat) {
if (control && ctrl && !meta && !shift && !repeat) {
action_back(input_manager->controller, action);
}
return;
case SDLK_s:
if (ctrl && !meta && !shift && !repeat) {
if (control && ctrl && !meta && !shift && !repeat) {
action_app_switch(input_manager->controller, action);
}
return;
case SDLK_m:
if (ctrl && !meta && !shift && !repeat) {
if (control && ctrl && !meta && !shift && !repeat) {
action_menu(input_manager->controller, action);
}
return;
case SDLK_p:
if (ctrl && !meta && !shift && !repeat) {
if (control && ctrl && !meta && !shift && !repeat) {
action_power(input_manager->controller, action);
}
return;
case SDLK_DOWN:
#ifdef __APPLE__
if (!ctrl && meta && !shift) {
if (control && !ctrl && meta && !shift) {
#else
if (ctrl && !meta && !shift) {
if (control && ctrl && !meta && !shift) {
#endif
// forward repeated events
action_volume_down(input_manager->controller, action);
@ -247,16 +250,16 @@ input_manager_process_key(struct input_manager *input_manager,
return;
case SDLK_UP:
#ifdef __APPLE__
if (!ctrl && meta && !shift) {
if (control && !ctrl && meta && !shift) {
#else
if (ctrl && !meta && !shift) {
if (control && ctrl && !meta && !shift) {
#endif
// forward repeated events
action_volume_up(input_manager->controller, action);
}
return;
case SDLK_v:
if (ctrl && !meta && !shift && !repeat
if (control && ctrl && !meta && !shift && !repeat
&& event->type == SDL_KEYDOWN) {
clipboard_paste(input_manager->controller);
}
@ -286,7 +289,8 @@ input_manager_process_key(struct input_manager *input_manager,
}
return;
case SDLK_n:
if (ctrl && !meta && !repeat && event->type == SDL_KEYDOWN) {
if (control && ctrl && !meta
&& !repeat && event->type == SDL_KEYDOWN) {
if (shift) {
collapse_notification_panel(input_manager->controller);
} else {
@ -299,6 +303,10 @@ input_manager_process_key(struct input_manager *input_manager,
return;
}
if (!control) {
return;
}
struct control_event control_event;
if (input_key_from_sdl_to_android(event, &control_event)) {
if (!controller_push_event(input_manager->controller, &control_event)) {
@ -334,12 +342,15 @@ is_outside_device_screen(struct input_manager *input_manager, int x, int y)
void
input_manager_process_mouse_button(struct input_manager *input_manager,
const SDL_MouseButtonEvent *event) {
// false if the user requested not to interact with the device
SDL_bool control = input_manager->control;
if (event->type == SDL_MOUSEBUTTONDOWN) {
if (event->button == SDL_BUTTON_RIGHT) {
if (control && event->button == SDL_BUTTON_RIGHT) {
press_back_or_turn_screen_on(input_manager->controller);
return;
}
if (event->button == SDL_BUTTON_MIDDLE) {
if (control && event->button == SDL_BUTTON_MIDDLE) {
action_home(input_manager->controller, ACTION_DOWN | ACTION_UP);
return;
}
@ -356,6 +367,10 @@ input_manager_process_mouse_button(struct input_manager *input_manager,
// otherwise, send the click event to the device
}
if (!control) {
return;
}
struct control_event control_event;
if (mouse_button_from_sdl_to_android(event,
input_manager->screen->frame_size,

View file

@ -11,6 +11,7 @@ struct input_manager {
struct controller *controller;
struct video_buffer *video_buffer;
struct screen *screen;
SDL_bool control;
};
void

View file

@ -16,6 +16,7 @@ struct args {
const char *record_filename;
enum recorder_format record_format;
SDL_bool fullscreen;
SDL_bool no_control;
SDL_bool no_display;
SDL_bool help;
SDL_bool version;
@ -58,6 +59,9 @@ static void usage(const char *arg0) {
" is preserved.\n"
" Default is %d%s.\n"
"\n"
" -n, --no-control\n"
" Disable device control (mirror the device in read-only).\n"
"\n"
" -N, --no-display\n"
" Do not display device (only when screen recording is\n"
" enabled).\n"
@ -277,6 +281,7 @@ parse_args(struct args *args, int argc, char *argv[]) {
{"fullscreen", no_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{"max-size", required_argument, NULL, 'm'},
{"no-control", no_argument, NULL, 'n'},
{"no-display", no_argument, NULL, 'N'},
{"port", required_argument, NULL, 'p'},
{"record", required_argument, NULL, 'r'},
@ -287,7 +292,7 @@ parse_args(struct args *args, int argc, char *argv[]) {
{NULL, 0, NULL, 0 },
};
int c;
while ((c = getopt_long(argc, argv, "b:c:fF:hm:Np:r:s:tTv", long_options,
while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:tTv", long_options,
NULL)) != -1) {
switch (c) {
case 'b':
@ -314,6 +319,9 @@ parse_args(struct args *args, int argc, char *argv[]) {
return SDL_FALSE;
}
break;
case 'n':
args->no_control = SDL_TRUE;
break;
case 'N':
args->no_display = SDL_TRUE;
break;
@ -396,6 +404,7 @@ main(int argc, char *argv[]) {
.max_size = DEFAULT_MAX_SIZE,
.bit_rate = DEFAULT_BIT_RATE,
.always_on_top = SDL_FALSE,
.no_control = SDL_FALSE,
.no_display = SDL_FALSE,
};
if (!parse_args(&args, argc, argv)) {
@ -435,6 +444,7 @@ main(int argc, char *argv[]) {
.show_touches = args.show_touches,
.fullscreen = args.fullscreen,
.always_on_top = args.always_on_top,
.no_control = args.no_control,
.no_display = args.no_display,
};
int res = scrcpy(&options) ? 0 : 1;

View file

@ -39,6 +39,7 @@ static struct input_manager input_manager = {
.controller = &controller,
.video_buffer = &video_buffer,
.screen = &screen,
.control = SDL_TRUE,
};
#if defined(__APPLE__) || defined(__WINDOWS__)
@ -75,7 +76,7 @@ enum event_result {
};
static enum event_result
handle_event(SDL_Event *event) {
handle_event(SDL_Event *event, SDL_bool control) {
switch (event->type) {
case EVENT_STREAM_STOPPED:
LOGD("Video stream stopped");
@ -102,23 +103,39 @@ handle_event(SDL_Event *event) {
}
break;
case SDL_TEXTINPUT:
if (!control) {
break;
}
input_manager_process_text_input(&input_manager, &event->text);
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
// some key events do not interact with the device, so process the
// event even if control is disabled
input_manager_process_key(&input_manager, &event->key);
break;
case SDL_MOUSEMOTION:
if (!control) {
break;
}
input_manager_process_mouse_motion(&input_manager, &event->motion);
break;
case SDL_MOUSEWHEEL:
if (!control) {
break;
}
input_manager_process_mouse_wheel(&input_manager, &event->wheel);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
// some mouse events do not interact with the device, so process
// the event even if control is disabled
input_manager_process_mouse_button(&input_manager, &event->button);
break;
case SDL_DROPFILE: {
if (!control) {
break;
}
file_handler_action_t action;
if (is_apk(event->drop.file)) {
action = ACTION_INSTALL_APK;
@ -133,7 +150,7 @@ handle_event(SDL_Event *event) {
}
static SDL_bool
event_loop(SDL_bool display) {
event_loop(SDL_bool display, SDL_bool control) {
#ifdef CONTINUOUS_RESIZING_WORKAROUND
if (display) {
SDL_AddEventWatch(event_watcher, NULL);
@ -141,7 +158,7 @@ event_loop(SDL_bool display) {
#endif
SDL_Event event;
while (SDL_WaitEvent(&event)) {
enum event_result result = handle_event(&event);
enum event_result result = handle_event(&event, control);
switch (result) {
case EVENT_RESULT_STOPPED_BY_USER:
return SDL_TRUE;
@ -248,6 +265,9 @@ scrcpy(const struct scrcpy_options *options) {
}
SDL_bool display = !options->no_display;
SDL_bool control = !options->no_control;
input_manager.control = control;
struct decoder *dec = NULL;
if (display) {
@ -257,7 +277,7 @@ scrcpy(const struct scrcpy_options *options) {
goto finally_destroy_server;
}
if (!file_handler_init(&file_handler, server.serial)) {
if (control && !file_handler_init(&file_handler, server.serial)) {
ret = SDL_FALSE;
server_stop(&server);
goto finally_destroy_video_buffer;
@ -293,6 +313,7 @@ scrcpy(const struct scrcpy_options *options) {
}
if (display) {
if (control) {
if (!controller_init(&controller, device_socket)) {
ret = SDL_FALSE;
goto finally_stop_stream;
@ -302,6 +323,7 @@ scrcpy(const struct scrcpy_options *options) {
ret = SDL_FALSE;
goto finally_destroy_controller;
}
}
if (!screen_init_rendering(&screen, device_name, frame_size,
options->always_on_top)) {
@ -319,18 +341,18 @@ scrcpy(const struct scrcpy_options *options) {
show_touches_waited = SDL_TRUE;
}
ret = event_loop(display);
ret = event_loop(display, control);
LOGD("quit...");
screen_destroy(&screen);
finally_stop_and_join_controller:
if (display) {
if (display && control) {
controller_stop(&controller);
controller_join(&controller);
}
finally_destroy_controller:
if (display) {
if (display && control) {
controller_destroy(&controller);
}
finally_stop_stream:
@ -343,7 +365,7 @@ finally_destroy_recorder:
recorder_destroy(&recorder);
}
finally_destroy_file_handler:
if (display) {
if (display && control) {
file_handler_stop(&file_handler);
file_handler_join(&file_handler);
file_handler_destroy(&file_handler);

View file

@ -15,6 +15,7 @@ struct scrcpy_options {
SDL_bool show_touches;
SDL_bool fullscreen;
SDL_bool always_on_top;
SDL_bool no_control;
SDL_bool no_display;
};