From bfcb9d06c351e4976cdc3b69a24bf35b8f1bb1c2 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Mon, 29 Nov 2021 21:46:29 +0100 Subject: [PATCH] Expose sync mode for injecting events Expose the inject input event mode so that it is possible to wait for the events to be "finished". This will be necessary to read the clipboard content only after the COPY or CUT key event is handled. PR #2834 --- .../com/genymobile/scrcpy/Controller.java | 16 +++++----- .../java/com/genymobile/scrcpy/Device.java | 31 +++++++++++-------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/server/src/main/java/com/genymobile/scrcpy/Controller.java b/server/src/main/java/com/genymobile/scrcpy/Controller.java index b52d413e..f853c85a 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/Controller.java @@ -55,7 +55,7 @@ public class Controller { public void control() throws IOException { // on start, power on the device if (!Device.isScreenOn()) { - device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER); + device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER, Device.INJECT_MODE_ASYNC); // dirty hack // After POWER is injected, the device is powered on asynchronously. @@ -144,7 +144,7 @@ public class Controller { if (keepPowerModeOff && action == KeyEvent.ACTION_UP && (keycode == KeyEvent.KEYCODE_POWER || keycode == KeyEvent.KEYCODE_WAKEUP)) { schedulePowerModeOff(); } - return device.injectKeyEvent(action, keycode, repeat, metaState); + return device.injectKeyEvent(action, keycode, repeat, metaState, Device.INJECT_MODE_ASYNC); } private boolean injectChar(char c) { @@ -155,7 +155,7 @@ public class Controller { return false; } for (KeyEvent event : events) { - if (!device.injectEvent(event)) { + if (!device.injectEvent(event, Device.INJECT_MODE_ASYNC)) { return false; } } @@ -219,7 +219,7 @@ public class Controller { MotionEvent event = MotionEvent .obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0); - return device.injectEvent(event); + return device.injectEvent(event, Device.INJECT_MODE_ASYNC); } private boolean injectScroll(Position position, int hScroll, int vScroll) { @@ -242,7 +242,7 @@ public class Controller { MotionEvent event = MotionEvent .obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, 0, 1f, 1f, DEFAULT_DEVICE_ID, 0, InputDevice.SOURCE_MOUSE, 0); - return device.injectEvent(event); + return device.injectEvent(event, Device.INJECT_MODE_ASYNC); } /** @@ -260,7 +260,7 @@ public class Controller { private boolean pressBackOrTurnScreenOn(int action) { if (Device.isScreenOn()) { - return device.injectKeyEvent(action, KeyEvent.KEYCODE_BACK, 0, 0); + return device.injectKeyEvent(action, KeyEvent.KEYCODE_BACK, 0, 0, Device.INJECT_MODE_ASYNC); } // Screen is off @@ -273,7 +273,7 @@ public class Controller { if (keepPowerModeOff) { schedulePowerModeOff(); } - return device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER); + return device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER, Device.INJECT_MODE_ASYNC); } private boolean setClipboard(String text, boolean paste, long sequence) { @@ -284,7 +284,7 @@ public class Controller { // On Android >= 7, also press the PASTE key if requested if (paste && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) { - device.pressReleaseKeycode(KeyEvent.KEYCODE_PASTE); + device.pressReleaseKeycode(KeyEvent.KEYCODE_PASTE, Device.INJECT_MODE_ASYNC); } if (sequence != ControlMessage.SEQUENCE_INVALID) { diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java index 35f4efd4..ba833a06 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/Device.java @@ -24,6 +24,10 @@ public final class Device { public static final int POWER_MODE_OFF = SurfaceControl.POWER_MODE_OFF; public static final int POWER_MODE_NORMAL = SurfaceControl.POWER_MODE_NORMAL; + public static final int INJECT_MODE_ASYNC = InputManager.INJECT_INPUT_EVENT_MODE_ASYNC; + public static final int INJECT_MODE_WAIT_FOR_RESULT = InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT; + public static final int INJECT_MODE_WAIT_FOR_FINISH = InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH; + public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1; public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2; @@ -164,7 +168,7 @@ public final class Device { return supportsInputEvents; } - public static boolean injectEvent(InputEvent inputEvent, int displayId) { + public static boolean injectEvent(InputEvent inputEvent, int displayId, int injectMode) { if (!supportsInputEvents(displayId)) { throw new AssertionError("Could not inject input event if !supportsInputEvents()"); } @@ -173,30 +177,31 @@ public final class Device { return false; } - return SERVICE_MANAGER.getInputManager().injectInputEvent(inputEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); + return SERVICE_MANAGER.getInputManager().injectInputEvent(inputEvent, injectMode); } - public boolean injectEvent(InputEvent event) { - return injectEvent(event, displayId); + public boolean injectEvent(InputEvent event, int injectMode) { + return injectEvent(event, displayId, injectMode); } - public static boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState, int displayId) { + public static boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState, int displayId, int injectMode) { long now = SystemClock.uptimeMillis(); KeyEvent event = new KeyEvent(now, now, action, keyCode, repeat, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD); - return injectEvent(event, displayId); + return injectEvent(event, displayId, injectMode); } - public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState) { - return injectKeyEvent(action, keyCode, repeat, metaState, displayId); + public boolean injectKeyEvent(int action, int keyCode, int repeat, int metaState, int injectMode) { + return injectKeyEvent(action, keyCode, repeat, metaState, displayId, injectMode); } - public static boolean pressReleaseKeycode(int keyCode, int displayId) { - return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0, displayId) && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0, displayId); + public static boolean pressReleaseKeycode(int keyCode, int displayId, int injectMode) { + return injectKeyEvent(KeyEvent.ACTION_DOWN, keyCode, 0, 0, displayId, injectMode) + && injectKeyEvent(KeyEvent.ACTION_UP, keyCode, 0, 0, displayId, injectMode); } - public boolean pressReleaseKeycode(int keyCode) { - return pressReleaseKeycode(keyCode, displayId); + public boolean pressReleaseKeycode(int keyCode, int injectMode) { + return pressReleaseKeycode(keyCode, displayId, injectMode); } public static boolean isScreenOn() { @@ -272,7 +277,7 @@ public final class Device { if (!isScreenOn()) { return true; } - return pressReleaseKeycode(KeyEvent.KEYCODE_POWER, displayId); + return pressReleaseKeycode(KeyEvent.KEYCODE_POWER, displayId, Device.INJECT_MODE_ASYNC); } /**