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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use winit::{
    event::{ElementState, Event, KeyEvent, WindowEvent},
    keyboard::{KeyCode, PhysicalKey},
};

/// A container for Window-based keyboard input events.
///
/// NOTE: Keys pressed and released during a single update (is that possible, really?) will show
/// as both released and pressed.
#[derive(Clone, Debug, Default)]
pub struct KeyBuf {
    chars: Vec<char>,
    held: Vec<KeyCode>,
    pressed: Vec<KeyCode>,
    released: Vec<KeyCode>,
}

impl KeyBuf {
    /// Returns `true` if any keys have been pressed for multiple frames.
    pub fn any_held(&self) -> bool {
        !self.held.is_empty()
    }

    /// Returns `true` if any keys have been pressed since the last frame.
    pub fn any_pressed(&self) -> bool {
        !self.pressed.is_empty()
    }

    /// Returns `true` if any keys have been released since the last frame.
    pub fn any_released(&self) -> bool {
        !self.released.is_empty()
    }

    /// Returns an iterator of characters typed since the last frame.
    pub fn chars(&self) -> impl Iterator<Item = char> + '_ {
        self.chars.iter().copied()
    }

    /// Call this before handling events.
    pub fn update(&mut self) {
        self.chars.clear();
        self.pressed.clear();
        self.released.clear();
    }

    /// Handles a single event.
    pub fn handle_event(&mut self, event: &Event<()>) -> bool {
        match event {
            Event::WindowEvent {
                event:
                    WindowEvent::KeyboardInput {
                        event:
                            KeyEvent {
                                physical_key: PhysicalKey::Code(key),
                                state,
                                text,
                                ..
                            },
                        ..
                    },
                ..
            } => {
                match state {
                    ElementState::Pressed => {
                        if let Err(idx) = self.pressed.binary_search(key) {
                            self.pressed.insert(idx, *key);
                        }

                        if let Err(idx) = self.held.binary_search(key) {
                            self.held.insert(idx, *key);
                        }
                    }
                    ElementState::Released => {
                        if let Ok(idx) = self.held.binary_search(key) {
                            self.held.remove(idx);
                        }

                        if let Err(idx) = self.released.binary_search(key) {
                            self.released.insert(idx, *key);
                        }
                    }
                }

                if let Some(text) = text {
                    self.chars.extend(text.as_str().chars());
                }

                true
            }
            _ => false,
        }
    }

    /// Returns `true` if the given key has been pressed since the last frame or held for multiple
    /// frames.
    pub fn is_down(&self, key: KeyCode) -> bool {
        self.is_held(key) || self.is_pressed(key)
    }

    /// Returns `true` if the given key has been pressed for multiple frames.
    pub fn is_held(&self, key: KeyCode) -> bool {
        self.held.binary_search(&key).is_ok()
    }

    /// Returns `true` if the given key has been pressed since the last frame.
    pub fn is_pressed(&self, key: KeyCode) -> bool {
        self.pressed.binary_search(&key).is_ok()
    }

    /// Returns `true` if the given key has been released since the last frame.
    pub fn is_released(&self, key: KeyCode) -> bool {
        self.released.binary_search(&key).is_ok()
    }

    /// Returns an iterator of keys pressed for multiple frames.
    pub fn held(&self) -> impl Iterator<Item = KeyCode> + '_ {
        self.held.iter().copied()
    }

    /// Returns an iterator of keys pressed since the last frame.
    pub fn pressed(&self) -> impl Iterator<Item = KeyCode> + '_ {
        self.pressed.iter().copied()
    }

    /// Returns an iterator of keys released since the last frame.
    pub fn released(&self) -> impl Iterator<Item = KeyCode> + '_ {
        self.released.iter().copied()
    }
}