Add option to mirror in read-only
Add an option to disable device control: -n/--no-control.
This commit is contained in:
parent
163cd36ccc
commit
8655ba7197
6 changed files with 92 additions and 32 deletions
11
README.md
11
README.md
|
@ -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_.
|
||||
|
|
|
@ -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,20 +342,23 @@ 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;
|
||||
}
|
||||
// double-click on black borders resize to fit the device screen
|
||||
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
|
||||
SDL_bool outside= is_outside_device_screen(input_manager,
|
||||
event->x,
|
||||
event->y);
|
||||
SDL_bool outside = is_outside_device_screen(input_manager,
|
||||
event->x,
|
||||
event->y);
|
||||
if (outside) {
|
||||
screen_resize_to_fit(input_manager->screen);
|
||||
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,
|
||||
|
|
|
@ -11,6 +11,7 @@ struct input_manager {
|
|||
struct controller *controller;
|
||||
struct video_buffer *video_buffer;
|
||||
struct screen *screen;
|
||||
SDL_bool control;
|
||||
};
|
||||
|
||||
void
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,14 +313,16 @@ scrcpy(const struct scrcpy_options *options) {
|
|||
}
|
||||
|
||||
if (display) {
|
||||
if (!controller_init(&controller, device_socket)) {
|
||||
ret = SDL_FALSE;
|
||||
goto finally_stop_stream;
|
||||
}
|
||||
if (control) {
|
||||
if (!controller_init(&controller, device_socket)) {
|
||||
ret = SDL_FALSE;
|
||||
goto finally_stop_stream;
|
||||
}
|
||||
|
||||
if (!controller_start(&controller)) {
|
||||
ret = SDL_FALSE;
|
||||
goto finally_destroy_controller;
|
||||
if (!controller_start(&controller)) {
|
||||
ret = SDL_FALSE;
|
||||
goto finally_destroy_controller;
|
||||
}
|
||||
}
|
||||
|
||||
if (!screen_init_rendering(&screen, device_name, frame_size,
|
||||
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue