Skip to content

Commit

Permalink
Fix clipboard copying on Wayland (#333)
Browse files Browse the repository at this point in the history
  • Loading branch information
replydev authored Oct 9, 2023
2 parents bd82d85 + b15e1df commit 6228967
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 45 deletions.
64 changes: 64 additions & 0 deletions src/clipboard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use base64::{engine::general_purpose, Engine as _};
use copypasta_ext::prelude::*;
#[cfg(target_os = "linux")]
use copypasta_ext::wayland_bin::WaylandBinClipboardContext;
use copypasta_ext::x11_bin::ClipboardContext as BinClipboardContext;
use copypasta_ext::x11_fork::ClipboardContext as ForkClipboardContext;
use crossterm::style::Print;
use std::{env, io};

pub enum CopyType {
Native,
OSC52,
}

pub fn copy_string_to_clipboard(content: String) -> Result<CopyType, ()> {
if ssh_clipboard(content.as_str()) {
Ok(CopyType::OSC52)
} else if wayland_clipboard(content.as_str()) || other_platform_clipboard(content.as_str()) {
Ok(CopyType::Native)
} else {
Err(())
}
}

fn ssh_clipboard(content: &str) -> bool {
env_var_set("SSH_CONNECTION")
// We do not use copypasta_ext::osc52 module because we have enabled terminal raw mode, so we print with crossterm utilities
// Check https://github.com/timvisee/rust-clipboard-ext/blob/371df19d2f961882a21c957f396d1e24548d1f28/src/osc52.rs#L92
&& crossterm::execute!(
io::stdout(),
Print(format!(
"\x1B]52;c;{}\x07",
general_purpose::STANDARD.encode(content)
))
)
.is_ok()
}
#[cfg(target_os = "linux")]
fn wayland_clipboard(content: &str) -> bool {
env_var_set("WAYLAND_DISPLAY")
&& WaylandBinClipboardContext::new()
.and_then(|mut ctx| ctx.set_contents(content.to_owned()))
.is_ok()
}

#[cfg(not(target_os = "linux"))]
fn wayland_clipboard(content: &str) -> bool {
false
}

fn other_platform_clipboard(content: &str) -> bool {
BinClipboardContext::new()
.and_then(|mut ctx| ctx.set_contents(content.to_owned()))
.is_ok()
|| ForkClipboardContext::new()
.and_then(|mut ctx| ctx.set_contents(content.to_owned()))
.is_ok()
}

fn env_var_set(env_var: &str) -> bool {
env::var(env_var)
.map(|v| !v.trim().is_empty())
.unwrap_or(false)
}
2 changes: 1 addition & 1 deletion src/interface/handler.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::clipboard::{copy_string_to_clipboard, CopyType};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};

use crate::interface::app::{App, AppResult};
use crate::interface::enums::Page::*;
use crate::otp::otp_type::OTPType;
use crate::utils::{copy_string_to_clipboard, CopyType};

use super::app::Popup;
use super::enums::Page;
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use zeroize::Zeroize;

mod args;
mod argument_functions;
mod clipboard;
mod crypto;
mod exporters;
mod importers;
Expand Down
44 changes: 0 additions & 44 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
use base64::{engine::general_purpose, Engine as _};
use copypasta_ext::prelude::*;
use copypasta_ext::x11_bin::ClipboardContext as BinClipboardContext;
use copypasta_ext::x11_fork::ClipboardContext as ForkClipboardContext;
use crossterm::style::Print;
use dirs::home_dir;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
use std::{env, io};

pub enum CopyType {
Native,
OSC52,
}

pub fn get_db_path() -> PathBuf {
match env::var("COTP_DB_PATH") {
Ok(value) => PathBuf::from(value),
Expand Down Expand Up @@ -89,37 +79,3 @@ pub fn verified_password(message: &str, minimum_length: usize) -> String {
return password;
}
}

fn in_ssh_shell() -> bool {
return !env::var("SSH_CONNECTION")
.unwrap_or_default()
.trim()
.is_empty();
}

pub fn copy_string_to_clipboard(content: String) -> Result<CopyType, ()> {
if in_ssh_shell()
&& crossterm::execute!(
io::stdout(),
Print(format!(
"\x1B]52;c;{}\x07",
general_purpose::STANDARD.encode(&content)
))
)
.is_ok()
{
// We do not use copypasta_ext::osc52 module because we have enabled terminal raw mode, so we print with crossterm utilities
// Check https://github.com/timvisee/rust-clipboard-ext/blob/371df19d2f961882a21c957f396d1e24548d1f28/src/osc52.rs#L92
Ok(CopyType::OSC52)
} else if BinClipboardContext::new()
.and_then(|mut ctx| ctx.set_contents(content.clone()))
.is_ok()
|| ForkClipboardContext::new()
.and_then(|mut ctx| ctx.set_contents(content))
.is_ok()
{
Ok(CopyType::Native)
} else {
Err(())
}
}

0 comments on commit 6228967

Please sign in to comment.