mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-08-03 22:58:51 +00:00
comments fix, move layerStack field to Device class, prevent sending input event to wrong display
This commit is contained in:
parent
5353dabc9a
commit
2ea23b7fa2
8 changed files with 43 additions and 26 deletions
|
@ -60,7 +60,7 @@ scrcpy_print_usage(const char *arg0) {
|
||||||
" -n, --no-control\n"
|
" -n, --no-control\n"
|
||||||
" Disable device control (mirror the device in read-only).\n"
|
" Disable device control (mirror the device in read-only).\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -d, --display\n"
|
" --display\n"
|
||||||
" Specify the display id to mirror, default 0\n"
|
" Specify the display id to mirror, default 0\n"
|
||||||
"\n"
|
"\n"
|
||||||
" -N, --no-display\n"
|
" -N, --no-display\n"
|
||||||
|
@ -413,6 +413,7 @@ guess_record_format(const char *filename) {
|
||||||
#define OPT_WINDOW_BORDERLESS 1011
|
#define OPT_WINDOW_BORDERLESS 1011
|
||||||
#define OPT_MAX_FPS 1012
|
#define OPT_MAX_FPS 1012
|
||||||
#define OPT_LOCK_VIDEO_ORIENTATION 1013
|
#define OPT_LOCK_VIDEO_ORIENTATION 1013
|
||||||
|
#define OPT_DISPLAY_ID 1014
|
||||||
|
|
||||||
bool
|
bool
|
||||||
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||||
|
@ -446,6 +447,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||||
{"window-height", required_argument, NULL, OPT_WINDOW_HEIGHT},
|
{"window-height", required_argument, NULL, OPT_WINDOW_HEIGHT},
|
||||||
{"window-borderless", no_argument, NULL,
|
{"window-borderless", no_argument, NULL,
|
||||||
OPT_WINDOW_BORDERLESS},
|
OPT_WINDOW_BORDERLESS},
|
||||||
|
{"display", required_argument, NULL, OPT_DISPLAY_ID},
|
||||||
{NULL, 0, NULL, 0 },
|
{NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -454,7 +456,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||||
optind = 0; // reset to start from the first argument in tests
|
optind = 0; // reset to start from the first argument in tests
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNpd:r:s:StTv", long_options,
|
while ((c = getopt_long(argc, argv, "b:c:fF:hm:nNp:r:s:StTv", long_options,
|
||||||
NULL)) != -1) {
|
NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'b':
|
case 'b':
|
||||||
|
@ -508,7 +510,7 @@ scrcpy_parse_args(struct scrcpy_cli_args *args, int argc, char *argv[]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case OPT_DISPLAY_ID:
|
||||||
if (!parse_display_id(optarg, &opts->display_id)) {
|
if (!parse_display_id(optarg, &opts->display_id)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,26 @@ public final class Device {
|
||||||
|
|
||||||
private final ServiceManager serviceManager = new ServiceManager();
|
private final ServiceManager serviceManager = new ServiceManager();
|
||||||
|
|
||||||
private final DisplayInfo displayInfo;
|
|
||||||
private ScreenInfo screenInfo;
|
private ScreenInfo screenInfo;
|
||||||
private RotationListener rotationListener;
|
private RotationListener rotationListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The surface flinger layer stack associated with this logical display.
|
||||||
|
*/
|
||||||
|
private final int layerStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logical display identifier.
|
||||||
|
*/
|
||||||
|
private final int displayId;
|
||||||
|
private final boolean isPresentationDisplay;
|
||||||
|
|
||||||
public Device(Options options) {
|
public Device(Options options) {
|
||||||
DisplayInfo displayInfo = serviceManager.getDisplayManager().getDisplayInfo();
|
DisplayInfo displayInfo = serviceManager.getDisplayManager().getDisplayInfo(options.getDisplayId());
|
||||||
screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize(), options.getLockedVideoOrientation());
|
screenInfo = ScreenInfo.computeScreenInfo(displayInfo, options.getCrop(), options.getMaxSize(), options.getLockedVideoOrientation());
|
||||||
|
layerStack = displayInfo.getLayerStack();
|
||||||
|
displayId = displayInfo.getDisplayId();
|
||||||
|
isPresentationDisplay = displayInfo.isPresentation();
|
||||||
registerRotationWatcher(new IRotationWatcher.Stub() {
|
registerRotationWatcher(new IRotationWatcher.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void onRotationChanged(int rotation) throws RemoteException {
|
public void onRotationChanged(int rotation) throws RemoteException {
|
||||||
|
@ -47,7 +60,7 @@ public final class Device {
|
||||||
Ln.w("Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted");
|
Ln.w("Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted");
|
||||||
}
|
}
|
||||||
if (!isSupportInputEvents()) {
|
if (!isSupportInputEvents()) {
|
||||||
Ln.w("Input events for display with flag FLAG_PRESENTATION, can be supported since API 29");
|
Ln.w("Sorry, can't support input events for displays with FLAG_PRESENTATION flag for devices with API lower then 29");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +68,10 @@ public final class Device {
|
||||||
return screenInfo;
|
return screenInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getLayerStack() {
|
||||||
|
return layerStack;
|
||||||
|
}
|
||||||
|
|
||||||
public Point getPhysicalPoint(Position position) {
|
public Point getPhysicalPoint(Position position) {
|
||||||
// it hides the field on purpose, to read it with a lock
|
// it hides the field on purpose, to read it with a lock
|
||||||
@SuppressWarnings("checkstyle:HiddenField")
|
@SuppressWarnings("checkstyle:HiddenField")
|
||||||
|
@ -86,7 +103,8 @@ public final class Device {
|
||||||
|
|
||||||
public boolean injectInputEvent(InputEvent inputEvent, int mode) {
|
public boolean injectInputEvent(InputEvent inputEvent, int mode) {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
|
||||||
InputManager.setDisplayId(inputEvent, displayInfo.getDisplayId());
|
if (!InputManager.setDisplayId(inputEvent, displayId))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,7 +119,7 @@ public final class Device {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return !displayInfo.isPresentation();
|
return !isPresentationDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerRotationWatcher(IRotationWatcher rotationWatcher) {
|
public void registerRotationWatcher(IRotationWatcher rotationWatcher) {
|
||||||
|
|
|
@ -7,12 +7,10 @@ public final class DisplayInfo {
|
||||||
private final int layerStack;
|
private final int layerStack;
|
||||||
private final int flags;
|
private final int flags;
|
||||||
|
|
||||||
public static final int DEFAULT_DISPLAY = 0x00000000;
|
public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 0x00000001;
|
||||||
|
|
||||||
public static final int FLAG_PRESENTATION = 0x00000008;
|
public static final int FLAG_PRESENTATION = 0x00000008;
|
||||||
|
|
||||||
public static final int FLAG_SUPPORTS_PROTECTED_BUFFERS = 0x00000001;
|
|
||||||
|
|
||||||
public DisplayInfo(int displayId, Size size, int rotation, int layerStack, int flags) {
|
public DisplayInfo(int displayId, Size size, int rotation, int layerStack, int flags) {
|
||||||
this.displayId = displayId;
|
this.displayId = displayId;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
|
@ -38,11 +36,11 @@ public final class DisplayInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPresentation() {
|
public boolean isPresentation() {
|
||||||
return (flags & FLAG_PRESENTATION) == FLAG_PRESENTATION;
|
return (flags & FLAG_PRESENTATION) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSupportProtectedBuffers() {
|
public boolean isSupportProtectedBuffers() {
|
||||||
return (flags & FLAG_SUPPORTS_PROTECTED_BUFFERS) == FLAG_SUPPORTS_PROTECTED_BUFFERS;
|
return (flags & FLAG_SUPPORTS_PROTECTED_BUFFERS) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||||
setSize(format, videoRect.width(), videoRect.height());
|
setSize(format, videoRect.width(), videoRect.height());
|
||||||
configure(codec, format);
|
configure(codec, format);
|
||||||
Surface surface = codec.createInputSurface();
|
Surface surface = codec.createInputSurface();
|
||||||
setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect);
|
setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, device.getLayerStack());
|
||||||
codec.start();
|
codec.start();
|
||||||
try {
|
try {
|
||||||
alive = encode(codec, fd);
|
alive = encode(codec, fd);
|
||||||
|
|
|
@ -14,7 +14,6 @@ public final class ScreenInfo {
|
||||||
* However, it does not include the locked video orientation.
|
* However, it does not include the locked video orientation.
|
||||||
*/
|
*/
|
||||||
private final Size unlockedVideoSize;
|
private final Size unlockedVideoSize;
|
||||||
private final int layerStack;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device rotation, related to the natural device orientation (0, 1, 2 or 3)
|
* Device rotation, related to the natural device orientation (0, 1, 2 or 3)
|
||||||
|
@ -31,7 +30,6 @@ public final class ScreenInfo {
|
||||||
this.unlockedVideoSize = unlockedVideoSize;
|
this.unlockedVideoSize = unlockedVideoSize;
|
||||||
this.deviceRotation = deviceRotation;
|
this.deviceRotation = deviceRotation;
|
||||||
this.lockedVideoOrientation = lockedVideoOrientation;
|
this.lockedVideoOrientation = lockedVideoOrientation;
|
||||||
this.layerStack = layerStack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect getContentRect() {
|
public Rect getContentRect() {
|
||||||
|
|
|
@ -80,8 +80,8 @@ public final class Server {
|
||||||
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
"The server version (" + BuildConfig.VERSION_NAME + ") does not match the client " + "(" + clientVersion + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.length != 9) {
|
if (args.length != 10) {
|
||||||
throw new IllegalArgumentException("Expecting 9 parameters");
|
throw new IllegalArgumentException("Expecting 10 parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
Options options = new Options();
|
Options options = new Options();
|
||||||
|
@ -111,7 +111,7 @@ public final class Server {
|
||||||
boolean control = Boolean.parseBoolean(args[8]);
|
boolean control = Boolean.parseBoolean(args[8]);
|
||||||
options.setControl(control);
|
options.setControl(control);
|
||||||
|
|
||||||
int displayId = Integer.parseInt(args[8]);
|
int displayId = Integer.parseInt(args[9]);
|
||||||
options.setDisplayId(displayId);
|
options.setDisplayId(displayId);
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.genymobile.scrcpy.wrappers;
|
||||||
import android.os.IInterface;
|
import android.os.IInterface;
|
||||||
|
|
||||||
import com.genymobile.scrcpy.DisplayInfo;
|
import com.genymobile.scrcpy.DisplayInfo;
|
||||||
import com.genymobile.scrcpy.Ln;
|
|
||||||
import com.genymobile.scrcpy.Size;
|
import com.genymobile.scrcpy.Size;
|
||||||
|
|
||||||
public final class DisplayManager {
|
public final class DisplayManager {
|
||||||
|
@ -16,6 +15,7 @@ public final class DisplayManager {
|
||||||
public DisplayInfo getDisplayInfo(int displayId) {
|
public DisplayInfo getDisplayInfo(int displayId) {
|
||||||
try {
|
try {
|
||||||
Object displayInfo = manager.getClass().getMethod("getDisplayInfo", int.class).invoke(manager, displayId);
|
Object displayInfo = manager.getClass().getMethod("getDisplayInfo", int.class).invoke(manager, displayId);
|
||||||
|
if (displayInfo == null) throw new IllegalArgumentException(suggestFixMessage(displayId, getDisplayIds()));
|
||||||
Class<?> cls = displayInfo.getClass();
|
Class<?> cls = displayInfo.getClass();
|
||||||
// width and height already take the rotation into account
|
// width and height already take the rotation into account
|
||||||
int width = cls.getDeclaredField("logicalWidth").getInt(displayInfo);
|
int width = cls.getDeclaredField("logicalWidth").getInt(displayInfo);
|
||||||
|
@ -25,7 +25,6 @@ public final class DisplayManager {
|
||||||
int flags = cls.getDeclaredField("flags").getInt(displayInfo);
|
int flags = cls.getDeclaredField("flags").getInt(displayInfo);
|
||||||
return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags);
|
return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof NullPointerException) suggestFix(displayId, getDisplayIds());
|
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,17 +37,17 @@ public final class DisplayManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void suggestFix(int displayId, int[] displayIds) {
|
private String suggestFixMessage(int displayId, int[] displayIds) {
|
||||||
if (displayIds == null || displayIds.length == 0)
|
if (displayIds == null || displayIds.length == 0)
|
||||||
return;
|
return null;
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("Failed to get displayId=[")
|
sb.append("Failed to get displayId=[")
|
||||||
.append(displayId)
|
.append(displayId)
|
||||||
.append("]\nTry to user one of these available display ids:\n");
|
.append("]\nTry to use one of these available display ids:\n");
|
||||||
for (int id : displayIds) {
|
for (int id : displayIds) {
|
||||||
sb.append("scrcpy --display ").append(id).append("\n");
|
sb.append("scrcpy --display ").append(id).append("\n");
|
||||||
}
|
}
|
||||||
Ln.e(sb.toString());
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,11 +38,13 @@ public final class InputManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setDisplayId(InputEvent inputEvent, int displayId) {
|
public static boolean setDisplayId(InputEvent inputEvent, int displayId) {
|
||||||
try {
|
try {
|
||||||
inputEvent.getClass().getMethod("setDisplayId", int.class).invoke(inputEvent, displayId);
|
inputEvent.getClass().getMethod("setDisplayId", int.class).invoke(inputEvent, displayId);
|
||||||
|
return true;
|
||||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||||
Ln.e("Could not invoke method", e);
|
Ln.e("Could not invoke method", e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue