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

Bring back old Copy / Paste system #1771

Closed
NekoGryphou opened this issue Sep 18, 2020 · 35 comments
Closed

Bring back old Copy / Paste system #1771

NekoGryphou opened this issue Sep 18, 2020 · 35 comments

Comments

@NekoGryphou
Copy link

The new copy / paste system is not ergonomic at all .
I'd much rather paste text in "letter by letter input" mode when I press ctrl + v rather than having to do alt + shit + v.
And when I do alt + v, it pastes the text from the clipboard which is not necessarily the one I want to put.

If i rebind the mod key to ctrl instead of alt, it's a real messe with copy / paste too.

Can you add an option to get back to the old behavior; I use this application all day long and it's getting complicated now and I'm losing time due to errors related to copy / paste.

Thanks you

@rom1v
Copy link
Collaborator

rom1v commented Sep 18, 2020

And when I do alt + v, it pastes the text from the clipboard which is not necessarily the one I want to put.

The content pasted by with Alt+v should be the same as the one pasted with Alt+Shift+v (and the same as the one pasted with Ctrl+v).

If this is not the case, then probably device.setClipboardText(text) does not work on your device ROM, see #1750 (possibly because your device is rooted #1678?).

Which Android version, which Android ROM? Could you try with another device?

@NekoGryphou
Copy link
Author

I've got an Samsung Galaxy S9+ and Android 10 samsung rom.
Not rooted.

But, why did you change ctrl + v to alt + v ?

@rom1v
Copy link
Collaborator

rom1v commented Sep 18, 2020

But, why did you change ctrl + v to alt + v ?

To forward the Ctrl key to the device.

See v1.15 highlights and #1598 for more details.
The new expected behavior is as described in the README: https://github.com/Genymobile/scrcpy#copy-paste

@NekoGryphou
Copy link
Author

When i hit ctrl + v or alt + v, it sync the computer clipboard to the device OR if there is something in the smartphone's clipboard, it pastes it and synchronizes after pasting the old text...

@rom1v
Copy link
Collaborator

rom1v commented Sep 18, 2020

Oh, wait, do you use v1.16?

Because there was a bug in v1.15: #1658

@NekoGryphou
Copy link
Author

Yes, i use the v1.16 version

@rom1v
Copy link
Collaborator

rom1v commented Sep 18, 2020

When i hit ctrl + v or alt + v, it sync the computer clipboard to the device OR if there is something in the smartphone's clipboard, it pastes it and synchronizes after pasting the old text...

OK, so IIUC, the second time you press Ctrl+v, it correctly pastes the expected content, right?

@rom1v rom1v added the bug label Sep 18, 2020
@NekoGryphou
Copy link
Author

Here's a video example : https://streamable.com/r1k9nc

@rom1v
Copy link
Collaborator

rom1v commented Sep 18, 2020

OK, thank you for the video. 👍

So it seems that device.setClipboardText(text) does something on the device (we see the content in the clipboard on your device), but is not pasted, neither with Ctrl+v nor Alt+v (unless the content is initially copied from the device).

You could also test adb shell input keyevent PASTE manually to paste, I guess you will have the same problem.

I think it's the very same issue as #1750.

I would say this is a device bug: once the content is in the clipboard (as shown above the device keyboard), injecting PASTE or pressing Ctrl+v should paste it.

Could you capture the logcat content when you press Ctrl+v in the scrcpy window for the first time (with a new random content, different from the previous one), please?

Start scrcpy and from a new terminal, execute:

adb logcat -c  # clear
# copy some text and press Ctrl+v in the scrcpy window
adb logcat -d > logcat.txt

@NekoGryphou
Copy link
Author

When i do adb shell input keyevent PASTE, it paste the older clipboard element, not the new one.
Github upload it's a bit buggy today, so here,s a link to the logcat.txt content : https://hastebin.com/umayuhecax.txt

@NekoGryphou
Copy link
Author

NekoGryphou commented Sep 18, 2020

Maybe it's a bug with Google Keyboard (the content is well copied in the clipboard of GBoard), but before the v1.16, things work perfectly with the "letter by letter paste" (alt + shift + v now)

@rom1v
Copy link
Collaborator

rom1v commented Sep 18, 2020

When i do adb shell input keyevent PASTE, it paste the older clipboard element, not the new one.

OK, so it suggests a device system bug (or intended restriction).

The method scrcpy uses to set the clipboard is "public" (usable by any app): ClipboardManager.setPrimaryClip().

I'm interested to know if you set the text from some app using this API and try to paste with adb shell input keyevent PASTE. This would allow to reproduce the problem without scrcpy.

There are probably some simple "clipboard manager" apps which allow to explicitly set some text to the clipboard using this.

@NekoGryphou
Copy link
Author

NekoGryphou commented Sep 18, 2020

I test with https://play.google.com/store/apps/details?id=devdnua.clipboard and it work when i paste the clipboard content
I don't really have the time to create an app for testing this, sorry.
However if you do one, i can test for you

@rom1v
Copy link
Collaborator

rom1v commented Sep 18, 2020

I test with https://play.google.com/store/apps/details?id=devdnua.clipboard and it work when i paste the clipboard content

😕

@rom1v
Copy link
Collaborator

rom1v commented Sep 18, 2020

I wrote a minimal scrcpy-like sample application to get and set the clipboard.

Download clipboard.dex
SHA256: 3c7205c58c26f4ed42feda56ce3c312b13b5ff11c980817bccdc5882f629fed2

Then push it to the device:

adb push clipboard.dex /data/local/tmp/

Then, you can execute:

# get the current clipboard text
adb shell CLASSPATH=/data/local/tmp/clipboard.dex app_process / Clipboard get
# set the clipboard text
adb shell CLASSPATH=/data/local/tmp/clipboard.dex app_process / Clipboard set abcdefgh

Please try to set the clipboard, check the result by reading the current content.
Then focus some text field on Android, and execute adb shell input keyevent PASTE to inject it.

What is the behavior?

source code
import android.content.ClipData;
import android.os.Build;
import android.os.IBinder;
import android.os.IInterface;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Clipboard {

    private static final String PACKAGE_NAME = "com.android.shell";
    private static final int USER_ID = 0;

    private static Method getPrimaryClipMethod;
    private static Method setPrimaryClipMethod;
    private static boolean legacySet;

    private static IInterface getService(String service, String type) {
        try {
            Method getServiceMethod = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class);
            IBinder binder = (IBinder) getServiceMethod.invoke(null, service);
            Method asInterfaceMethod = Class.forName(type + "$Stub").getMethod("asInterface", IBinder.class);
            return (IInterface) asInterfaceMethod.invoke(null, binder);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

    private static IInterface getClipboardManager() {
        return getService("clipboard", "android.content.IClipboard");
    }

    private static Method getGetPrimaryClipMethod(IInterface manager) throws NoSuchMethodException {
        if (getPrimaryClipMethod == null) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class);
            } else {
                getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class, int.class);
            }
        }
        return getPrimaryClipMethod;
    }

    private static Method getSetPrimaryClipMethod(IInterface manager) throws NoSuchMethodException {
        if (setPrimaryClipMethod == null) {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class);
            } else {
                setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class, int.class);
            }
        }
        return setPrimaryClipMethod;
    }

    private static ClipData getPrimaryClip(Method method, IInterface manager) throws InvocationTargetException, IllegalAccessException {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            return (ClipData) method.invoke(manager, PACKAGE_NAME);
        }
        return (ClipData) method.invoke(manager, PACKAGE_NAME, USER_ID);
    }

    private static void setPrimaryClip(Method method, IInterface manager, ClipData clipData)
            throws InvocationTargetException, IllegalAccessException {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            method.invoke(manager, clipData, PACKAGE_NAME);
        } else {
            method.invoke(manager, clipData, PACKAGE_NAME, USER_ID);
        }
    }

    public static CharSequence getText(IInterface manager) {
        try {
            Method method = getGetPrimaryClipMethod(manager);
            ClipData clipData = getPrimaryClip(method, manager);
            if (clipData == null || clipData.getItemCount() == 0) {
                return null;
            }
            return clipData.getItemAt(0).getText();
        } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
            System.err.println("Could not invoke method");
            return null;
        }
    }

    public static boolean setText(IInterface manager, CharSequence text) {
        try {
            Method method = getSetPrimaryClipMethod(manager);
            ClipData clipData = ClipData.newPlainText(null, text);
            setPrimaryClip(method, manager, clipData);
            return true;
        } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
            System.err.println("Could not invoke method");
            return false;
        }
    }

    private static void syntax() {
        System.err.println("Syntax: adb shell CLASSPATH=/data/local/tmp/clipboard app_process / Clipboard [options]");
        System.err.println("options:");
        System.err.println("    get");
        System.err.println("    set 'SOME TEXT'");
        System.exit(1);
    }

    private static void error() {
        syntax();
        System.exit(1);
    }

    private static CharSequence getClipboard() {
        IInterface manager = getClipboardManager();
        return getText(manager);
    }

    public static boolean setClipboard(CharSequence text) {
        IInterface manager = getClipboardManager();
        return setText(manager, text);
    }

    public static void main(String... args) throws Exception {
        if (args.length == 0) {
            error();
        }
        if ("get".equals(args[0])) {
            if (args.length != 1) {
                error();
            }
            System.out.println("get: " + getClipboard());
        } else if ("set".equals(args[0])) {
            if (args.length != 2) {
                error();
            }
            String text = args[1];
            if (setClipboard(text)) {
                System.out.println("set: " + text);
            } else {
                System.err.println("set error");
            }
        } else {
            error();
        }
    }
}

Compile with:

javac -source 1.7 -target 1.7 Clipboard.java -cp "$ANDROID_HOME"/platforms/android-30/android.jar
~/android/sdk/build-tools/30.0.0/dx --dex --output clipboard.dex Clipboard.class

@rom1v
Copy link
Collaborator

rom1v commented Sep 20, 2020

Did you have some time to test?

@NekoGryphou
Copy link
Author

NekoGryphou commented Sep 21, 2020

Sorry, i've been a bit busy this week-end.
I just tested your application and the clipboard doesn't work.

CMD :
cmd

> adb push clipboarD.dex /data/local/tmp/
clipboard.dex: 1 file pushed, 0 skipped. 1.1 MB/s (4720 bytes in 0.004s)

> adb shell CLASSPATH=/data/local/tmp/clipboard.dex app_process / Clipboard get
get: 923756

> adb shell CLASSPATH=/data/local/tmp/clipboard.dex app_process / Clipboard set abcdefgh
set: abcdefgh

> adb shell CLASSPATH=/data/local/tmp/clipboarD.dex app_process / Clipboard get
get: abcdefgh

> adb shell input keyevent PASTE

Device after PASTE event :
device

923756

Otherwise, can you tell me how to remove the .dex file from my phone ?

@rom1v
Copy link
Collaborator

rom1v commented Sep 21, 2020

OK, thank you for the test 👍

Otherwise, can you tell me how to remove the .dex file from my phone ?

adb shell rm /data/local/tmp/clipboard.dex

@NekoGryphou
Copy link
Author

NekoGryphou commented Sep 21, 2020

adb shell rm /data/local/tmp/clipboard.dex

Thanks 👍

@NekoGryphou
Copy link
Author

Any news about a potential patch? :3

@rom1v
Copy link
Collaborator

rom1v commented Sep 30, 2020

No, the test confirms that your device does not behave as expected. I don't have a solution for this. 😞

@NekoGryphou
Copy link
Author

oh :c

@gmiwoj
Copy link

gmiwoj commented Oct 2, 2020

seconded.
i'm still on 1.14 because of this. copy pasta works perfectly on 1.14 and is pretty much unusable for me on 1.16

pls bring it back or at least make it an option

@rom1v
Copy link
Collaborator

rom1v commented Oct 2, 2020

Could you confirm that the issue only occurs with paste, but that copy works correctly: if you select a text then press Ctrl+c on the device (in the scrcpy window), could you paste it on the computer?

@hoanngothanh
Copy link

Could you confirm that the issue only occurs with paste, but that copy works correctly: if you select a text then press Ctrl+c on the device (in the scrcpy window), could you paste it on the computer?

Hi rom1v
I can confirm when I copy from scrcpy window I can paste it to PC. But copy from pc then pastes to scrcpy have issue. I'm using the latest version of scrcpy

@rom1v
Copy link
Collaborator

rom1v commented Oct 6, 2020

I've just implemented an option on a separate branch (legacy_paste):

scrcpy --legacy-paste

Could you please test it?

For windows users, take both scrcpy.exe and scrcpy-server, and replace them in your scrcpy v1.16 release.

For other platforms, take scrcpy-server and build only the client.

  • scrcpy.exe
    SHA256: 38b541d7cef76d424a72316faae02a9e8f78c021cb5d0d60721d701c43bafd13
  • scrcpy-server
    SHA256: 467beb2762d822766ccf76fc7bd47cd3950293d21eab041c62b0b5bd279039c1

rom1v added a commit that referenced this issue Oct 6, 2020
Some devices do not behave as expected when setting the device clipboard
programmatically.

Add an option --legacy-paste to change the behavior of Ctrl+v and MOD+v
so that they inject the computer clipboard text as a sequence of key
events (the same way as MOD+Shift+v).

Fixes #1750 <#1750>
Fixes #1771 <#1771>
@rom1v
Copy link
Collaborator

rom1v commented Oct 12, 2020

Could you please test? I'm interested in knowing if it solves your problem.

@NekoGryphou
Copy link
Author

NekoGryphou commented Oct 12, 2020

CTRL + V paste "letter by letter" now

@rom1v
Copy link
Collaborator

rom1v commented Oct 12, 2020

Yes, that's the workaround if the device PASTE does not behave as expected. 👍

Is it a better behavior?

@NekoGryphou
Copy link
Author

it's better than a buggy thing ^^
Thanks !

@atscripter
Copy link

@rom1v Tested, working. Thank you.

@atscripter
Copy link

Can we get one for scrcpy-noconsole.exe too? :)

@NekoGryphou
Copy link
Author

Any new version planned with this ?

rom1v added a commit that referenced this issue Nov 7, 2020
Some devices do not behave as expected when setting the device clipboard
programmatically.

Add an option --legacy-paste to change the behavior of Ctrl+v and MOD+v
so that they inject the computer clipboard text as a sequence of key
events (the same way as MOD+Shift+v).

Fixes #1750 <#1750>
Fixes #1771 <#1771>
@rom1v
Copy link
Collaborator

rom1v commented Nov 7, 2020

--legacy-paste option merged into dev: d5f059c

@XeonG
Copy link

XeonG commented Jan 17, 2021

Also having this problem with pasting not working... I did try the legacy paste argument on the cmd line which works.. but its buggy it just leaves out characters, and doesn't even paste the whole clipboard from there pc.

copy works fine.. just not pasting from the pc, Samsung note9

is there any solution to this.. I'd be fine with legacy paste if it actually pasted all the characters from the clipboard.

jellopuddingstick added a commit to jellopuddingstick/scrcpy that referenced this issue Jan 23, 2021
scrcpy v1.17

Changes since v1.16:
 - Fix errors on Android 11 (Genymobile#1468)
 - Add --encoder option (Genymobile#1810, Genymobile#1827)
 - Add --forward-all-clicks option (Genymobile#1302, Genymobile#1613)
 - Add --legacy-paste option (Genymobile#1750, Genymobile#1771)
 - Workaround screen off/on issue on exit (Genymobile#1670)
 - Rework console/noconsole versions on Windows (Genymobile#1875, Genymobile#1988)
 - Terminate server properly without killing it on close (Genymobile#1992)
 - List available shortcut keys on error (Genymobile#1681)
 - Upgrade platform-tools to 30.0.5 (adb) in Windows releases
 - Upgrade SDL to 2.0.14 in Windows releases
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants