From a139509f118f239ffa132caa042f3bbd1818de9d Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Fri, 2 Feb 2018 14:52:23 +0100 Subject: [PATCH] Turn screen on on right-click The right-click is almost useless on Android, so use it to turn the screen on. Add a new control event type (command) to request the server to turn the screen on. --- app/src/controlevent.c | 3 ++ app/src/controlevent.h | 6 ++++ app/src/scrcpy.c | 16 ++++++++++ .../com/genymobile/scrcpy/ControlEvent.java | 12 +++++++- .../genymobile/scrcpy/ControlEventReader.java | 8 +++++ .../java/com/genymobile/scrcpy/Device.java | 5 ++++ .../genymobile/scrcpy/EventController.java | 24 +++++++++++++++ .../scrcpy/wrappers/PowerManager.java | 30 +++++++++++++++++++ .../scrcpy/wrappers/ServiceManager.java | 4 +++ 9 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java diff --git a/app/src/controlevent.c b/app/src/controlevent.c index c63da32d..4e5517c4 100644 --- a/app/src/controlevent.c +++ b/app/src/controlevent.c @@ -52,6 +52,9 @@ int control_event_serialize(const struct control_event *event, unsigned char *bu write32(&buf[9], (Uint32) event->scroll_event.hscroll); write32(&buf[13], (Uint32) event->scroll_event.vscroll); return 17; + case CONTROL_EVENT_TYPE_COMMAND: + buf[1] = event->command_event.action; + return 2; default: SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown event type: %u", (unsigned) event->type); return 0; diff --git a/app/src/controlevent.h b/app/src/controlevent.h index 077fb7ef..71807f64 100644 --- a/app/src/controlevent.h +++ b/app/src/controlevent.h @@ -17,8 +17,11 @@ enum control_event_type { CONTROL_EVENT_TYPE_TEXT, CONTROL_EVENT_TYPE_MOUSE, CONTROL_EVENT_TYPE_SCROLL, + CONTROL_EVENT_TYPE_COMMAND, }; +#define CONTROL_EVENT_COMMAND_SCREEN_ON 0 + struct control_event { enum control_event_type type; union { @@ -40,6 +43,9 @@ struct control_event { Sint32 hscroll; Sint32 vscroll; } scroll_event; + struct { + int action; + } command_event; }; }; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 0eb9da7c..c4b88ac3 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -293,6 +293,18 @@ static void send_keycode(enum android_keycode keycode, const char *name) { } } +static void turn_screen_on(void) { + struct control_event control_event = { + .type = CONTROL_EVENT_TYPE_COMMAND, + .command_event = { + .action = CONTROL_EVENT_COMMAND_SCREEN_ON, + }, + }; + if (!controller_push_event(&controller, &control_event)) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Cannot turn screen on"); + } +} + static SDL_bool handle_new_frame(void) { mutex_lock(frames.mutex); AVFrame *frame = frames.rendering_frame; @@ -432,6 +444,10 @@ static void handle_mouse_motion(const SDL_MouseMotionEvent *event, struct size s } static void handle_mouse_button(const SDL_MouseButtonEvent *event, struct size screen_size) { + if (event->button == SDL_BUTTON_RIGHT) { + turn_screen_on(); + return; + }; struct control_event control_event; if (mouse_button_from_sdl_to_android(event, screen_size, &control_event)) { if (!controller_push_event(&controller, &control_event)) { diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java b/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java index 521038b0..44d7cdd6 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java @@ -9,11 +9,14 @@ public class ControlEvent { public static final int TYPE_TEXT = 1; public static final int TYPE_MOUSE = 2; public static final int TYPE_SCROLL = 3; + public static final int TYPE_COMMAND = 4; + + public static final int COMMAND_SCREEN_ON = 0; private int type; private String text; private int metaState; // KeyEvent.META_* - private int action; // KeyEvent.ACTION_* or MotionEvent.ACTION_* + private int action; // KeyEvent.ACTION_* or MotionEvent.ACTION_* or COMMAND_* private int keycode; // KeyEvent.KEYCODE_* private int buttons; // MotionEvent.BUTTON_* private Position position; @@ -57,6 +60,13 @@ public class ControlEvent { return event; } + public static ControlEvent createCommandControlEvent(int action) { + ControlEvent event = new ControlEvent(); + event.type = TYPE_COMMAND; + event.action = action; + return event; + } + public int getType() { return type; } diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java b/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java index fec2aab1..b5becee1 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java @@ -10,6 +10,7 @@ public class ControlEventReader { private static final int KEYCODE_PAYLOAD_LENGTH = 9; private static final int MOUSE_PAYLOAD_LENGTH = 13; private static final int SCROLL_PAYLOAD_LENGTH = 16; + private static final int COMMAND_PAYLOAD_LENGTH = 1; private final byte[] rawBuffer = new byte[128]; private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer); @@ -86,6 +87,13 @@ public class ControlEventReader { int vScroll = buffer.getInt(); return ControlEvent.createScrollControlEvent(position, hScroll, vScroll); } + case ControlEvent.TYPE_COMMAND: { + if (buffer.remaining() < COMMAND_PAYLOAD_LENGTH) { + break; + } + int action = toUnsigned(buffer.get()); + return ControlEvent.createCommandControlEvent(action); + } default: Ln.w("Unknown event type: " + type); } diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java index 234090bf..b663a0ab 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/Device.java @@ -6,6 +6,7 @@ import android.os.RemoteException; import android.view.IRotationWatcher; import com.genymobile.scrcpy.wrappers.InputManager; +import com.genymobile.scrcpy.wrappers.PowerManager; import com.genymobile.scrcpy.wrappers.ServiceManager; public final class Device { @@ -93,6 +94,10 @@ public final class Device { return serviceManager.getInputManager(); } + public PowerManager getPowerManager() { + return serviceManager.getPowerManager(); + } + public void registerRotationWatcher(IRotationWatcher rotationWatcher) { serviceManager.getWindowManager().registerRotationWatcher(rotationWatcher); } diff --git a/server/src/main/java/com/genymobile/scrcpy/EventController.java b/server/src/main/java/com/genymobile/scrcpy/EventController.java index 8103e251..32397f51 100644 --- a/server/src/main/java/com/genymobile/scrcpy/EventController.java +++ b/server/src/main/java/com/genymobile/scrcpy/EventController.java @@ -9,6 +9,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import com.genymobile.scrcpy.wrappers.InputManager; +import com.genymobile.scrcpy.wrappers.PowerManager; import java.io.IOException; @@ -16,6 +17,7 @@ public class EventController { private final Device device; private final InputManager inputManager; + private final PowerManager powerManager; private final DesktopConnection connection; private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); @@ -28,6 +30,7 @@ public class EventController { this.device = device; this.connection = connection; inputManager = device.getInputManager(); + powerManager = device.getPowerManager(); initPointer(); } @@ -79,6 +82,10 @@ public class EventController { break; case ControlEvent.TYPE_SCROLL: injectScroll(controlEvent.getPosition(), controlEvent.getHScroll(), controlEvent.getVScroll()); + break; + case ControlEvent.TYPE_COMMAND: + executeCommand(controlEvent.getAction()); + break; } return true; } @@ -137,7 +144,24 @@ public class EventController { return injectEvent(event); } + private boolean injectKeycode(int keyCode) { + return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0) + && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0); + } + private boolean injectEvent(InputEvent event) { return inputManager.injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); } + + private boolean turnScreenOn() { + return powerManager.isScreenOn() || injectKeycode(KeyEvent.KEYCODE_POWER); + } + + private boolean executeCommand(int action) { + switch (action) { + case ControlEvent.COMMAND_SCREEN_ON: + return turnScreenOn(); + } + return false; + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java new file mode 100644 index 00000000..b53add80 --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/PowerManager.java @@ -0,0 +1,30 @@ +package com.genymobile.scrcpy.wrappers; + +import android.os.Build; +import android.os.IInterface; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class PowerManager { + private final IInterface manager; + private final Method isScreenOnMethod; + + public PowerManager(IInterface manager) { + this.manager = manager; + try { + String methodName = Build.VERSION.SDK_INT >= 20 ? "isInteractive" : "isScreenOn"; + isScreenOnMethod = manager.getClass().getMethod(methodName); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + public boolean isScreenOn() { + try { + return (Boolean) isScreenOnMethod.invoke(manager); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new AssertionError(e); + } + } +} diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java index c76a85f0..949eae27 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java @@ -37,4 +37,8 @@ public class ServiceManager { public InputManager getInputManager() { return new InputManager(getService("input", "android.hardware.input.IInputManager")); } + + public PowerManager getPowerManager() { + return new PowerManager(getService("power", "android.os.IPowerManager")); + } }