mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-07-31 21:28:52 +00:00
Always synchronize clipboard on explicit COPY/CUT
If --no-clipboard-autosync is enabled, the automatic clipboard synchronization performed whenever the device clipboard changes is disabled. But on explicit COPY and CUT scrcpy shortcuts (MOD+c and MOD+x), the clipboard should still be synchronized, so that it remains possible to copy-paste from the device to the computer. This is consistent with the behavior of MOD+v, which pastes the computer clipboard to the device. Refs #2228 <https://github.com/Genymobile/scrcpy/issues/2228> Refs #2817 <https://github.com/Genymobile/scrcpy/pull/2817> PR #2834 <https://github.com/Genymobile/scrcpy/pull/2834>
This commit is contained in:
parent
bfcb9d06c3
commit
e2b3968c66
9 changed files with 102 additions and 26 deletions
|
@ -20,6 +20,10 @@ public final class ControlMessage {
|
|||
|
||||
public static final long SEQUENCE_INVALID = 0;
|
||||
|
||||
public static final int COPY_KEY_NONE = 0;
|
||||
public static final int COPY_KEY_COPY = 1;
|
||||
public static final int COPY_KEY_CUT = 2;
|
||||
|
||||
private int type;
|
||||
private String text;
|
||||
private int metaState; // KeyEvent.META_*
|
||||
|
@ -31,6 +35,7 @@ public final class ControlMessage {
|
|||
private Position position;
|
||||
private int hScroll;
|
||||
private int vScroll;
|
||||
private int copyKey;
|
||||
private boolean paste;
|
||||
private int repeat;
|
||||
private long sequence;
|
||||
|
@ -82,6 +87,13 @@ public final class ControlMessage {
|
|||
return msg;
|
||||
}
|
||||
|
||||
public static ControlMessage createGetClipboard(int copyKey) {
|
||||
ControlMessage msg = new ControlMessage();
|
||||
msg.type = TYPE_GET_CLIPBOARD;
|
||||
msg.copyKey = copyKey;
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static ControlMessage createSetClipboard(long sequence, String text, boolean paste) {
|
||||
ControlMessage msg = new ControlMessage();
|
||||
msg.type = TYPE_SET_CLIPBOARD;
|
||||
|
@ -151,6 +163,10 @@ public final class ControlMessage {
|
|||
return vScroll;
|
||||
}
|
||||
|
||||
public int getCopyKey() {
|
||||
return copyKey;
|
||||
}
|
||||
|
||||
public boolean getPaste() {
|
||||
return paste;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ public class ControlMessageReader {
|
|||
static final int INJECT_SCROLL_EVENT_PAYLOAD_LENGTH = 20;
|
||||
static final int BACK_OR_SCREEN_ON_LENGTH = 1;
|
||||
static final int SET_SCREEN_POWER_MODE_PAYLOAD_LENGTH = 1;
|
||||
static final int GET_CLIPBOARD_LENGTH = 1;
|
||||
static final int SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH = 9;
|
||||
|
||||
private static final int MESSAGE_MAX_SIZE = 1 << 18; // 256k
|
||||
|
@ -70,6 +71,9 @@ public class ControlMessageReader {
|
|||
case ControlMessage.TYPE_BACK_OR_SCREEN_ON:
|
||||
msg = parseBackOrScreenOnEvent();
|
||||
break;
|
||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||
msg = parseGetClipboard();
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||
msg = parseSetClipboard();
|
||||
break;
|
||||
|
@ -79,7 +83,6 @@ public class ControlMessageReader {
|
|||
case ControlMessage.TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||
case ControlMessage.TYPE_EXPAND_SETTINGS_PANEL:
|
||||
case ControlMessage.TYPE_COLLAPSE_PANELS:
|
||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||
case ControlMessage.TYPE_ROTATE_DEVICE:
|
||||
msg = ControlMessage.createEmpty(type);
|
||||
break;
|
||||
|
@ -162,6 +165,14 @@ public class ControlMessageReader {
|
|||
return ControlMessage.createBackOrScreenOn(action);
|
||||
}
|
||||
|
||||
private ControlMessage parseGetClipboard() {
|
||||
if (buffer.remaining() < GET_CLIPBOARD_LENGTH) {
|
||||
return null;
|
||||
}
|
||||
int copyKey = toUnsigned(buffer.get());
|
||||
return ControlMessage.createGetClipboard(copyKey);
|
||||
}
|
||||
|
||||
private ControlMessage parseSetClipboard() {
|
||||
if (buffer.remaining() < SET_CLIPBOARD_FIXED_PAYLOAD_LENGTH) {
|
||||
return null;
|
||||
|
|
|
@ -21,6 +21,7 @@ public class Controller {
|
|||
private final Device device;
|
||||
private final DesktopConnection connection;
|
||||
private final DeviceMessageSender sender;
|
||||
private final boolean clipboardAutosync;
|
||||
|
||||
private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
|
||||
|
||||
|
@ -31,9 +32,10 @@ public class Controller {
|
|||
|
||||
private boolean keepPowerModeOff;
|
||||
|
||||
public Controller(Device device, DesktopConnection connection) {
|
||||
public Controller(Device device, DesktopConnection connection, boolean clipboardAutosync) {
|
||||
this.device = device;
|
||||
this.connection = connection;
|
||||
this.clipboardAutosync = clipboardAutosync;
|
||||
initPointers();
|
||||
sender = new DeviceMessageSender(connection);
|
||||
}
|
||||
|
@ -114,10 +116,7 @@ public class Controller {
|
|||
Device.collapsePanels();
|
||||
break;
|
||||
case ControlMessage.TYPE_GET_CLIPBOARD:
|
||||
String clipboardText = Device.getClipboardText();
|
||||
if (clipboardText != null) {
|
||||
sender.pushClipboardText(clipboardText);
|
||||
}
|
||||
getClipboard(msg.getCopyKey());
|
||||
break;
|
||||
case ControlMessage.TYPE_SET_CLIPBOARD:
|
||||
setClipboard(msg.getText(), msg.getPaste(), msg.getSequence());
|
||||
|
@ -276,6 +275,25 @@ public class Controller {
|
|||
return device.pressReleaseKeycode(KeyEvent.KEYCODE_POWER, Device.INJECT_MODE_ASYNC);
|
||||
}
|
||||
|
||||
private void getClipboard(int copyKey) {
|
||||
// On Android >= 7, press the COPY or CUT key if requested
|
||||
if (copyKey != ControlMessage.COPY_KEY_NONE && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && device.supportsInputEvents()) {
|
||||
int key = copyKey == ControlMessage.COPY_KEY_COPY ? KeyEvent.KEYCODE_COPY : KeyEvent.KEYCODE_CUT;
|
||||
// Wait until the event is finished, to ensure that the clipboard text we read just after is the correct one
|
||||
device.pressReleaseKeycode(key, Device.INJECT_MODE_WAIT_FOR_FINISH);
|
||||
}
|
||||
|
||||
// If clipboard autosync is enabled, then the device clipboard is synchronized to the computer clipboard whenever it changes, in
|
||||
// particular when COPY or CUT are injected, so it should not be synchronized twice. On Android < 7, do not synchronize at all rather than
|
||||
// copying an old clipboard content.
|
||||
if (!clipboardAutosync) {
|
||||
String clipboardText = Device.getClipboardText();
|
||||
if (clipboardText != null) {
|
||||
sender.pushClipboardText(clipboardText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setClipboard(String text, boolean paste, long sequence) {
|
||||
boolean ok = device.setClipboardText(text);
|
||||
if (ok) {
|
||||
|
|
|
@ -74,7 +74,7 @@ public final class Server {
|
|||
Thread controllerThread = null;
|
||||
Thread deviceMessageSenderThread = null;
|
||||
if (options.getControl()) {
|
||||
final Controller controller = new Controller(device, connection);
|
||||
final Controller controller = new Controller(device, connection, options.getClipboardAutosync());
|
||||
|
||||
// asynchronous
|
||||
controllerThread = startController(controller);
|
||||
|
|
|
@ -219,6 +219,7 @@ public class ControlMessageReaderTest {
|
|||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlMessage.TYPE_GET_CLIPBOARD);
|
||||
dos.writeByte(ControlMessage.COPY_KEY_COPY);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
|
@ -226,6 +227,7 @@ public class ControlMessageReaderTest {
|
|||
ControlMessage event = reader.next();
|
||||
|
||||
Assert.assertEquals(ControlMessage.TYPE_GET_CLIPBOARD, event.getType());
|
||||
Assert.assertEquals(ControlMessage.COPY_KEY_COPY, event.getCopyKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue