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

Use powershell.exe instead of clip.exe to copy to WSL clipboard #1

Merged

Conversation

johnDeSilencio
Copy link
Contributor

Problem

Copying to clipboard in WSL environment using clip.exe leads to garbled data being copied to clipboard for Unicode point characters (e.g. πŸ’―). Using powershell.exe set-clipboard instead copies Unicode point characters to the clipboard correctly.

Evidence

I have a crate that I put together for fun called emojicp. I liked your crate because it gave me the widest number of environments to run emojicp in. However, it seems to fail for WSL environments.

Below are 10 emojis that I tried to copy to my clipboard in WSL alongside what was actually copied to my clipboard:

Emoji Name Expected Output Expected Output (Hex) Actual Output Actual Output (Hex)
white_check_mark βœ… e2 9c 85 ✅ ce 93 c2 a3 c3 a0
santa πŸŽ… f0 9f 8e 85 ≑ƒÄà e2 89 a1 c6 92 c3 84 c3 a0
monkey πŸ’ f0 9f 90 92 ≑ƒÉÆ e2 89 a1 c6 92 c3 89 c3 86
see_no_evil πŸ™ˆ f0 9f 99 88 ≑ƒÖΓͺ e2 89 a1 c6 92 c3 96 c3 aa
hear_no_evil πŸ™‰ f0 9f 99 89 ≑ƒÖë e2 89 a1 c6 92 c3 96 c3 ab
speak_no_evil πŸ™Š f0 9f 99 8a ≑ƒÖè e2 89 a1 c6 92 c3 96 c3 a8
monkey_face 🐡 f0 9f 90 b5 ≑ƒÉ║ e2 89 a1 c6 92 c3 89 e2 95 a1
sunglasses 😎 f0 9f 98 8e ≑ƒÿÄ e2 89 a1 c6 92 c3 bf c3 84
oncoming_automobile 🚘 f0 9f 9a 98 β‰‘Ζ’ΓœΓΏ e2 89 a1 c6 92 c3 9c c3 bf
orangutan 🦧 f0 9f a6 a7 ≑ƒΒͺΒΊ e2 89 a1 c6 92 c2 aa c2 ba
japanese_goblin πŸ‘Ί f0 9f 91 ba ቑƒæ║ e1 89 a1 c6 92 c3 a6 e2 95 91

Solution

After reading a lot of obscure WSL GitHub issues and playing around with encodings, the only solution that actually fixed my use case was replacing clip.exe with powershell.exe set-clipboard altogether. Now, with powershell.exe set-clipboard, I can copy emojis to my clipboard in WSL just fine.

@rgwood
Copy link
Owner

rgwood commented Dec 19, 2023

Thank you for the great PR+description! It might be a few days before I have time to test this on WSL but it looks good.

The only concern I have is that PowerShell can be quite slow to launch. Not the end of the world though, I think correctness is more important than speed here.

@johnDeSilencio
Copy link
Contributor Author

You're welcome! Thank you for putting together a great crate 😁

I've also observed powershell being slow. I'm open to trying to rework clip.exe. I just wasn't able to get it to work on WSL in the couple of hours I was fiddling with it.

I would also wait on merging the PR. I was testing again this morning and saw that the way Rust is doing escaping, this PR breaks for copying string with double quotes " in them. Gonna try to push another commit today to fix that edge case.

@johnDeSilencio
Copy link
Contributor Author

The most recent commit should address the quote escaping issue. I use single-quotes ' instead of double-quotes " inside the format!() macro. Run this Rust program in WSL and you should see that strings with single-quotes and strings with double-quotes both get copied to your clipboard successfully:

use std::process::Command;
use std::io::Read;

fn main() {
    for s in &["'πŸ¦€'", "\"πŸ¦€\""] {
        let mut command = Command::new("powershell.exe");
        command.arg("-NoProfile").arg("-Command").arg(&format!("Set-Clipboard -Value '{}'", s.replace("'", "''")));
        println!("{:?}", command);

        let mut command = command.spawn().unwrap();
        command.wait().unwrap();

        println!("Copied {} to your clipboard. Press ENTER to continue...", s);
        let buffer = &mut [0u8];
        std::io::stdin().read_exact(buffer).unwrap();
    }
}

@rgwood
Copy link
Owner

rgwood commented Dec 24, 2023

Thanks for your patience, finally had a chance to test this.

Timing-wise Powershell is not great but OK; 150-300ms on my 12900K desktop.

I tried adding a test, and it looks like setting emoji content works but getting it from the clipboard does not:

#[test]
fn set_and_get() -> Result<()> {
    let text = "Hello, world! 🌍";
    set_clipboard(text)?;

    let clipboard_contents = get_clipboard()?;
    assert_eq!(clipboard_contents, text);

    Ok(())
}
---- set_and_get stdout ----
Copy finished in 172ms
thread 'set_and_get' panicked at 'assertion failed: `(left == right)`
  left: `"Hello, world! ??"`,
 right: `"Hello, world! 🌍"`', src/lib.rs:94:5

If you have time/energy/interest, it would be nice to get that working. In the meantime, this looks like a strict improvement and I'm happy to merge it.

@rgwood rgwood merged commit 6a1d0ff into rgwood:main Dec 24, 2023
@rgwood
Copy link
Owner

rgwood commented Dec 24, 2023

Published to Cargo as v0.2.3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants