Narsil / rdev

Simple library to listen and send events to keyboard and mouse (MacOS, Windows, Linux)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is there a way to stop listening?

powerory opened this issue · comments

Hi,

I am trying to use rdev to handle global mouse movement in my application.
Because listen function has blocking i/f, I call it in the new thread by thread::spawn.
However in this case, that thread is not terminated even if my main thread is terminated by user i/f.

Is there a way to stop listen function or some functions like try_listen to able to receive some signals from external?

Did you manage to find a way through your problem on this ?

Did you manage to find a way through your problem on this ?

I didn't find a way in rdev. But I found another crate which does not block.

I think you can just keep a Arc so that the rdev thread can check for it in a loop. and when you are exiting the main thread, you can just trigger the bool, and do thread.join() to wait for rdev thread to close. condvar might be a decent choice too if you are okay with some latency in the rdev thread loop. in the rdev thread loop, just panic in the listen closure when bool/condvar is triggered.

although, it would definitely be nice for there to be support to stop listening to events properly instead of silly workarounds. maybe the closure can return a bool, and if it returns false, rdev listen can stop.

what crate did are you using that doesn't block btw?

I think you can just keep a Arc so that the rdev thread can check for it in a loop. and when you are exiting the main thread, you can just trigger the bool, and do thread.join() to wait for rdev thread to close. condvar might be a decent choice too if you are okay with some latency in the rdev thread loop. in the rdev thread loop, just panic in the listen closure when bool/condvar is triggered.

although, it would definitely be nice for there to be support to stop listening to events properly instead of silly workarounds. maybe the closure can return a bool, and if it returns false, rdev listen can stop.

what crate did are you using that doesn't block btw?

I tried to use select! macro in futures to receive external stop signal from other thread.
That is might a similar way you advise, I guess, but it did not work. (I am sorry that I don't know why.)

And I'm using device_query(https://crates.io/crates/device_query) crate for now.

I tried to use select! macro in futures to receive external stop signal from other thread.
That is might a similar way you advise, I guess, but it did not work. (I am sorry that I don't know why.)

And I'm using device_query(https://crates.io/crates/device_query) crate for now.

Ah.. I came here from device query crate. DQ doesn't support scroll and I wanted that. And I also had to check all keys to know which keys changed from press to release.

Futures won't work because rdev is not async. The closure is sync and the only way to exit is to panic inside closure when you get quit signal either via arc atomic bool or a channel. And you can't do thread join as that will panic main thread too. Unless you use catch unwind .

The only way forward is for rdev to make the closure return a bool and if closure returns false, rdev stops listening and exits the loop.

hello, nothing new here right ? i kinda need this feature

It's kind of really hard to model a non blocking listening because of how the various OS implements those listeners.

What OS is this bug on ? It seems extremely weird that exiting main thread doesn't stop a child thread (this should be handled by the OS not by you).

I don't think there's issue with blocking listening, I think the issue is stopping rdev when you're done with it. Some programs or libraries don't constantly need to get HID events and would spin up a worker thread to handle that and stop it when it's no longer needed. I believe just having the closure return a bool (even better a flag enum) that says whether or not you want to keep blocking or stop the listening for events and return would prevent issues down the road from people just dropping the listener when it's done.

@Narsil I'd like to take a stab at implementing a way of stopping the grab on Windows. (I don't have Linux or Mac machines)
Any pointers?

Unfortunately no, it's been a while I didn't go deeply into this. I just remember grabbing globally is a mess. (lots of globals everywhere)

We Can't Stop listening
so i have to change my whole architecture of my app
which turned out to be a good choice 👍 for my app .

but still there must be reason behind it for not implementing this simple feature ?

+1 here looking for closure that can return some information whether keep listening or not.

This might help

// Define AtomicBool 
static SHOULD_STOP: AtomicBool = AtomicBool::new(false);

// Start Event listener using Tokio
async fn start_event_listener() {
    let (schan, mut rchan) = mpsc::unbounded_channel();
    let listener_handle = task::spawn_blocking(move || {
        listen(move |event| {
            schan
                .send(event)
                .unwrap_or_else(|e| println!("Could not send event {:?}", e));
        })
    });
    while !SHOULD_STOP.load(Ordering::Relaxed) {
        if let Some(event) = rchan.recv().await {
           // Handle Events
            on_event_recieved(event);
        }
    }
    let _join_handle = listener_handle.await.unwrap();
}


// Start listener
SHOULD_STOP.store(false, Ordering::Relaxed);
tokio::spawn(start_event_listener());

// Stop Listener
SHOULD_STOP.store(true, Ordering::Relaxed);

#137

I pushed some code to provide stop_listen function on macos, may help you~