Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 77 additions & 4 deletions src-tauri/src/clipboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fn paste_via_clipboard(
#[cfg(target_os = "linux")]
fn try_send_key_combo_linux(paste_method: &PasteMethod) -> Result<bool, String> {
if is_wayland() {
// Wayland: prefer wtype, then dotool
// Wayland: prefer wtype, then dotool, then ydotool
if is_wtype_available() {
info!("Using wtype for key combo");
send_key_combo_via_wtype(paste_method)?;
Expand All @@ -70,13 +70,23 @@ fn try_send_key_combo_linux(paste_method: &PasteMethod) -> Result<bool, String>
send_key_combo_via_dotool(paste_method)?;
return Ok(true);
}
if is_ydotool_available() {
info!("Using ydotool for key combo");
send_key_combo_via_ydotool(paste_method)?;
return Ok(true);
}
} else {
// X11: prefer xdotool
// X11: prefer xdotool, then ydotool
if is_xdotool_available() {
info!("Using xdotool for key combo");
send_key_combo_via_xdotool(paste_method)?;
return Ok(true);
}
if is_ydotool_available() {
info!("Using ydotool for key combo");
send_key_combo_via_ydotool(paste_method)?;
return Ok(true);
}
}

Ok(false)
Expand All @@ -87,7 +97,7 @@ fn try_send_key_combo_linux(paste_method: &PasteMethod) -> Result<bool, String>
#[cfg(target_os = "linux")]
fn try_direct_typing_linux(text: &str) -> Result<bool, String> {
if is_wayland() {
// Wayland: prefer wtype, then dotool
// Wayland: prefer wtype, then dotool, then ydotool
if is_wtype_available() {
info!("Using wtype for direct text input");
type_text_via_wtype(text)?;
Expand All @@ -98,13 +108,23 @@ fn try_direct_typing_linux(text: &str) -> Result<bool, String> {
type_text_via_dotool(text)?;
return Ok(true);
}
if is_ydotool_available() {
info!("Using ydotool for direct text input");
type_text_via_ydotool(text)?;
return Ok(true);
}
} else {
// X11: prefer xdotool
// X11: prefer xdotool, then ydotool
if is_xdotool_available() {
info!("Using xdotool for direct text input");
type_text_via_xdotool(text)?;
return Ok(true);
}
if is_ydotool_available() {
info!("Using ydotool for direct text input");
type_text_via_ydotool(text)?;
return Ok(true);
}
}

Ok(false)
Expand All @@ -130,6 +150,16 @@ fn is_dotool_available() -> bool {
.unwrap_or(false)
}

/// Check if ydotool is available (uinput-based, works on both Wayland and X11)
#[cfg(target_os = "linux")]
fn is_ydotool_available() -> bool {
Command::new("which")
.arg("ydotool")
.output()
.map(|output| output.status.success())
.unwrap_or(false)
}

#[cfg(target_os = "linux")]
fn is_xdotool_available() -> bool {
Command::new("which")
Expand Down Expand Up @@ -204,6 +234,24 @@ fn type_text_via_dotool(text: &str) -> Result<(), String> {
Ok(())
}

/// Type text directly via ydotool (uinput-based, requires ydotoold daemon).
#[cfg(target_os = "linux")]
fn type_text_via_ydotool(text: &str) -> Result<(), String> {
let output = Command::new("ydotool")
.arg("type")
.arg("--")
.arg(text)
.output()
.map_err(|e| format!("Failed to execute ydotool: {}", e))?;

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(format!("ydotool failed: {}", stderr));
}

Ok(())
}

/// Send a key combination (e.g., Ctrl+V) via wtype on Wayland.
#[cfg(target_os = "linux")]
fn send_key_combo_via_wtype(paste_method: &PasteMethod) -> Result<(), String> {
Expand Down Expand Up @@ -250,6 +298,31 @@ fn send_key_combo_via_dotool(paste_method: &PasteMethod) -> Result<(), String> {
Ok(())
}

/// Send a key combination (e.g., Ctrl+V) via ydotool (requires ydotoold daemon).
#[cfg(target_os = "linux")]
fn send_key_combo_via_ydotool(paste_method: &PasteMethod) -> Result<(), String> {
// ydotool uses Linux input event keycodes with format <keycode>:<pressed>
// where pressed is 1 for down, 0 for up. Keycodes: ctrl=29, shift=42, v=47, insert=110
let args: Vec<&str> = match paste_method {
PasteMethod::CtrlV => vec!["key", "29:1", "47:1", "47:0", "29:0"],
PasteMethod::ShiftInsert => vec!["key", "42:1", "110:1", "110:0", "42:0"],
PasteMethod::CtrlShiftV => vec!["key", "29:1", "42:1", "47:1", "47:0", "42:0", "29:0"],
_ => return Err("Unsupported paste method".into()),
};

let output = Command::new("ydotool")
.args(&args)
.output()
.map_err(|e| format!("Failed to execute ydotool: {}", e))?;

if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(format!("ydotool failed: {}", stderr));
}

Ok(())
}

/// Send a key combination (e.g., Ctrl+V) via xdotool on X11.
#[cfg(target_os = "linux")]
fn send_key_combo_via_xdotool(paste_method: &PasteMethod) -> Result<(), String> {
Expand Down