diff --git a/app/src/control_msg.c b/app/src/control_msg.c index 9c3d9849fa..2161c29ae5 100644 --- a/app/src/control_msg.c +++ b/app/src/control_msg.c @@ -62,6 +62,7 @@ control_msg_serialize(const struct control_msg *msg, unsigned char *buf) { case CONTROL_MSG_TYPE_EXPAND_NOTIFICATION_PANEL: case CONTROL_MSG_TYPE_COLLAPSE_NOTIFICATION_PANEL: case CONTROL_MSG_TYPE_GET_CLIPBOARD: + case CONTROL_MSG_TYPE_LOCK_SCREEN: // no additional data return 1; default: diff --git a/app/src/control_msg.h b/app/src/control_msg.h index e7fdfc4cb5..b3e1cd4e99 100644 --- a/app/src/control_msg.h +++ b/app/src/control_msg.h @@ -25,6 +25,7 @@ enum control_msg_type { CONTROL_MSG_TYPE_GET_CLIPBOARD, CONTROL_MSG_TYPE_SET_CLIPBOARD, CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE, + CONTROL_MSG_TYPE_LOCK_SCREEN, }; enum screen_power_mode { diff --git a/app/src/main.c b/app/src/main.c index 3be74d6b8f..5b1716afed 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -32,6 +32,7 @@ struct args { bool always_on_top; bool turn_screen_off; bool render_expired_frames; + bool lock_screen_when_closing; }; static void usage(const char *arg0) { @@ -118,6 +119,9 @@ static void usage(const char *arg0) { " --window-title text\n" " Set a custom window title.\n" "\n" + " --lock-screen-when-closing\n" + " Lock device screen when closing scrcpy.\n" + "\n" "Shortcuts:\n" "\n" " " CTRL_OR_CMD "+f\n" @@ -309,34 +313,37 @@ guess_record_format(const char *filename) { return 0; } -#define OPT_RENDER_EXPIRED_FRAMES 1000 -#define OPT_WINDOW_TITLE 1001 -#define OPT_PUSH_TARGET 1002 +#define OPT_RENDER_EXPIRED_FRAMES 1000 +#define OPT_WINDOW_TITLE 1001 +#define OPT_PUSH_TARGET 1002 +#define OPT_LOCK_SCREEN_WHEN_CLOSING 1003 static bool parse_args(struct args *args, int argc, char *argv[]) { static const struct option long_options[] = { - {"always-on-top", no_argument, NULL, 'T'}, - {"bit-rate", required_argument, NULL, 'b'}, - {"crop", required_argument, NULL, 'c'}, - {"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'}, - {"push-target", required_argument, NULL, + {"always-on-top", no_argument, NULL, 'T'}, + {"bit-rate", required_argument, NULL, 'b'}, + {"crop", required_argument, NULL, 'c'}, + {"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'}, + {"push-target", required_argument, NULL, OPT_PUSH_TARGET}, - {"record", required_argument, NULL, 'r'}, - {"record-format", required_argument, NULL, 'F'}, - {"render-expired-frames", no_argument, NULL, + {"record", required_argument, NULL, 'r'}, + {"record-format", required_argument, NULL, 'F'}, + {"render-expired-frames", no_argument, NULL, OPT_RENDER_EXPIRED_FRAMES}, - {"serial", required_argument, NULL, 's'}, - {"show-touches", no_argument, NULL, 't'}, - {"turn-screen-off", no_argument, NULL, 'S'}, - {"version", no_argument, NULL, 'v'}, - {"window-title", required_argument, NULL, + {"serial", required_argument, NULL, 's'}, + {"show-touches", no_argument, NULL, 't'}, + {"turn-screen-off", no_argument, NULL, 'S'}, + {"version", no_argument, NULL, 'v'}, + {"window-title", required_argument, NULL, OPT_WINDOW_TITLE}, + {"lock-screen-when-closing", no_argument, NULL, + OPT_LOCK_SCREEN_WHEN_CLOSING}, {NULL, 0, NULL, 0 }, }; int c; @@ -405,6 +412,9 @@ parse_args(struct args *args, int argc, char *argv[]) { case OPT_PUSH_TARGET: args->push_target = optarg; break; + case OPT_LOCK_SCREEN_WHEN_CLOSING: + args->lock_screen_when_closing = true; + break; default: // getopt prints the error message on stderr return false; @@ -475,6 +485,7 @@ main(int argc, char *argv[]) { .no_display = false, .turn_screen_off = false, .render_expired_frames = false, + .lock_screen_when_closing = false, }; if (!parse_args(&args, argc, argv)) { return 1; @@ -521,6 +532,7 @@ main(int argc, char *argv[]) { .display = !args.no_display, .turn_screen_off = args.turn_screen_off, .render_expired_frames = args.render_expired_frames, + .lock_screen_when_closing = args.lock_screen_when_closing, }; int res = scrcpy(&options) ? 0 : 1; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index ed9887789b..9ea6a27669 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -234,6 +234,16 @@ wait_show_touches(process_t process) { process_check_success(process, "show_touches"); } +static void +lock_screen(struct controller *controller) { + struct control_msg msg; + msg.type = CONTROL_MSG_TYPE_LOCK_SCREEN; + + if (!controller_push_msg(controller, &msg)) { + LOGW("Could not request 'turn screen off'"); + } +} + static SDL_LogPriority sdl_priority_from_av_level(int level) { switch (level) { @@ -411,6 +421,10 @@ scrcpy(const struct scrcpy_options *options) { ret = event_loop(options->display, options->control); LOGD("quit..."); + if (options->lock_screen_when_closing) { + lock_screen(&controller); + } + screen_destroy(&screen); end: diff --git a/app/src/scrcpy.h b/app/src/scrcpy.h index faeb246f1c..a160e9609a 100644 --- a/app/src/scrcpy.h +++ b/app/src/scrcpy.h @@ -22,6 +22,7 @@ struct scrcpy_options { bool display; bool turn_screen_off; bool render_expired_frames; + bool lock_screen_when_closing; }; bool diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java b/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java index a1cd873ab2..72a266e8f8 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlMessage.java @@ -15,6 +15,7 @@ public final class ControlMessage { public static final int TYPE_GET_CLIPBOARD = 7; public static final int TYPE_SET_CLIPBOARD = 8; public static final int TYPE_SET_SCREEN_POWER_MODE = 9; + public static final int TYPE_LOCK_SCREEN = 10; private int type; private String text; diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java b/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java index 8ced049da2..988ab0326a 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlMessageReader.java @@ -75,6 +75,7 @@ public ControlMessage next() { case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL: case ControlMessage.TYPE_COLLAPSE_NOTIFICATION_PANEL: case ControlMessage.TYPE_GET_CLIPBOARD: + case ControlMessage.TYPE_LOCK_SCREEN: msg = ControlMessage.createEmpty(type); break; default: diff --git a/server/src/main/java/com/genymobile/scrcpy/Controller.java b/server/src/main/java/com/genymobile/scrcpy/Controller.java index 263fc2fc37..fb972c47a7 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/Controller.java @@ -96,6 +96,9 @@ private void handleEvent() throws IOException { case ControlMessage.TYPE_BACK_OR_SCREEN_ON: pressBackOrTurnScreenOn(); break; + case ControlMessage.TYPE_LOCK_SCREEN: + lockScreen(); + break; case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL: device.expandNotificationPanel(); break; @@ -198,4 +201,12 @@ private boolean pressBackOrTurnScreenOn() { int keycode = device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_POWER; return injectKeycode(keycode); } + + private boolean lockScreen() { + if (!device.isScreenOn()) { + return true; + } + int keycode = KeyEvent.KEYCODE_POWER; + return injectKeycode(keycode); + } }