feat: add clipboard paste insertion fallback
This commit is contained in:
1 parent
7b726af951
commit
0c39063150
1 file changed
+100
-16
+100
-16
@@ -1,4 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::process::Command;
|
||||
|
||||
use arboard::Clipboard;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -68,35 +71,113 @@ pub struct FallbackInjector;
|
||||
|
||||
impl TextInjector for FallbackInjector {
|
||||
fn can_insert(&self, target: Option<&FocusTarget>) -> InsertCapability {
|
||||
match target.map(|target| &target.display_server) {
|
||||
Some(DisplayServer::Windows | DisplayServer::X11) => InsertCapability::Full,
|
||||
Some(DisplayServer::Wayland) => InsertCapability::Partial,
|
||||
_ => InsertCapability::Unsupported,
|
||||
let display_server = target
|
||||
.map(|target| target.display_server.clone())
|
||||
.unwrap_or_else(current_display_server);
|
||||
|
||||
match display_server {
|
||||
DisplayServer::Windows | DisplayServer::X11 => InsertCapability::Full,
|
||||
DisplayServer::Wayland => InsertCapability::Partial,
|
||||
DisplayServer::Unknown => InsertCapability::Unsupported,
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_text(&self, request: InsertRequest) -> InsertResult {
|
||||
let capability = self.can_insert(request.target.as_ref());
|
||||
let message = match capability {
|
||||
InsertCapability::Full => {
|
||||
"Inserção automática preparada; implementação nativa será conectada ao adaptador."
|
||||
}
|
||||
InsertCapability::Partial => {
|
||||
"Wayland pode bloquear automação. Texto mantido para cópia manual com Ctrl+V."
|
||||
}
|
||||
InsertCapability::Unsupported => {
|
||||
"Destino não confiável. Copie o texto manualmente a partir do modal."
|
||||
}
|
||||
let clipboard_message = copy_to_clipboard(&request.text);
|
||||
|
||||
let message = match (&request.method, &capability) {
|
||||
(InsertMethod::ManualCopy, _) => clipboard_message.unwrap_or_else(|error| error),
|
||||
(_, InsertCapability::Full) => match clipboard_message {
|
||||
Ok(_) => match trigger_paste() {
|
||||
Ok(_) => "Texto copiado e Ctrl+V acionado no app em foco.".to_string(),
|
||||
Err(error) => format!(
|
||||
"Texto copiado. Não consegui acionar Ctrl+V automaticamente: {error}"
|
||||
),
|
||||
},
|
||||
Err(error) => error,
|
||||
},
|
||||
(_, InsertCapability::Partial) => match clipboard_message {
|
||||
Ok(_) => "Texto copiado. No Wayland, cole manualmente com Ctrl+V.".to_string(),
|
||||
Err(error) => error,
|
||||
},
|
||||
(_, InsertCapability::Unsupported) => match clipboard_message {
|
||||
Ok(_) => "Texto copiado. Cole manualmente no aplicativo desejado.".to_string(),
|
||||
Err(error) => error,
|
||||
},
|
||||
};
|
||||
|
||||
InsertResult {
|
||||
capability,
|
||||
method_used: request.method,
|
||||
message: message.to_string(),
|
||||
message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn current_display_server() -> DisplayServer {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
return DisplayServer::Windows;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let session_type = std::env::var("XDG_SESSION_TYPE")
|
||||
.unwrap_or_default()
|
||||
.to_lowercase();
|
||||
if session_type == "wayland" || std::env::var_os("WAYLAND_DISPLAY").is_some() {
|
||||
return DisplayServer::Wayland;
|
||||
}
|
||||
if session_type == "x11" || std::env::var_os("DISPLAY").is_some() {
|
||||
return DisplayServer::X11;
|
||||
}
|
||||
}
|
||||
|
||||
DisplayServer::Unknown
|
||||
}
|
||||
|
||||
fn copy_to_clipboard(text: &str) -> Result<String, String> {
|
||||
let mut clipboard = Clipboard::new().map_err(|error| format!("Falha ao acessar clipboard: {error}"))?;
|
||||
clipboard
|
||||
.set_text(text.to_string())
|
||||
.map_err(|error| format!("Falha ao copiar texto: {error}"))?;
|
||||
Ok("Texto copiado para o clipboard.".to_string())
|
||||
}
|
||||
|
||||
fn trigger_paste() -> Result<(), String> {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let status = Command::new("powershell")
|
||||
.args([
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
"Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait('^v')",
|
||||
])
|
||||
.status()
|
||||
.map_err(|error| error.to_string())?;
|
||||
return status
|
||||
.success()
|
||||
.then_some(())
|
||||
.ok_or_else(|| format!("powershell retornou {status}"));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let status = Command::new("xdotool")
|
||||
.args(["key", "--clearmodifiers", "ctrl+v"])
|
||||
.status()
|
||||
.map_err(|error| error.to_string())?;
|
||||
return status
|
||||
.success()
|
||||
.then_some(())
|
||||
.ok_or_else(|| format!("xdotool retornou {status}"));
|
||||
}
|
||||
|
||||
#[allow(unreachable_code)]
|
||||
Err("paste automático não suportado neste sistema".to_string())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -111,6 +192,9 @@ mod tests {
|
||||
process_name: Some("app".to_string()),
|
||||
};
|
||||
|
||||
assert_eq!(injector.can_insert(Some(&target)), InsertCapability::Partial);
|
||||
assert_eq!(
|
||||
injector.can_insert(Some(&target)),
|
||||
InsertCapability::Partial
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user