libxdo/
lib.rs

1//! High level bindings to [libxdo](http://www.semicomplete.com/files/xdotool/docs/html/)
2
3#![warn(missing_docs)]
4
5extern crate libxdo_sys as sys;
6
7use std::ffi::{CString, NulError};
8use std::convert::From;
9use std::error::Error;
10use std::fmt;
11
12/// The main handle type which provides access to the various operations.
13pub struct XDo {
14    handle: *mut sys::xdo_t,
15}
16
17/// An error that can happen when trying to create an `XDo` instance.
18#[derive(Debug)]
19pub enum CreationError {
20    /// The provided string parameter had an interior null byte in it.
21    Nul(NulError),
22    /// Libxdo failed to create an instance. No further information available.
23    Ffi,
24}
25
26impl fmt::Display for CreationError {
27    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28        match *self {
29            CreationError::Nul(ref err) => {
30                write!(f,
31                       "Failed to create XDo instance: Nul byte in argument: {}",
32                       err)
33            }
34            CreationError::Ffi => write!(f, "Libxdo failed to create an instance."),
35        }
36    }
37}
38
39impl Error for CreationError {
40    fn description(&self) -> &str {
41        match *self {
42            CreationError::Nul(_) => "libxdo creation error: Nul byte in argument",
43            CreationError::Ffi => "libxdo creation error: Ffi error",
44        }
45    }
46    fn cause(&self) -> Option<&Error> {
47        match *self {
48            CreationError::Nul(ref err) => Some(err),
49            CreationError::Ffi => None,
50        }
51    }
52}
53
54impl From<NulError> for CreationError {
55    fn from(err: NulError) -> CreationError {
56        CreationError::Nul(err)
57    }
58}
59
60/// An error that can happen while executing an operation.
61#[derive(Debug)]
62pub enum OpError {
63    /// The provided string parameter had an interior null byte in it.
64    Nul(NulError),
65    /// Libxdo failed, returning an error code.
66    Ffi(i32),
67}
68
69impl fmt::Display for OpError {
70    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71        match *self {
72            OpError::Nul(ref err) => {
73                write!(f, "Xdo operation failed: Nul byte in argument: {}", err)
74            }
75            OpError::Ffi(code) => write!(f, "Xdo operation failed. Error code {}.", code),
76        }
77    }
78}
79
80impl Error for OpError {
81    fn description(&self) -> &str {
82        match *self {
83            OpError::Nul(_) => "xdo operation failure: Nul byte in argument",
84            OpError::Ffi(_) => "xdo operation failure: Ffi error",
85        }
86    }
87    fn cause(&self) -> Option<&Error> {
88        match *self {
89            OpError::Nul(ref err) => Some(err),
90            OpError::Ffi(_) => None,
91        }
92    }
93}
94
95impl From<NulError> for OpError {
96    fn from(err: NulError) -> Self {
97        OpError::Nul(err)
98    }
99}
100
101/// Result of an `XDo` operation.
102pub type OpResult = Result<(), OpError>;
103
104macro_rules! xdo (
105    ($fncall: expr) => {
106        unsafe {
107            match $fncall {
108                0 => Ok(()),
109                code => Err(OpError::Ffi(code))
110            }
111        }
112    }
113);
114
115impl XDo {
116    /// Creates a new `XDo` instance.
117    ///
118    /// # Parameters
119    ///
120    /// display - An optional string display name, such as `":0"`. If `None`, uses `$DISPLAY`.
121    ///
122    /// # Returns
123    ///
124    /// Returns a new `XDo` instance, or a `CreationError` on error.
125    pub fn new(display: Option<&str>) -> Result<XDo, CreationError> {
126        let c_string;
127        let display = match display {
128            Some(display) => {
129                c_string = CString::new(display)?;
130                c_string.as_ptr()
131            }
132            None => ::std::ptr::null(),
133        };
134        let handle = unsafe { sys::xdo_new(display) };
135        if handle.is_null() {
136            return Err(CreationError::Ffi);
137        }
138        Ok(XDo { handle: handle })
139    }
140    /// Moves the mouse to the specified position.
141    pub fn move_mouse(&self, x: i32, y: i32, screen: i32) -> OpResult {
142        xdo!(sys::xdo_move_mouse(self.handle, x, y, screen))
143    }
144    /// Moves the mouse relative to the current position.
145    pub fn move_mouse_relative(&self, x: i32, y: i32) -> OpResult {
146        xdo!(sys::xdo_move_mouse_relative(self.handle, x, y))
147    }
148    /// Does a mouse click.
149    pub fn click(&self, button: i32) -> OpResult {
150        xdo!(sys::xdo_click_window(self.handle, sys::CURRENTWINDOW, button))
151    }
152    /// Holds a mouse button down.
153    pub fn mouse_down(&self, button: i32) -> OpResult {
154        xdo!(sys::xdo_mouse_down(self.handle, sys::CURRENTWINDOW, button))
155    }
156    /// Releases a mouse button.
157    pub fn mouse_up(&self, button: i32) -> OpResult {
158        xdo!(sys::xdo_mouse_up(self.handle, sys::CURRENTWINDOW, button))
159    }
160    /// Types the specified text.
161    pub fn enter_text(&self, text: &str, delay_microsecs: u32) -> OpResult {
162        let string = CString::new(text)?;
163        xdo!(sys::xdo_enter_text_window(self.handle,
164                                        sys::CURRENTWINDOW,
165                                        string.as_ptr(),
166                                        delay_microsecs))
167    }
168    /// Does the specified key sequence.
169    pub fn send_keysequence(&self, sequence: &str, delay_microsecs: u32) -> OpResult {
170        let string = CString::new(sequence)?;
171        xdo!(sys::xdo_send_keysequence_window(self.handle,
172                                              sys::CURRENTWINDOW,
173                                              string.as_ptr(),
174                                              delay_microsecs))
175    }
176    /// Releases the specified key sequence.
177    pub fn send_keysequence_up(&self, sequence: &str, delay_microsecs: u32) -> OpResult {
178        let string = CString::new(sequence)?;
179        xdo!(sys::xdo_send_keysequence_window_up(self.handle,
180                                                 sys::CURRENTWINDOW,
181                                                 string.as_ptr(),
182                                                 delay_microsecs))
183    }
184    /// Presses the specified key sequence down.
185    pub fn send_keysequence_down(&self, sequence: &str, delay_microsecs: u32) -> OpResult {
186        let string = CString::new(sequence)?;
187        xdo!(sys::xdo_send_keysequence_window_down(self.handle,
188                                                   sys::CURRENTWINDOW,
189                                                   string.as_ptr(),
190                                                   delay_microsecs))
191    }
192}
193
194impl Drop for XDo {
195    fn drop(&mut self) {
196        unsafe {
197            sys::xdo_free(self.handle);
198        }
199    }
200}