Compare commits
5 Commits
linux_maco
...
issue5542
Author | SHA1 | Date | |
---|---|---|---|
330264cdc6 | |||
3e689020ba | |||
3d1f036c04 | |||
3d5294c1e5 | |||
1d2f16dbb5 |
@ -23,14 +23,20 @@ To control the device without mirroring:
|
||||
scrcpy --no-video --no-audio
|
||||
```
|
||||
|
||||
By default, mouse mode is switched to UHID if video mirroring is disabled (a
|
||||
relative mouse mode is required).
|
||||
By default, the mouse is disabled when video playback is turned off.
|
||||
|
||||
To control the device using a relative mouse, enable UHID mouse mode:
|
||||
|
||||
```bash
|
||||
scrcpy --no-video --no-audio --mouse=uhid
|
||||
scrcpy --no-video --no-audio -M # short version
|
||||
```
|
||||
|
||||
To also use a UHID keyboard, set it explicitly:
|
||||
|
||||
```bash
|
||||
scrcpy --no-video --no-audio --keyboard=uhid
|
||||
scrcpy --no-video --no-audio -K # short version
|
||||
scrcpy --no-video --no-audio --mouse=uhid --keyboard=uhid
|
||||
scrcpy --no-video --no-audio -MK # short version
|
||||
```
|
||||
|
||||
To use AOA instead (over USB only):
|
||||
|
@ -207,13 +207,15 @@ public final class CleanUp {
|
||||
}
|
||||
}
|
||||
|
||||
if (displayId != Device.DISPLAY_ID_NONE && Device.isScreenOn(displayId)) {
|
||||
// Change the power of the main display when mirroring a virtual display
|
||||
int targetDisplayId = displayId != Device.DISPLAY_ID_NONE ? displayId : 0;
|
||||
if (Device.isScreenOn(targetDisplayId)) {
|
||||
if (powerOffScreen) {
|
||||
Ln.i("Power off screen");
|
||||
Device.powerOffScreen(displayId);
|
||||
Device.powerOffScreen(targetDisplayId);
|
||||
} else if (restoreDisplayPower) {
|
||||
Ln.i("Restoring display power");
|
||||
Device.setDisplayPower(displayId, true);
|
||||
Device.setDisplayPower(targetDisplayId, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,7 +281,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
setClipboard(msg.getText(), msg.getPaste(), msg.getSequence());
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_DISPLAY_POWER:
|
||||
if (supportsInputEvents && displayId != Device.DISPLAY_ID_NONE) {
|
||||
if (supportsInputEvents) {
|
||||
setDisplayPower(msg.getOn());
|
||||
}
|
||||
break;
|
||||
@ -356,16 +356,27 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
// it hides the field on purpose, to read it with atomic access
|
||||
@SuppressWarnings("checkstyle:HiddenField")
|
||||
DisplayData displayData = this.displayData.get();
|
||||
assert displayData != null : "Cannot receive a touch event without a display";
|
||||
// In scrcpy, displayData should never be null (a touch event can only be generated from the client on a video frame), but it is possible
|
||||
// to send events without video playback using scrcpy-server alone (except for virtual displays).
|
||||
assert displayData != null || displayId != Device.DISPLAY_ID_NONE : "Cannot receive a touch event without a display";
|
||||
|
||||
Point point = displayData.positionMapper.map(position);
|
||||
if (point == null) {
|
||||
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
|
||||
Size eventSize = position.getScreenSize();
|
||||
Size currentSize = displayData.positionMapper.getVideoSize();
|
||||
Ln.v("Ignore touch event generated for size " + eventSize + " (current size is " + currentSize + ")");
|
||||
Point point;
|
||||
int targetDisplayId;
|
||||
if (displayData != null) {
|
||||
point = displayData.positionMapper.map(position);
|
||||
if (point == null) {
|
||||
if (Ln.isEnabled(Ln.Level.VERBOSE)) {
|
||||
Size eventSize = position.getScreenSize();
|
||||
Size currentSize = displayData.positionMapper.getVideoSize();
|
||||
Ln.v("Ignore touch event generated for size " + eventSize + " (current size is " + currentSize + ")");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
targetDisplayId = displayData.virtualDisplayId;
|
||||
} else {
|
||||
// No display, use the raw coordinates
|
||||
point = position.getPoint();
|
||||
targetDisplayId = displayId;
|
||||
}
|
||||
|
||||
int pointerIndex = pointersState.getPointerIndex(pointerId);
|
||||
@ -421,7 +432,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
// First button pressed: ACTION_DOWN
|
||||
MotionEvent downEvent = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_DOWN, pointerCount, pointerProperties,
|
||||
pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0);
|
||||
if (!Device.injectEvent(downEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
if (!Device.injectEvent(downEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -432,7 +443,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
if (!InputManager.setActionButton(pressEvent, actionButton)) {
|
||||
return false;
|
||||
}
|
||||
if (!Device.injectEvent(pressEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
if (!Device.injectEvent(pressEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -446,7 +457,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
if (!InputManager.setActionButton(releaseEvent, actionButton)) {
|
||||
return false;
|
||||
}
|
||||
if (!Device.injectEvent(releaseEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
if (!Device.injectEvent(releaseEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -454,7 +465,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
// Last button released: ACTION_UP
|
||||
MotionEvent upEvent = MotionEvent.obtain(lastTouchDown, now, MotionEvent.ACTION_UP, pointerCount, pointerProperties,
|
||||
pointerCoords, 0, buttons, 1f, 1f, DEFAULT_DEVICE_ID, 0, source, 0);
|
||||
if (!Device.injectEvent(upEvent, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
if (!Device.injectEvent(upEvent, targetDisplayId, Device.INJECT_MODE_ASYNC)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -465,7 +476,7 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
|
||||
MotionEvent event = MotionEvent.obtain(lastTouchDown, now, action, pointerCount, pointerProperties, pointerCoords, 0, buttons, 1f, 1f,
|
||||
DEFAULT_DEVICE_ID, 0, source, 0);
|
||||
return Device.injectEvent(event, displayData.virtualDisplayId, Device.INJECT_MODE_ASYNC);
|
||||
return Device.injectEvent(event, targetDisplayId, Device.INJECT_MODE_ASYNC);
|
||||
}
|
||||
|
||||
private boolean injectScroll(Position position, float hScroll, float vScroll, int buttons) {
|
||||
@ -691,9 +702,12 @@ public class Controller implements AsyncProcessor, VirtualDisplayListener {
|
||||
}
|
||||
|
||||
private void setDisplayPower(boolean on) {
|
||||
boolean setDisplayPowerOk = Device.setDisplayPower(displayId, on);
|
||||
// Change the power of the main display when mirroring a virtual display
|
||||
int targetDisplayId = displayId != Device.DISPLAY_ID_NONE ? displayId : 0;
|
||||
boolean setDisplayPowerOk = Device.setDisplayPower(targetDisplayId, on);
|
||||
if (setDisplayPowerOk) {
|
||||
keepDisplayPowerOff = !on;
|
||||
// Do not keep display power off for virtual displays: MOD+p must wake up the physical device
|
||||
keepDisplayPowerOff = displayId != Device.DISPLAY_ID_NONE && !on;
|
||||
Ln.i("Device display turned " + (on ? "on" : "off"));
|
||||
if (cleanUp != null) {
|
||||
boolean mustRestoreOnExit = !on;
|
||||
|
@ -40,6 +40,10 @@ public final class Device {
|
||||
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;
|
||||
|
||||
// The new display power method introduced in Android 15 does not work as expected:
|
||||
// <https://github.com/Genymobile/scrcpy/issues/5530>
|
||||
private static final boolean USE_ANDROID_15_DISPLAY_POWER = false;
|
||||
|
||||
private Device() {
|
||||
// not instantiable
|
||||
}
|
||||
@ -127,7 +131,7 @@ public final class Device {
|
||||
public static boolean setDisplayPower(int displayId, boolean on) {
|
||||
assert displayId != Device.DISPLAY_ID_NONE;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= AndroidVersions.API_35_ANDROID_15) {
|
||||
if (USE_ANDROID_15_DISPLAY_POWER && Build.VERSION.SDK_INT >= AndroidVersions.API_35_ANDROID_15) {
|
||||
return ServiceManager.getDisplayManager().requestDisplayPower(displayId, on);
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,9 @@ public final class DisplayManager {
|
||||
if ("onDisplayChanged".equals(method.getName())) {
|
||||
listener.onDisplayChanged((int) args[0]);
|
||||
}
|
||||
if ("toString".equals(method.getName())) {
|
||||
return "DisplayListener";
|
||||
}
|
||||
return null;
|
||||
});
|
||||
try {
|
||||
|
Reference in New Issue
Block a user