-
-
Notifications
You must be signed in to change notification settings - Fork 11.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android 13 [preview] Inject input event not working #3186
Comments
Oh, that's pretty bad. Thank you for the report. Does |
I try following input command are working.
and the ADB toybox version of my device is Thank |
That's good news, this means that we could find a solution to make it work (once the sources of Android 13 are published). |
Could you please test with synchronous event injection: diffdiff --git a/server/src/main/java/com/genymobile/scrcpy/Controller.java b/server/src/main/java/com/genymobile/scrcpy/Controller.java
index 481c512f..7912eeb1 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Controller.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Controller.java
@@ -57,7 +57,7 @@ public class Controller {
public void control() throws IOException {
// on start, power on the device
if (!Device.isScreenOn()) {
- device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER, Device.INJECT_MODE_ASYNC);
+ device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER, Device.INJECT_MODE_WAIT_FOR_FINISH);
// dirty hack
// After POWER is injected, the device is powered on asynchronously.
@@ -154,7 +154,7 @@ public class Controller {
return false;
}
for (KeyEvent event : events) {
- if (!device.injectEvent(event, Device.INJECT_MODE_ASYNC)) {
+ if (!device.injectEvent(event, Device.INJECT_MODE_WAIT_FOR_RESULT)) {
return false;
}
}
@@ -218,7 +218,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, Device.INJECT_MODE_ASYNC);
+ return device.injectEvent(event, Device.INJECT_MODE_WAIT_FOR_FINISH);
}
private boolean injectScroll(Position position, int hScroll, int vScroll, int buttons) {
@@ -241,7 +241,7 @@ public class Controller {
MotionEvent event = MotionEvent
.obtain(lastTouchDown, now, MotionEvent.ACTION_SCROLL, 1, pointerProperties, pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0,
InputDevice.SOURCE_MOUSE, 0);
- return device.injectEvent(event, Device.INJECT_MODE_ASYNC);
+ return device.injectEvent(event, Device.INJECT_MODE_WAIT_FOR_RESULT);
}
/**
@@ -259,7 +259,7 @@ public class Controller {
private boolean pressBackOrTurnScreenOn(int action) {
if (Device.isScreenOn()) {
- return device.injectKeyEvent(action, KeyEvent.KEYCODE_BACK, 0, 0, Device.INJECT_MODE_ASYNC);
+ return device.injectKeyEvent(action, KeyEvent.KEYCODE_BACK, 0, 0, Device.INJECT_MODE_WAIT_FOR_FINISH);
}
// Screen is off
@@ -272,7 +272,7 @@ public class Controller {
if (keepPowerModeOff) {
schedulePowerModeOff();
}
- return device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER, Device.INJECT_MODE_ASYNC);
+ return device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER, Device.INJECT_MODE_WAIT_FOR_RESULT);
}
private void getClipboard(int copyKey) {
@@ -302,7 +302,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.INJECT_MODE_ASYNC);
+ device.pressReleaseKeycode(KeyEvent.KEYCODE_PASTE, Device.INJECT_MODE_WAIT_FOR_FINISH);
}
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 763a7fad..57642e30 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Device.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Device.java
@@ -292,7 +292,7 @@ public final class Device {
if (!isScreenOn()) {
return true;
}
- return pressReleaseKeycode(KeyEvent.KEYCODE_POWER, displayId, Device.INJECT_MODE_ASYNC);
+ return pressReleaseKeycode(KeyEvent.KEYCODE_POWER, displayId, Device.INJECT_MODE_WAIT_FOR_RESULT);
}
/** Here is a binary (to replace in your v1.23 release):
|
I try it it's still failed, Input event not working. Here is the error response
And I found the |
Since 9a7d7dbfb55e19e56f932c8820448514837f39c6 (already in Android 12), this code run in the input manager service, so it does not run with shell permissions anymore (like scrcpy does). They probably added more checks to reject such injections from "outside". I'm a bit afraid that the only solution will be to call |
Oh! it's bad news, How about get the permission in |
I think vysor use the same mechanism as scrcpy to inject input events. Could you test it on your Android 13? |
I found vysor can run well on Android 13. Maybe is a good news, but I can't figure out how it obtain the permission. You are right vysor also use |
Yes, this is good news 👍 Thank you. Could you please post the logcat warnings when you try to inject key events with scrcpy? (the logs in the first post seems to refer to motion events only) |
Could you also test with this change, please? diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java
index 763a7fad..f6e34f56 100644
--- a/server/src/main/java/com/genymobile/scrcpy/Device.java
+++ b/server/src/main/java/com/genymobile/scrcpy/Device.java
@@ -188,7 +188,7 @@ public final class Device {
throw new AssertionError("Could not inject input event if !supportsInputEvents()");
}
- if (displayId != 0 && !InputManager.setDisplayId(inputEvent, displayId)) {
+ if (!InputManager.setDisplayId(inputEvent, displayId)) {
return false;
}
|
I try the new version server file. It's still not working. |
I have changed |
I found that ADB command
this is the code I tested using C#
By this method injectEvent is working. |
Thank you for your tests.
I guess it's the same mechanism as
June, 2022? You get security updates early 😄
Or in bash: echo 'tap 1000 2000' | nc localhost 4004 Btw, I could not find the error messages from the first post on They have probably been added in code that has not been published yet… |
Does Vysor work on this version? |
Yes, I'm using early security upadtes patch.
Yes, It work good in this version. I have another question what if directly use |
Let's try (still by reflection, because diffdiff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java
index 61168993..3ba4f97a 100644
--- a/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java
+++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/InputManager.java
@@ -14,13 +14,13 @@ public final class InputManager {
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1;
public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2;
- private final IInterface manager;
+ private final android.hardware.input.InputManager manager;
private Method injectInputEventMethod;
private boolean alternativeInjectInputEventMethod;
private static Method setDisplayIdMethod;
- public InputManager(IInterface manager) {
+ public InputManager(android.hardware.input.InputManager manager) {
this.manager = manager;
}
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 6f4b9c04..ea2a0784 100644
--- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java
+++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
import android.os.IBinder;
import android.os.IInterface;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@SuppressLint("PrivateApi,DiscouragedPrivateApi")
@@ -56,7 +57,13 @@ public final class ServiceManager {
public InputManager getInputManager() {
if (inputManager == null) {
- inputManager = new InputManager(getService("input", "android.hardware.input.IInputManager"));
+ try {
+ Method getInstanceMethod = android.hardware.input.InputManager.class.getDeclaredMethod("getInstance");
+ android.hardware.input.InputManager im = (android.hardware.input.InputManager) getInstanceMethod.invoke(null);
+ inputManager = new InputManager(im);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new AssertionError(e);
+ }
}
return inputManager;
}
It can find it, but not invoke it:
|
Congratulations!!! It's working.
Very good news, thanks god is friday!! |
Awesome! Thank you very much. 🎉 I'll merge that soon, then publish a new version (1.24). I expect many people to report the issue next year, with always the same answer "upgrade to scrcpy >= 1.24" 😄 (similar to #2129 for Android 12) |
Could you please also test other scrcpy features (shortcuts, copy-paste, |
I have check major function of scrcpy, there look's good. |
Hello @rom1v, i have a question about this part of code, when i try run in under Android 13 to injectEvent, i receive this exception : java.lang.SecurityException: Injecting input events requires the caller (or the source of the instrumentation, if any) to have the INJECT_EVENTS permission. I'm curious how do you bypass this exception in Android 13 ? Thanks in advance for your reply |
@itech-apps How do you execute the code? Is it from an Android app? |
Thanks for your reply @rom1v. Yes, i have take the part of InputManager as done (by method reflection ..) and then run it on my test app : |
Here is the ROM version : TP1A.220624.021 |
You can't run this from an Android app (you could not get the permission). That's the reason why scrcpy is not an Android app, but a java program executed from |
Ah, oki thank you @rom1v. |
Environment
Describe the bug
Inject input event is failed in Android 13, both failed in Mouse event and keyboard event.
adb logcat :
The text was updated successfully, but these errors were encountered: