mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-09-01 15:15:44 +00:00
Implement device-to-computer clipboard copy
On Ctrl+C: - the client sends a GET_CLIPBOARD command to the device; - the device retrieve its current clipboard text and sends it in a GET_CLIPBOARD device event; - the client sets this text as the system clipboard text, so that it can be pasted in another application. Fixes <https://github.com/Genymobile/scrcpy/issues/145>
This commit is contained in:
parent
3149e2cf4a
commit
63c078ee6c
13 changed files with 109 additions and 0 deletions
|
@ -12,6 +12,7 @@ public final class ControlEvent {
|
|||
public static final int TYPE_BACK_OR_SCREEN_ON = 4;
|
||||
public static final int TYPE_EXPAND_NOTIFICATION_PANEL = 5;
|
||||
public static final int TYPE_COLLAPSE_NOTIFICATION_PANEL = 6;
|
||||
public static final int TYPE_GET_CLIPBOARD = 7;
|
||||
|
||||
private int type;
|
||||
private String text;
|
||||
|
|
|
@ -66,6 +66,7 @@ public class ControlEventReader {
|
|||
case ControlEvent.TYPE_BACK_OR_SCREEN_ON:
|
||||
case ControlEvent.TYPE_EXPAND_NOTIFICATION_PANEL:
|
||||
case ControlEvent.TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
||||
case ControlEvent.TYPE_GET_CLIPBOARD:
|
||||
controlEvent = ControlEvent.createSimpleControlEvent(type);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -139,6 +139,14 @@ public final class Device {
|
|||
serviceManager.getStatusBarManager().collapsePanels();
|
||||
}
|
||||
|
||||
public String getClipboardText() {
|
||||
CharSequence s = serviceManager.getClipboardManager().getText();
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
static Rect flipRect(Rect crop) {
|
||||
return new Rect(crop.top, crop.left, crop.bottom, crop.right);
|
||||
}
|
||||
|
|
|
@ -90,6 +90,10 @@ public class EventController {
|
|||
case ControlEvent.TYPE_COLLAPSE_NOTIFICATION_PANEL:
|
||||
device.collapsePanels();
|
||||
break;
|
||||
case ControlEvent.TYPE_GET_CLIPBOARD:
|
||||
String clipboardText = device.getClipboardText();
|
||||
sender.pushClipboardText(clipboardText);
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package com.genymobile.scrcpy.wrappers;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.os.IInterface;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ClipboardManager {
|
||||
private final IInterface manager;
|
||||
private final Method getPrimaryClipMethod;
|
||||
|
||||
public ClipboardManager(IInterface manager) {
|
||||
this.manager = manager;
|
||||
try {
|
||||
getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public CharSequence getText() {
|
||||
try {
|
||||
ClipData clipData = (ClipData) getPrimaryClipMethod.invoke(manager, "com.android.shell");
|
||||
if (clipData == null || clipData.getItemCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
return clipData.getItemAt(0).getText();
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ public final class ServiceManager {
|
|||
private InputManager inputManager;
|
||||
private PowerManager powerManager;
|
||||
private StatusBarManager statusBarManager;
|
||||
private ClipboardManager clipboardManager;
|
||||
|
||||
public ServiceManager() {
|
||||
try {
|
||||
|
@ -68,4 +69,11 @@ public final class ServiceManager {
|
|||
}
|
||||
return statusBarManager;
|
||||
}
|
||||
|
||||
public ClipboardManager getClipboardManager() {
|
||||
if (clipboardManager == null) {
|
||||
clipboardManager = new ClipboardManager(getService("clipboard", "android.content.IClipboard"));
|
||||
}
|
||||
return clipboardManager;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -174,6 +174,22 @@ public class ControlEventReaderTest {
|
|||
Assert.assertEquals(ControlEvent.TYPE_COLLAPSE_NOTIFICATION_PANEL, event.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseGetClipboardEvent() throws IOException {
|
||||
ControlEventReader reader = new ControlEventReader();
|
||||
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeByte(ControlEvent.TYPE_GET_CLIPBOARD);
|
||||
|
||||
byte[] packet = bos.toByteArray();
|
||||
|
||||
reader.readFrom(new ByteArrayInputStream(packet));
|
||||
ControlEvent event = reader.next();
|
||||
|
||||
Assert.assertEquals(ControlEvent.TYPE_GET_CLIPBOARD, event.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiEvents() throws IOException {
|
||||
ControlEventReader reader = new ControlEventReader();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue