Skip to main content

radiant_rs/core/
input.rs

1use crate::prelude::*;
2use crate::core::Display;
3
4pub const NUM_KEYS: usize = 256;
5pub const NUM_BUTTONS: usize = 16;
6
7/// The current state of a key or mousebutton.
8#[derive(Debug, PartialEq, Copy, Clone)]
9pub enum InputState {
10    /// The key is not currently pressed.
11    Up,
12    /// The key was just pressed. This state is reported only once per key-press.
13    Pressed,
14    /// The key has been pressed and is still being held down.
15    Down,
16    /// The key has just been released. This state is reported only once per key-release.
17    Released,
18    /// The key is still being held down. When used as text-input, a letter repeat is expected.
19    Repeat,
20}
21
22pub struct InputData {
23    pub mouse           : (i32, i32),
24    pub mouse_delta     : (i32, i32),
25    pub button          : [ InputState; NUM_BUTTONS ],
26    pub key             : [ InputState; NUM_KEYS ],
27    pub should_close    : bool,
28    pub cursor_grabbed  : bool,
29    pub has_focus       : bool,
30    pub dimensions      : (u32, u32),
31}
32
33impl InputData {
34    pub fn new() -> InputData {
35        InputData {
36            mouse           : (0, 0),
37            mouse_delta     : (0, 0),
38            button          : [ InputState::Up; NUM_BUTTONS ],
39            key             : [ InputState::Up; NUM_KEYS ],
40            should_close    : false,
41            cursor_grabbed  : false,
42            has_focus       : true,
43            dimensions      : (0, 0),
44        }
45    }
46    pub fn reset(self: &mut Self) {
47        // todo: store poll_id, check if released/pressed(poll_id) == poll_id
48        for key_id in 0..NUM_KEYS {
49            match self.key[key_id] {
50                InputState::Pressed | InputState::Repeat => {
51                    self.key[key_id] = InputState::Down;
52                }
53                InputState::Released => {
54                    self.key[key_id] = InputState::Up;
55                }
56                _ => { }
57            }
58        }
59
60        for button_id in 0..NUM_BUTTONS {
61            match self.button[button_id] {
62                InputState::Pressed => {
63                    self.button[button_id] = InputState::Down;
64                }
65                InputState::Released => {
66                    self.button[button_id] = InputState::Up;
67                }
68                _ => { }
69            }
70        }
71
72        self.mouse_delta = (0, 0);
73    }
74}
75
76enum_from_primitive! {
77    #[derive(Clone, Copy, Debug, PartialEq)]
78    /// Input key and mousebutton ids
79    pub enum InputId {
80        Key1,
81        Key2,
82        Key3,
83        Key4,
84        Key5,
85        Key6,
86        Key7,
87        Key8,
88        Key9,
89        Key0,
90
91        A,
92        B,
93        C,
94        D,
95        E,
96        F,
97        G,
98        H,
99        I,
100        J,
101        K,
102        L,
103        M,
104        N,
105        O,
106        P,
107        Q,
108        R,
109        S,
110        T,
111        U,
112        V,
113        W,
114        X,
115        Y,
116        Z,
117
118        Escape,
119
120        F1,
121        F2,
122        F3,
123        F4,
124        F5,
125        F6,
126        F7,
127        F8,
128        F9,
129        F10,
130        F11,
131        F12,
132        F13,
133        F14,
134        F15,
135
136        Snapshot,
137        Scroll,
138        Pause,
139
140        Insert,
141        Home,
142        Delete,
143        End,
144        PageDown,
145        PageUp,
146
147        CursorLeft,
148        CursorUp,
149        CursorRight,
150        CursorDown,
151
152        Backspace,
153        Return,
154        Space,
155
156        Numlock,
157        Numpad0,
158        Numpad1,
159        Numpad2,
160        Numpad3,
161        Numpad4,
162        Numpad5,
163        Numpad6,
164        Numpad7,
165        Numpad8,
166        Numpad9,
167
168        AbntC1,
169        AbntC2,
170        Add,
171        Apostrophe,
172        Apps,
173        At,
174        Ax,
175        Backslash,
176        Calculator,
177        Capital,
178        Caret,
179        Colon,
180        Comma,
181        Convert,
182        Decimal,
183        Divide,
184        Equals,
185        Grave,
186        Kana,
187        Kanji,
188        LAlt,
189        LBracket,
190        LControl,
191        LMenu,
192        LShift,
193        LWin,
194        Mail,
195        MediaSelect,
196        MediaStop,
197        Minus,
198        Multiply,
199        Mute,
200        MyComputer,
201        NextTrack,
202        NoConvert,
203        NumpadComma,
204        NumpadEnter,
205        NumpadEquals,
206        OEM102,
207        Period,
208        PlayPause,
209        Power,
210        PrevTrack,
211        RAlt,
212        RBracket,
213        RControl,
214        RMenu,
215        RShift,
216        RWin,
217        Semicolon,
218        Slash,
219        Sleep,
220        Stop,
221        Subtract,
222        Sysrq,
223        Tab,
224        Underline,
225        Unlabeled,
226        VolumeDown,
227        VolumeUp,
228        Wake,
229        WebBack,
230        WebFavorites,
231        WebForward,
232        WebHome,
233        WebRefresh,
234        WebSearch,
235        WebStop,
236        Yen,
237        Compose,
238        NavigateForward,
239        NavigateBackward,
240
241        Mouse1 = NUM_KEYS as isize +0,
242        Mouse2 = NUM_KEYS as isize +1,
243        Mouse3 = NUM_KEYS as isize +2,
244        Mouse4 = NUM_KEYS as isize +3,
245        Mouse5 = NUM_KEYS as isize +4,
246        Mouse6 = NUM_KEYS as isize +5,
247        Mouse7 = NUM_KEYS as isize +6,
248        Mouse8 = NUM_KEYS as isize +7,
249        Mouse9 = NUM_KEYS as isize +8,
250        Mouse10 = NUM_KEYS as isize +9,
251        Mouse11 = NUM_KEYS as isize +10,
252        Mouse12 = NUM_KEYS as isize +11,
253        Mouse13 = NUM_KEYS as isize +12,
254        Mouse14 = NUM_KEYS as isize +13,
255        Mouse15 = NUM_KEYS as isize +14,
256        Mouse16 = NUM_KEYS as isize +15,
257
258        Unsupported = (NUM_KEYS + NUM_BUTTONS) as isize,
259    }
260}
261
262impl InputId {
263    pub fn button(id: usize) -> InputId {
264        use enum_primitive::FromPrimitive;
265        let base = InputId::Mouse1 as isize;
266        if (id >= 1) & (id <= 16) {
267            InputId::from_isize(base + (id as isize - 1)).unwrap()
268        } else {
269            InputId::Unsupported
270        }
271    }
272}
273
274/// Basic keyboard and mouse support.
275#[derive(Clone)]
276pub struct Input {
277    pub (crate) input_data: Arc<RwLock<InputData>>,
278}
279
280impl Debug for Input {
281    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
282        write!(f, "Input")
283    }
284}
285
286impl Input {
287
288    /// Creates a new instance.
289    pub fn new(display: &Display) -> Self {
290        Input {
291            input_data: display.input_data.clone(),
292        }
293    }
294
295    /// Returns an iterator over all keys and buttons.
296    pub fn iter(self: &Self) -> InputIterator<'_> {
297        InputIterator {
298            input_data: self.input_data.read().unwrap(),
299            position: 0,
300        }
301    }
302
303    /// Returns current mouse coordinates relative to the window.
304    pub fn mouse(self: &Self) -> (i32, i32) {
305        self.get().mouse
306    }
307
308    /// Returns mouse delta coordinates since last [`Display::poll_events()`](struct.Display.html#method.poll_events).
309    pub fn mouse_delta(self: &Self) -> (i32, i32) {
310        self.get().mouse_delta
311    }
312
313    /// Returns true if given key is down/pressed.
314    pub fn down(self: &Self, key: InputId) -> bool {
315        let id = key as usize;
316        let data = self.get();
317        if id < NUM_KEYS {
318            (data.key[id] == InputState::Pressed) || (data.key[id] == InputState::Down) || (data.key[id] == InputState::Repeat)
319        } else {
320            (data.button[id - NUM_KEYS] == InputState::Pressed) || (data.button[id - NUM_KEYS] == InputState::Down)
321        }
322    }
323
324    /// Returns true if given key was just pressed or repeated due to still being held down (if `report_repeats` is true).
325    pub fn pressed(self: &Self, key: InputId, report_repeats: bool) -> bool {
326        let id = key as usize;
327        let data = self.get();
328        if id < NUM_KEYS {
329            (data.key[id] == InputState::Pressed) || (report_repeats && data.key[id] == InputState::Repeat)
330        } else {
331            data.button[id - NUM_KEYS] == InputState::Pressed
332        }
333    }
334
335    /// Returns true if given key is up/released.
336    pub fn up(self: &Self, key: InputId) -> bool {
337        let id = key as usize;
338        let data = self.get();
339        if id < NUM_KEYS {
340            data.key[id] == InputState::Released || (data.key[id] == InputState::Up)
341        } else {
342            data.button[id - NUM_KEYS] == InputState::Released || (data.button[id - NUM_KEYS] == InputState::Up)
343        }
344    }
345
346    /// Returns true if given key was just released.
347    pub fn released(self: &Self, key: InputId) -> bool {
348        let id = key as usize;
349        let data = self.get();
350        if id < NUM_KEYS {
351            data.key[id] == InputState::Released
352        } else {
353            data.button[id - NUM_KEYS] == InputState::Released
354        }
355    }
356
357    /// Returns InputState for given key.
358    pub fn state(self: &Self, key: InputId) -> InputState {
359        let id = key as usize;
360        let data = self.get();
361        if id < NUM_KEYS {
362            data.key[id]
363        } else {
364            data.button[id - NUM_KEYS]
365        }
366    }
367
368    /// Returns input data.
369    fn get(self: &Self) -> RwLockReadGuard<'_, InputData> {
370        self.input_data.read().unwrap()
371    }
372}
373
374/// An iterator over all keys and buttons.
375pub struct InputIterator<'a> {
376    input_data: RwLockReadGuard<'a, InputData>,
377    position: usize,
378}
379
380impl<'a> InputIterator<'a> {
381    /// Returns an iterator over all keys currently pressed.
382    pub fn down(self: Self) -> InputDownIterator<'a> {
383        InputDownIterator(self)
384    }
385    /// Returns an iterator over all keys not currently pressed.
386    pub fn up(self: Self) -> InputUpIterator<'a> {
387        InputUpIterator(self)
388    }
389}
390
391impl<'a> Iterator for InputIterator<'a> {
392    type Item = (InputId, InputState);
393
394    fn next(self: &mut Self) -> Option<(InputId, InputState)> {
395
396        use enum_primitive::FromPrimitive;
397        let position = self.position;
398        self.position += 1;
399
400        if position < NUM_KEYS {
401            Some((InputId::from_usize(position).unwrap_or(InputId::Unsupported), self.input_data.key[position]))
402        } else if position < NUM_KEYS + NUM_BUTTONS {
403            Some((InputId::from_usize(position).unwrap_or(InputId::Unsupported), self.input_data.button[position - NUM_KEYS]))
404        } else {
405            None
406        }
407    }
408}
409
410/// An iterator over all keys all buttons currently pressed.
411pub struct InputDownIterator<'a>(InputIterator<'a>);
412
413impl<'a> Iterator for InputDownIterator<'a> {
414    type Item = InputId;
415
416    fn next(self: &mut Self) -> Option<InputId> {
417        while let Some(current) = self.0.next() {
418            let (input_id, button_state) = current;
419            if (button_state == InputState::Down) || (button_state == InputState::Pressed) {
420                return Some(input_id);
421            }
422        }
423        None
424    }
425}
426
427/// An iterator over all keys all buttons currently not pressed.
428pub struct InputUpIterator<'a>(InputIterator<'a>);
429
430impl<'a> Iterator for InputUpIterator<'a> {
431    type Item = InputId;
432
433    fn next(self: &mut Self) -> Option<InputId> {
434        while let Some(current) = self.0.next() {
435            let (input_id, button_state) = current;
436            if (button_state == InputState::Up) || (button_state == InputState::Released) {
437                return Some(input_id);
438            }
439        }
440        None
441    }
442}