Skip to main content

dotzuki_renderer/
input.rs

1#[cfg(feature = "gpu")]
2use winit::keyboard::KeyCode;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5#[repr(u8)]
6pub enum GbButton {
7    A = 0,
8    B = 1,
9    Select = 2,
10    Start = 3,
11    Right = 4,
12    Left = 5,
13    Up = 6,
14    Down = 7,
15}
16
17impl GbButton {
18    pub const ALL: [GbButton; 8] = [
19        GbButton::A,
20        GbButton::B,
21        GbButton::Select,
22        GbButton::Start,
23        GbButton::Right,
24        GbButton::Left,
25        GbButton::Up,
26        GbButton::Down,
27    ];
28
29    pub fn bit_mask(self) -> u8 {
30        1 << (self as u8)
31    }
32}
33
34#[derive(Debug, Clone)]
35pub struct InputState {
36    current: u8,
37    previous: u8,
38}
39
40impl InputState {
41    pub fn new() -> Self {
42        Self {
43            current: 0,
44            previous: 0,
45        }
46    }
47
48    pub fn is_held(&self, button: GbButton) -> bool {
49        self.current & button.bit_mask() != 0
50    }
51
52    pub fn is_just_pressed(&self, button: GbButton) -> bool {
53        let mask = button.bit_mask();
54        (self.current & mask != 0) && (self.previous & mask == 0)
55    }
56
57    pub fn is_just_released(&self, button: GbButton) -> bool {
58        let mask = button.bit_mask();
59        (self.current & mask == 0) && (self.previous & mask != 0)
60    }
61
62    pub fn any_held(&self) -> bool {
63        self.current != 0
64    }
65
66    pub fn any_just_pressed(&self) -> bool {
67        (self.current & !self.previous) != 0
68    }
69
70    pub fn raw_current(&self) -> u8 {
71        self.current
72    }
73
74    pub fn raw_previous(&self) -> u8 {
75        self.previous
76    }
77
78    pub fn begin_frame(&mut self) {
79        self.previous = self.current;
80    }
81
82    pub fn press(&mut self, button: GbButton) {
83        self.current |= button.bit_mask();
84    }
85
86    pub fn release(&mut self, button: GbButton) {
87        self.current &= !button.bit_mask();
88    }
89
90    #[cfg(feature = "gpu")]
91    pub fn set_from_keycode(&mut self, keycode: KeyCode, pressed: bool) {
92        if let Some(button) = keycode_to_gb_button(keycode) {
93            if pressed {
94                self.press(button);
95            } else {
96                self.release(button);
97            }
98        }
99    }
100
101    pub fn clear(&mut self) {
102        self.current = 0;
103        self.previous = 0;
104    }
105
106    pub fn set_from_bitmask(&mut self, mask: u8) {
107        self.current = mask;
108    }
109}
110
111impl Default for InputState {
112    fn default() -> Self {
113        Self::new()
114    }
115}
116
117#[cfg(feature = "gpu")]
118pub fn keycode_to_gb_button(keycode: KeyCode) -> Option<GbButton> {
119    match keycode {
120        // Arrow keys / WASD → D-pad
121        KeyCode::ArrowUp | KeyCode::KeyW => Some(GbButton::Up),
122        KeyCode::ArrowDown | KeyCode::KeyS => Some(GbButton::Down),
123        KeyCode::ArrowLeft | KeyCode::KeyA => Some(GbButton::Left),
124        KeyCode::ArrowRight | KeyCode::KeyD => Some(GbButton::Right),
125        // Z → A button, X → B button
126        KeyCode::KeyZ => Some(GbButton::A),
127        KeyCode::KeyX => Some(GbButton::B),
128        // Enter/Space → Start, Backspace/RightShift → Select
129        KeyCode::Enter | KeyCode::Space => Some(GbButton::Start),
130        KeyCode::Backspace | KeyCode::ShiftRight => Some(GbButton::Select),
131        _ => None,
132    }
133}