pub use openlogi_core::binding::ButtonId;
#[derive(Clone, Debug)]
pub enum MouseEvent {
Button {
id: ButtonId,
pressed: bool,
},
Scroll {
delta_x: f32,
delta_y: f32,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EventDisposition {
PassThrough,
Suppress,
}
#[derive(Debug, thiserror::Error)]
pub enum HookError {
#[error("mouse event hook is not supported on this platform")]
Unsupported,
#[error(
"macOS Accessibility permission is required to capture mouse events; \
grant it in System Settings → Privacy & Security → Accessibility"
)]
AccessibilityDenied,
#[error("CGEventTap setup failed: {0}")]
MacOsTap(String),
}
pub struct Hook {
#[cfg(target_os = "macos")]
inner: Option<macos::HookInner>,
#[cfg(not(target_os = "macos"))]
never: std::convert::Infallible,
}
impl Drop for Hook {
fn drop(&mut self) {
#[cfg(target_os = "macos")]
if let Some(inner) = self.inner.take() {
macos::stop(inner);
}
#[cfg(not(target_os = "macos"))]
{}
}
}
impl Hook {
pub fn start(
cb: impl Fn(MouseEvent) -> EventDisposition + Send + Sync + 'static,
) -> Result<Self, HookError> {
#[cfg(target_os = "macos")]
{
macos::start(cb).map(|inner| Self { inner: Some(inner) })
}
#[cfg(not(target_os = "macos"))]
{
let _ = cb;
Err(HookError::Unsupported)
}
}
#[cfg_attr(
not(target_os = "macos"),
allow(
unused_mut,
reason = "`mut self` is only consumed by the macOS teardown path"
)
)]
pub fn stop(mut self) {
#[cfg(target_os = "macos")]
if let Some(inner) = self.inner.take() {
macos::stop(inner);
}
#[cfg(not(target_os = "macos"))]
match self.never {}
}
#[must_use]
pub fn has_accessibility() -> bool {
#[cfg(target_os = "macos")]
{
macos::has_accessibility()
}
#[cfg(not(target_os = "macos"))]
{
true
}
}
pub fn prompt_accessibility() {
#[cfg(target_os = "macos")]
{
macos::prompt_accessibility();
}
}
}
#[must_use]
pub fn frontmost_bundle_id() -> Option<String> {
#[cfg(target_os = "macos")]
{
macos::frontmost_bundle_id()
}
#[cfg(not(target_os = "macos"))]
{
None
}
}
#[cfg(target_os = "macos")]
mod macos;
#[cfg(test)]
mod tests;