Add experimental support for clipboard backend on linux.
This commit is contained in:
parent
0a651cc187
commit
30c127786d
|
@ -203,3 +203,11 @@ void delete_string(int32_t count) {
|
|||
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "BackSpace", 8000);
|
||||
}
|
||||
}
|
||||
|
||||
void trigger_paste() {
|
||||
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Control_L+v", 8000);
|
||||
}
|
||||
|
||||
void trigger_terminal_paste() {
|
||||
xdo_send_keysequence_window(xdo_context, CURRENTWINDOW, "Control_L+Shift+v", 8000);
|
||||
}
|
|
@ -42,4 +42,14 @@ extern "C" void send_string(const char * string);
|
|||
*/
|
||||
extern "C" void delete_string(int32_t count);
|
||||
|
||||
/*
|
||||
* Trigger normal paste ( Pressing CTRL+V )
|
||||
*/
|
||||
extern "C" void trigger_paste();
|
||||
|
||||
/*
|
||||
* Trigger terminal paste ( Pressing CTRL+SHIFT+V )
|
||||
*/
|
||||
extern "C" void trigger_terminal_paste();
|
||||
|
||||
#endif //ESPANSO_BRIDGE_H
|
||||
|
|
54
src/clipboard/linux.rs
Normal file
54
src/clipboard/linux.rs
Normal file
|
@ -0,0 +1,54 @@
|
|||
use std::process::{Command, ExitStatus, Stdio};
|
||||
use std::io::{Write, Read};
|
||||
|
||||
pub struct LinuxClipboardManager {
|
||||
|
||||
}
|
||||
|
||||
impl super::ClipboardManager for LinuxClipboardManager {
|
||||
fn initialize(&self) {
|
||||
// TODO: check if xclip is present and log an error otherwise.
|
||||
}
|
||||
|
||||
fn get_clipboard(&self) -> Option<String> {
|
||||
let res = Command::new("xclip")
|
||||
.args(&["-o", "-sel", "clip"])
|
||||
.output();
|
||||
|
||||
if let Ok(output) = res {
|
||||
if output.status.success() {
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
return Some((*s).to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn set_clipboard(&self, payload: &str) {
|
||||
let mut res = Command::new("xclip")
|
||||
.args(&["-sel", "clip"])
|
||||
.stdin(Stdio::piped())
|
||||
.spawn();
|
||||
|
||||
if let Ok(mut child) = res {
|
||||
let mut stdin = child.stdin.as_mut();
|
||||
|
||||
if let Some(mut output) = stdin {
|
||||
output.write_all(payload.as_bytes());
|
||||
|
||||
// let status = child.wait();
|
||||
//
|
||||
// if let Ok(status) = status {
|
||||
// if !status.success() {
|
||||
// //TODO: log error
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LinuxClipboardManager {
|
||||
|
||||
}
|
22
src/clipboard/mod.rs
Normal file
22
src/clipboard/mod.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
#[cfg(target_os = "windows")]
|
||||
mod windows;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod linux;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
mod macos;
|
||||
|
||||
pub trait ClipboardManager {
|
||||
fn initialize(&self);
|
||||
fn get_clipboard(&self) -> Option<String>;
|
||||
fn set_clipboard(&self, payload: &str);
|
||||
}
|
||||
|
||||
// LINUX IMPLEMENTATION
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn get_manager() -> impl ClipboardManager {
|
||||
let manager = linux::LinuxClipboardManager{};
|
||||
manager.initialize();
|
||||
manager
|
||||
}
|
|
@ -1,19 +1,22 @@
|
|||
use crate::matcher::{Match, MatchReceiver};
|
||||
use crate::keyboard::KeyboardSender;
|
||||
use crate::config::Configs;
|
||||
use crate::clipboard::ClipboardManager;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub struct Engine<S> where S: KeyboardSender {
|
||||
pub struct Engine<S, C> where S: KeyboardSender, C: ClipboardManager {
|
||||
sender: S,
|
||||
clipboard_manager: Arc<C>,
|
||||
configs: Configs,
|
||||
}
|
||||
|
||||
impl <S> Engine<S> where S: KeyboardSender{
|
||||
pub fn new(sender: S, configs: Configs) -> Engine<S> where S: KeyboardSender {
|
||||
Engine{sender, configs }
|
||||
impl <S, C> Engine<S, C> where S: KeyboardSender, C: ClipboardManager{
|
||||
pub fn new(sender: S, clipboard_manager: Arc<C>, configs: Configs) -> Engine<S, C> where S: KeyboardSender, C: ClipboardManager {
|
||||
Engine{sender, clipboard_manager, configs }
|
||||
}
|
||||
}
|
||||
|
||||
impl <S> MatchReceiver for Engine<S> where S: KeyboardSender{
|
||||
impl <S, C> MatchReceiver for Engine<S, C> where S: KeyboardSender, C: ClipboardManager{
|
||||
fn on_match(&self, m: &Match) {
|
||||
self.sender.delete_string(m.trigger.len() as i32);
|
||||
|
||||
|
@ -21,7 +24,9 @@ impl <S> MatchReceiver for Engine<S> where S: KeyboardSender{
|
|||
// while on windows and macos, we need to emulate a Enter key press.
|
||||
|
||||
if cfg!(target_os = "linux") {
|
||||
self.sender.send_string(m.replace.as_str());
|
||||
self.clipboard_manager.set_clipboard(m.replace.as_str());
|
||||
self.sender.trigger_paste();
|
||||
//self.sender.send_string(m.replace.as_str());
|
||||
}else{
|
||||
// To handle newlines, substitute each "\n" char with an Enter key press.
|
||||
let splits = m.replace.lines();
|
||||
|
|
|
@ -47,6 +47,12 @@ impl super::KeyboardSender for LinuxKeyboardSender {
|
|||
// On linux this is not needed, so NOOP
|
||||
}
|
||||
|
||||
fn trigger_paste(&self) {
|
||||
unsafe { trigger_paste(); }
|
||||
|
||||
// TODO: detect when in terminal and use trigger_terminal_paste() instead
|
||||
}
|
||||
|
||||
fn delete_string(&self, count: i32) {
|
||||
unsafe {delete_string(count)}
|
||||
}
|
||||
|
@ -94,4 +100,6 @@ extern {
|
|||
fn cleanup();
|
||||
fn send_string(string: *const c_char);
|
||||
fn delete_string(count: i32);
|
||||
fn trigger_paste();
|
||||
fn trigger_terminal_paste();
|
||||
}
|
|
@ -18,6 +18,7 @@ pub trait KeyboardInterceptor {
|
|||
pub trait KeyboardSender {
|
||||
fn send_string(&self, s: &str);
|
||||
fn send_enter(&self);
|
||||
fn trigger_paste(&self);
|
||||
fn delete_string(&self, count: i32);
|
||||
}
|
||||
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -1,10 +1,11 @@
|
|||
use std::sync::mpsc;
|
||||
use std::sync::{mpsc, Arc};
|
||||
use crate::keyboard::KeyboardInterceptor;
|
||||
use crate::matcher::Matcher;
|
||||
use crate::matcher::scrolling::ScrollingMatcher;
|
||||
use crate::engine::Engine;
|
||||
use crate::config::Configs;
|
||||
use crate::ui::UIManager;
|
||||
use crate::clipboard::ClipboardManager;
|
||||
use std::thread;
|
||||
use clap::{App, Arg};
|
||||
use std::path::Path;
|
||||
|
@ -14,6 +15,7 @@ mod matcher;
|
|||
mod engine;
|
||||
mod config;
|
||||
mod ui;
|
||||
mod clipboard;
|
||||
|
||||
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
|
@ -54,11 +56,16 @@ fn espanso_main(configs: Configs) {
|
|||
let ui_manager = ui::get_uimanager();
|
||||
ui_manager.notify("Hello guys");
|
||||
|
||||
let clipboard_manager = clipboard::get_manager();
|
||||
let clipboard_manager_arc = Arc::new(clipboard_manager);
|
||||
|
||||
let (txc, rxc) = mpsc::channel();
|
||||
|
||||
let sender = keyboard::get_sender();
|
||||
|
||||
let engine = Engine::new(sender, configs.clone());
|
||||
let engine = Engine::new(sender,
|
||||
Arc::clone(&clipboard_manager_arc),
|
||||
configs.clone());
|
||||
|
||||
thread::spawn(move || {
|
||||
let matcher = ScrollingMatcher::new(configs.clone(), engine);
|
||||
|
|
Loading…
Reference in New Issue
Block a user