Skip to main content

anvilkit_input/
input_state.rs

1//! # 输入状态
2//!
3//! 追踪键盘按键和鼠标按钮的当前帧状态和上一帧状态,
4//! 支持 pressed / just_pressed / just_released 查询。
5
6use std::collections::HashSet;
7use bevy_ecs::prelude::*;
8use glam::Vec2;
9
10/// 键盘键码
11///
12/// 常用键的枚举,与 winit VirtualKeyCode 对应。
13///
14/// # 示例
15///
16/// ```rust
17/// use anvilkit_input::input_state::KeyCode;
18/// let key = KeyCode::W;
19/// assert_ne!(key, KeyCode::S);
20/// ```
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum KeyCode {
23    // Letters
24    A, B, C, D, E, F, G, H, I, J, K, L, M,
25    N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
26    // Numbers
27    Key0, Key1, Key2, Key3, Key4,
28    Key5, Key6, Key7, Key8, Key9,
29    // Function keys
30    F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
31    // Special keys
32    Space, Enter, Escape, Tab, Backspace, Delete,
33    Left, Right, Up, Down,
34    LShift, RShift, LControl, RControl, LAlt, RAlt,
35}
36
37impl KeyCode {
38    /// 将 winit KeyCode 映射到 AnvilKit KeyCode
39    pub fn from_winit(key: winit::keyboard::KeyCode) -> Option<KeyCode> {
40        use winit::keyboard::KeyCode as WK;
41        match key {
42            WK::KeyA => Some(KeyCode::A), WK::KeyB => Some(KeyCode::B),
43            WK::KeyC => Some(KeyCode::C), WK::KeyD => Some(KeyCode::D),
44            WK::KeyE => Some(KeyCode::E), WK::KeyF => Some(KeyCode::F),
45            WK::KeyG => Some(KeyCode::G), WK::KeyH => Some(KeyCode::H),
46            WK::KeyI => Some(KeyCode::I), WK::KeyJ => Some(KeyCode::J),
47            WK::KeyK => Some(KeyCode::K), WK::KeyL => Some(KeyCode::L),
48            WK::KeyM => Some(KeyCode::M), WK::KeyN => Some(KeyCode::N),
49            WK::KeyO => Some(KeyCode::O), WK::KeyP => Some(KeyCode::P),
50            WK::KeyQ => Some(KeyCode::Q), WK::KeyR => Some(KeyCode::R),
51            WK::KeyS => Some(KeyCode::S), WK::KeyT => Some(KeyCode::T),
52            WK::KeyU => Some(KeyCode::U), WK::KeyV => Some(KeyCode::V),
53            WK::KeyW => Some(KeyCode::W), WK::KeyX => Some(KeyCode::X),
54            WK::KeyY => Some(KeyCode::Y), WK::KeyZ => Some(KeyCode::Z),
55            WK::Digit0 => Some(KeyCode::Key0), WK::Digit1 => Some(KeyCode::Key1),
56            WK::Digit2 => Some(KeyCode::Key2), WK::Digit3 => Some(KeyCode::Key3),
57            WK::Digit4 => Some(KeyCode::Key4), WK::Digit5 => Some(KeyCode::Key5),
58            WK::Digit6 => Some(KeyCode::Key6), WK::Digit7 => Some(KeyCode::Key7),
59            WK::Digit8 => Some(KeyCode::Key8), WK::Digit9 => Some(KeyCode::Key9),
60            WK::F1 => Some(KeyCode::F1), WK::F2 => Some(KeyCode::F2),
61            WK::F3 => Some(KeyCode::F3), WK::F4 => Some(KeyCode::F4),
62            WK::F5 => Some(KeyCode::F5), WK::F6 => Some(KeyCode::F6),
63            WK::F7 => Some(KeyCode::F7), WK::F8 => Some(KeyCode::F8),
64            WK::F9 => Some(KeyCode::F9), WK::F10 => Some(KeyCode::F10),
65            WK::F11 => Some(KeyCode::F11), WK::F12 => Some(KeyCode::F12),
66            WK::Space => Some(KeyCode::Space), WK::Enter => Some(KeyCode::Enter),
67            WK::Escape => Some(KeyCode::Escape), WK::Tab => Some(KeyCode::Tab),
68            WK::Backspace => Some(KeyCode::Backspace), WK::Delete => Some(KeyCode::Delete),
69            WK::ArrowLeft => Some(KeyCode::Left), WK::ArrowRight => Some(KeyCode::Right),
70            WK::ArrowUp => Some(KeyCode::Up), WK::ArrowDown => Some(KeyCode::Down),
71            WK::ShiftLeft => Some(KeyCode::LShift), WK::ShiftRight => Some(KeyCode::RShift),
72            WK::ControlLeft => Some(KeyCode::LControl), WK::ControlRight => Some(KeyCode::RControl),
73            WK::AltLeft => Some(KeyCode::LAlt), WK::AltRight => Some(KeyCode::RAlt),
74            _ => None,
75        }
76    }
77}
78
79/// 鼠标按钮
80///
81/// # 示例
82///
83/// ```rust
84/// use anvilkit_input::input_state::MouseButton;
85/// let btn = MouseButton::Left;
86/// assert_ne!(btn, MouseButton::Right);
87/// ```
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
89pub enum MouseButton {
90    Left,
91    Right,
92    Middle,
93}
94
95impl MouseButton {
96    /// 将 winit MouseButton 映射到 AnvilKit MouseButton
97    pub fn from_winit(button: winit::event::MouseButton) -> Option<MouseButton> {
98        match button {
99            winit::event::MouseButton::Left => Some(MouseButton::Left),
100            winit::event::MouseButton::Right => Some(MouseButton::Right),
101            winit::event::MouseButton::Middle => Some(MouseButton::Middle),
102            _ => None,
103        }
104    }
105}
106
107/// 输入状态资源
108///
109/// 每帧追踪键盘和鼠标的完整输入状态。
110/// 支持 pressed(持续按下)、just_pressed(本帧按下)、just_released(本帧松开)查询。
111///
112/// # 示例
113///
114/// ```rust
115/// use anvilkit_input::input_state::{InputState, KeyCode, MouseButton};
116///
117/// let mut input = InputState::new();
118///
119/// // 模拟按键
120/// input.press_key(KeyCode::W);
121/// assert!(input.is_key_pressed(KeyCode::W));
122/// assert!(input.is_key_just_pressed(KeyCode::W));
123///
124/// // 帧结束
125/// input.end_frame();
126/// assert!(input.is_key_pressed(KeyCode::W));
127/// assert!(!input.is_key_just_pressed(KeyCode::W));
128///
129/// // 松开
130/// input.release_key(KeyCode::W);
131/// assert!(!input.is_key_pressed(KeyCode::W));
132/// assert!(input.is_key_just_released(KeyCode::W));
133/// ```
134#[derive(Resource)]
135pub struct InputState {
136    /// 当前帧按下的键
137    keys_pressed: HashSet<KeyCode>,
138    /// 本帧新按下的键
139    keys_just_pressed: HashSet<KeyCode>,
140    /// 本帧刚松开的键
141    keys_just_released: HashSet<KeyCode>,
142
143    /// 当前帧按下的鼠标按钮
144    mouse_pressed: HashSet<MouseButton>,
145    /// 本帧新按下的鼠标按钮
146    mouse_just_pressed: HashSet<MouseButton>,
147    /// 本帧刚松开的鼠标按钮
148    mouse_just_released: HashSet<MouseButton>,
149
150    /// 鼠标位置(像素坐标)
151    mouse_position: Vec2,
152    /// 鼠标本帧移动量(像素)
153    mouse_delta: Vec2,
154    /// 滚轮本帧滚动量(行数)
155    scroll_delta: f32,
156}
157
158impl InputState {
159    /// 创建空的输入状态
160    pub fn new() -> Self {
161        Self {
162            keys_pressed: HashSet::new(),
163            keys_just_pressed: HashSet::new(),
164            keys_just_released: HashSet::new(),
165            mouse_pressed: HashSet::new(),
166            mouse_just_pressed: HashSet::new(),
167            mouse_just_released: HashSet::new(),
168            mouse_position: Vec2::ZERO,
169            mouse_delta: Vec2::ZERO,
170            scroll_delta: 0.0,
171        }
172    }
173
174    // --- Keyboard ---
175
176    /// 记录按键按下
177    pub fn press_key(&mut self, key: KeyCode) {
178        if self.keys_pressed.insert(key) {
179            self.keys_just_pressed.insert(key);
180        }
181    }
182
183    /// 记录按键松开
184    pub fn release_key(&mut self, key: KeyCode) {
185        if self.keys_pressed.remove(&key) {
186            self.keys_just_released.insert(key);
187        }
188    }
189
190    /// 键是否正在按下
191    pub fn is_key_pressed(&self, key: KeyCode) -> bool {
192        self.keys_pressed.contains(&key)
193    }
194
195    /// 键是否本帧刚按下
196    pub fn is_key_just_pressed(&self, key: KeyCode) -> bool {
197        self.keys_just_pressed.contains(&key)
198    }
199
200    /// 键是否本帧刚松开
201    pub fn is_key_just_released(&self, key: KeyCode) -> bool {
202        self.keys_just_released.contains(&key)
203    }
204
205    // --- Mouse buttons ---
206
207    /// 记录鼠标按钮按下
208    pub fn press_mouse(&mut self, button: MouseButton) {
209        if self.mouse_pressed.insert(button) {
210            self.mouse_just_pressed.insert(button);
211        }
212    }
213
214    /// 记录鼠标按钮松开
215    pub fn release_mouse(&mut self, button: MouseButton) {
216        if self.mouse_pressed.remove(&button) {
217            self.mouse_just_released.insert(button);
218        }
219    }
220
221    /// 鼠标按钮是否正在按下
222    pub fn is_mouse_pressed(&self, button: MouseButton) -> bool {
223        self.mouse_pressed.contains(&button)
224    }
225
226    /// 鼠标按钮是否本帧刚按下
227    pub fn is_mouse_just_pressed(&self, button: MouseButton) -> bool {
228        self.mouse_just_pressed.contains(&button)
229    }
230
231    /// 鼠标按钮是否本帧刚松开
232    pub fn is_mouse_just_released(&self, button: MouseButton) -> bool {
233        self.mouse_just_released.contains(&button)
234    }
235
236    // --- Mouse position/motion ---
237
238    /// 设置鼠标位置
239    pub fn set_mouse_position(&mut self, position: Vec2) {
240        self.mouse_position = position;
241    }
242
243    /// 累加鼠标移动量
244    pub fn add_mouse_delta(&mut self, delta: Vec2) {
245        self.mouse_delta += delta;
246    }
247
248    /// 获取鼠标位置
249    pub fn mouse_position(&self) -> Vec2 {
250        self.mouse_position
251    }
252
253    /// 获取本帧鼠标移动量
254    pub fn mouse_delta(&self) -> Vec2 {
255        self.mouse_delta
256    }
257
258    /// 累加滚轮滚动量
259    pub fn add_scroll_delta(&mut self, delta: f32) {
260        self.scroll_delta += delta;
261    }
262
263    /// 获取本帧滚轮滚动量
264    pub fn scroll_delta(&self) -> f32 {
265        self.scroll_delta
266    }
267
268    // --- Frame lifecycle ---
269
270    /// 帧结束,清除 just_pressed / just_released / delta 状态
271    pub fn end_frame(&mut self) {
272        self.keys_just_pressed.clear();
273        self.keys_just_released.clear();
274        self.mouse_just_pressed.clear();
275        self.mouse_just_released.clear();
276        self.mouse_delta = Vec2::ZERO;
277        self.scroll_delta = 0.0;
278    }
279
280    /// 获取当前按下的所有键
281    pub fn pressed_keys(&self) -> &HashSet<KeyCode> {
282        &self.keys_pressed
283    }
284}
285
286impl Default for InputState {
287    fn default() -> Self {
288        Self::new()
289    }
290}
291
292#[cfg(test)]
293mod tests {
294    use super::*;
295
296    #[test]
297    fn test_key_press_release() {
298        let mut input = InputState::new();
299
300        input.press_key(KeyCode::W);
301        assert!(input.is_key_pressed(KeyCode::W));
302        assert!(input.is_key_just_pressed(KeyCode::W));
303        assert!(!input.is_key_just_released(KeyCode::W));
304
305        input.end_frame();
306        assert!(input.is_key_pressed(KeyCode::W));
307        assert!(!input.is_key_just_pressed(KeyCode::W));
308
309        input.release_key(KeyCode::W);
310        assert!(!input.is_key_pressed(KeyCode::W));
311        assert!(input.is_key_just_released(KeyCode::W));
312
313        input.end_frame();
314        assert!(!input.is_key_just_released(KeyCode::W));
315    }
316
317    #[test]
318    fn test_mouse_buttons() {
319        let mut input = InputState::new();
320
321        input.press_mouse(MouseButton::Left);
322        assert!(input.is_mouse_pressed(MouseButton::Left));
323        assert!(input.is_mouse_just_pressed(MouseButton::Left));
324
325        input.end_frame();
326        assert!(input.is_mouse_pressed(MouseButton::Left));
327        assert!(!input.is_mouse_just_pressed(MouseButton::Left));
328    }
329
330    #[test]
331    fn test_mouse_delta() {
332        let mut input = InputState::new();
333        input.add_mouse_delta(Vec2::new(5.0, 3.0));
334        input.add_mouse_delta(Vec2::new(2.0, -1.0));
335        assert_eq!(input.mouse_delta(), Vec2::new(7.0, 2.0));
336
337        input.end_frame();
338        assert_eq!(input.mouse_delta(), Vec2::ZERO);
339    }
340
341    #[test]
342    fn test_scroll_delta() {
343        let mut input = InputState::new();
344        input.add_scroll_delta(1.5);
345        input.add_scroll_delta(-0.5);
346        assert_eq!(input.scroll_delta(), 1.0);
347
348        input.end_frame();
349        assert_eq!(input.scroll_delta(), 0.0);
350    }
351
352    #[test]
353    fn test_duplicate_press() {
354        let mut input = InputState::new();
355        input.press_key(KeyCode::A);
356        input.press_key(KeyCode::A); // duplicate
357        assert_eq!(input.pressed_keys().len(), 1);
358    }
359}