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