1 #![cfg(windows)]
2 //! This crate provide simple means to operate with Windows clipboard.
3 //!
4 //!# Note keeping Clipboard around:
5 //!
6 //! In Windows [Clipboard](struct.Clipboard.html) opens globally and only one application can set data onto format at the time.
7 //!
8 //! Therefore as soon as operations are finished, user is advised to close [Clipboard](struct.Clipboard.html).
9 //!
10 //!# Features
11 //!
12 //! - `std` - Enables usage of `std`, including `std::error::Error` trait.
13 //!
14 //!# Clipboard
15 //!
16 //! All read and write access to Windows clipboard requires user to open it.
17 //!
18 //!# Usage
19 //!
20 //!## Getter
21 //!
22 //! Library provides various extractors from clipboard to particular format using [Getter](trait.Getter.html):
23 //!
24 //! - [RawData](formats/struct.RawData.html) - Reads raw bytes from specified format.
25 //! - [Unicode](formats/struct.Unicode.html) - Reads unicode string from clipboard.
26 //! - [Bitmap](formats/struct.Bitmap.html) - Reads RGB data of image on clipboard.
27 //! - [FileList](formats/struct.FileList.html) - Reads list of files from clipboard.
28 //!
29 //! Depending on format, getter can extract data into various data types.
30 //!
31 //!## Setter
32 //!
33 //! Library provides various setters onto clipboard by using [Setter](trait.Setter.html):
34 //!
35 //! - [RawData](formats/struct.RawData.html) - Writes raw bytes onto specified format.
36 //! - [Unicode](formats/struct.Unicode.html) - Writes unicode string onto clipboard.
37 //! - [Bitmap](formats/struct.Bitmap.html) - Writes RGB data of image on clipboard.
38 //!
39 //! Default setters are generic over type allowing anything that can be referenced as byte slice or
40 //! `str`
41 //!
42 //!## Manually lock clipboard
43 //!
44 //!```
45 //!use clipboard_win::{Clipboard, formats, Getter, Setter};
46 //!
47 //!const SAMPLE: &str = "MY loli sample ^^";
48 //!
49 //!let _clip = Clipboard::new_attempts(10).expect("Open clipboard");
50 //!formats::Unicode.write_clipboard(&SAMPLE).expect("Write sample");
51 //!
52 //!let mut output = String::new();
53 //!
54 //!assert_eq!(formats::Unicode.read_clipboard(&mut output).expect("Read sample"), SAMPLE.len());
55 //!assert_eq!(output, SAMPLE);
56 //!
57 //!//Efficiently re-use buffer ;)
58 //!output.clear();
59 //!assert_eq!(formats::Unicode.read_clipboard(&mut output).expect("Read sample"), SAMPLE.len());
60 //!assert_eq!(output, SAMPLE);
61 //!
62 //!//Or take the same string twice?
63 //!assert_eq!(formats::Unicode.read_clipboard(&mut output).expect("Read sample"), SAMPLE.len());
64 //!assert_eq!(format!("{0}{0}", SAMPLE), output);
65 //!
66 //!```
67 //!
68 //!## Simplified API
69 //!
70 //!```
71 //!use clipboard_win::{formats, get_clipboard, set_clipboard};
72 //!
73 //!let text = "my sample ><";
74 //!
75 //!set_clipboard(formats::Unicode, text).expect("To set clipboard");
76 //!//Type is necessary as string can be stored in various storages
77 //!let result: String = get_clipboard(formats::Unicode).expect("To set clipboard");
78 //!assert_eq!(result, text)
79 //!```
80 
81 #![no_std]
82 #![warn(missing_docs)]
83 #![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
84 
85 extern crate alloc;
86 
87 pub mod formats;
88 pub mod raw;
89 pub(crate) mod utils;
90 
91 pub use raw::{get_owner, empty, seq_num, size, is_format_avail, register_format, count_formats, EnumFormats};
92 pub use formats::Unicode;
93 
94 ///Alias to result used by this crate
95 pub type SysResult<T> = Result<T, error_code::SystemError>;
96 
97 ///Clipboard instance, which allows to perform clipboard ops.
98 ///
99 ///# Note:
100 ///
101 ///You can have only one such instance across your program.
102 ///
103 ///# Warning:
104 ///
105 ///In Windows Clipboard opens globally and only one application can set data
106 ///onto format at the time.
107 ///
108 ///Therefore as soon as operations are finished, user is advised to close Clipboard.
109 pub struct Clipboard {
110     _dummy: ()
111 }
112 
113 impl Clipboard {
114     #[inline(always)]
115     ///Attempts to open clipboard, returning clipboard instance on success.
new() -> SysResult<Self>116     pub fn new() -> SysResult<Self> {
117         raw::open().map(|_| Self { _dummy: () })
118     }
119 
120     #[inline(always)]
121     ///Attempts to open clipboard, associating it with specified `owner` and returning clipboard instance on success.
new_for(owner: winapi::shared::windef::HWND) -> SysResult<Self>122     pub fn new_for(owner: winapi::shared::windef::HWND) -> SysResult<Self> {
123         raw::open_for(owner).map(|_| Self { _dummy: () })
124     }
125 
126     #[inline(always)]
127     ///Attempts to open clipboard, giving it `num` retries in case of failure.
new_attempts(num: usize) -> SysResult<Self>128     pub fn new_attempts(num: usize) -> SysResult<Self> {
129         Self::new_attempts_for(core::ptr::null_mut(), num)
130     }
131 
132     #[inline]
133     ///Attempts to open clipboard, giving it `num` retries in case of failure.
new_attempts_for(owner: winapi::shared::windef::HWND, mut num: usize) -> SysResult<Self>134     pub fn new_attempts_for(owner: winapi::shared::windef::HWND, mut num: usize) -> SysResult<Self> {
135         loop {
136             match Self::new_for(owner) {
137                 Ok(this) => break Ok(this),
138                 Err(err) => match num {
139                     0 => break Err(err),
140                     _ => num -= 1,
141                 }
142             }
143 
144             //0 causes to yield remaining time in scheduler, but remain to be scheduled once again.
145             unsafe { winapi::um::synchapi::Sleep(0) };
146         }
147     }
148 }
149 
150 impl Drop for Clipboard {
drop(&mut self)151     fn drop(&mut self) {
152         let _ = raw::close();
153     }
154 }
155 
156 ///Describes format getter, specifying data type as type param
157 ///
158 ///Default implementations only perform write, without opening/closing clipboard
159 pub trait Getter<Type> {
160     ///Reads content of clipboard into `out`, returning number of bytes read on success, or otherwise 0.
read_clipboard(&self, out: &mut Type) -> SysResult<usize>161     fn read_clipboard(&self, out: &mut Type) -> SysResult<usize>;
162 }
163 
164 ///Describes format setter, specifying data type as type param
165 ///
166 ///Default implementations only perform write, without opening/closing clipboard
167 pub trait Setter<Type> {
168     ///Writes content of `data` onto clipboard, returning whether it was successful or not
write_clipboard(&self, data: &Type) -> SysResult<()>169     fn write_clipboard(&self, data: &Type) -> SysResult<()>;
170 }
171 
172 #[inline(always)]
173 ///Runs provided callable with open clipboard, returning whether clipboard was open successfully.
174 ///
175 ///If clipboard fails to open, callable is not invoked.
with_clipboard<F: FnMut()>(mut cb: F) -> SysResult<()>176 pub fn with_clipboard<F: FnMut()>(mut cb: F) -> SysResult<()> {
177     let _clip = Clipboard::new()?;
178     cb();
179     Ok(())
180 }
181 
182 #[inline(always)]
183 ///Runs provided callable with open clipboard, returning whether clipboard was open successfully.
184 ///
185 ///If clipboard fails to open, attempts `num` number of retries before giving up.
186 ///In which case closure is not called
with_clipboard_attempts<F: FnMut()>(num: usize, mut cb: F) -> SysResult<()>187 pub fn with_clipboard_attempts<F: FnMut()>(num: usize, mut cb: F) -> SysResult<()> {
188     let _clip = Clipboard::new_attempts(num)?;
189     cb();
190     Ok(())
191 }
192 
193 #[inline(always)]
194 ///Retrieve data from clipboard.
get<R: Default, T: Getter<R>>(format: T) -> SysResult<R>195 pub fn get<R: Default, T: Getter<R>>(format: T) -> SysResult<R> {
196     let mut result = R::default();
197     format.read_clipboard(&mut result).map(|_| result)
198 }
199 
200 #[inline(always)]
201 ///Shortcut to retrieve data from clipboard.
202 ///
203 ///It opens clipboard and gets output, if possible.
get_clipboard<R: Default, T: Getter<R>>(format: T) -> SysResult<R>204 pub fn get_clipboard<R: Default, T: Getter<R>>(format: T) -> SysResult<R> {
205     let _clip = Clipboard::new_attempts(10)?;
206     get(format)
207 }
208 
209 #[inline(always)]
210 ///Set data onto clipboard.
set<R, T: Setter<R>>(format: T, data: R) -> SysResult<()>211 pub fn set<R, T: Setter<R>>(format: T, data: R) -> SysResult<()> {
212     format.write_clipboard(&data)
213 }
214 
215 #[inline(always)]
216 ///Shortcut to set data onto clipboard.
217 ///
218 ///It opens clipboard and attempts to set data.
set_clipboard<R, T: Setter<R>>(format: T, data: R) -> SysResult<()>219 pub fn set_clipboard<R, T: Setter<R>>(format: T, data: R) -> SysResult<()> {
220     let _clip = Clipboard::new_attempts(10)?;
221     set(format, data)
222 }
223 
224 ///Shortcut to retrieve string from clipboard.
225 ///
226 ///It opens clipboard and gets string, if possible.
227 #[inline(always)]
get_clipboard_string() -> SysResult<alloc::string::String>228 pub fn get_clipboard_string() -> SysResult<alloc::string::String> {
229     get_clipboard(Unicode)
230 }
231 
232 ///Shortcut to set string onto clipboard.
233 ///
234 ///It opens clipboard and attempts to set string.
235 #[inline(always)]
set_clipboard_string(data: &str) -> SysResult<()>236 pub fn set_clipboard_string(data: &str) -> SysResult<()> {
237     set_clipboard(Unicode, data)
238 }
239