Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting key release with crossterm with rust

I'm trying to detect key releasing instead of pressing using crossterm. I'm using the basic example named event-stream-tokio. I need tokio runtime for the project.

Link to the example code: https://github.com/crossterm-rs/crossterm/blob/master/examples/event-stream-tokio.rs

Anyway, when I'm trying to amend the example to catch key release and not press - I'm not able to do so. Only the press kind is detected.

Does anybody know how to make it work?

Here is my changed function in that example:

async fn print_events() {
    let mut reader = EventStream::new();

    loop {
        let mut delay = Delay::new(Duration::from_millis(1_000)).fuse();
        let mut event = reader.next().fuse();

        select! {
            _ = delay => { println!(".\r"); },
            maybe_event = event => {
                match maybe_event {
                    Some(Ok(event)) => {
                        println!("Event::{:?}\r", event);

                        if event == Event::Key(
                            // Here I changed the example
                            KeyEvent::new_with_kind(
                                KeyCode::Char('c'),
                                KeyModifiers::NONE,
                                KeyEventKind::Release
                            )) {
                            println!("c key was released!. position is: {:?}\r", position());
                        }

                        if event == Event::Key(KeyCode::Esc.into()) {
                            break;
                        }
                    }
                    Some(Err(e)) => println!("Error: {:?}\r", e),
                    None => break,
                }
            }
        };
    }
}

Printing the position of the cursor is not important. It's only part of their example.

Thanks!

like image 426
Mithrandir Avatar asked Oct 17 '25 06:10

Mithrandir


2 Answers

The default behavior of terminals is that what you get is not a stream of key state events but a stream of text — of characters typed. There is no concept of key-up.

However, the kitty keyboard protocol is a set of extensions which some terminals support to allow reporting key-up events, and that is what crossterm's KeyEventKind is about. You have to enable the features by using PushKeyboardEnhancementFlags, and you have to be using a terminal that implements that extension. Otherwise you will never see a release event.

like image 162
Kevin Reid Avatar answered Oct 19 '25 20:10

Kevin Reid


While you can't do it directly with crossterm, there is a way to do it. Namely, I used the device_query crate which provides the state of keys pressed and not pressed. It is harder to wire up everything since you need to do it poll-based, and maybe it's un-idiomatic, but it is possible!

To be more specific, in my case, I wanted to check when the spacebar is released, so when pressing down the spacebar I do a very quick loop (almost busy looping) checking if the spacebar is at any moment not pressed, which indicates the key has been released.

Again, it's better to avoid this if possible, but in my case it was crucial and so I'm writing the answer here if anyone else is in the same scenario and stumbles upon this question just like I did :)

like image 35
Odilf Avatar answered Oct 19 '25 20:10

Odilf



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!