1use gilrs::{Axis, Button, Event, Gilrs};
2use winit::event::{ElementState, MouseButton, WindowEvent};
3use winit::keyboard::{Key, NamedKey};
4
5const LEFT: usize = 0;
7const RIGHT: usize = 1;
8const UP: usize = 2;
9const DOWN: usize = 3;
10
11#[derive(Clone, Copy)]
18struct ArrowRepeat {
19 held: bool,
21 timer: f32,
23}
24
25impl ArrowRepeat {
26 const fn new() -> Self {
27 Self {
28 held: false,
29 timer: 0.0,
30 }
31 }
32}
33
34pub struct Input {
43 pub gilrs: Option<Gilrs>,
46
47 pub mouse_x: f32,
49 pub mouse_y: f32,
51
52 pub left_pressed: bool,
54 pub left_just_pressed: bool,
56 pub left_just_released: bool,
58
59 pub scroll_delta: f32,
61
62 pub text_input: Vec<char>,
64
65 pub backspace: bool,
67 pub enter: bool,
69 pub escape: bool,
71 pub tab: bool,
73
74 pub arrow_left: bool,
76 pub arrow_right: bool,
78 pub arrow_up: bool,
80 pub arrow_down: bool,
82
83 pub shift: bool,
85 pub ctrl: bool,
87
88 pub key_a: bool,
90 pub key_c: bool,
92 pub key_x: bool,
94 pub key_v: bool,
96
97 pub space: bool,
99 pub home: bool,
101
102 pub last_hw_key: Option<std::time::Instant>,
104
105 arrows: [ArrowRepeat; 4],
108}
109
110impl Default for Input {
111 fn default() -> Self {
112 Self::new()
113 }
114}
115
116impl Input {
117 #[must_use]
119 pub const fn new() -> Self {
120 Self {
121 gilrs: None,
122 mouse_x: 0.0,
123 mouse_y: 0.0,
124 left_pressed: false,
125 left_just_pressed: false,
126 left_just_released: false,
127 scroll_delta: 0.0,
128 text_input: Vec::new(),
129 backspace: false,
130 enter: false,
131 escape: false,
132 tab: false,
133 arrow_left: false,
134 arrow_right: false,
135 arrow_up: false,
136 arrow_down: false,
137 shift: false,
138 ctrl: false,
139 key_a: false,
140 key_c: false,
141 key_x: false,
142 key_v: false,
143 space: false,
144 home: false,
145 last_hw_key: None,
146 arrows: [ArrowRepeat::new(); 4],
147 }
148 }
149
150 #[must_use]
152 pub fn new_with_gilrs() -> Self {
153 let mut s = Self::new();
154 s.gilrs = Gilrs::new().ok();
155 s
156 }
157
158 pub fn poll_gamepad(&mut self) {
164 let Some(mut g) = self.gilrs.take() else {
165 return;
166 };
167 while let Some(event) = g.next_event() {
168 self.handle_gamepad_event(event);
169 }
170 self.gilrs = Some(g);
171 }
172
173 pub fn handle_gamepad_event(&mut self, event: Event) {
178 use gilrs::EventType::{AxisChanged, ButtonPressed, ButtonReleased};
179 match event.event {
180 ButtonPressed(Button::DPadLeft, _) => {
181 if !self.arrows[LEFT].held {
182 self.arrow_left = true;
183 }
184 self.arrows[LEFT].held = true;
185 }
186 ButtonPressed(Button::DPadRight, _) => {
187 if !self.arrows[RIGHT].held {
188 self.arrow_right = true;
189 }
190 self.arrows[RIGHT].held = true;
191 }
192 ButtonPressed(Button::DPadUp, _) => {
193 if !self.arrows[UP].held {
194 self.arrow_up = true;
195 }
196 self.arrows[UP].held = true;
197 }
198 ButtonPressed(Button::DPadDown, _) => {
199 if !self.arrows[DOWN].held {
200 self.arrow_down = true;
201 }
202 self.arrows[DOWN].held = true;
203 }
204
205 ButtonReleased(Button::DPadLeft, _) => {
206 self.arrows[LEFT].held = false;
207 self.arrows[LEFT].timer = 0.0;
208 }
209 ButtonReleased(Button::DPadRight, _) => {
210 self.arrows[RIGHT].held = false;
211 self.arrows[RIGHT].timer = 0.0;
212 }
213 ButtonReleased(Button::DPadUp, _) => {
214 self.arrows[UP].held = false;
215 self.arrows[UP].timer = 0.0;
216 }
217 ButtonReleased(Button::DPadDown, _) => {
218 self.arrows[DOWN].held = false;
219 self.arrows[DOWN].timer = 0.0;
220 }
221
222 ButtonPressed(Button::South, _) => {
223 self.space = true;
224 }
225 ButtonPressed(Button::East, _) => {
226 self.escape = true;
227 }
228 ButtonPressed(Button::Start, _) => {
229 self.enter = true;
230 }
231 ButtonPressed(Button::Mode, _) => {
232 self.home = true;
233 }
234 ButtonPressed(Button::LeftTrigger, _) => {
235 self.tab = true;
236 self.shift = true;
237 }
238 ButtonPressed(Button::RightTrigger, _) => {
239 self.tab = true;
240 }
241 ButtonReleased(Button::LeftTrigger, _) => {
242 self.shift = false;
243 }
244
245 AxisChanged(Axis::LeftStickX | Axis::DPadX, v, _) => self.axis_horizontal(v),
246 AxisChanged(Axis::LeftStickY, v, _) => self.axis_vertical_stick(v),
247 AxisChanged(Axis::DPadY, v, _) => self.axis_dpad_y(v),
248 _ => {}
249 }
250 }
251
252 pub fn begin_frame(&mut self, dt: f32) {
259 const INITIAL_DELAY: f32 = 0.4;
260 const REPEAT_RATE: f32 = 0.08;
261
262 self.left_just_pressed = false;
263 self.left_just_released = false;
264 self.scroll_delta = 0.0;
265 self.text_input.clear();
266 self.backspace = false;
267 self.enter = false;
268 self.escape = false;
269 self.tab = false;
270 self.arrow_left = false;
271 self.arrow_right = false;
272 self.arrow_up = false;
273 self.arrow_down = false;
274 self.space = false;
275 self.home = false;
276 self.key_a = false;
277 self.key_c = false;
278 self.key_x = false;
279 self.key_v = false;
280
281 Self::tick_repeat(
283 self.arrows[LEFT].held,
284 &mut self.arrows[LEFT].timer,
285 &mut self.arrow_left,
286 dt,
287 INITIAL_DELAY,
288 REPEAT_RATE,
289 );
290 Self::tick_repeat(
291 self.arrows[RIGHT].held,
292 &mut self.arrows[RIGHT].timer,
293 &mut self.arrow_right,
294 dt,
295 INITIAL_DELAY,
296 REPEAT_RATE,
297 );
298 Self::tick_repeat(
299 self.arrows[UP].held,
300 &mut self.arrows[UP].timer,
301 &mut self.arrow_up,
302 dt,
303 INITIAL_DELAY,
304 REPEAT_RATE,
305 );
306 Self::tick_repeat(
307 self.arrows[DOWN].held,
308 &mut self.arrows[DOWN].timer,
309 &mut self.arrow_down,
310 dt,
311 INITIAL_DELAY,
312 REPEAT_RATE,
313 );
314 }
315
316 #[must_use]
321 pub fn keyboard_present(&self) -> bool {
322 self.last_hw_key
323 .is_some_and(|t| t.elapsed() < std::time::Duration::from_secs(3))
324 }
325
326 pub fn handle_event(&mut self, event: &WindowEvent, pw: f32, ph: f32) {
331 match event {
332 WindowEvent::CursorMoved { position, .. } => {
333 let unit = ph / 1080.0;
334 let ox = ((pw / ph) * 1080.0).mul_add(-unit, pw) * 0.5;
335 self.mouse_x = ((pw / ph) * 1080.0).mul_add(-0.5, (position.x as f32 - ox) / unit);
336 self.mouse_y = position.y as f32 / unit - 540.0;
337 }
338
339 WindowEvent::MouseWheel { delta, .. } => {
340 self.scroll_delta += match delta {
341 winit::event::MouseScrollDelta::LineDelta(_, y) => *y,
342 winit::event::MouseScrollDelta::PixelDelta(pos) => pos.y as f32 / 20.0,
343 };
344 }
345
346 WindowEvent::MouseInput {
347 button: MouseButton::Left,
348 state,
349 ..
350 } => match state {
351 ElementState::Pressed => {
352 self.left_pressed = true;
353 self.left_just_pressed = true;
354 }
355 ElementState::Released => {
356 self.left_pressed = false;
357 self.left_just_released = true;
358 }
359 },
360
361 WindowEvent::KeyboardInput { event, .. } if event.state == ElementState::Pressed => {
362 self.handle_key_press(event);
363 }
364
365 WindowEvent::KeyboardInput { event, .. } if event.state == ElementState::Released => {
366 match &event.logical_key {
367 Key::Named(NamedKey::Shift) => {
368 self.shift = false;
369 }
370 Key::Named(NamedKey::Control) => {
371 self.ctrl = false;
372 }
373 Key::Named(NamedKey::ArrowLeft) => {
374 self.arrows[LEFT].held = false;
375 self.arrows[LEFT].timer = 0.0;
376 }
377 Key::Named(NamedKey::ArrowRight) => {
378 self.arrows[RIGHT].held = false;
379 self.arrows[RIGHT].timer = 0.0;
380 }
381 Key::Named(NamedKey::ArrowUp) => {
382 self.arrows[UP].held = false;
383 self.arrows[UP].timer = 0.0;
384 }
385 Key::Named(NamedKey::ArrowDown) => {
386 self.arrows[DOWN].held = false;
387 self.arrows[DOWN].timer = 0.0;
388 }
389 _ => {}
390 }
391 }
392
393 _ => {}
394 }
395 }
396
397 fn handle_key_press(&mut self, event: &winit::event::KeyEvent) {
407 match &event.logical_key {
408 Key::Named(NamedKey::Backspace) => {
409 self.last_hw_key = Some(std::time::Instant::now());
410 self.backspace = true;
411 }
412 Key::Named(NamedKey::Enter) => {
413 self.enter = true;
414 }
415 Key::Named(NamedKey::Escape) => {
416 self.escape = true;
417 }
418 Key::Named(NamedKey::Tab) => {
419 self.tab = true;
420 }
421 Key::Named(NamedKey::Shift) => {
422 self.shift = true;
423 }
424 Key::Named(NamedKey::Control) => {
425 self.ctrl = true;
426 }
427 Key::Named(NamedKey::Space) => {
428 self.space = true;
429 }
430 Key::Named(NamedKey::ArrowLeft) => {
431 if !self.arrows[LEFT].held {
432 self.arrow_left = true;
433 }
434 self.arrows[LEFT].held = true;
435 }
436 Key::Named(NamedKey::ArrowRight) => {
437 if !self.arrows[RIGHT].held {
438 self.arrow_right = true;
439 }
440 self.arrows[RIGHT].held = true;
441 }
442 Key::Named(NamedKey::ArrowUp) => {
443 if !self.arrows[UP].held {
444 self.arrow_up = true;
445 }
446 self.arrows[UP].held = true;
447 }
448 Key::Named(NamedKey::ArrowDown) => {
449 if !self.arrows[DOWN].held {
450 self.arrow_down = true;
451 }
452 self.arrows[DOWN].held = true;
453 }
454 Key::Character(s) => {
455 self.last_hw_key = Some(std::time::Instant::now());
456 match s.to_lowercase().as_str() {
457 "a" => self.key_a = true,
458 "c" => self.key_c = true,
459 "x" => self.key_x = true,
460 "v" => self.key_v = true,
461 _ => {}
462 }
463 }
464 _ => {}
465 }
466 if let Some(text) = &event.text {
467 for ch in text.chars() {
468 if !ch.is_control() {
469 self.text_input.push(ch);
470 }
471 }
472 }
473 }
474
475 fn axis_2d(&mut self, v: f32, neg_idx: usize, pos_idx: usize) -> (bool, bool) {
482 const DEADZONE: f32 = 0.3;
483 if v < -DEADZONE {
484 let pulse = !self.arrows[neg_idx].held;
485 self.arrows[neg_idx].held = true;
486 self.arrows[pos_idx].held = false;
487 self.arrows[pos_idx].timer = 0.0;
488 (pulse, false)
489 } else if v > DEADZONE {
490 let pulse = !self.arrows[pos_idx].held;
491 self.arrows[pos_idx].held = true;
492 self.arrows[neg_idx].held = false;
493 self.arrows[neg_idx].timer = 0.0;
494 (false, pulse)
495 } else {
496 self.arrows[neg_idx].held = false;
497 self.arrows[neg_idx].timer = 0.0;
498 self.arrows[pos_idx].held = false;
499 self.arrows[pos_idx].timer = 0.0;
500 (false, false)
501 }
502 }
503
504 fn axis_horizontal(&mut self, v: f32) {
506 let (l, r) = self.axis_2d(v, LEFT, RIGHT);
507 if l {
508 self.arrow_left = true;
509 }
510 if r {
511 self.arrow_right = true;
512 }
513 }
514
515 fn axis_vertical_stick(&mut self, v: f32) {
517 let (d, u) = self.axis_2d(v, DOWN, UP);
519 if u {
520 self.arrow_up = true;
521 }
522 if d {
523 self.arrow_down = true;
524 }
525 }
526
527 fn axis_dpad_y(&mut self, v: f32) {
529 let (u, d) = self.axis_2d(v, UP, DOWN);
531 if u {
532 self.arrow_up = true;
533 }
534 if d {
535 self.arrow_down = true;
536 }
537 }
538
539 fn tick_repeat(
545 held: bool,
546 timer: &mut f32,
547 pulse: &mut bool,
548 dt: f32,
549 initial: f32,
550 rate: f32,
551 ) {
552 if !held {
553 *timer = 0.0;
554 return;
555 }
556 *timer += dt;
557 if *timer >= initial {
558 let repeat_t = *timer - initial;
559 let prev = (repeat_t - dt).max(0.0);
560 if (repeat_t / rate).floor() > (prev / rate).floor() {
561 *pulse = true;
562 }
563 }
564 }
565}