use crate::error::Result;
use crate::hotkeys::{Key, Modifiers};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum KeyState {
Pressed,
Released,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MouseButton {
Left,
Right,
Middle,
X1,
X2,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum GlobalInputEvent {
Keyboard {
key: Key,
state: KeyState,
modifiers: Modifiers,
},
Mouse {
button: MouseButton,
state: KeyState,
x: i32,
y: i32,
},
MouseMove {
x: i32,
y: i32,
},
}
pub trait GlobalInputHandler: Send + Sync {
fn on_event(&self, event: GlobalInputEvent);
}
pub struct GlobalInput {
handler: Arc<dyn GlobalInputHandler>,
inner: Mutex<Option<PlatformInput>>,
include_mouse_move: bool,
}
impl GlobalInput {
pub fn new(handler: Arc<dyn GlobalInputHandler>) -> Self {
Self {
handler,
inner: Mutex::new(None),
include_mouse_move: false,
}
}
pub fn with_mouse_move(mut self, on: bool) -> Self {
self.include_mouse_move = on;
self
}
pub fn start(&self) -> Result<()> {
let mut guard = self.inner.lock().unwrap();
if guard.is_some() {
return Ok(());
}
let p = PlatformInput::start(self.handler.clone(), self.include_mouse_move)?;
*guard = Some(p);
Ok(())
}
pub fn stop(&self) {
if let Some(p) = self.inner.lock().unwrap().take() {
p.stop();
}
}
}
impl Drop for GlobalInput {
fn drop(&mut self) {
if let Some(p) = self.inner.lock().unwrap().take() {
p.stop();
}
}
}
enum PlatformInput {
#[cfg(windows)]
Windows(crate::input_win::WinInput),
#[cfg(target_os = "macos")]
Macos(crate::input_mac::MacInput),
#[cfg(not(any(windows, target_os = "macos")))]
Unsupported,
}
impl PlatformInput {
fn start(handler: Arc<dyn GlobalInputHandler>, include_mouse_move: bool) -> Result<Self> {
#[cfg(windows)]
{
Ok(PlatformInput::Windows(crate::input_win::WinInput::start(
handler,
include_mouse_move,
)?))
}
#[cfg(target_os = "macos")]
{
Ok(PlatformInput::Macos(crate::input_mac::MacInput::start(
handler,
include_mouse_move,
)?))
}
#[cfg(not(any(windows, target_os = "macos")))]
{
let _ = (handler, include_mouse_move);
Err(crate::error::RdesktopError::UnsupportedPlatform(
"global input hooks are only supported on Windows and macOS".into(),
))
}
}
fn stop(self) {
match self {
#[cfg(windows)]
PlatformInput::Windows(w) => w.stop(),
#[cfg(target_os = "macos")]
PlatformInput::Macos(m) => m.stop(),
#[cfg(not(any(windows, target_os = "macos")))]
PlatformInput::Unsupported => {}
}
}
}