How can I capture the same keyboard event from different threads using crossterm in rust?

84 Views Asked by At

I have a loop which spawns a set of threads. Each thread is listening to a different key. I want to do something in each thread based on the character pressed event.

This is the function I am using. (InputConfig is just a struct that contains the key, for example and x):

#[cfg(target_os = "windows")]
pub fn wait_until_user_input(input_config: &InputConfig) {
    loop {
        if let Ok(_) = poll(Duration::from_millis(20)) {
            println!("Event polled, expecting '{}'", input_config.key.unwrap());
            match read().unwrap() {
                Event::Key(KeyEvent {
                    code,
                    modifiers: _,
                    kind,
                    state: _,
                }) => {
                    if code == KeyCode::Char(input_config.key.unwrap())
                        && kind == KeyEventKind::Press
                    {
                        break;
                    }
                    println!(
                        "Expected: '{}', Found: '{:?}' {:?}",
                        input_config.key.unwrap(),
                        code,
                        kind
                    );
                }
                _ => {
                    println!("No event");
                }
            }
        }

        // Sleep for a short duration to avoid high CPU usage while waiting for input.
        thread::sleep(Duration::from_millis(20));
    }
}

When I run it like this I get the following output when I press space:

Expected: 'x', Found: 'Char(' ')' Press
Expected: ' ', Found: 'Char(' ')' Release
Event polled, expecting 'x'
Event polled, expecting ' '

So it seems that each thread captures each event and the next thread will not get the same exact event. So in this example, if I want to press space and press to make an action, it will randomly not work because the thread of x will steal that event.

How can I "share" the events between threads?

This is how I spawn the threads:

// The configuration
#[derive(Debug, Clone)]
pub struct InputConfig {
    pub key: Option<char>,
    // ...

}

let input_configs = vec![
    InputConfig {
        key: Some(' '),
    },
    InputConfig {
        key: Some('x'),
    },
];

// Spawn the threads
let mut handles = vec![];
for (n, config) in input_configs.iter().enumerate() {

    // ...
    let cloned_config = config.clone();
    // ...
    
    let handle = thread::spawn(move || {
        // ...
        wait_until_user_input(&cloned_config)
        // ...
    });

    handles.push(handle);
}

// Wait for all threads to finish
for handle in handles {
    handle.join().expect("Thread panicked");
}
0

There are 0 best solutions below