diff --git a/examples/helloworld.rs b/examples/helloworld.rs index 3847ba4..99b73e8 100644 --- a/examples/helloworld.rs +++ b/examples/helloworld.rs @@ -1,14 +1,20 @@ -use clipboard_rs::{Clipboard, ClipboardContext}; +use clipboard_rs::{Clipboard, ClipboardContext, ContentFormat}; fn main() { let ctx = ClipboardContext::new().unwrap(); let types = ctx.available_formats().unwrap(); println!("{:?}", types); + let has_rtf = ctx.has(ContentFormat::Rtf); + println!("has_rtf={}", has_rtf); + let rtf = ctx.get_rich_text().unwrap(); println!("rtf={}", rtf); + let has_html = ctx.has(ContentFormat::Html); + println!("has_html={}", has_html); + let html = ctx.get_html().unwrap(); println!("html={}", html); diff --git a/src/common.rs b/src/common.rs index 1604a3d..6ceb3b9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -5,6 +5,14 @@ use std::io::Cursor; pub type Result = std::result::Result>; pub type CallBack = Box; +pub enum ContentFormat<'a> { + Text, + Rtf, + Html, + Image, + Other(&'a str), +} + pub struct RustImageData { width: u32, height: u32, diff --git a/src/lib.rs b/src/lib.rs index 47ad29b..f9b0fb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ pub mod common; mod platform; -use common::{CallBack, Result, RustImageData}; +pub use common::{CallBack, ContentFormat, Result, RustImageData}; pub use image::imageops::FilterType; use platform::WatcherShutdown; pub use platform::{ClipboardContext, ClipboardWatcherContext}; @@ -9,6 +9,8 @@ pub trait Clipboard: Send { /// en: Get all formats of the current content in the clipboard fn available_formats(&self) -> Result>; + fn has(&self, format: ContentFormat) -> bool; + /// zh: 清空剪切板 /// en: clear clipboard fn clear(&self) -> Result<()>; diff --git a/src/platform/macos.rs b/src/platform/macos.rs index 7161858..7973399 100644 --- a/src/platform/macos.rs +++ b/src/platform/macos.rs @@ -1,5 +1,5 @@ use crate::common::{CallBack, Result, RustImage, RustImageData}; -use crate::{Clipboard, ClipboardWatcher}; +use crate::{Clipboard, ClipboardWatcher, ContentFormat}; use cocoa::appkit::{ NSPasteboard, NSPasteboardTypeHTML, NSPasteboardTypePNG, NSPasteboardTypeRTF, NSPasteboardTypeString, @@ -297,6 +297,37 @@ impl Clipboard for ClipboardContext { unsafe { self.clipboard.clearContents() }; Ok(()) } + + fn has(&self, format: ContentFormat) -> bool { + match format { + ContentFormat::Text => unsafe { + let types = NSArray::arrayWithObject(nil, NSPasteboardTypeString); + // https://developer.apple.com/documentation/appkit/nspasteboard/1526078-availabletypefromarray?language=objc + // The first pasteboard type in types that is available on the pasteboard, or nil if the receiver does not contain any of the types in types. + // self.clipboard.availableTypeFromArray(types) + self.clipboard.availableTypeFromArray(types) != nil + }, + ContentFormat::Rtf => unsafe { + let types = NSArray::arrayWithObject(nil, NSPasteboardTypeRTF); + self.clipboard.availableTypeFromArray(types) != nil + }, + ContentFormat::Html => unsafe { + // Currently only judge whether there is a public.html format + let types = NSArray::arrayWithObjects(nil, &[NSPasteboardTypeHTML]); + self.clipboard.availableTypeFromArray(types) != nil + }, + ContentFormat::Image => unsafe { + // Currently only judge whether there is a png format + let types = NSArray::arrayWithObjects(nil, &[NSPasteboardTypePNG]); + self.clipboard.availableTypeFromArray(types).is_null() + }, + ContentFormat::Other(format) => unsafe { + let types = + NSArray::arrayWithObjects(nil, &[NSString::alloc(nil).init_str(format)]); + self.clipboard.availableTypeFromArray(types).is_null() + }, + } + } } pub struct WatcherShutdown { diff --git a/src/platform/win.rs b/src/platform/win.rs index 4cd240c..e60e799 100644 --- a/src/platform/win.rs +++ b/src/platform/win.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::common::{CallBack, Result, RustImage, RustImageData}; -use crate::{Clipboard, ClipboardWatcher}; +use crate::{Clipboard, ClipboardWatcher, ContentFormat}; use clipboard_win::types::c_uint; use clipboard_win::{ formats, get_clipboard, raw, set_clipboard, Clipboard as ClipboardWin, SysResult, @@ -136,11 +136,12 @@ impl Clipboard for ClipboardContext { } fn get_buffer(&self, format: &str) -> Result> { - let format_uint = self.format_map.get(format); + let format_uint = clipboard_win::register_format(format); if format_uint.is_none() { - return Err("format not found".into()); + return Err("register format error".into()); } - let buffer = get_clipboard(formats::RawData(*format_uint.unwrap())); + let format_uint = format_uint.unwrap().get(); + let buffer = get_clipboard(formats::RawData(format_uint)); match buffer { Ok(data) => Ok(data), Err(_) => Err("get buffer error".into()), @@ -186,11 +187,12 @@ impl Clipboard for ClipboardContext { } fn set_buffer(&self, format: &str, buffer: Vec) -> Result<()> { - let format_uint = self.format_map.get(format); + let format_uint = clipboard_win::register_format(format); if format_uint.is_none() { - return Err("format not found".into()); + return Err("register format error".into()); } - let res = set_clipboard(formats::RawData(*format_uint.unwrap()), buffer); + let format_uint = format_uint.unwrap().get(); + let res = set_clipboard(formats::RawData(format_uint), buffer); if res.is_err() { return Err("set buffer error".into()); } @@ -230,6 +232,31 @@ impl Clipboard for ClipboardContext { } Ok(()) } + + fn has(&self, format: ContentFormat) -> bool { + match format { + ContentFormat::Text => clipboard_win::is_format_avail(formats::CF_UNICODETEXT), + ContentFormat::Rtf => { + let cf_rtf_uint = self.format_map.get(CF_RTF).unwrap(); + clipboard_win::is_format_avail(*cf_rtf_uint) + } + ContentFormat::Html => { + let cf_html_uint = self.format_map.get(CF_HTML).unwrap(); + clipboard_win::is_format_avail(*cf_html_uint) + } + ContentFormat::Image => { + let cf_png_uint = self.format_map.get(CF_PNG).unwrap(); + clipboard_win::is_format_avail(*cf_png_uint) + } + ContentFormat::Other(format) => { + let format_uint = clipboard_win::register_format(format); + if let Some(format_uint) = format_uint { + return clipboard_win::is_format_avail(format_uint.get()); + } + false + } + } + } } impl ClipboardWatcher for ClipboardWatcherContext { diff --git a/tests/string_test.rs b/tests/string_test.rs index 9183339..7eec33f 100644 --- a/tests/string_test.rs +++ b/tests/string_test.rs @@ -1,4 +1,4 @@ -use clipboard_rs::{Clipboard, ClipboardContext}; +use clipboard_rs::{Clipboard, ClipboardContext, ContentFormat}; #[test] fn test_string() { @@ -9,13 +9,16 @@ fn test_string() { let test_plain_txt = "hello world"; ctx.set_text(test_plain_txt.to_string()).unwrap(); + assert!(ctx.has(ContentFormat::Text)); assert_eq!(ctx.get_text().unwrap(), test_plain_txt); let test_rich_txt = "\x1b[1m\x1b[4m\x1b[31mHello, Rust!\x1b[0m"; ctx.set_rich_text(test_rich_txt.to_string()).unwrap(); + assert!(ctx.has(ContentFormat::Rtf)); assert_eq!(ctx.get_rich_text().unwrap(), test_rich_txt); let test_html = "

Hello, Rust!

"; ctx.set_html(test_html.to_string()).unwrap(); + assert!(ctx.has(ContentFormat::Html)); assert_eq!(ctx.get_html().unwrap(), test_html); }