Narsil / rdev

Simple library to listen and send events to keyboard and mouse (MacOS, Windows, Linux)
MIT License
534 stars 135 forks source link

Is there a way to stop listening? #72

Open powerory opened 2 years ago

powerory commented 2 years ago

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?

TyronDonovan commented 2 years ago

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

powerory commented 2 years ago

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.

coderedart commented 2 years ago

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?

TyronDonovan commented 2 years ago

We need to collaborate and have a chat. If you don’t mind sending me a msg +27827885994

Get Outlook for iOShttps://aka.ms/o0ukef


From: Red Artist @.> Sent: Friday, January 21, 2022 4:18:51 AM To: Narsil/rdev @.> Cc: TyronDonovan @.>; Comment @.> Subject: Re: [Narsil/rdev] Is there a way to stop listening? (Issue #72)

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.

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

— Reply to this email directly, view it on GitHubhttps://github.com/Narsil/rdev/issues/72#issuecomment-1018102154, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AQT62H7WJBGP5UOMEKX5IUTUXC7AXANCNFSM5LX7LQVA. You are receiving this because you commented.Message ID: @.***>

powerory commented 2 years ago

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.

coderedart commented 2 years ago

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.

Zenthae commented 2 years ago

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

Narsil commented 2 years ago

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).

donicrosby commented 1 year ago

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.

stefnotch commented 1 year ago

@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?

Narsil commented 1 year ago

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)

SurajRaika commented 11 months ago

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 ?

Zhou-Tx commented 11 months ago

我已收到你发的邮件,谢谢

michaelritsema commented 11 months ago

I'm not associated with this project but forked and used for years. I'd recommend one of the options:

On Tue, Dec 12, 2023 at 10:32 PM SurajRaika @.***> wrote:

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 ?

— Reply to this email directly, view it on GitHub https://github.com/Narsil/rdev/issues/72#issuecomment-1853253311, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHCE73OXE52TOKUBFU3JCDYJEVWJAVCNFSM5LX7LQVKU5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TCOBVGMZDKMZTGEYQ . You are receiving this because you are subscribed to this thread.Message ID: @.***>

luftaquila commented 8 months ago

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

rohitsangwan01 commented 6 months ago

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);
qzd1989 commented 4 months ago

https://github.com/Narsil/rdev/pull/137

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

Zhou-Tx commented 4 months ago

我已收到你发的邮件,谢谢