1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
//! A module for handling key events

use std::io;

#[cfg(feature = "crossterm")]
mod crossterm;
#[cfg(feature = "termion")]
mod termion;

#[cfg(feature = "crossterm")]
pub use self::crossterm::CrosstermEvents;

#[cfg(feature = "termion")]
pub use self::termion::TermionEvents;

mod keys;
mod movement;

pub use keys::{KeyCode, KeyEvent, KeyModifiers};
pub use movement::Movement;

/// Gets the default [`EventIterator`] based on the features enabled.
#[cfg(any(feature = "crossterm", feature = "termion"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "crossterm", feature = "termion"))))]
pub fn get_events() -> impl EventIterator {
    #[cfg(feature = "crossterm")]
    return CrosstermEvents::new();

    // XXX: Only works when crossterm and termion are the only two available backends
    //
    // Instead of directly checking for termion, we check for not crossterm so that compiling
    // (documentation) with both features enabled will not error
    #[cfg(not(feature = "crossterm"))]
    return TermionEvents::new();
}

/// A trait to represent a source of [`KeyEvent`]s.
pub trait EventIterator {
    /// Get the next event
    fn next_event(&mut self) -> io::Result<KeyEvent>;
}

/// A simple wrapper around a [`KeyEvent`] iterator that can be used in tests.
///
/// Even though [`EventIterator`] expects the iterator to be infinite, only having enough events to
/// complete the test is necessary.
///
/// It will also check that the internal iterator is fully exhausted on [`Drop`].
///
/// # Panics
///
/// It will panic if the events run out [`next_event`] is called, or if there are events remaining
/// when dropped.
///
/// [`next_event`]: TestEvents::next_event
#[derive(Debug, Clone)]
pub struct TestEvents<E: Iterator<Item = KeyEvent>> {
    events: E,
}

impl<E: Iterator<Item = KeyEvent>> TestEvents<E> {
    /// Create a new `TestEvents`
    pub fn new<I: IntoIterator<IntoIter = E, Item = KeyEvent>>(iter: I) -> Self {
        Self {
            events: iter.into_iter(),
        }
    }
}

impl TestEvents<std::iter::Empty<KeyEvent>> {
    /// Create a new `TestEvents` which yields no events
    pub fn empty() -> Self {
        Self {
            events: std::iter::empty(),
        }
    }
}

impl<E: Iterator<Item = KeyEvent>> EventIterator for TestEvents<E> {
    fn next_event(&mut self) -> io::Result<KeyEvent> {
        Ok(self
            .events
            .next()
            .expect("Events ran out, but another one was requested"))
    }
}

impl<E: Iterator<Item = KeyEvent>> Drop for TestEvents<E> {
    fn drop(&mut self) {
        let mut count = 0;

        while self.events.next().is_some() {
            count += 1
        }

        assert_eq!(
            count, 0,
            "Events did not fully run out, {} events have not been consumed",
            count
        );
    }
}