Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Events stuck until new event arrives when thread sleeps #964

Open
skius opened this issue Jan 12, 2025 · 4 comments
Open

Events stuck until new event arrives when thread sleeps #964

skius opened this issue Jan 12, 2025 · 4 comments

Comments

@skius
Copy link

skius commented Jan 12, 2025

Describe the bug
If the thread that also polls for events sleeps, then it seems that some events (I wasn't able to narrow down which events specifically - I suspect it's the events that happen during the sleep) will not be poll()'d/read() on subsequent calls and only get flushed once new events (after the sleep) arrive.

To Reproduce
Run the following code (crossterm 0.28.1), wiggle the mouse a lot for a few seconds, then stop triggering any events. Wait a bit until the log shows no more changes, then press a keyboard button and notice how suddenly mouse events start appearing in the log despite the fact that there should only be the keyboard event.

use std::{io, time::Duration};

use crossterm::{
    cursor::position,
    event::{poll, read, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
    execute,
    terminal::{disable_raw_mode, enable_raw_mode},
};

fn print_events() -> io::Result<()> {
    loop {
        // Note: 1ms polls still cause the issue
        if poll(Duration::from_nanos(1))? {
            // It's guaranteed that read() won't block if `poll` returns `Ok(true)`
            let event = read()?;

            println!("Event::{:?}\r", event);

            if event == Event::Key(KeyCode::Char('c').into()) {
                println!("Cursor position: {:?}\r", position());
            }

            if event == Event::Key(KeyCode::Esc.into()) {
                break;
            }
        } else {
            // sleep 1s
            std::thread::sleep(Duration::from_secs(1));
        }
    }

    Ok(())
}

fn main() -> io::Result<()> {
    enable_raw_mode()?;

    let mut stdout = io::stdout();
    execute!(stdout, EnableMouseCapture)?;

    if let Err(e) = print_events() {
        println!("Error: {:?}\r", e);
    }

    execute!(stdout, DisableMouseCapture)?;

    disable_raw_mode()
}

Expected behavior
I'm not sure if this is already expected/unfixable due to how events and sleeping works under the hood, but I would expect poll()/read() to return the mouse events that are 'stuck' until a new event is triggered after a thread sleep.

OS
Windows 11, WSL2, Ubuntu 22.04.5

Terminal/Console
Windows Terminal
I can't seem to trigger the same behavior on gnome-terminal on WSLg, but that's so many layers of abstraction that it could just be too slow.

@skius
Copy link
Author

skius commented Jan 12, 2025

FWIW I was able to fix this for my use case by moving all event reading logic into a separate thread and pushing it to the main thread via a mpsc::channel. I suppose this is just how things work, but I'll leave the issue open if someone with more experience wants to chime in.

@joshka
Copy link
Collaborator

joshka commented Jan 13, 2025

Running your code on macOS also doesn't trigger the problem. That suggests that it might be a Windows specific issue. The code paths for getting events are quite different Windows vs non-windows.

@joshka
Copy link
Collaborator

joshka commented Jan 13, 2025

Running the code on a Windows 11 ARM VM (from a terminal in VSCode running PowerShell), I see that this ends up not even seeing the mouse events while the sleep is happening. They're not lagged like you mention, they just don't register at all.

@skius
Copy link
Author

skius commented Jan 13, 2025

I can reproduce your results on native (as opposed to WSL) Windows 11 x86 (Windows Terminal, PowerShell): mouse events are not being registered while the thread is sleeping. Keyboard events are being registered, however.

EDIT: Actually, I believe only the last mouse event is registered when the thread is sleeping, as I cannot get my code to not print any mouse events at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants