diff --git a/src/mouse.rs b/src/mouse.rs index 7c0c95f..4ce28fe 100644 --- a/src/mouse.rs +++ b/src/mouse.rs @@ -9,8 +9,8 @@ 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()) + pub fn new() -> Result> { + Ok(Mouse(sys::Mouse::new()?)) } /// This method moves the mouse around diff --git a/src/sys/linux.rs b/src/sys/linux.rs index f2e4f4d..9d661da 100644 --- a/src/sys/linux.rs +++ b/src/sys/linux.rs @@ -1,22 +1,25 @@ use crate::types::keys::Keys; use crate::types::Point; -use std::error::Error; +use std::error; +use std::fmt; use libc; -use libc::{c_int, c_void, c_char}; -use std::{ptr}; +use libc::{c_char, c_int, c_void}; +use std::ptr; type XDO = *const c_void; type WINDOW = c_int; type INTPTR = *mut c_int; +const XDO_SUCCESS: c_int = 0; + fn xdo_translate_key(key: &Keys) -> c_int { match key { Keys::LEFT => 1, Keys::WHEEL | Keys::MIDDLE => 2, Keys::RIGHT => 3, - _ => panic!("Invalid key passed: {:?}", key) + _ => panic!("Invalid key passed: {:?}", key), } } @@ -29,9 +32,31 @@ impl From<(c_int, c_int)> for Point { } } +/// xdo logs errors to stderr (sometimes!) and does not communicate them back to +/// the caller in a programmatic way, so the best we can do is a generic +/// " failed" :/ +#[derive(Debug)] +pub struct Error; + +impl error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "xdo operation failed") + } +} + +fn check_xdo(result: c_int) -> Result<(), Box> { + if result == XDO_SUCCESS { + Ok(()) + } else { + Err(Box::new(Error)) + } +} + pub struct Mouse { xdo: XDO, - current_window: c_int + current_window: c_int, } #[link(name = "xdo")] @@ -40,55 +65,61 @@ extern "C" { fn xdo_free(xdo: XDO); fn xdo_move_mouse(xdo: XDO, x: c_int, y: c_int, screen: c_int) -> c_int; - fn xdo_mouse_down(xdo: XDO, window: WINDOW, button: c_int); - fn xdo_mouse_up(xdo: XDO, window: WINDOW, button: c_int); - fn xdo_click_window(xdo: XDO, window: WINDOW, button: c_int); - fn xdo_get_mouse_location(xdo: XDO, x: INTPTR, y: INTPTR, screen_num: INTPTR); + fn xdo_mouse_down(xdo: XDO, window: WINDOW, button: c_int) -> c_int; + fn xdo_mouse_up(xdo: XDO, window: WINDOW, button: c_int) -> c_int; + fn xdo_click_window(xdo: XDO, window: WINDOW, button: c_int) -> c_int; + fn xdo_get_mouse_location(xdo: XDO, x: INTPTR, y: INTPTR, screen_num: INTPTR) -> c_int; } impl Mouse { - pub fn new() -> Self { - Mouse { - xdo: unsafe { xdo_new(ptr::null()) }, - current_window: 0 + pub fn new() -> Result> { + let xdo = unsafe { xdo_new(ptr::null()) }; + if xdo.is_null() { + return Err(Box::new(Error)); } + + Ok(Mouse { + xdo, + current_window: 0, + }) } - pub fn move_to(&self, x: i32, y: i32) -> Result<(), Box> { - unsafe { - xdo_move_mouse(self.xdo, x as c_int, y as c_int, 0); - } - Ok(()) + pub fn move_to(&self, x: i32, y: i32) -> Result<(), Box> { + let result = unsafe { xdo_move_mouse(self.xdo, x as c_int, y as c_int, 0) }; + check_xdo(result) } - pub fn press<'a>(&self, key: &'a Keys) -> Result<(), Box> { - unsafe { - xdo_mouse_down(self.xdo, self.current_window, xdo_translate_key(key)) - } - Ok(()) + pub fn press<'a>(&self, key: &'a Keys) -> Result<(), Box> { + let result = + unsafe { xdo_mouse_down(self.xdo, self.current_window, xdo_translate_key(key)) }; + check_xdo(result) } - pub fn release<'a>(&self, key: &'a Keys) -> Result<(), Box> { - unsafe { - xdo_mouse_up(self.xdo, self.current_window, xdo_translate_key(key)) - } - Ok(()) + pub fn release<'a>(&self, key: &'a Keys) -> Result<(), Box> { + let result = unsafe { xdo_mouse_up(self.xdo, self.current_window, xdo_translate_key(key)) }; + check_xdo(result) } - pub fn get_position(&self) -> Result> { + pub fn get_position(&self) -> Result> { let pos: Point; unsafe { let mut x: c_int = 0; let mut y: c_int = 0; let mut _screen_num: c_int = 0; - xdo_get_mouse_location(self.xdo, &mut x as INTPTR, &mut y as INTPTR, &mut _screen_num as INTPTR); + let result = xdo_get_mouse_location( + self.xdo, + &mut x as INTPTR, + &mut y as INTPTR, + &mut _screen_num as INTPTR, + ); + check_xdo(result)?; pos = (x, y).into(); } Ok(pos) } - pub fn wheel(&self, mut delta: i32) -> Result<(), Box> { + pub fn wheel(&self, mut delta: i32) -> Result<(), Box> { let key = if delta < 0 { 4 } else { 5 }; if delta < 0 { @@ -96,9 +127,8 @@ impl Mouse { } for _ in 0..delta { - unsafe { - xdo_click_window(self.xdo, self.current_window, key); - } + let result = unsafe { xdo_click_window(self.xdo, self.current_window, key) }; + check_xdo(result)?; } Ok(()) } @@ -106,8 +136,8 @@ impl Mouse { impl Drop for Mouse { fn drop(&mut self) { - unsafe { - xdo_free(self.xdo); + unsafe { + xdo_free(self.xdo); } } } diff --git a/src/sys/macos.rs b/src/sys/macos.rs index 2b78461..df41c36 100644 --- a/src/sys/macos.rs +++ b/src/sys/macos.rs @@ -54,7 +54,7 @@ impl Mouse { ) } - pub fn new() -> Mouse { + pub fn new() -> Result> { Mouse } diff --git a/src/sys/windows.rs b/src/sys/windows.rs index 7bfe761..7e17894 100644 --- a/src/sys/windows.rs +++ b/src/sys/windows.rs @@ -84,10 +84,10 @@ impl Mouse { } } - pub fn new() -> Mouse { - Mouse { - user32: libloading::Library::new("user32").unwrap(), - } + pub fn new() -> Result> { + Ok(Mouse { + user32: libloading::Library::new("user32")?, + }) } pub fn move_to(&self, x: i32, y: i32) -> Result<(), Box> {