From 3b2b3625e478855392c98367818a360dfba239bf Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Thu, 28 Nov 2024 21:10:06 +0100 Subject: [PATCH] Accept positional control events without display The position of touch and scroll must normally be "resolved" with a "position mapper" associated to the display. But to support the injection of such events with scrcpy-server alone without video, handle the case where there is no display. Fixes #5542 --- .../genymobile/scrcpy/control/Controller.java | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java index e6901f4bb4..a0bdc58427 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java @@ -355,19 +355,30 @@ private Pair getEventPointAndDisplayId(Position position) { // 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 positional 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 positional event generated for size " + eventSize + " (current size is " + currentSize + ")"); + // In scrcpy, displayData should never be null (a touch event can only be generated from the client when a video frame is present). + // However, it is possible to send events without video playback when using scrcpy-server alone (except for virtual displays). + assert displayData != null || displayId != Device.DISPLAY_ID_NONE : "Cannot receive a positional event without a display"; + + 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 positional event generated for size " + eventSize + " (current size is " + currentSize + ")"); + } + return null; } - return null; + targetDisplayId = displayData.virtualDisplayId; + } else { + // No display, use the raw coordinates + point = position.getPoint(); + targetDisplayId = displayId; } - return Pair.create(point, displayData.virtualDisplayId); + return Pair.create(point, targetDisplayId); } private boolean injectTouch(int action, long pointerId, Position position, float pressure, int actionButton, int buttons) {