Skip to content
This repository has been archived by the owner on Apr 1, 2023. It is now read-only.

Commit

Permalink
opt: handle grab exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
Asura committed Dec 10, 2022
1 parent 4051761 commit 67d41bd
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 49 deletions.
5 changes: 4 additions & 1 deletion examples/grab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ fn main() {
let delay = Duration::from_secs(5);

println!("[*] starting grab listen...");
start_grab_listen(callback);
if let Err(err) = start_grab_listen(callback){
eprintln!("start grab listen error: {:?}", err);
return;
};

println!("[*] grab keys(5s), try to press Ctrl+C, won't work on other applications");
enable_grab();
Expand Down
95 changes: 49 additions & 46 deletions src/linux/grab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,47 +78,37 @@ fn ungrab_keys(display: *mut Display) {
}
}

pub fn enable_grab() -> Result<(), GrabError> {
pub fn enable_grab() {
if let Some(tx) = &*SENDER.lock().unwrap() {
tx.send(GrabEvent::Grab).ok();
/* if too fast: poll cannot perceive events */
thread::sleep(Duration::from_millis(50));
} else {
return Err(GrabError::ListenError);
};
Ok(())
}
}

pub fn disable_grab() -> Result<(), GrabError> {
pub fn disable_grab() {
if let Some(tx) = &*SENDER.lock().unwrap() {
tx.send(GrabEvent::UnGrab).ok();
thread::sleep(Duration::from_millis(50));
} else {
return Err(GrabError::ListenError);
};
Ok(())
}
}

pub fn start_grab_listen<T>(callback: T)
pub fn start_grab_listen<T>(callback: T) -> Result<(), GrabError>
where
T: FnMut(Event) -> Option<Event> + 'static,
{
unsafe {
GLOBAL_CALLBACK = Some(Box::new(callback));
}
start_grab_service();
thread::sleep(Duration::from_millis(50));
start_grab_service()?;
thread::sleep(Duration::from_millis(100));
Ok(())
}

pub fn exit_grab_listen() -> Result<(), GrabError> {
pub fn exit_grab_listen() {
if let Some(tx) = &*SENDER.lock().unwrap() {
if tx.send(GrabEvent::Exit).is_err() {
return Err(GrabError::ListenError);
};
} else {
return Err(GrabError::ListenError);
};
Ok(())
tx.send(GrabEvent::Exit).ok();
}
}

fn send_to_client(grab: bool) {
Expand All @@ -131,10 +121,11 @@ fn send_to_client(grab: bool) {
};
}

fn start_grab_service() {
fn start_grab_service() -> Result<(), GrabError> {
let (send, recv) = std::sync::mpsc::channel::<GrabEvent>();
*SENDER.lock().unwrap() = Some(send);
start_grab_thread();

start_grab_thread()?;

thread::spawn(move || loop {
if let Ok(data) = recv.recv() {
Expand All @@ -156,6 +147,8 @@ fn start_grab_service() {
}
}
});

Ok(())
}

fn unlink_socket(path: impl AsRef<Path>) {
Expand All @@ -168,19 +161,22 @@ fn unlink_socket(path: impl AsRef<Path>) {
}
}

fn start_grab_thread() {
fn start_grab_thread() -> Result<(), GrabError> {
let (error_sender, error_recv) = std::sync::mpsc::channel::<GrabError>();

thread::spawn(move || {
// init the thread
let display = unsafe { xlib::XOpenDisplay(ptr::null()) };
/* todo! how to get Exception*/
if display.is_null() {
panic!("[-] grab error in rdev: MissingDisplayError");
error_sender.send(GrabError::MissingDisplayError).ok();
return;
}
let screen_number = unsafe { xlib::XDefaultScreen(display) };
/* todo! Multiple Display */
let screen = unsafe { xlib::XScreenOfDisplay(display, screen_number) };
if screen.is_null() {
panic!("[-] grab error in rdev: XScreenOfDisplay Error");
error_sender.send(GrabError::MissScreenError).ok();
return;
}
let grab_window = unsafe { xlib::XRootWindowOfScreen(screen) };

Expand All @@ -192,31 +188,32 @@ fn start_grab_thread() {
unlink_socket(FILE_PATH);
let socket = match UnixDatagram::bind(FILE_PATH) {
Ok(socket) => socket,
Err(err) => panic!("[-] grab error in rdev: {:?}", err),
};
if socket.set_nonblocking(true).is_err() {
panic!("[-] grab error in rdev: set_nonblocking");
Err(err) => {
error_sender.send(GrabError::IoError(err)).ok();
return;
}
};
if let Err(err) = socket.set_nonblocking(true) {
error_sender.send(GrabError::IoError(err)).ok();
return;
}

if let Ok(mut poll) = Poll::new() {
let mut events = Events::with_capacity(128);
if poll
.registry()
.register(&mut SourceFd(&grab_fd), GRAB_KEY, Interest::READABLE)
.is_err()
if let Err(err) =
poll.registry()
.register(&mut SourceFd(&grab_fd), GRAB_KEY, Interest::READABLE)
{
panic!("[-] grab error in rdev: Poll register grab fd failed");
error_sender.send(GrabError::IoError(err)).ok();
return;
};
if poll
.registry()
.register(
&mut SourceFd(&socket.as_raw_fd()),
SERVICE_CLIENT,
Interest::READABLE,
)
.is_err()
{
panic!("[-] grab error in rdev: Poll register socket fd failed");
if let Err(err) = poll.registry().register(
&mut SourceFd(&socket.as_raw_fd()),
SERVICE_CLIENT,
Interest::READABLE,
) {
error_sender.send(GrabError::IoError(err)).ok();
return;
};

let mut x_event: xlib::XEvent = unsafe { zeroed() };
Expand Down Expand Up @@ -258,4 +255,10 @@ fn start_grab_thread() {
panic!("[-] grab error in rdev: Create Poll failed");
}
});
thread::sleep(Duration::from_millis(100));
if let Ok(err) = error_recv.try_recv() {
Err(err)
} else {
Ok(())
}
}
7 changes: 5 additions & 2 deletions src/rdev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub enum ListenError {
/// Errors that occur when trying to grab OS events.
/// Be careful on Mac, not setting accessibility does not cause an error
/// it justs ignores events.
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug)]
#[non_exhaustive]
pub enum GrabError {
ListenError,
Expand All @@ -49,14 +49,17 @@ pub enum GrabError {
/// Linux
MissingDisplayError,
/// Linux
MissScreenError,
/// Linux
KeyboardError,
/// Windows
KeyHookError(u32),
/// Windows
MouseHookError(u32),
/// All
SimulateError,
// IoError(std::io::Error),

IoError(std::io::Error)
}

// impl From<std::io::Error> for GrabError {
Expand Down

0 comments on commit 67d41bd

Please sign in to comment.