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 pub use error_code::SystemError;
95 ///Alias to result used by this crate
96 pub type SysResult<T> = Result<T, error_code::SystemError>;
97 
98 ///Clipboard instance, which allows to perform clipboard ops.
99 ///
100 ///# Note:
101 ///
102 ///You can have only one such instance across your program.
103 ///
104 ///# Warning:
105 ///
106 ///In Windows Clipboard opens globally and only one application can set data
107 ///onto format at the time.
108 ///
109 ///Therefore as soon as operations are finished, user is advised to close Clipboard.
110 pub struct Clipboard {
111     _dummy: ()
112 }
113 
114 impl Clipboard {
115     #[inline(always)]
116     ///Attempts to open clipboard, returning clipboard instance on success.
new() -> SysResult<Self>117     pub fn new() -> SysResult<Self> {
118         raw::open().map(|_| Self { _dummy: () })
119     }
120 
121     #[inline(always)]
122     ///Attempts to open clipboard, associating it with specified `owner` and returning clipboard instance on success.
new_for(owner: winapi::shared::windef::HWND) -> SysResult<Self>123     pub fn new_for(owner: winapi::shared::windef::HWND) -> SysResult<Self> {
124         raw::open_for(owner).map(|_| Self { _dummy: () })
125     }
126 
127     #[inline(always)]
128     ///Attempts to open clipboard, giving it `num` retries in case of failure.
new_attempts(num: usize) -> SysResult<Self>129     pub fn new_attempts(num: usize) -> SysResult<Self> {
130         Self::new_attempts_for(core::ptr::null_mut(), num)
131     }
132 
133     #[inline]
134     ///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>135     pub fn new_attempts_for(owner: winapi::shared::windef::HWND, mut num: usize) -> SysResult<Self> {
136         loop {
137             match Self::new_for(owner) {
138                 Ok(this) => break Ok(this),
139                 Err(err) => match num {
140                     0 => break Err(err),
141                     _ => num -= 1,
142                 }
143             }
144 
145             //0 causes to yield remaining time in scheduler, but remain to be scheduled once again.
146             unsafe { winapi::um::synchapi::Sleep(0) };
147         }
148     }
149 }
150 
151 impl Drop for Clipboard {
drop(&mut self)152     fn drop(&mut self) {
153         let _ = raw::close();
154     }
155 }
156 
157 ///Describes format getter, specifying data type as type param
158 ///
159 ///Default implementations only perform write, without opening/closing clipboard
160 pub trait Getter<Type> {
161     ///Reads content of clipboard into `out`, returning number of bytes read on success, or otherwise 0.
read_clipboard(&self, out: &mut Type) -> SysResult<usize>162     fn read_clipboard(&self, out: &mut Type) -> SysResult<usize>;
163 }
164 
165 ///Describes format setter, specifying data type as type param
166 ///
167 ///Default implementations only perform write, without opening/closing clipboard
168 pub trait Setter<Type> {
169     ///Writes content of `data` onto clipboard, returning whether it was successful or not
write_clipboard(&self, data: &Type) -> SysResult<()>170     fn write_clipboard(&self, data: &Type) -> SysResult<()>;
171 }
172 
173 #[inline(always)]
174 ///Runs provided callable with open clipboard, returning whether clipboard was open successfully.
175 ///
176 ///If clipboard fails to open, callable is not invoked.
with_clipboard<F: FnMut()>(mut cb: F) -> SysResult<()>177 pub fn with_clipboard<F: FnMut()>(mut cb: F) -> SysResult<()> {
178     let _clip = Clipboard::new()?;
179     cb();
180     Ok(())
181 }
182 
183 #[inline(always)]
184 ///Runs provided callable with open clipboard, returning whether clipboard was open successfully.
185 ///
186 ///If clipboard fails to open, attempts `num` number of retries before giving up.
187 ///In which case closure is not called
with_clipboard_attempts<F: FnMut()>(num: usize, mut cb: F) -> SysResult<()>188 pub fn with_clipboard_attempts<F: FnMut()>(num: usize, mut cb: F) -> SysResult<()> {
189     let _clip = Clipboard::new_attempts(num)?;
190     cb();
191     Ok(())
192 }
193 
194 #[inline(always)]
195 ///Retrieve data from clipboard.
get<R: Default, T: Getter<R>>(format: T) -> SysResult<R>196 pub fn get<R: Default, T: Getter<R>>(format: T) -> SysResult<R> {
197     let mut result = R::default();
198     format.read_clipboard(&mut result).map(|_| result)
199 }
200 
201 #[inline(always)]
202 ///Shortcut to retrieve data from clipboard.
203 ///
204 ///It opens clipboard and gets output, if possible.
get_clipboard<R: Default, T: Getter<R>>(format: T) -> SysResult<R>205 pub fn get_clipboard<R: Default, T: Getter<R>>(format: T) -> SysResult<R> {
206     let _clip = Clipboard::new_attempts(10)?;
207     get(format)
208 }
209 
210 #[inline(always)]
211 ///Set data onto clipboard.
set<R, T: Setter<R>>(format: T, data: R) -> SysResult<()>212 pub fn set<R, T: Setter<R>>(format: T, data: R) -> SysResult<()> {
213     format.write_clipboard(&data)
214 }
215 
216 #[inline(always)]
217 ///Shortcut to set data onto clipboard.
218 ///
219 ///It opens clipboard and attempts to set data.
set_clipboard<R, T: Setter<R>>(format: T, data: R) -> SysResult<()>220 pub fn set_clipboard<R, T: Setter<R>>(format: T, data: R) -> SysResult<()> {
221     let _clip = Clipboard::new_attempts(10)?;
222     set(format, data)
223 }
224 
225 ///Shortcut to retrieve string from clipboard.
226 ///
227 ///It opens clipboard and gets string, if possible.
228 #[inline(always)]
get_clipboard_string() -> SysResult<alloc::string::String>229 pub fn get_clipboard_string() -> SysResult<alloc::string::String> {
230     get_clipboard(Unicode)
231 }
232 
233 ///Shortcut to set string onto clipboard.
234 ///
235 ///It opens clipboard and attempts to set string.
236 #[inline(always)]
set_clipboard_string(data: &str) -> SysResult<()>237 pub fn set_clipboard_string(data: &str) -> SysResult<()> {
238     set_clipboard(Unicode, data)
239 }
240