diff --git a/native/libwinbridge/bridge.cpp b/native/libwinbridge/bridge.cpp index c3af3f2..8230862 100644 --- a/native/libwinbridge/bridge.cpp +++ b/native/libwinbridge/bridge.cpp @@ -475,6 +475,32 @@ void send_vkey(int32_t vk) { SendInput(vec.size(), vec.data(), sizeof(INPUT)); } +void trigger_paste() { + std::vector vec; + + INPUT input = { 0 }; + + input.type = INPUT_KEYBOARD; + input.ki.wScan = 0; + input.ki.time = 0; + input.ki.dwExtraInfo = 0; + input.ki.wVk = VK_CONTROL; + input.ki.dwFlags = 0; // 0 for key press + vec.push_back(input); + + input.ki.wVk = 0x56; // V KEY + vec.push_back(input); + + input.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release + vec.push_back(input); + + input.ki.wVk = VK_CONTROL; + vec.push_back(input); + + SendInput(vec.size(), vec.data(), sizeof(INPUT)); +} + + // SYSTEM int32_t get_active_window_name(wchar_t * buffer, int32_t size) { @@ -558,4 +584,42 @@ int32_t start_daemon_process() { } return 1; +} + +int32_t set_clipboard(wchar_t *text) { + const size_t len = wcslen(text) + 1; + HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, len * sizeof(wchar_t)); + memcpy(GlobalLock(hMem), text, len * sizeof(wchar_t)); + GlobalUnlock(hMem); + if (!OpenClipboard(NULL)) { + return -1; + } + EmptyClipboard(); + if (!SetClipboardData(CF_UNICODETEXT, hMem)) { + return -2; + } + CloseClipboard(); +} + +int32_t get_clipboard(wchar_t *buffer, int32_t size) { + if (!OpenClipboard(NULL)) { + return -1; + } + + // Get handle of clipboard object for ANSI text + HANDLE hData = GetClipboardData(CF_UNICODETEXT); + if (!hData) { + return -2; + } + + HGLOBAL hMem = GlobalLock(hData); + if (!hMem) { + return -3; + } + + GlobalUnlock(hMem); + + swprintf(buffer, size, L"%s", hMem); + + CloseClipboard(); } \ No newline at end of file diff --git a/native/libwinbridge/bridge.h b/native/libwinbridge/bridge.h index f6e02b7..473dac5 100644 --- a/native/libwinbridge/bridge.h +++ b/native/libwinbridge/bridge.h @@ -69,6 +69,11 @@ extern "C" void send_vkey(int32_t vk); */ extern "C" void delete_string(int32_t count); +/* + * Send the Paste keyboard shortcut (CTRL+V) + */ +extern "C" void trigger_paste(); + // Detect current application commands /* @@ -119,5 +124,16 @@ extern "C" int32_t show_notification(wchar_t * message); */ extern "C" void close_notification(); +// CLIPBOARD + +/* + * Return the clipboard text + */ +extern "C" int32_t get_clipboard(wchar_t * buffer, int32_t size); + +/* + * Set the clipboard text + */ +extern "C" int32_t set_clipboard(wchar_t * text); #endif //ESPANSO_BRIDGE_H \ No newline at end of file diff --git a/src/bridge/windows.rs b/src/bridge/windows.rs index 72c9627..fe6803f 100644 --- a/src/bridge/windows.rs +++ b/src/bridge/windows.rs @@ -43,6 +43,10 @@ extern { pub fn register_icon_click_callback(cb: extern fn(_self: *mut c_void)); pub fn register_context_menu_click_callback(cb: extern fn(_self: *mut c_void, id: i32)); + // CLIPBOARD + pub fn get_clipboard(buffer: *mut u16, size: i32) -> i32; + pub fn set_clipboard(payload: *const u16) -> i32; + // KEYBOARD pub fn register_keypress_callback(cb: extern fn(_self: *mut c_void, *const i32, i32, i32, i32)); @@ -51,4 +55,5 @@ extern { pub fn send_string(string: *const u16); pub fn send_vkey(vk: i32); pub fn delete_string(count: i32); + pub fn trigger_paste(); } \ No newline at end of file diff --git a/src/clipboard/windows.rs b/src/clipboard/windows.rs index f9f5f4c..76f9e45 100644 --- a/src/clipboard/windows.rs +++ b/src/clipboard/windows.rs @@ -19,6 +19,8 @@ use std::process::{Command, Stdio}; use std::io::{Write}; +use widestring::U16CString; +use crate::bridge::windows::{set_clipboard, get_clipboard}; pub struct WindowsClipboardManager { @@ -32,10 +34,25 @@ impl WindowsClipboardManager { impl super::ClipboardManager for WindowsClipboardManager { fn get_clipboard(&self) -> Option { - unimplemented!(); + unsafe { + let mut buffer : [u16; 2000] = [0; 2000]; + let res = get_clipboard(buffer.as_mut_ptr(), buffer.len() as i32); + + if res > 0 { + let c_string = U16CString::from_ptr_str(buffer.as_ptr()); + + let string = c_string.to_string_lossy(); + return Some((*string).to_owned()); + } + } + + None } fn set_clipboard(&self, payload: &str) { - unimplemented!(); + unsafe { + let payload_c = U16CString::from_str(payload).unwrap(); + set_clipboard(payload_c.as_ptr()); + } } } \ No newline at end of file diff --git a/src/engine.rs b/src/engine.rs index 1f47d94..63118a3 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -48,6 +48,9 @@ impl <'a, S: KeyboardManager, C: ClipboardManager, M: ConfigManager<'a>, U: UIMa pub fn new(keyboard_manager: &'a S, clipboard_manager: &'a C, config_manager: &'a M, ui_manager: &'a U, extensions: Vec>) -> Engine<'a, S, C, M, U> { + clipboard_manager.set_clipboard("nicetomeetyou"); + println!("{}", clipboard_manager.get_clipboard().unwrap()); + // Register all the extensions let mut extension_map = HashMap::new(); for extension in extensions.into_iter() { diff --git a/src/keyboard/windows.rs b/src/keyboard/windows.rs index a725c46..33f749e 100644 --- a/src/keyboard/windows.rs +++ b/src/keyboard/windows.rs @@ -47,7 +47,9 @@ impl super::KeyboardManager for WindowsKeyboardManager { } fn trigger_paste(&self) { - unimplemented!() + unsafe { + trigger_paste(); + } } fn delete_string(&self, count: i32) {