1use optic_core::{NetworkEvents, Size2D};
2
3use crate::window::Window;
4use gilrs;
5use winit::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent};
6use winit::keyboard::{ModifiersState, PhysicalKey};
7pub use winit::keyboard::KeyCode;
8
9#[derive(Copy, Clone)]
16pub struct ButtonState {
17 pub held: bool,
18 pub press_frame: u64,
19 pub release_frame: u64,
20}
21
22#[derive(Debug, Clone, Copy)]
33pub enum Is {
34 Pressed,
35 Released,
36 Held,
37}
38
39#[derive(Debug, Clone, Copy)]
41pub enum Mouse {
42 Left,
43 Right,
44 Middle,
45 Back,
46 Forward,
47 Other(u16),
48}
49
50fn mouse_index(m: &Mouse) -> usize {
51 match m {
52 Mouse::Left => 0,
53 Mouse::Right => 1,
54 Mouse::Middle => 2,
55 Mouse::Back => 3,
56 Mouse::Forward => 4,
57 Mouse::Other(n) => (5 + *n as usize).min(7),
58 }
59}
60
61fn key_index(kc: &KeyCode) -> usize {
62 match kc {
63 KeyCode::KeyA => 0, KeyCode::KeyB => 1, KeyCode::KeyC => 2, KeyCode::KeyD => 3,
64 KeyCode::KeyE => 4, KeyCode::KeyF => 5, KeyCode::KeyG => 6, KeyCode::KeyH => 7,
65 KeyCode::KeyI => 8, KeyCode::KeyJ => 9, KeyCode::KeyK => 10, KeyCode::KeyL => 11,
66 KeyCode::KeyM => 12, KeyCode::KeyN => 13, KeyCode::KeyO => 14, KeyCode::KeyP => 15,
67 KeyCode::KeyQ => 16, KeyCode::KeyR => 17, KeyCode::KeyS => 18, KeyCode::KeyT => 19,
68 KeyCode::KeyU => 20, KeyCode::KeyV => 21, KeyCode::KeyW => 22, KeyCode::KeyX => 23,
69 KeyCode::KeyY => 24, KeyCode::KeyZ => 25,
70 KeyCode::Digit0 => 26, KeyCode::Digit1 => 27, KeyCode::Digit2 => 28, KeyCode::Digit3 => 29,
71 KeyCode::Digit4 => 30, KeyCode::Digit5 => 31, KeyCode::Digit6 => 32, KeyCode::Digit7 => 33,
72 KeyCode::Digit8 => 34, KeyCode::Digit9 => 35,
73 KeyCode::F1 => 36, KeyCode::F2 => 37, KeyCode::F3 => 38, KeyCode::F4 => 39,
74 KeyCode::F5 => 40, KeyCode::F6 => 41, KeyCode::F7 => 42, KeyCode::F8 => 43,
75 KeyCode::F9 => 44, KeyCode::F10 => 45, KeyCode::F11 => 46, KeyCode::F12 => 47,
76 KeyCode::F13 => 48, KeyCode::F14 => 49, KeyCode::F15 => 50, KeyCode::F16 => 51,
77 KeyCode::F17 => 52, KeyCode::F18 => 53, KeyCode::F19 => 54, KeyCode::F20 => 55,
78 KeyCode::F21 => 56, KeyCode::F22 => 57, KeyCode::F23 => 58, KeyCode::F24 => 59,
79 KeyCode::Escape => 60,
80 KeyCode::Enter => 61, KeyCode::Tab => 62, KeyCode::Space => 63, KeyCode::Backspace => 64,
81 KeyCode::Delete => 65, KeyCode::Insert => 66,
82 KeyCode::Home => 67, KeyCode::End => 68,
83 KeyCode::PageUp => 69, KeyCode::PageDown => 70,
84 KeyCode::ArrowUp => 71, KeyCode::ArrowDown => 72, KeyCode::ArrowLeft => 73, KeyCode::ArrowRight => 74,
85 KeyCode::ShiftLeft => 75, KeyCode::ShiftRight => 76,
86 KeyCode::ControlLeft => 77, KeyCode::ControlRight => 78,
87 KeyCode::AltLeft => 79, KeyCode::AltRight => 80,
88 KeyCode::SuperLeft => 81, KeyCode::SuperRight => 82,
89 KeyCode::CapsLock => 83, KeyCode::ScrollLock => 84, KeyCode::NumLock => 85,
90 KeyCode::PrintScreen => 86, KeyCode::Pause => 87,
91 KeyCode::Minus => 88, KeyCode::Equal => 89,
92 KeyCode::BracketLeft => 90, KeyCode::BracketRight => 91,
93 KeyCode::Semicolon => 92, KeyCode::Quote => 93, KeyCode::Comma => 94, KeyCode::Period => 95, KeyCode::Slash => 96,
94 KeyCode::Backslash => 97, KeyCode::IntlBackslash => 98,
95 KeyCode::Numpad0 => 99, KeyCode::Numpad1 => 100, KeyCode::Numpad2 => 101, KeyCode::Numpad3 => 102,
96 KeyCode::Numpad4 => 103, KeyCode::Numpad5 => 104, KeyCode::Numpad6 => 105, KeyCode::Numpad7 => 106,
97 KeyCode::Numpad8 => 107, KeyCode::Numpad9 => 108,
98 KeyCode::NumpadDecimal => 109, KeyCode::NumpadDivide => 110, KeyCode::NumpadMultiply => 111,
99 KeyCode::NumpadSubtract => 112, KeyCode::NumpadAdd => 113, KeyCode::NumpadEnter => 114, KeyCode::NumpadEqual => 115,
100 KeyCode::ContextMenu => 116,
101 _ => 255,
102 }
103}
104
105fn mouse_from_winit(b: MouseButton) -> Mouse {
106 match b {
107 MouseButton::Left => Mouse::Left,
108 MouseButton::Right => Mouse::Right,
109 MouseButton::Middle => Mouse::Middle,
110 MouseButton::Back => Mouse::Back,
111 MouseButton::Forward => Mouse::Forward,
112 MouseButton::Other(n) => Mouse::Other(n),
113 }
114}
115
116fn check_state(s: &ButtonState, action: Is, frame: u64) -> bool {
117 match action {
118 Is::Pressed => s.press_frame == frame,
119 Is::Released => s.release_frame == frame,
120 Is::Held => s.held,
121 }
122}
123
124pub const MAX_GAMEPADS: usize = 4;
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum GamepadButton {
130 A, B, X, Y,
131 LB, RB, LT, RT,
132 Back, Start, Guide,
133 LeftStick, RightStick,
134 DPadUp, DPadDown, DPadLeft, DPadRight,
135 Other(u8),
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140pub enum GamepadAxis {
141 LeftX, LeftY,
142 RightX, RightY,
143 LeftTrigger, RightTrigger,
144}
145
146fn gamepad_button_index(b: &GamepadButton) -> usize {
147 match b {
148 GamepadButton::A => 0,
149 GamepadButton::B => 1,
150 GamepadButton::X => 2,
151 GamepadButton::Y => 3,
152 GamepadButton::LB => 4,
153 GamepadButton::RB => 5,
154 GamepadButton::LT => 6,
155 GamepadButton::RT => 7,
156 GamepadButton::Back => 8,
157 GamepadButton::Start => 9,
158 GamepadButton::Guide => 10,
159 GamepadButton::LeftStick => 11,
160 GamepadButton::RightStick => 12,
161 GamepadButton::DPadUp => 13,
162 GamepadButton::DPadDown => 14,
163 GamepadButton::DPadLeft => 15,
164 GamepadButton::DPadRight => 16,
165 GamepadButton::Other(n) => 17 + (*n as usize).min(2),
166 }
167}
168
169fn gamepad_axis_index(a: &GamepadAxis) -> usize {
170 match a {
171 GamepadAxis::LeftX => 0,
172 GamepadAxis::LeftY => 1,
173 GamepadAxis::RightX => 2,
174 GamepadAxis::RightY => 3,
175 GamepadAxis::LeftTrigger => 4,
176 GamepadAxis::RightTrigger => 5,
177 }
178}
179
180fn gamepad_button_from_gilrs(b: gilrs::Button) -> GamepadButton {
181 use gilrs::Button;
182 match b {
183 Button::South => GamepadButton::A,
184 Button::East => GamepadButton::B,
185 Button::West => GamepadButton::X,
186 Button::North => GamepadButton::Y,
187 Button::LeftTrigger => GamepadButton::LB,
188 Button::RightTrigger => GamepadButton::RB,
189 Button::LeftTrigger2 => GamepadButton::LT,
190 Button::RightTrigger2 => GamepadButton::RT,
191 Button::Select => GamepadButton::Back,
192 Button::Start => GamepadButton::Start,
193 Button::Mode => GamepadButton::Guide,
194 Button::LeftThumb => GamepadButton::LeftStick,
195 Button::RightThumb => GamepadButton::RightStick,
196 Button::DPadUp => GamepadButton::DPadUp,
197 Button::DPadDown => GamepadButton::DPadDown,
198 Button::DPadLeft => GamepadButton::DPadLeft,
199 Button::DPadRight => GamepadButton::DPadRight,
200 Button::Unknown => GamepadButton::Other(0),
201 _ => GamepadButton::Other(1),
202 }
203}
204
205fn gamepad_axis_from_gilrs(a: gilrs::Axis) -> GamepadAxis {
206 use gilrs::Axis;
207 match a {
208 Axis::LeftStickX => GamepadAxis::LeftX,
209 Axis::LeftStickY => GamepadAxis::LeftY,
210 Axis::RightStickX => GamepadAxis::RightX,
211 Axis::RightStickY => GamepadAxis::RightY,
212 Axis::LeftZ => GamepadAxis::LeftTrigger,
213 Axis::RightZ => GamepadAxis::RightTrigger,
214 _ => GamepadAxis::LeftX,
215 }
216}
217
218pub struct Events {
263 pub keys: [ButtonState; 256],
264 pub mouse_buttons: [ButtonState; 8],
265 pub mouse_scroll_line: Option<(f32, f32)>,
266 pub mouse_scroll_pixel: Option<(f64, f64)>,
267 pub modifiers: ModifiersState,
268 pub gamepad_connected: [bool; MAX_GAMEPADS],
269 pub gamepad_buttons: [[ButtonState; 20]; MAX_GAMEPADS],
270 pub gamepad_axes: [[f32; 6]; MAX_GAMEPADS],
271 pub resize_event: Option<Size2D>,
272 pub close_requested: bool,
273 pub focused: bool,
274 pub frame: u64,
275 pub network: NetworkEvents,
276}
277
278fn empty_buttons<const N: usize>() -> [ButtonState; N] {
279 [ButtonState { held: false, press_frame: 0, release_frame: 0 }; N]
280}
281
282impl Events {
283 pub fn new() -> Self {
285 Self {
286 keys: empty_buttons::<256>(),
287 mouse_buttons: empty_buttons::<8>(),
288 mouse_scroll_line: None,
289 mouse_scroll_pixel: None,
290 modifiers: ModifiersState::default(),
291 gamepad_connected: [false; MAX_GAMEPADS],
292 gamepad_buttons: [empty_buttons::<20>(); MAX_GAMEPADS],
293 gamepad_axes: [[0.0f32; 6]; MAX_GAMEPADS],
294 resize_event: None,
295 close_requested: false,
296 focused: true,
297 frame: 1,
298 network: NetworkEvents::default(),
299 }
300 }
301
302 pub fn clear(&mut self) {
304 self.keys = empty_buttons::<256>();
305 self.mouse_buttons = empty_buttons::<8>();
306 self.mouse_scroll_line = None;
307 self.mouse_scroll_pixel = None;
308 self.gamepad_buttons = [empty_buttons::<20>(); MAX_GAMEPADS];
309 self.gamepad_axes = [[0.0f32; 6]; MAX_GAMEPADS];
310 self.resize_event = None;
311 self.close_requested = false;
312 self.focused = true;
313 self.frame = 1;
314 self.network = NetworkEvents::default();
315 }
316
317 pub fn process_window_event(&mut self, event: &WindowEvent, _window: &Window) {
323 match event {
324 WindowEvent::KeyboardInput { event, .. } => {
325 if let PhysicalKey::Code(kc) = event.physical_key {
326 let idx = key_index(&kc);
327 if idx < 256 {
328 let s = &mut self.keys[idx];
329 match event.state {
330 ElementState::Pressed => {
331 if !s.held {
332 s.press_frame = self.frame;
333 }
334 s.held = true;
335 }
336 ElementState::Released => {
337 if s.held {
338 s.release_frame = self.frame;
339 }
340 s.held = false;
341 }
342 }
343 }
344 }
345 }
346 WindowEvent::MouseInput { button, state, .. } => {
347 let m = mouse_from_winit(*button);
348 let idx = mouse_index(&m);
349 if idx < 8 {
350 let s = &mut self.mouse_buttons[idx];
351 match state {
352 ElementState::Pressed => {
353 if !s.held {
354 s.press_frame = self.frame;
355 }
356 s.held = true;
357 }
358 ElementState::Released => {
359 if s.held {
360 s.release_frame = self.frame;
361 }
362 s.held = false;
363 }
364 }
365 }
366 }
367 WindowEvent::MouseWheel { delta, phase: TouchPhase::Moved, .. }
368 | WindowEvent::MouseWheel { delta, phase: TouchPhase::Started, .. } => {
369 match delta {
370 MouseScrollDelta::LineDelta(x, y) => {
371 self.mouse_scroll_line = Some((*x, *y));
372 }
373 MouseScrollDelta::PixelDelta(p) => {
374 self.mouse_scroll_pixel = Some((p.x, p.y));
375 }
376 }
377 }
378 WindowEvent::Resized(size) => {
379 self.resize_event = Some(Size2D::from(size.width, size.height));
380 }
381 WindowEvent::CloseRequested => {
382 self.close_requested = true;
383 }
384 WindowEvent::Focused(yes) => {
385 self.focused = *yes;
386 }
387 WindowEvent::ModifiersChanged(mods) => {
388 self.modifiers = mods.state();
389 }
390 _ => {}
391 }
392 }
393
394 pub fn process_gilrs_event(&mut self, event: &gilrs::Event) {
396 let idx: usize = event.id.into();
397 if idx >= MAX_GAMEPADS { return; }
398
399 match &event.event {
400 gilrs::EventType::Connected => {
401 self.gamepad_connected[idx] = true;
402 }
403 gilrs::EventType::Disconnected => {
404 self.gamepad_connected[idx] = false;
405 self.gamepad_buttons[idx] = empty_buttons::<20>();
406 self.gamepad_axes[idx] = [0.0f32; 6];
407 }
408 gilrs::EventType::ButtonPressed(button, _) => {
409 let gp = gamepad_button_from_gilrs(*button);
410 let bi = gamepad_button_index(&gp);
411 let pad_btns: &mut [ButtonState; 20] = &mut self.gamepad_buttons[idx];
412 if bi < 20 {
413 if !pad_btns[bi].held {
414 pad_btns[bi].press_frame = self.frame;
415 }
416 pad_btns[bi].held = true;
417 }
418 }
419 gilrs::EventType::ButtonRepeated(button, _) => {
420 let gp = gamepad_button_from_gilrs(*button);
421 let bi = gamepad_button_index(&gp);
422 let pad_btns: &mut [ButtonState; 20] = &mut self.gamepad_buttons[idx];
423 if bi < 20 {
424 pad_btns[bi].press_frame = self.frame;
425 }
426 }
427 gilrs::EventType::ButtonReleased(button, _) => {
428 let gp = gamepad_button_from_gilrs(*button);
429 let bi = gamepad_button_index(&gp);
430 let pad_btns: &mut [ButtonState; 20] = &mut self.gamepad_buttons[idx];
431 if bi < 20 {
432 if pad_btns[bi].held {
433 pad_btns[bi].release_frame = self.frame;
434 }
435 pad_btns[bi].held = false;
436 }
437 }
438 gilrs::EventType::AxisChanged(axis, val, _) => {
439 let ga = gamepad_axis_from_gilrs(*axis);
440 let ai = gamepad_axis_index(&ga);
441 let axes: &mut [f32; 6] = &mut self.gamepad_axes[idx];
442 if ai < 6 {
443 axes[ai] = *val;
444 }
445 }
446 _ => {}
447 }
448 }
449
450 pub fn end_frame(&mut self) {
456 self.frame += 1;
457 self.mouse_scroll_line = None;
458 self.mouse_scroll_pixel = None;
459 self.resize_event = None;
460 self.network.packets.clear();
461 self.network.peers_connected.clear();
462 self.network.peers_disconnected.clear();
463 }
464
465 pub fn key(&self, kc: KeyCode, action: Is) -> bool {
469 let idx = key_index(&kc);
470 if idx >= 256 { return false; }
471 check_state(&self.keys[idx], action, self.frame)
472 }
473
474 pub fn key_combo(&self, primary: KeyCode, modifier: KeyCode, action: Is) -> bool {
485 self.key(primary, action) && self.key(modifier, Is::Held)
486 }
487
488 pub fn key_combo_n(&self, keys: &[(KeyCode, Is)]) -> bool {
490 keys.iter().all(|(kc, action)| self.key(*kc, *action))
491 }
492
493 pub fn any_key(&self, action: Is) -> bool {
495 self.keys.iter().any(|s| check_state(s, action, self.frame))
496 }
497
498 pub fn mouse(&self, m: Mouse, action: Is) -> bool {
502 let idx = mouse_index(&m);
503 if idx >= 8 { return false; }
504 check_state(&self.mouse_buttons[idx], action, self.frame)
505 }
506
507 pub fn any_mouse(&self, action: Is) -> bool {
509 self.mouse_buttons.iter().any(|s| check_state(s, action, self.frame))
510 }
511
512 pub const GAMEPAD_AXIS_DEADZONE: f32 = 0.15;
516
517 pub fn gamepad_connected(&self, id: usize) -> bool {
519 if id >= MAX_GAMEPADS { return false; }
520 self.gamepad_connected[id]
521 }
522
523 pub fn gamepad_count(&self) -> usize {
525 self.gamepad_connected.iter().filter(|c| **c).count()
526 }
527
528 pub fn gamepad_button(&self, id: usize, button: GamepadButton, action: Is) -> bool {
530 if id >= MAX_GAMEPADS { return false; }
531 let idx = gamepad_button_index(&button);
532 if idx >= 20 { return false; }
533 check_state(&self.gamepad_buttons[id][idx], action, self.frame)
534 }
535
536 pub fn any_gamepad_button(&self, id: usize, action: Is) -> bool {
538 if id >= MAX_GAMEPADS { return false; }
539 self.gamepad_buttons[id].iter().any(|s| check_state(s, action, self.frame))
540 }
541
542 pub fn any_gamepad(&self, action: Is) -> bool {
544 for id in 0..MAX_GAMEPADS {
545 if self.gamepad_connected[id] && self.any_gamepad_button(id, action) {
546 return true;
547 }
548 }
549 false
550 }
551
552 pub fn gamepad_axis_raw(&self, id: usize, axis: GamepadAxis) -> f32 {
554 if id >= MAX_GAMEPADS { return 0.0; }
555 let idx = gamepad_axis_index(&axis);
556 if idx >= 6 { return 0.0; }
557 self.gamepad_axes[id][idx]
558 }
559
560 pub fn gamepad_axis(&self, id: usize, axis: GamepadAxis) -> f32 {
564 let v = self.gamepad_axis_raw(id, axis);
565 if v.abs() < Self::GAMEPAD_AXIS_DEADZONE { 0.0 } else { v }
566 }
567
568 pub fn gamepad_axis_deadzoned(&self, id: usize, axis: GamepadAxis, deadzone: f32) -> f32 {
570 let v = self.gamepad_axis_raw(id, axis);
571 if v.abs() < deadzone { 0.0 } else { v }
572 }
573}