mouse-rs 0.4.2

Library to control your mouse via rust
Documentation
use std::{error, fmt};

use core_graphics::{
    display::{CGDisplayMoveCursorToPoint, CGError, CGMainDisplayID},
    event::{CGEvent, CGEventTapLocation, CGEventType, CGMouseButton, ScrollEventUnit},
    event_source::{CGEventSource, CGEventSourceStateID},
    geometry::CGPoint,
};

use crate::types::{keys::*, Point};

impl From<CGPoint> for Point {
    fn from(other: CGPoint) -> Point {
        Point {
            x: other.x as _,
            y: other.y as _,
        }
    }
}

impl Into<CGPoint> for Point {
    fn into(self) -> CGPoint {
        CGPoint::new(self.x as _, self.y as _)
    }
}

#[derive(Debug)]
pub enum Error<'a> {
    CGDisplayMoveCursorToPoint(CGError),
    CGEventNotCreated,
    CGEventSourceStateInvalid,

    InvalidButtonStr(&'a str),
}

impl<'a> error::Error for Error<'a> {}

impl<'a> fmt::Display for Error<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::CGDisplayMoveCursorToPoint(err) => {
                write!(f, "error in call to CGDisplayMoveCursorToPoint: {}", err)
            }
            Error::CGEventNotCreated => write!(f, "CGEvent could not be created"),
            Error::CGEventSourceStateInvalid => write!(f, "invalid CGEventSourceStateID"),

            Error::InvalidButtonStr(button) => write!(f, "invalid button str: {:?}", button),
        }
    }
}

pub struct Mouse;

impl Mouse {
    fn event_source<'a>() -> Result<CGEventSource, Error<'a>> {
        Ok(
            CGEventSource::new(CGEventSourceStateID::CombinedSessionState)
                .or(Err(Error::CGEventSourceStateInvalid))?,
        )
    }

    pub fn new() -> Mouse {
        Mouse
    }

    pub fn move_to(&self, x: i32, y: i32) -> Result<(), Box<dyn error::Error>> {
        let point = CGPoint::new(x as _, y as _);

        match unsafe { CGDisplayMoveCursorToPoint(CGMainDisplayID(), point) } {
            0 => Ok(()),
            err => Err(Box::new(Error::CGDisplayMoveCursorToPoint(err))),
        }
    }

    pub fn press<'a>(&self, button: &'a Keys) -> Result<(), Box<dyn error::Error + 'a>> {
        let (event_type, mouse_button) = match button {
            Keys::LEFT => Ok((CGEventType::LeftMouseDown, CGMouseButton::Left)),
            Keys::MIDDLE => Ok((CGEventType::OtherMouseDown, CGMouseButton::Center)),
            Keys::RIGHT => Ok((CGEventType::RightMouseDown, CGMouseButton::Right)),
            _ => Err(Box::new(Error::InvalidButtonStr(""))),
        }?;

        CGEvent::new_mouse_event(
            Self::event_source()?,
            event_type,
            self.get_position()?.into(),
            mouse_button,
        )
        .or(Err(Error::CGEventNotCreated))?
        .post(CGEventTapLocation::HID);

        Ok(())
    }

    pub fn release<'a>(&self, button: &'a Keys) -> Result<(), Box<dyn error::Error + 'a>> {
        let (event_type, mouse_button) = match button {
            Keys::LEFT => Ok((CGEventType::LeftMouseUp, CGMouseButton::Left)),
            Keys::WHEEL | Keys::MIDDLE => Ok((CGEventType::OtherMouseUp, CGMouseButton::Center)),
            Keys::RIGHT => Ok((CGEventType::RightMouseUp, CGMouseButton::Right)),
            _ => Err(Box::new(Error::InvalidButtonStr(""))),
        }?;

        CGEvent::new_mouse_event(
            Self::event_source()?,
            event_type,
            self.get_position()?.into(),
            mouse_button,
        )
        .or(Err(Error::CGEventNotCreated))?
        .post(CGEventTapLocation::HID);

        Ok(())
    }

    pub fn get_position(&self) -> Result<Point, Box<dyn error::Error>> {
        Ok(CGEvent::new(Self::event_source()?)
            .or(Err(Error::CGEventNotCreated))?
            .location()
            .into())
    }

    pub fn wheel(&self, delta: i32) -> Result<(), Box<dyn error::Error>> {
        CGEvent::new_scroll_event(Self::event_source()?, ScrollEventUnit::LINE, 1, delta, 0, 0)
            .or(Err(Error::CGEventNotCreated))?
            .post(CGEventTapLocation::HID);

        Ok(())
    }
}