#![cfg(windows)]
use std::io;
use windows_win::{
raw,
Window,
Messages
};
use winapi::um::winuser::{
AddClipboardFormatListener,
RemoveClipboardFormatListener
};
pub trait ClipboardHandler {
fn on_clipboard_change(&mut self) -> CallbackResult;
fn on_clipboard_error(&mut self, error: io::Error) -> CallbackResult {
CallbackResult::StopWithError(error)
}
}
pub enum CallbackResult {
Next,
Stop,
StopWithError(io::Error)
}
pub struct Master<H> {
handler: H
}
pub struct ClipboardListener(winapi::shared::windef::HWND);
impl ClipboardListener {
#[inline]
pub fn new(window: &Window) -> io::Result<Self> {
let window = window.inner();
unsafe {
if AddClipboardFormatListener(window) != 1 {
Err(io::Error::last_os_error())
} else {
Ok(ClipboardListener(window))
}
}
}
}
impl Drop for ClipboardListener {
fn drop(&mut self) {
unsafe {
RemoveClipboardFormatListener(self.0);
}
}
}
impl<H: ClipboardHandler> Master<H> {
pub fn new(handler: H) -> Self {
Master {
handler
}
}
pub fn run(&mut self) -> io::Result<()> {
let window = Window::from_builder(raw::window::Builder::new().class_name("STATIC").parent_message())?;
let _guard = ClipboardListener::new(&window)?;
let mut result = Ok(());
for msg in Messages::new().window(Some(window.inner())).low(Some(797)).high(Some(797)) {
match msg {
Ok(_) => {
match self.handler.on_clipboard_change() {
CallbackResult::Next => (),
CallbackResult::Stop => break,
CallbackResult::StopWithError(error) => {
result = Err(error);
break;
}
}
},
Err(error) => {
match self.handler.on_clipboard_error(error) {
CallbackResult::Next => (),
CallbackResult::Stop => break,
CallbackResult::StopWithError(error) => {
result = Err(error);
break;
}
}
}
}
}
result
}
}