diff --git a/README.md b/README.md index d875fd9989..4ef28ab203 100644 --- a/README.md +++ b/README.md @@ -440,8 +440,12 @@ scrcpy -S Or by pressing MOD+o at any time. -To turn it back on, press MOD+Shift+o (or -`POWER`, MOD+p). +To turn it back on, press MOD+Shift+o. + +On Android, the `POWER` button always turns the screen on. For convenience, if +`POWER` is sent via scrcpy (via right-click or Ctrl+p), it +will force to turn the screen off after a small delay (on a best effort basis). +The physical `POWER` button will still cause the screen to be turned on. It can be useful to also prevent the device to sleep: diff --git a/server/src/main/java/com/genymobile/scrcpy/Controller.java b/server/src/main/java/com/genymobile/scrcpy/Controller.java index f32e5ec04e..2ad26a9506 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/Controller.java @@ -8,11 +8,16 @@ import android.view.MotionEvent; import java.io.IOException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; public class Controller { private static final int DEVICE_ID_VIRTUAL = -1; + private static final ScheduledExecutorService EXECUTOR = Executors.newSingleThreadScheduledExecutor(); + private final Device device; private final DesktopConnection connection; private final DeviceMessageSender sender; @@ -24,6 +29,8 @@ public class Controller { private final MotionEvent.PointerProperties[] pointerProperties = new MotionEvent.PointerProperties[PointersState.MAX_POINTERS]; private final MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[PointersState.MAX_POINTERS]; + private boolean keepPowerModeOff; + public Controller(Device device, DesktopConnection connection) { this.device = device; this.connection = connection; @@ -117,6 +124,7 @@ private void handleEvent() throws IOException { int mode = msg.getAction(); boolean setPowerModeOk = Device.setScreenPowerMode(mode); if (setPowerModeOk) { + keepPowerModeOff = mode == Device.POWER_MODE_OFF; Ln.i("Device screen turned " + (mode == Device.POWER_MODE_OFF ? "off" : "on")); } } @@ -130,6 +138,9 @@ private void handleEvent() throws IOException { } private boolean injectKeycode(int action, int keycode, int repeat, int metaState) { + if (keepPowerModeOff && action == KeyEvent.ACTION_UP && (keycode == KeyEvent.KEYCODE_POWER || keycode == KeyEvent.KEYCODE_WAKEUP)) { + schedulePowerModeOff(); + } return device.injectKeyEvent(action, keycode, repeat, metaState); } @@ -223,8 +234,24 @@ private boolean injectScroll(Position position, int hScroll, int vScroll) { return device.injectEvent(event); } + /** + * Schedule a call to set power mode to off after a small delay. + */ + private static void schedulePowerModeOff() { + EXECUTOR.schedule(new Runnable() { + @Override + public void run() { + Ln.i("Forcing screen off"); + Device.setScreenPowerMode(Device.POWER_MODE_OFF); + } + }, 200, TimeUnit.MILLISECONDS); + } + private boolean pressBackOrTurnScreenOn() { int keycode = device.isScreenOn() ? KeyEvent.KEYCODE_BACK : KeyEvent.KEYCODE_WAKEUP; + if (keepPowerModeOff && keycode == KeyEvent.KEYCODE_WAKEUP) { + schedulePowerModeOff(); + } return device.injectKeycode(keycode); }