Skip to content
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

Add virtual display feature #5370

Merged
merged 19 commits into from
Oct 28, 2024
Merged

Add virtual display feature #5370

merged 19 commits into from
Oct 28, 2024

Conversation

rom1v
Copy link
Collaborator

@rom1v rom1v commented Oct 12, 2024

This PR adds the possibility to start a new virtual display instead of mirroring the screen.

Implementation

There are 3 steps:

  1. refactors
  2. rework event handling for virtual displays
  3. add virtual display features

Refactors

The (7) firsts commits refactor to move code from Device to Controller and ScreenCapture, to prepare the next commits.

Events handling

The commit Inject display-related events to virtual display aims to fix #4598 and #5137 (based on the work by @mengyanshou in #5137 and #5214), also necessary for making virtual display events work.

Basically, for event injection, there are two display ids:

  • the source display id (--display-id=…, default to 0 for the main display)
  • the id of the virtual display used for mirroring

(In case the ScreenCapture uses the "SurfaceControl API", then both ids are equals, but this is an implementation detail.)

In order to make events work correctly in all cases:

  • the virtual display id must be used for events relative to the display (mouse and touch events with coordinates);
  • the source display id must be used for other events (like key events).

Virtual display

Then, based on the discussions in #1887 and the work by @yume-chan and @anirudhb:

The commit Add virtual display feature implements a first version of virtual display support:

scrcpy --new-display=1920x1080
scrcpy --new-display=1920x1080/420  # force 420 dpi
scrcpy --new-display         # use the default screen size and density
scrcpy --new-display=/240    # use the default screen size and 240 dpi
scrcpy --new-display -m1920  # use the default screen size and density, scaled to fit in 1920

The size is fixed (not resizable).

On a Pixel 8, the virtual display contains a menu, so it is possible to open an app easily.

On other devices, it may be empty. In that case, you can start your app manually. Find the new display id is scrcpy logs (let's say it's 42), and start an app manually:

adb shell am start -a android.settings.SETTINGS --display 42

To start an app manually:

adb shell cmd package resolve-activity --brief org.mozilla.firefox | tail -n 1  # get the activity name
adb shell am start -S -n org.mozilla.firefox/.App --display 5

TODO

Start app

The feature really needs a new command to start an app, for example:

# not implemented, just an idea
scrcpy --new-display --start-app=firefox

I might need to rework how arguments are passed to the server (to start an app "My gallery" for example), because currently it does not support spaces or other special characters (see bec3321).

I don't know if the expected behavior is to just have a virtual display and open any app (like on Pixel 8, where there is a "launcher"), or expose something like a "single app" feature.

It probably depends on the device (I don't know if it's possible to limit a single app on Pixel 8 for example, or to navigate to other apps on device without a launcher). What do you think? (also ref discussion #1887 (comment) @4nric)

Detect failure

If I run scrcpy --new-display on a Nexus 5 with Android 6, it does not fail, it just waits indefinitely for a frame. How to detect that "it works"? Should we only use checks based on the Android version?


Draft v2

Start app

Here is a draft v2, with new options to list and start apps (edit: changed by #5370 (comment)):

scrcpy --list-apps
scrcpy --new-display --start-app=org.mozilla.firefox  # start app by package name
scrcpy --new-display --start-app=?firefox             # start app by name with '?' prefix (takes more time)
scrcpy --start-app=org.mozilla.firefox   # also works for real display mirroring
scrcpy --start-app=+org.mozilla.firefox  # prefix by '+' to force-stop before starting the app

There is a performance issue on some devices to retrieve the app names (but not package names), because loadLabel() must be called for each app). As a consequence, --list-apps may take several seconds, and selecting an application by name may also take time. However, starting via package name is quick. Any solution welcome.

@huynhtanloc2612
Copy link

Hi @rom1v, binary file cannot be downloaded

@rom1v
Copy link
Collaborator Author

rom1v commented Oct 12, 2024

@huynhtanloc2612 Thanks, fixed.

@huynhtanloc2612
Copy link

@rom1v
There is a minor bug which is that the primary screen does not turn on again after closing scrcpy tool (something like when using with the option --no-cleanup)
My command: scrcpy -SK --new-display=1920x1080/200

@vaddisrinivas
Copy link

tested this on mac(m1pro) - works!

Steps I followed -

  • clone and switch to branch
  • install dependencies
  • build
  • install
  • tested for -this issue

@mengyanshou
Copy link
Contributor

mengyanshou commented Oct 14, 2024

Thank you for your contribution.

Test platform: Mac(M2)/Meizu 21

Test way:

git fetch origin pull/5370/head:pr-5370
git checkout pr-5370
meson setup x --buildtype=release --strip -Db_lto=true
ninja -Cx  # DO NOT RUN AS ROOT
./run x --new-display=1920x1080

I mainly tested the following scenarios:

  • Without using the --new-display option, using scrcpy --display xxx to render the virtual display screen, the click events work normally.
  • Using scrcpy --new-display=1920x1080, the created virtual display can be clicked normally.

Due to this flag

VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS

On the Meizu device I tested, the Launcher will start on this virtual display. This is not an issue, but rather an unexpected benefit.

Here is a screenshot.

截屏2024-10-14 20 49 52

By the way, I have ported scrcpy to Android.

Once I complete the remaining work, I invite you to experience this software. Thank you very much.

@eiyooooo
Copy link
Contributor

A small issue: IME will not appear on the virtual display unless the following setting is applied:

adb shell settings put global force_desktop_mode_on_external_displays 1

This is likely because the ImePolicy is not set to DISPLAY_IME_POLICY_LOCAL, as indicated by the getImePolicy() method.


Additionally, on some devices, the launcher displays incorrectly on non-default screens.

@4nric
Copy link

4nric commented Oct 15, 2024

Additionally, on some devices, the launcher displays incorrectly on non-default screens.

Launcher I tested that works: Lawnchair (playstore, github). Another instance of the launcher can be opened on secondary displays without additional flags. Good enough for quickly launching apps for now

scrcpy --new-display
adb shell am start -n app.lawnchair.play/app.lawnchair.LawnchairLauncher --display 12
scrcpy-vd-lawnchair.mp4

@4nric
Copy link

4nric commented Oct 15, 2024

@rom1v thank you for working on this feature!

I'm getting permission issue on android 12. @yume-chan's proof-of-concept works on this device

[server] INFO: Device: [samsung] samsung SM-G975F (Android 12)
[server] ERROR: Could not create display
java.lang.SecurityException: Requires ADD_TRUSTED_DISPLAY permission to create a trusted virtual display.
        at android.os.Parcel.createExceptionOrNull(Parcel.java:2438)
        at android.os.Parcel.createException(Parcel.java:2422)
        at android.os.Parcel.readException(Parcel.java:2405)
        at android.os.Parcel.readException(Parcel.java:2347)
        at android.hardware.display.IDisplayManager$Stub$Proxy.createVirtualDisplay(IDisplayManager.java:2020)
        at android.hardware.display.DisplayManagerGlobal.createVirtualDisplay(DisplayManagerGlobal.java:694)
        at android.hardware.display.DisplayManagerGlobal.createVirtualDisplay(DisplayManagerGlobal.java:664)
        at android.hardware.display.DisplayManager.createVirtualDisplay(DisplayManager.java:1390)
        at android.hardware.display.DisplayManager.createVirtualDisplay(DisplayManager.java:1357)
        at android.hardware.display.DisplayManager.createVirtualDisplay(DisplayManager.java:1302)
        at com.genymobile.scrcpy.wrappers.DisplayManager.createNewVirtualDisplay(DisplayManager.java:138)
        at com.genymobile.scrcpy.video.NewDisplayCapture.start(NewDisplayCapture.java:95)
        at com.genymobile.scrcpy.video.SurfaceEncoder.streamCapture(SurfaceEncoder.java:89)
        at com.genymobile.scrcpy.video.SurfaceEncoder.lambda$start$0$com-genymobile-scrcpy-video-SurfaceEncoder(SurfaceEncoder.java:279)
        at com.genymobile.scrcpy.video.SurfaceEncoder$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
        at java.lang.Thread.run(Thread.java:920)
Caused by: android.os.RemoteException: Remote stack trace:
        at com.android.server.display.DisplayManagerService$BinderService.createVirtualDisplay(DisplayManagerService.java:4070)
        at android.hardware.display.IDisplayManager$Stub.onTransact(IDisplayManager.java:887)
        at android.os.Binder.execTransactInternal(Binder.java:1215)
        at android.os.Binder.execTransact(Binder.java:1179)

[server] ERROR: Exception on thread Thread[video,5,main]
java.lang.AssertionError: Could not create display
        at com.genymobile.scrcpy.video.NewDisplayCapture.start(NewDisplayCapture.java:100)
        at com.genymobile.scrcpy.video.SurfaceEncoder.streamCapture(SurfaceEncoder.java:89)
        at com.genymobile.scrcpy.video.SurfaceEncoder.lambda$start$0$com-genymobile-scrcpy-video-SurfaceEncoder(SurfaceEncoder.java:279)
        at com.genymobile.scrcpy.video.SurfaceEncoder$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
        at java.lang.Thread.run(Thread.java:920)
INFO: Renderer: direct3d
WARN: Device disconnected
ERROR: Demuxer 'audio': stream disabled due to connection error

@rom1v
Copy link
Collaborator Author

rom1v commented Oct 15, 2024

We probably need to remove this flag for Android < 13 (according to c7b04a6):

diff --git a/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
index 0622998ed..9440199ce 100644
--- a/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
+++ b/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
@@ -85,7 +85,6 @@ public class NewDisplayCapture extends SurfaceCapture {
                     | VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
                     | VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL
                     | VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
-                    | VIRTUAL_DISPLAY_FLAG_TRUSTED
                     | VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP
                     | VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED
                     | VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED

@eiyooooo
Copy link
Contributor

eiyooooo commented Oct 15, 2024

We probably need to remove this flag for Android < 13 (according to c7b04a6):

diff --git a/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java b/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
index 0622998ed..9440199ce 100644
--- a/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
+++ b/server/src/main/java/com/genymobile/scrcpy/video/NewDisplayCapture.java
@@ -85,7 +85,6 @@ public class NewDisplayCapture extends SurfaceCapture {
                     | VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT
                     | VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL
                     | VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
-                    | VIRTUAL_DISPLAY_FLAG_TRUSTED
                     | VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP
                     | VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED
                     | VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED

According to my research, the flags VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP, VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED, and VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED require at least Android 12L (Build.VERSION_CODES.S_V2) to be used.

The flags VIRTUAL_DISPLAY_FLAG_TRUSTED, VIRTUAL_DISPLAY_FLAG_OWN_FOCUS and VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP require at least Android 13 (Build.VERSION_CODES.TIRAMISU) to be used.

@rom1v
Copy link
Collaborator Author

rom1v commented Oct 15, 2024

@eiyooooo The flag exists, but apparently in Android 12, shell does not have permission to create a virtual display with this flag enabled.

@eiyooooo
Copy link
Contributor

eiyooooo commented Oct 15, 2024

@eiyooooo The flag exists, but apparently in Android 12, shell does not have permission to create a virtual display with this flag enabled.

Yes, at least Android 13 is required to use the VIRTUAL_DISPLAY_FLAG_TRUSTED flag.

@rom1v
Copy link
Collaborator Author

rom1v commented Oct 15, 2024

Yes, at least Android 12L is required to use the VIRTUAL_DISPLAY_FLAG_TRUSTED flag.

If you don't pass it, what happens?

@eiyooooo
Copy link
Contributor

Yes, at least Android 12L is required to use the VIRTUAL_DISPLAY_FLAG_TRUSTED flag.

If you don't pass it, what happens?

Based on my tests, the flags VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS, VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP, VIRTUAL_DISPLAY_FLAG_OWN_FOCUS, and VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP require a trusted virtual display to function properly.

@eiyooooo
Copy link
Contributor

scrcpy.exe --new-display
scrcpy 2.7 <https://github.com/Genymobile/scrcpy>
INFO: ADB device found:
INFO:     -->   (usb)  R5CN210NXME                     device  SM_G986U1
C:\q\software\scrcpy-win64-v2.4\scrcpy-win64-v2.7-35-g765e...file pushed, 0 skipped. 106.6 MB/s (72764 bytes in 0.001s)
[server] INFO: Device: [samsung] samsung SM-G986U1 (Android 13)
INFO: Renderer: direct3d
INFO: Texture: 1920x1080
[server] INFO: New display id: 2
adb shell am start --display 2 -n com.samsung.android.app.notes/com.samsung.android.app.notes.memolist.MemoListActivity
Starting: Intent { cmp=com.samsung.android.app.notes/.memolist.MemoListActivity }

Exception occurred while executing 'start':
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
        at com.android.server.wm.MultiTaskingTaskLaunchParamsModifier.calculate(MultiTaskingTaskLaunchParamsModifier.java:228)
        at com.android.server.wm.MultiTaskingTaskLaunchParamsModifier.onCalculate(MultiTaskingTaskLaunchParamsModifier.java:154)
        at com.android.server.wm.LaunchParamsController.calculate(LaunchParamsController.java:142)
        at com.android.server.wm.ActivityStarter.computeLaunchParams(ActivityStarter.java:3110)
        at com.android.server.wm.ActivityStarter.startActivityInner(ActivityStarter.java:2658)
        at com.android.server.wm.ActivityStarter.startActivityUnchecked(ActivityStarter.java:2470)
        at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:1808)
        at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:1026)
        at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1943)
        at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1816)
        at com.android.server.am.ActivityManagerService.startActivityAsUserWithFeature(ActivityManagerService.java:3747)        at com.android.server.am.ActivityManagerShellCommand.runStartActivity(ActivityManagerShellCommand.java:656)
        at com.android.server.am.ActivityManagerShellCommand.onCommand(ActivityManagerShellCommand.java:222)
        at com.android.modules.utils.BasicShellCommandHandler.exec(BasicShellCommandHandler.java:97)
        at android.os.ShellCommand.exec(ShellCommand.java:38)
        at com.android.server.am.ActivityManagerService.onShellCommand(ActivityManagerService.java:11276)
        at android.os.Binder.shellCommand(Binder.java:1085)
        at android.os.Binder.onTransact(Binder.java:903)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:5643)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3135)
        at android.os.Binder.execTransactInternal(Binder.java:1321)
        at android.os.Binder.execTransact(Binder.java:1280)

On the S20+ (Android 13), after multiple attempts to create virtual displays using scrcpy.exe --new-display, the display ID always remains 2, and apps fail to start in the virtual display created by scrcpy when the VIRTUAL_DISPLAY_FLAG_OWN_FOCUS flag is set. 😞
However, when this flag is not set, everything works fine.

@biomagnet biomagnet mentioned this pull request Oct 19, 2024
1 task
@rom1v
Copy link
Collaborator Author

rom1v commented Oct 19, 2024

I added features to list and start apps. I updated the main post, and also published a binary for this new version.

Please test and give feedback 😉

@rom1v
Copy link
Collaborator Author

rom1v commented Oct 19, 2024

@eiyooooo I added a commit to fix flags depending on Android versions: 5ee42ea

However, I have no device with Android 12 or 12L to test, so don't hesitate to suggest a patch with the correct flags.

@eiyooooo
Copy link
Contributor

eiyooooo commented Oct 19, 2024

I added a commit to fix flags depending on Android versions: 5ee42ea

However, I have no device with Android 12 or 12L to test, so don't hesitate to suggest a patch with the correct flags.

After digging deeper, I found that Android 12L still encounters the following issue:

java.lang.SecurityException: Requires ADD_TRUSTED_DISPLAY permission to create a trusted virtual display.

References:

Therefore, I think this part of the code:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {

should be updated to:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {

@rom1v
Copy link
Collaborator Author

rom1v commented Oct 20, 2024

@eiyooooo OK.

Commit that granted Shell the ADD_TRUSTED_DISPLAY permission

Indeed, it has been merged in Android 13:

# in aosp/framework_base
git tag --contains 990e3429636382175ca8e7bf04df054f48fbd130

I first added readable Android version constants (already merged into dev): 3acffaa (the Android way to select a version was a mess, I had to check the mapping every time).

Then I set the TRUSTED and other flags only since Android 13: e05be0b

@eiyooooo
Copy link
Contributor

I first added readable Android version constants (already merged into dev): 3acffaa (the Android way to select a version was a mess, I had to check the mapping every time).

@rom1v By the way, Android 15 has been released, so you'll need to add a new Android version constant. 😄

public static final int API_35_ANDROID_15 = Build.VERSION_CODES.VANILLA_ICE_CREAM;

@rom1v
Copy link
Collaborator Author

rom1v commented Oct 20, 2024

@eiyooooo Done: a46150f

@rom1v
Copy link
Collaborator Author

rom1v commented Oct 20, 2024

Given that loading the app names may take time (several seconds), by default, I reworked so that --start-app only accepts package names by default:

scrpcy --start-app=org.mozilla.firefox

For convenience, however, it is still possible to explicitly select an app by its name (but with some delay) by adding a ? prefix:

scrcpy --start-app=?firefox

Like in the previous version, a + prefix force-stops the app before starting:

scrcpy --new-display --start-app=+org.mozilla.firefox   # by package name
scrcpy --new-display --start-app=+?firefox              # by name

@yume-chan
Copy link
Contributor

yume-chan commented Nov 4, 2024

I don't know if the audio output is related to a specific display

FYI, Actually there is per-display audio routing for companion service: https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/media/java/android/media/PlayerBase.java;l=582;drc=0a293aabaef57434b7cde9f431bacf6dc3ee7fe2

If we create the VirtualDisplay using companion service: https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java;l=494;drc=0a293aabaef57434b7cde9f431bacf6dc3ee7fe2

It also modifies audio routing like my previous comment, just automatically based on the display the app is on.

Companion service is a hidden API for projecting displays, inputs, audio and even cameras to companion devices (like smart watches). Normally it needs a companion device to work, but shell apps can use the testing API to create a fake one: https://cs.android.com/android/platform/superproject/main/+/main:cts/tests/tests/companion/common/src/android/companion/cts/common/AppHelper.kt;l=29;drc=831c3ced50d5574cd5645afc0277bc6c59e83278

I was particularly interested in the virtual camera injection feature, but it's hide behind a flag that's disabled by default.

rom1v added a commit that referenced this pull request Nov 19, 2024
Listen to display size changes and rotate the virtual display
accordingly.

Note: use `git show -b` to Show this commit ignoring whitespace changes.

Fixes #5428 <#5428>
Refs #5370 <#5370>
PR #5455 <#5455>
rom1v added a commit that referenced this pull request Nov 19, 2024
Listen to display size changes and rotate the virtual display
accordingly.

Note: use `git show -b` to Show this commit ignoring whitespace changes.

Fixes #5428 <#5428>
Refs #5370 <#5370>
PR #5455 <#5455>
rom1v added a commit that referenced this pull request Nov 20, 2024
Allow capturing virtual displays at a lower resolution using
-m/--max-size.

In the original implementation in #5370, the virtual display size was
necessarily the same as the capture size. The --max-size value was only
allowed to determine the virtual display size when no explicit size was
provided.

Since the dpi was scaled down accordingly, it is often better to create
a virtual display at the target capture size directly. However, not
everything is rendered according to the virtual display DPI. For
example, a page in Firefox is rendered too big on small virtual
displays. Thus, it makes sense to be able create a virtual display at a
given size, and capture it at a lower resolution with --max-size. This
is now possible using OpenGL filters.

Therefore, change the behavior of --max-size for virtual displays:
 - it does not impact --new-display without size argument anymore (the
   virtual display size is the main display size);
 - it is used to limit the capture size (whether an explicit size is
   provided or not).

This new behavior is consistent with main display capture.

Refs #5370 comment <#5370 (comment)>
Refs <#5370>
@rom1v
Copy link
Collaborator Author

rom1v commented Nov 20, 2024

I changed the behavior of --max-size for virtual displays: #5506.

rom1v added a commit that referenced this pull request Nov 21, 2024
Allow capturing virtual displays at a lower resolution using
-m/--max-size.

In the original implementation in #5370, the virtual display size was
necessarily the same as the capture size. The --max-size value was only
allowed to determine the virtual display size when no explicit size was
provided.

Since the dpi was scaled down accordingly, it is often better to create
a virtual display at the target capture size directly. However, not
everything is rendered according to the virtual display DPI. For
example, a page in Firefox is rendered too big on small virtual
displays. Thus, it makes sense to be able create a virtual display at a
given size, and capture it at a lower resolution with --max-size. This
is now possible using OpenGL filters.

Therefore, change the behavior of --max-size for virtual displays:
 - --max-size does not impact --new-display without size argument
   anymore (the virtual display size is the main display size);
 - it is used to limit the capture size (whether an explicit size is
   provided or not).

This new behavior is consistent with main display capture.

Refs #5370 comment <#5370 (comment)>
Refs #5370 <#5370>
PR #5506 <#5506>
@Xtr126
Copy link

Xtr126 commented Nov 26, 2024

I wonder why the virtual display automatic resize feature was dropped Controller.java#217 would be cool to have apps streaming with resizeable windows

@rom1v
Copy link
Collaborator Author

rom1v commented Nov 26, 2024

@Xtr126 The work I did to implement virtual display i based on previous work, as mentioned in the post:

Then, based on the discussions in #1887 and the work by @yume-chan and @anirudhb

In particular, the prototype by @anirudhb attempted to support resizing: https://github.com/anirudhb/scrcpy/commits/virtual-display/

But there is more work need it to make it work properly (and this brings new problems to solve), and virtual displays was already a lot of work, so I preferred implementing a non-resizable version first. Making it resizable could be done in the future.

rom1v added a commit that referenced this pull request Dec 5, 2024
When mirroring a secondary display, touch and scroll events must be sent
to the mirroring virtual display id (with coordinates relative to the
virtual display size), rather than to the original display (with
coordinates relative to the original display size).

This behavior, introduced by d193967,
was also applied for the main display for consistency.

However, this mechanism has been found to cause some UI elements to
become unclickable.

To minimize inconveniences, restore the previous behavior when mirroring
the main display: send all events to the original display id (0) with
coordinates relative to the original display size.

Fixes #5545 <#5545>
Fixes #5605 <#5605>
Refs #4598 <#4598>
Refs #5137 <#5137>
Refs #5370 <#5370>
rom1v added a commit that referenced this pull request Dec 5, 2024
When mirroring a secondary display, touch and scroll events must be sent
to the mirroring virtual display id (with coordinates relative to the
virtual display size), rather than to the original display (with
coordinates relative to the original display size).

This behavior, introduced by d193967,
was also applied for the main display for consistency. However, it has
been found to cause some UI elements to become unclickable.

To minimize inconveniences, restore the previous behavior when mirroring
the main display: send all events to the original display id (0) with
coordinates relative to the original display size.

Fixes #5545 <#5545>
Fixes #5605 <#5605>
Refs #4598 <#4598>
Refs #5137 <#5137>
Refs #5370 <#5370>
rom1v added a commit that referenced this pull request Dec 7, 2024
When mirroring a secondary display, touch and scroll events must be sent
to the mirroring virtual display id (with coordinates relative to the
virtual display size), rather than to the original display (with
coordinates relative to the original display size).

This behavior, introduced by d193967,
was also applied for the main display for consistency. However, it
causes some UI elements to become unclickable.

To minimize inconveniences, restore the previous behavior when mirroring
the main display: send all events to the original display id (0) with
coordinates relative to the original display size.

Fixes #5545 <#5545>
Fixes #5605 <#5605>
Fixes #5616 <#5616>
Refs #4598 <#4598>
Refs #5137 <#5137>
Refs #5370 <#5370>
PR #5614 <#5614>
@mauriciofelippe
Copy link

I'm getting a issue, when the phone goes to lock screen i lose control(keyboard and left&right buttons, if a home button is pressed it is work, so just input actions related to lock screen works.) of virtual display.

@rom1v
Copy link
Collaborator Author

rom1v commented Dec 18, 2024

@mauriciofelippe On Samsung phones, clicks stop working on virtual display when the device goes to sleep apparently: #5557 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.