Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mouse, Box<dyn std::error::Error>> {
Ok(Mouse(sys::Mouse::new()?))
}

/// This method moves the mouse around
Expand Down
102 changes: 66 additions & 36 deletions src/sys/linux.rs
Original file line number Diff line number Diff line change
@@ -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),
}
}

Expand All @@ -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
/// "<operation> 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<dyn error::Error>> {
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")]
Expand All @@ -40,74 +65,79 @@ 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<Mouse, Box<dyn error::Error>> {
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<dyn Error>> {
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<dyn error::Error>> {
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<dyn Error>> {
unsafe {
xdo_mouse_down(self.xdo, self.current_window, xdo_translate_key(key))
}
Ok(())
pub fn press<'a>(&self, key: &'a Keys) -> Result<(), Box<dyn error::Error>> {
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<dyn Error>> {
unsafe {
xdo_mouse_up(self.xdo, self.current_window, xdo_translate_key(key))
}
Ok(())
pub fn release<'a>(&self, key: &'a Keys) -> Result<(), Box<dyn error::Error>> {
let result = unsafe { xdo_mouse_up(self.xdo, self.current_window, xdo_translate_key(key)) };
check_xdo(result)
}

pub fn get_position(&self) -> Result<Point, Box<dyn Error>> {
pub fn get_position(&self) -> Result<Point, Box<dyn error::Error>> {
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<dyn std::error::Error>> {
pub fn wheel(&self, mut delta: i32) -> Result<(), Box<dyn error::Error>> {
let key = if delta < 0 { 4 } else { 5 };

if delta < 0 {
delta = -delta;
}

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(())
}
}

impl Drop for Mouse {
fn drop(&mut self) {
unsafe {
xdo_free(self.xdo);
unsafe {
xdo_free(self.xdo);
}
}
}
2 changes: 1 addition & 1 deletion src/sys/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl Mouse {
)
}

pub fn new() -> Mouse {
pub fn new() -> Result<Mouse, Box<dyn std::error::Error>> {
Mouse
}

Expand Down
8 changes: 4 additions & 4 deletions src/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ impl Mouse {
}
}

pub fn new() -> Mouse {
Mouse {
user32: libloading::Library::new("user32").unwrap(),
}
pub fn new() -> Result<Mouse, Box<dyn std::error::Error>> {
Ok(Mouse {
user32: libloading::Library::new("user32")?,
})
}

pub fn move_to(&self, x: i32, y: i32) -> Result<(), Box<dyn std::error::Error>> {
Expand Down