From 7b352fc5b5d61c14631c554462ced38e409f2df5 Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Sat, 19 Aug 2023 16:17:22 +1000 Subject: [PATCH 1/2] Add documentation and refactor (at least for macOS) --- src/lib.rs | 4 +-- src/mouse.rs | 88 ++++++++++++++++++++++++++++++++++-------------- src/sys/macos.rs | 44 ++++++++++++------------ tests/main.rs | 14 ++++---- 4 files changed, 93 insertions(+), 57 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 48649d4..a5c8f78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,9 +29,9 @@ //! ``` //! //! ## Linux disclaimer -//! If you're running into problems building on linux you need to install libxdo-dev. +//! If you're running into problems building on Linux, try installing libxdo-dev. //! -//! #### Ubuntu +//! ### Ubuntu //! ```bash //! sudo apt-get install libxdo-dev //! ``` diff --git a/src/mouse.rs b/src/mouse.rs index 7c0c95f..d56f569 100644 --- a/src/mouse.rs +++ b/src/mouse.rs @@ -1,23 +1,24 @@ +use crate::sys; use crate::types::keys::Keys; -use crate::{sys, types::Point}; +use crate::types::Point; -/// Struct for the mouse +/// Represents the user's mouse pointer. /// -/// This struct represents a mouse and doesn't hold any values +/// This is an abstraction of the internal [`sys::Mouse`] struct. pub struct Mouse(sys::Mouse); -#[allow(unreachable_code, unused_variables)] impl Mouse { - /// This method creates a new mouse instance, must always be run before anything else - pub fn new() -> Mouse { - Mouse(sys::Mouse::new()) + #[must_use] + /// Create a new [`Mouse`]. + pub const fn new() -> Self { + Self(sys::Mouse::new()) } - /// This method moves the mouse around + /// Move the mouse to the position `(x, y)`, where the origin `(0, 0)` is the top-left of the screen. /// /// # Examples /// - /// ```no_run + /// ```rust, no_run /// use mouse_rs::{types::keys::*, Mouse}; /// /// fn move_mouse() { @@ -26,17 +27,21 @@ impl Mouse { /// } /// /// ``` + /// + /// # Errors + /// + /// Fails if the mouse cannot move to the position. pub fn move_to(&self, x: i32, y: i32) -> Result<(), Box> { - self.0.move_to(x, y) + sys::Mouse::move_to(x, y) } - /// This method presses the given button in + /// Press a button on the mouse and hold it. /// - /// *NOTE: This doesn't release the button so it will keep pressing* + /// _NOTE: This doesn't release the button so it will be kept held until [`Self::release`] is called._ /// /// # Examples /// - /// ```no_run + /// ```rust, no_run /// use mouse_rs::{types::keys::Keys, Mouse}; /// /// fn press_button() { @@ -50,16 +55,24 @@ impl Mouse { /// mouse.release(&Keys::RIGHT).expect("Unable to release button"); // This will press the right mouse quickly /// } /// ``` + /// + /// # Errors + /// + /// Fails if the button cannot be pressed. pub fn press<'a>(&self, button: &'a Keys) -> Result<(), Box> { - self.0.press(button) + sys::Mouse::press(button) } - /// This will release the button as noted above + /// Release a button. Normally used after [`Self::press`]. + /// + /// # Errors + /// + /// Fails if the button cannot be released. pub fn release<'a>(&self, button: &'a Keys) -> Result<(), Box> { - self.0.release(button) + sys::Mouse::release(button) } - /// This gets the current mouse position + /// Return the current mouse position. /// /// # Example /// @@ -72,13 +85,17 @@ impl Mouse { /// println!("X = {}, Y = {}", pos.x, pos.y) /// } /// ``` + /// + /// # Errors + /// + /// Fails if the mouse position cannot be retrieved. pub fn get_position(&self) -> Result> { - self.0.get_position() + sys::Mouse::get_position() } - /// This will scroll the mouse, + /// Scroll the mouse. /// - /// For scrolling down use negative values, for scrolling up use positive values + /// For scrolling down use negative values, for scrolling up use positive values. /// /// # Examples /// @@ -95,18 +112,37 @@ impl Mouse { /// mouse.wheel(-1); /// } /// ``` + /// + /// # Errors + /// + /// Fails if the mouse cannot be scrolled. pub fn wheel(&self, delta: i32) -> Result<(), Box> { - self.0.wheel(delta) + sys::Mouse::wheel(delta) } - /// This is the exact same as wheel + /// Alias for [`Self::wheel`]. + /// + /// # Errors + /// + /// See [`Self::wheel`]. pub fn scroll(&self, delta: i32) -> Result<(), Box> { - self.0.wheel(delta) + sys::Mouse::wheel(delta) } - // Does the exact same thing as press and release combined, but into one function + /// Click a mouse button by pressing then releasing. + /// + /// # Errors + /// + /// Fails if [`Self::press`] or [`Self::release`] fails. pub fn click<'a>(&self, button: &'a Keys) -> Result<(), Box> { - self.0.press(button).unwrap_or(()); - self.0.release(button) + sys::Mouse::press(button)?; + sys::Mouse::release(button)?; + Ok(()) + } +} + +impl Default for Mouse { + fn default() -> Self { + Self::new() } } diff --git a/src/sys/macos.rs b/src/sys/macos.rs index 2b78461..2a438ab 100644 --- a/src/sys/macos.rs +++ b/src/sys/macos.rs @@ -6,20 +6,24 @@ use core_graphics::{ geometry::CGPoint, }; -use crate::types::{keys::*, Point}; +use crate::types::{keys::Keys, Point}; impl From for Point { - fn from(other: CGPoint) -> Point { - Point { + #[allow(clippy::cast_possible_truncation)] + fn from(other: CGPoint) -> Self { + Self { x: other.x as _, y: other.y as _, } } } -impl Into for Point { - fn into(self) -> CGPoint { - CGPoint::new(self.x as _, self.y as _) +impl From for CGPoint { + fn from(value: Point) -> Self { + Self { + x: value.x.into(), + y: value.y.into(), + } } } @@ -39,7 +43,7 @@ impl<'a> fmt::Display for Error<'a> { Error::CGEventNotCreated => write!(f, "CGEvent could not be created"), Error::CGEventSourceStateInvalid => write!(f, "invalid CGEventSourceStateID"), - Error::InvalidButtonStr(button) => write!(f, "invalid button str: {:?}", button), + Error::InvalidButtonStr(button) => write!(f, "invalid button str: {button:?}"), } } } @@ -48,18 +52,16 @@ pub struct Mouse; impl Mouse { fn event_source<'a>() -> Result> { - Ok( - CGEventSource::new(CGEventSourceStateID::CombinedSessionState) - .or(Err(Error::CGEventSourceStateInvalid))?, - ) + CGEventSource::new(CGEventSourceStateID::CombinedSessionState) + .or(Err(Error::CGEventSourceStateInvalid)) } - pub fn new() -> Mouse { - Mouse + pub const fn new() -> Self { + Self } - pub fn move_to(&self, x: i32, y: i32) -> Result<(), Box> { - let point = CGPoint::new(x as _, y as _); + pub fn move_to(x: i32, y: i32) -> Result<(), Box> { + let point = CGPoint::new(x.into(), y.into()); CGEvent::new_mouse_event( Self::event_source()?, @@ -73,7 +75,7 @@ impl Mouse { Ok(()) } - pub fn press<'a>(&self, button: &'a Keys) -> Result<(), Box> { + pub fn press<'a>(button: &'a Keys) -> Result<(), Box> { let (event_type, mouse_button) = match button { Keys::LEFT => Ok((CGEventType::LeftMouseDown, CGMouseButton::Left)), Keys::MIDDLE => Ok((CGEventType::OtherMouseDown, CGMouseButton::Center)), @@ -84,7 +86,7 @@ impl Mouse { CGEvent::new_mouse_event( Self::event_source()?, event_type, - self.get_position()?.into(), + Self::get_position()?.into(), mouse_button, ) .or(Err(Error::CGEventNotCreated))? @@ -93,7 +95,7 @@ impl Mouse { Ok(()) } - pub fn release<'a>(&self, button: &'a Keys) -> Result<(), Box> { + pub fn release<'a>(button: &'a Keys) -> Result<(), Box> { let (event_type, mouse_button) = match button { Keys::LEFT => Ok((CGEventType::LeftMouseUp, CGMouseButton::Left)), Keys::WHEEL | Keys::MIDDLE => Ok((CGEventType::OtherMouseUp, CGMouseButton::Center)), @@ -104,7 +106,7 @@ impl Mouse { CGEvent::new_mouse_event( Self::event_source()?, event_type, - self.get_position()?.into(), + Self::get_position()?.into(), mouse_button, ) .or(Err(Error::CGEventNotCreated))? @@ -113,14 +115,14 @@ impl Mouse { Ok(()) } - pub fn get_position(&self) -> Result> { + pub fn get_position() -> Result> { Ok(CGEvent::new(Self::event_source()?) .or(Err(Error::CGEventNotCreated))? .location() .into()) } - pub fn wheel(&self, delta: i32) -> Result<(), Box> { + pub fn wheel(delta: i32) -> Result<(), Box> { CGEvent::new_scroll_event(Self::event_source()?, ScrollEventUnit::LINE, 1, delta, 0, 0) .or(Err(Error::CGEventNotCreated))? .post(CGEventTapLocation::HID); diff --git a/tests/main.rs b/tests/main.rs index 638ada8..d7b1f84 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -1,29 +1,27 @@ #[cfg(test)] -#[allow(unused_must_use)] mod mouse { use mouse_rs::{types::keys::Keys, Mouse}; #[test] fn move_and_press() { let mouse = Mouse::new(); - mouse.move_to(500, 500); - let pos = mouse.get_position().unwrap(); + mouse.move_to(500, 500).expect("Unable to move mouse"); mouse.press(&Keys::RIGHT).expect("Unable to press button"); - mouse.release(&Keys::RIGHT).expect("Something went wrong"); - mouse.click(&Keys::WHEEL).expect("Something went wrong"); + mouse.release(&Keys::RIGHT).expect("Unable to release button"); + mouse.click(&Keys::WHEEL).expect("Unable to click button"); } #[test] fn scroll_wheel() { let mouse = Mouse::new(); - mouse.wheel(1); + mouse.wheel(1).expect("Unable to scroll mouse"); } #[test] fn press_button() { let mouse = Mouse::new(); - mouse.press(&Keys::MIDDLE); - mouse.release(&Keys::MIDDLE); + mouse.press(&Keys::MIDDLE).expect("Unable to press button"); + mouse.release(&Keys::MIDDLE).expect("Unable to release button"); } // #[test] From a8f11fe8e4d39f09858b18d2130ff0785577644f Mon Sep 17 00:00:00 2001 From: Matthew Li Date: Sat, 19 Aug 2023 16:28:50 +1000 Subject: [PATCH 2/2] Add `move_by` method (fixes #23) --- src/mouse.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mouse.rs b/src/mouse.rs index d56f569..c80baf9 100644 --- a/src/mouse.rs +++ b/src/mouse.rs @@ -139,6 +139,17 @@ impl Mouse { sys::Mouse::release(button)?; Ok(()) } + + /// Move the mouse, relative to the current position. + /// + /// # Errors + /// + /// Fails if [`Self::get_position`] or [`Self::move_to`] fails. + pub fn move_by(&self, delta_x: i32, delta_y: i32) -> Result<(), Box> { + let position = self.get_position()?; + self.move_to(position.x + delta_x, position.y + delta_y)?; + Ok(()) + } } impl Default for Mouse {