diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index ed3ae669..0b60dbdc 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -9,7 +9,6 @@ import com.genymobile.scrcpy.audio.AudioRawRecorder; import com.genymobile.scrcpy.audio.AudioSource; import com.genymobile.scrcpy.control.ControlChannel; import com.genymobile.scrcpy.control.Controller; -import com.genymobile.scrcpy.control.DeviceMessage; import com.genymobile.scrcpy.device.ConfigurationException; import com.genymobile.scrcpy.device.DesktopConnection; import com.genymobile.scrcpy.device.Device; @@ -142,7 +141,7 @@ public final class Server { boolean sendDummyByte = options.getSendDummyByte(); boolean camera = video && options.getVideoSource() == VideoSource.CAMERA; - final Device device = camera ? null : new Device(options); + final Device device = camera ? null : new Device(); Workarounds.apply(); @@ -158,10 +157,6 @@ public final class Server { ControlChannel controlChannel = connection.getControlChannel(); Controller controller = new Controller( device, options.getDisplayId(), controlChannel, cleanUp, options.getClipboardAutosync(), options.getPowerOn()); - device.setClipboardListener(text -> { - DeviceMessage msg = DeviceMessage.createClipboard(text); - controller.getSender().send(msg); - }); asyncProcessors.add(controller); } 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 ee2e1749..e6463563 100644 --- a/server/src/main/java/com/genymobile/scrcpy/control/Controller.java +++ b/server/src/main/java/com/genymobile/scrcpy/control/Controller.java @@ -7,9 +7,11 @@ import com.genymobile.scrcpy.device.Device; import com.genymobile.scrcpy.device.Point; import com.genymobile.scrcpy.device.Position; import com.genymobile.scrcpy.util.Ln; +import com.genymobile.scrcpy.wrappers.ClipboardManager; import com.genymobile.scrcpy.wrappers.InputManager; import com.genymobile.scrcpy.wrappers.ServiceManager; +import android.content.IOnPrimaryClipChangedListener; import android.content.Intent; import android.os.Build; import android.os.SystemClock; @@ -23,6 +25,7 @@ import java.io.IOException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; public class Controller implements AsyncProcessor { @@ -48,6 +51,8 @@ public class Controller implements AsyncProcessor { private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); + private final AtomicBoolean isSettingClipboard = new AtomicBoolean(); + private long lastTouchDown; private final PointersState pointersState = new PointersState(); private final MotionEvent.PointerProperties[] pointerProperties = new MotionEvent.PointerProperties[PointersState.MAX_POINTERS]; @@ -69,6 +74,29 @@ public class Controller implements AsyncProcessor { if (!supportsInputEvents) { Ln.w("Input events are not supported for secondary displays before Android 10"); } + + if (clipboardAutosync) { + // If control and autosync are enabled, synchronize Android clipboard to the computer automatically + ClipboardManager clipboardManager = ServiceManager.getClipboardManager(); + if (clipboardManager != null) { + clipboardManager.addPrimaryClipChangedListener(new IOnPrimaryClipChangedListener.Stub() { + @Override + public void dispatchPrimaryClipChanged() { + if (isSettingClipboard.get()) { + // This is a notification for the change we are currently applying, ignore it + return; + } + String text = Device.getClipboardText(); + if (text != null) { + DeviceMessage msg = DeviceMessage.createClipboard(text); + sender.send(msg); + } + } + }); + } else { + Ln.w("No clipboard manager, copy-paste between device and computer will not work"); + } + } } private UhidManager getUhidManager() { @@ -148,10 +176,6 @@ public class Controller implements AsyncProcessor { sender.join(); } - public DeviceMessageSender getSender() { - return sender; - } - private boolean handleEvent() throws IOException { ControlMessage msg; try { @@ -452,7 +476,9 @@ public class Controller implements AsyncProcessor { } private boolean setClipboard(String text, boolean paste, long sequence) { - boolean ok = device.setClipboardText(text); + isSettingClipboard.set(true); + boolean ok = Device.setClipboardText(text); + isSettingClipboard.set(false); if (ok) { Ln.i("Device clipboard set"); } diff --git a/server/src/main/java/com/genymobile/scrcpy/device/Device.java b/server/src/main/java/com/genymobile/scrcpy/device/Device.java index 7972d740..1765ccf2 100644 --- a/server/src/main/java/com/genymobile/scrcpy/device/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/device/Device.java @@ -1,7 +1,6 @@ package com.genymobile.scrcpy.device; import com.genymobile.scrcpy.AndroidVersions; -import com.genymobile.scrcpy.Options; import com.genymobile.scrcpy.util.Ln; import com.genymobile.scrcpy.video.ScreenInfo; import com.genymobile.scrcpy.wrappers.ClipboardManager; @@ -11,7 +10,6 @@ import com.genymobile.scrcpy.wrappers.ServiceManager; import com.genymobile.scrcpy.wrappers.SurfaceControl; import com.genymobile.scrcpy.wrappers.WindowManager; -import android.content.IOnPrimaryClipChangedListener; import android.graphics.Rect; import android.os.Build; import android.os.IBinder; @@ -21,7 +19,6 @@ import android.view.InputEvent; import android.view.KeyCharacterMap; import android.view.KeyEvent; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; public final class Device { @@ -36,43 +33,8 @@ public final class Device { public static final int LOCK_VIDEO_ORIENTATION_UNLOCKED = -1; public static final int LOCK_VIDEO_ORIENTATION_INITIAL = -2; - public interface ClipboardListener { - void onClipboardTextChanged(String text); - } - - private ClipboardListener clipboardListener; - private final AtomicBoolean isSettingClipboard = new AtomicBoolean(); - private final AtomicReference screenInfo = new AtomicReference<>(); // set by the ScreenCapture instance - public Device(Options options) { - if (options.getControl() && options.getClipboardAutosync()) { - // If control and autosync are enabled, synchronize Android clipboard to the computer automatically - ClipboardManager clipboardManager = ServiceManager.getClipboardManager(); - if (clipboardManager != null) { - clipboardManager.addPrimaryClipChangedListener(new IOnPrimaryClipChangedListener.Stub() { - @Override - public void dispatchPrimaryClipChanged() { - if (isSettingClipboard.get()) { - // This is a notification for the change we are currently applying, ignore it - return; - } - synchronized (Device.this) { - if (clipboardListener != null) { - String text = getClipboardText(); - if (text != null) { - clipboardListener.onClipboardTextChanged(text); - } - } - } - } - }); - } else { - Ln.w("No clipboard manager, copy-paste between device and computer will not work"); - } - } - } - public Point getPhysicalPoint(Position position) { // it hides the field on purpose, to read it with atomic access @SuppressWarnings("checkstyle:HiddenField") @@ -142,10 +104,6 @@ public final class Device { return ServiceManager.getPowerManager().isScreenOn(); } - public synchronized void setClipboardListener(ClipboardListener clipboardListener) { - this.clipboardListener = clipboardListener; - } - public static void expandNotificationPanel() { ServiceManager.getStatusBarManager().expandNotificationsPanel(); } @@ -170,7 +128,7 @@ public final class Device { return s.toString(); } - public boolean setClipboardText(String text) { + public static boolean setClipboardText(String text) { ClipboardManager clipboardManager = ServiceManager.getClipboardManager(); if (clipboardManager == null) { return false; @@ -185,10 +143,7 @@ public final class Device { return false; } - isSettingClipboard.set(true); - boolean ok = clipboardManager.setText(text); - isSettingClipboard.set(false); - return ok; + return clipboardManager.setText(text); } /**