Skip to content

Commit 6228967

Browse files
authored
Fix clipboard copying on Wayland (#333)
2 parents bd82d85 + b15e1df commit 6228967

File tree

4 files changed

+66
-45
lines changed

4 files changed

+66
-45
lines changed

src/clipboard.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use base64::{engine::general_purpose, Engine as _};
2+
use copypasta_ext::prelude::*;
3+
#[cfg(target_os = "linux")]
4+
use copypasta_ext::wayland_bin::WaylandBinClipboardContext;
5+
use copypasta_ext::x11_bin::ClipboardContext as BinClipboardContext;
6+
use copypasta_ext::x11_fork::ClipboardContext as ForkClipboardContext;
7+
use crossterm::style::Print;
8+
use std::{env, io};
9+
10+
pub enum CopyType {
11+
Native,
12+
OSC52,
13+
}
14+
15+
pub fn copy_string_to_clipboard(content: String) -> Result<CopyType, ()> {
16+
if ssh_clipboard(content.as_str()) {
17+
Ok(CopyType::OSC52)
18+
} else if wayland_clipboard(content.as_str()) || other_platform_clipboard(content.as_str()) {
19+
Ok(CopyType::Native)
20+
} else {
21+
Err(())
22+
}
23+
}
24+
25+
fn ssh_clipboard(content: &str) -> bool {
26+
env_var_set("SSH_CONNECTION")
27+
// We do not use copypasta_ext::osc52 module because we have enabled terminal raw mode, so we print with crossterm utilities
28+
// Check https://github.com/timvisee/rust-clipboard-ext/blob/371df19d2f961882a21c957f396d1e24548d1f28/src/osc52.rs#L92
29+
&& crossterm::execute!(
30+
io::stdout(),
31+
Print(format!(
32+
"\x1B]52;c;{}\x07",
33+
general_purpose::STANDARD.encode(content)
34+
))
35+
)
36+
.is_ok()
37+
}
38+
#[cfg(target_os = "linux")]
39+
fn wayland_clipboard(content: &str) -> bool {
40+
env_var_set("WAYLAND_DISPLAY")
41+
&& WaylandBinClipboardContext::new()
42+
.and_then(|mut ctx| ctx.set_contents(content.to_owned()))
43+
.is_ok()
44+
}
45+
46+
#[cfg(not(target_os = "linux"))]
47+
fn wayland_clipboard(content: &str) -> bool {
48+
false
49+
}
50+
51+
fn other_platform_clipboard(content: &str) -> bool {
52+
BinClipboardContext::new()
53+
.and_then(|mut ctx| ctx.set_contents(content.to_owned()))
54+
.is_ok()
55+
|| ForkClipboardContext::new()
56+
.and_then(|mut ctx| ctx.set_contents(content.to_owned()))
57+
.is_ok()
58+
}
59+
60+
fn env_var_set(env_var: &str) -> bool {
61+
env::var(env_var)
62+
.map(|v| !v.trim().is_empty())
63+
.unwrap_or(false)
64+
}

src/interface/handler.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
use crate::clipboard::{copy_string_to_clipboard, CopyType};
12
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
23

34
use crate::interface::app::{App, AppResult};
45
use crate::interface::enums::Page::*;
56
use crate::otp::otp_type::OTPType;
6-
use crate::utils::{copy_string_to_clipboard, CopyType};
77

88
use super::app::Popup;
99
use super::enums::Page;

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use zeroize::Zeroize;
1414

1515
mod args;
1616
mod argument_functions;
17+
mod clipboard;
1718
mod crypto;
1819
mod exporters;
1920
mod importers;

src/utils.rs

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,8 @@
1-
use base64::{engine::general_purpose, Engine as _};
2-
use copypasta_ext::prelude::*;
3-
use copypasta_ext::x11_bin::ClipboardContext as BinClipboardContext;
4-
use copypasta_ext::x11_fork::ClipboardContext as ForkClipboardContext;
5-
use crossterm::style::Print;
61
use dirs::home_dir;
72
use std::path::PathBuf;
83
use std::time::{SystemTime, UNIX_EPOCH};
94
use std::{env, io};
105

11-
pub enum CopyType {
12-
Native,
13-
OSC52,
14-
}
15-
166
pub fn get_db_path() -> PathBuf {
177
match env::var("COTP_DB_PATH") {
188
Ok(value) => PathBuf::from(value),
@@ -89,37 +79,3 @@ pub fn verified_password(message: &str, minimum_length: usize) -> String {
8979
return password;
9080
}
9181
}
92-
93-
fn in_ssh_shell() -> bool {
94-
return !env::var("SSH_CONNECTION")
95-
.unwrap_or_default()
96-
.trim()
97-
.is_empty();
98-
}
99-
100-
pub fn copy_string_to_clipboard(content: String) -> Result<CopyType, ()> {
101-
if in_ssh_shell()
102-
&& crossterm::execute!(
103-
io::stdout(),
104-
Print(format!(
105-
"\x1B]52;c;{}\x07",
106-
general_purpose::STANDARD.encode(&content)
107-
))
108-
)
109-
.is_ok()
110-
{
111-
// We do not use copypasta_ext::osc52 module because we have enabled terminal raw mode, so we print with crossterm utilities
112-
// Check https://github.com/timvisee/rust-clipboard-ext/blob/371df19d2f961882a21c957f396d1e24548d1f28/src/osc52.rs#L92
113-
Ok(CopyType::OSC52)
114-
} else if BinClipboardContext::new()
115-
.and_then(|mut ctx| ctx.set_contents(content.clone()))
116-
.is_ok()
117-
|| ForkClipboardContext::new()
118-
.and_then(|mut ctx| ctx.set_contents(content))
119-
.is_ok()
120-
{
121-
Ok(CopyType::Native)
122-
} else {
123-
Err(())
124-
}
125-
}

0 commit comments

Comments
 (0)