#[cfg(windows)]
use std::thread;
#[cfg(windows)]
use std::time::Duration;
#[cfg(windows)]
use windows_sys::Win32::Foundation::GlobalFree;
#[cfg(windows)]
use windows_sys::Win32::System::DataExchange::{
CloseClipboard, EmptyClipboard, GetClipboardData, OpenClipboard, SetClipboardData,
};
#[cfg(windows)]
use windows_sys::Win32::System::Memory::{
GlobalAlloc, GlobalLock, GlobalSize, GlobalUnlock, GMEM_MOVEABLE,
};
#[cfg(windows)]
pub fn copy_to_system_clipboard(text: &str) {
const CF_UNICODETEXT: u32 = 13;
let mut utf16: Vec<u16> = text.encode_utf16().collect();
utf16.push(0); let size_bytes = utf16.len() * std::mem::size_of::<u16>();
let hmem = unsafe { GlobalAlloc(GMEM_MOVEABLE, size_bytes) };
if hmem.is_null() {
return;
}
unsafe {
let dst = GlobalLock(hmem) as *mut u16;
if dst.is_null() {
let _ = GlobalFree(hmem);
return;
}
std::ptr::copy_nonoverlapping(utf16.as_ptr(), dst, utf16.len());
GlobalUnlock(hmem);
}
let mut transferred = false;
for _ in 0..5 {
let opened = unsafe { OpenClipboard(std::ptr::null_mut()) };
if opened == 0 {
thread::sleep(Duration::from_millis(2));
continue;
}
unsafe {
if EmptyClipboard() != 0
&& !SetClipboardData(CF_UNICODETEXT, hmem).is_null()
{
transferred = true;
}
let _ = CloseClipboard();
}
break;
}
if !transferred {
unsafe {
let _ = GlobalFree(hmem);
}
}
}
#[cfg(not(windows))]
pub fn copy_to_system_clipboard(_text: &str) {}
#[cfg(windows)]
pub fn read_from_system_clipboard() -> Option<String> {
const CF_UNICODETEXT: u32 = 13;
for _ in 0..5 {
let opened = unsafe { OpenClipboard(std::ptr::null_mut()) };
if opened == 0 {
thread::sleep(Duration::from_millis(2));
continue;
}
let result = unsafe {
let hmem = GetClipboardData(CF_UNICODETEXT);
let ptr = if !hmem.is_null() {
GlobalLock(hmem) as *const u16
} else {
std::ptr::null()
};
let text = if !ptr.is_null() {
let alloc_bytes = GlobalSize(hmem) as usize;
let max_u16s =
(alloc_bytes / std::mem::size_of::<u16>()).min(1_000_000);
let found = (0..max_u16s).position(|i| *ptr.add(i) == 0).map(|len| {
let slice = std::slice::from_raw_parts(ptr, len);
String::from_utf16_lossy(slice).replace("\r\n", "\n")
});
GlobalUnlock(hmem);
found
} else {
None
};
let _ = CloseClipboard();
text
};
return result;
}
None
}
#[cfg(not(windows))]
pub fn read_from_system_clipboard() -> Option<String> { None }