1use alloc::vec::Vec;
2use core::{any::TypeId, hash::Hash, iter, mem};
3
4use bevy::{
5 ecs::{schedule::ScheduleLabel, system::SystemParam},
6 input::mouse::{AccumulatedMouseMotion, AccumulatedMouseScroll},
7 platform::collections::HashSet,
8 prelude::*,
9 utils::TypeIdMap,
10};
11use log::{debug, trace};
12
13use crate::prelude::*;
14
15pub(crate) fn update_pending(mut reader: InputReader) {
16 reader.update_pending();
17}
18
19#[derive(SystemParam)]
23pub(crate) struct InputReader<'w, 's> {
24 keys: Option<Res<'w, ButtonInput<KeyCode>>>,
25 mouse_buttons: Option<Res<'w, ButtonInput<MouseButton>>>,
26 mouse_motion: Option<Res<'w, AccumulatedMouseMotion>>,
27 mouse_scroll: Option<Res<'w, AccumulatedMouseScroll>>,
28 gamepads: Query<'w, 's, &'static Gamepad>,
29 action_sources: Res<'w, ActionSources>,
30 consumed: ResMut<'w, ConsumedInputs>,
31 pending: ResMut<'w, PendingBindings>,
32 gamepad_device: Local<'s, GamepadDevice>,
33 skip_ignore_check: Local<'s, bool>,
34}
35
36impl InputReader<'_, '_> {
37 pub(crate) fn update_pending(&mut self) {
39 *self.skip_ignore_check = true;
42
43 let mut pending = mem::take(&mut *self.pending);
45 pending.ignored.clear();
46 pending.bindings.retain(|&binding| {
47 if self.value(binding).as_bool() {
48 pending.ignored.add(binding, *self.gamepad_device);
49 true
50 } else {
51 trace!("'{binding}' reset and no longer ignored");
52 false
53 }
54 });
55 *self.pending = pending;
56
57 *self.skip_ignore_check = false
58 }
59
60 pub(crate) fn clear_consumed<S: ScheduleLabel>(&mut self) {
62 self.consumed.entry(TypeId::of::<S>()).or_default().clear();
63 }
64
65 pub(crate) fn set_gamepad(&mut self, gamepad: impl Into<GamepadDevice>) {
67 *self.gamepad_device = gamepad.into();
68 }
69
70 pub(crate) fn value(&self, binding: impl Into<Binding>) -> ActionValue {
74 let binding = binding.into();
75 match binding {
76 Binding::Keyboard { key, mod_keys } => {
77 let pressed = self.action_sources.keyboard
78 && self.keys.as_ref().is_some_and(|k| k.pressed(key))
79 && self.mod_keys_pressed(mod_keys)
80 && !self.ignored(binding);
81
82 pressed.into()
83 }
84 Binding::MouseButton { button, mod_keys } => {
85 let pressed = self.action_sources.mouse_buttons
86 && self
87 .mouse_buttons
88 .as_ref()
89 .is_some_and(|b| b.pressed(button))
90 && self.mod_keys_pressed(mod_keys)
91 && !self.ignored(binding);
92
93 pressed.into()
94 }
95 Binding::MouseMotion { mod_keys } => {
96 if !self.action_sources.mouse_motion
97 || !self.mod_keys_pressed(mod_keys)
98 || self.ignored(binding)
99 {
100 return Vec2::ZERO.into();
101 }
102
103 self.mouse_motion
104 .as_ref()
105 .map(|m| m.delta)
106 .unwrap_or_default()
107 .into()
108 }
109 Binding::MouseWheel { mod_keys } => {
110 if !self.action_sources.mouse_wheel
111 || !self.mod_keys_pressed(mod_keys)
112 || self.ignored(binding)
113 {
114 return Vec2::ZERO.into();
115 }
116
117 self.mouse_scroll
118 .as_ref()
119 .map(|s| s.delta)
120 .unwrap_or_default()
121 .into()
122 }
123 Binding::GamepadButton(button) => {
124 if !self.action_sources.gamepad_button || self.ignored(binding) {
125 return 0.0.into();
126 }
127
128 let value = match *self.gamepad_device {
129 GamepadDevice::Any => self
130 .gamepads
131 .iter()
132 .filter_map(|gamepad| gamepad.get(button))
133 .find(|&value| value != 0.0),
134 GamepadDevice::Single(entity) => self
135 .gamepads
136 .get(entity)
137 .ok()
138 .and_then(|gamepad| gamepad.get(button)),
139 GamepadDevice::None => return 0.0.into(),
140 };
141
142 value.unwrap_or_default().into()
143 }
144 Binding::GamepadAxis(axis) => {
145 if !self.action_sources.gamepad_axis || self.ignored(binding) {
146 return 0.0.into();
147 }
148
149 let value = match *self.gamepad_device {
150 GamepadDevice::Any => self
151 .gamepads
152 .iter()
153 .filter_map(|gamepad| gamepad.get_unclamped(axis))
154 .reduce(|acc, v| acc + v),
155 GamepadDevice::Single(entity) => self
156 .gamepads
157 .get(entity)
158 .ok()
159 .and_then(|gamepad| gamepad.get(axis)),
160 GamepadDevice::None => return 0.0.into(),
161 };
162
163 let value = value.unwrap_or_default();
164 value.into()
165 }
166 Binding::AnyKey => {
167 if self.ignored(Binding::AnyKey) {
168 return false.into();
169 }
170
171 if self.action_sources.keyboard
172 && self
173 .keys
174 .iter()
175 .flat_map(|k| k.get_pressed())
176 .any(|&k| !self.ignored(k))
177 {
178 return true.into();
179 }
180
181 if self.action_sources.mouse_buttons
182 && self
183 .mouse_buttons
184 .iter()
185 .flat_map(|b| b.get_pressed())
186 .any(|&b| !self.ignored(b))
187 {
188 return true.into();
189 }
190
191 if self.action_sources.gamepad_button {
192 match *self.gamepad_device {
193 GamepadDevice::Single(entity) => {
194 if let Ok(gamepad) = self.gamepads.get(entity)
195 && gamepad.get_pressed().any(|&b| !self.ignored(b))
196 {
197 return true.into();
198 }
199 }
200 GamepadDevice::Any => {
201 for gamepad in &self.gamepads {
202 if gamepad.get_pressed().any(|&b| !self.ignored(b)) {
203 return true.into();
204 }
205 }
206 }
207 GamepadDevice::None => (),
208 };
209 }
210
211 false.into()
212 }
213 Binding::None => false.into(),
214 }
215 }
216
217 fn mod_keys_pressed(&self, mod_keys: ModKeys) -> bool {
218 if !mod_keys.is_empty() && !self.action_sources.keyboard {
219 return false;
220 }
221
222 for keys in mod_keys.iter_keys() {
223 if self.keys.as_ref().is_none_or(|k| !k.any_pressed(keys)) {
224 return false;
225 }
226 }
227
228 true
229 }
230
231 fn ignored(&self, binding: impl Into<Binding>) -> bool {
232 if *self.skip_ignore_check {
233 return false;
234 }
235
236 let keys_ignored =
237 self.pending.ignored.any_key || self.consumed.values().any(|ignored| ignored.any_key);
238 let mut iter = iter::once(&self.pending.ignored).chain(self.consumed.values());
239 match binding.into() {
240 Binding::Keyboard { key, mod_keys } => {
241 iter.any(|i| i.keys.contains(&key) || i.mod_keys.intersects(mod_keys))
242 || keys_ignored
243 }
244 Binding::MouseButton { button, mod_keys } => {
245 iter.any(|i| i.mouse_buttons.contains(&button) || i.mod_keys.intersects(mod_keys))
246 || keys_ignored
247 }
248 Binding::MouseMotion { mod_keys } => {
249 iter.any(|inputs| inputs.mouse_motion || inputs.mod_keys.intersects(mod_keys))
250 }
251 Binding::MouseWheel { mod_keys } => {
252 iter.any(|inputs| inputs.mouse_wheel || inputs.mod_keys.intersects(mod_keys))
253 }
254 Binding::GamepadButton(button) => {
255 let input = GamepadInput {
256 gamepad: *self.gamepad_device,
257 input: button,
258 };
259 iter.any(|inputs| inputs.gamepad_buttons.contains(&input)) || keys_ignored
260 }
261 Binding::GamepadAxis(axis) => {
262 let input = GamepadInput {
263 gamepad: *self.gamepad_device,
264 input: axis,
265 };
266 iter.any(|inputs| inputs.gamepad_axes.contains(&input))
267 }
268 Binding::AnyKey => keys_ignored,
269 Binding::None => false,
270 }
271 }
272
273 pub(crate) fn consume<S: ScheduleLabel>(&mut self, binding: impl Into<Binding>) {
277 self.consumed
278 .entry(TypeId::of::<S>())
279 .or_default()
280 .add(binding.into(), *self.gamepad_device);
281 }
282}
283
284#[derive(Resource, Reflect)]
314pub struct ActionSources {
315 pub keyboard: bool,
316 pub mouse_buttons: bool,
317 pub mouse_motion: bool,
318 pub mouse_wheel: bool,
319 pub gamepad_button: bool,
320 pub gamepad_axis: bool,
321}
322
323impl Default for ActionSources {
324 fn default() -> Self {
325 Self {
326 keyboard: true,
327 mouse_buttons: true,
328 mouse_motion: true,
329 mouse_wheel: true,
330 gamepad_button: true,
331 gamepad_axis: true,
332 }
333 }
334}
335
336#[derive(Resource, Default, Deref, DerefMut)]
345pub(crate) struct ConsumedInputs(TypeIdMap<IgnoredInputs>);
346
347#[derive(Resource, Default)]
352pub(crate) struct PendingBindings {
353 bindings: Vec<Binding>,
354
355 ignored: IgnoredInputs,
357}
358
359impl PendingBindings {
360 pub(crate) fn extend(&mut self, iter: impl Iterator<Item = Binding>) {
361 self.bindings
362 .extend(iter.inspect(|binding| debug!("ignoring '{binding}' until reset")));
363 }
364}
365
366#[derive(Default)]
367pub(crate) struct IgnoredInputs {
368 keys: HashSet<KeyCode>,
369 mod_keys: ModKeys,
370 mouse_buttons: HashSet<MouseButton>,
371 mouse_motion: bool,
372 mouse_wheel: bool,
373 gamepad_buttons: HashSet<GamepadInput<GamepadButton>>,
374 gamepad_axes: HashSet<GamepadInput<GamepadAxis>>,
375 any_key: bool,
376}
377
378impl IgnoredInputs {
379 fn add(&mut self, binding: Binding, gamepad: GamepadDevice) {
380 match binding {
381 Binding::Keyboard { key, mod_keys } => {
382 self.keys.insert(key);
383 self.mod_keys.insert(mod_keys);
384 }
385 Binding::MouseButton { button, mod_keys } => {
386 self.mouse_buttons.insert(button);
387 self.mod_keys.insert(mod_keys);
388 }
389 Binding::MouseMotion { mod_keys } => {
390 self.mouse_motion = true;
391 self.mod_keys.insert(mod_keys);
392 }
393 Binding::MouseWheel { mod_keys } => {
394 self.mouse_wheel = true;
395 self.mod_keys.insert(mod_keys);
396 }
397 Binding::GamepadButton(button) => {
398 let input = GamepadInput {
399 gamepad,
400 input: button,
401 };
402
403 self.gamepad_buttons.insert(input);
404 }
405 Binding::GamepadAxis(axis) => {
406 let input = GamepadInput {
407 gamepad,
408 input: axis,
409 };
410
411 self.gamepad_axes.insert(input);
412 }
413 Binding::AnyKey => self.any_key = true,
414 Binding::None => (),
415 }
416 }
417
418 fn clear(&mut self) {
419 self.keys.clear();
420 self.mod_keys = ModKeys::empty();
421 self.mouse_buttons.clear();
422 self.mouse_motion = false;
423 self.mouse_wheel = false;
424 self.gamepad_buttons.clear();
425 self.gamepad_axes.clear();
426 self.any_key = false;
427 }
428}
429
430#[derive(Hash, PartialEq, Eq)]
432struct GamepadInput<T: Hash + Eq> {
433 gamepad: GamepadDevice,
434 input: T,
435}
436
437#[cfg(test)]
438mod tests {
439 use bevy::{
440 ecs::system::SystemState,
441 input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel},
442 };
443
444 use super::*;
445
446 #[test]
447 fn keyboard() {
448 let (mut world, mut state) = init_world();
449
450 let key = KeyCode::Space;
451 world.resource_mut::<ButtonInput<KeyCode>>().press(key);
452
453 let mut reader = state.get_mut(&mut world);
454 assert_eq!(reader.value(key), true.into());
455 assert_eq!(reader.value(Binding::AnyKey), true.into());
456 assert_eq!(reader.value(KeyCode::Escape), false.into());
457 assert_eq!(reader.value(key.with_mod_keys(ModKeys::ALT)), false.into());
458
459 reader.consume::<PreUpdate>(key);
460 assert_eq!(reader.value(key), false.into());
461 assert_eq!(reader.value(Binding::AnyKey), false.into());
462 }
463
464 #[test]
465 fn mouse_button() {
466 let (mut world, mut state) = init_world();
467
468 let button = MouseButton::Left;
469 world
470 .resource_mut::<ButtonInput<MouseButton>>()
471 .press(button);
472
473 let mut reader = state.get_mut(&mut world);
474 assert_eq!(reader.value(button), true.into());
475 assert_eq!(reader.value(Binding::AnyKey), true.into());
476 assert_eq!(reader.value(MouseButton::Right), false.into());
477 assert_eq!(
478 reader.value(button.with_mod_keys(ModKeys::CONTROL)),
479 false.into()
480 );
481
482 reader.consume::<PreUpdate>(button);
483 assert_eq!(reader.value(button), false.into());
484 assert_eq!(reader.value(Binding::AnyKey), false.into());
485 }
486
487 #[test]
488 fn mouse_motion() {
489 let (mut world, mut state) = init_world();
490
491 let value = Vec2::ONE;
492 world.insert_resource(AccumulatedMouseMotion { delta: value });
493
494 let binding = Binding::mouse_motion();
495 let mut reader = state.get_mut(&mut world);
496 reader.clear_consumed::<PreUpdate>();
497 assert_eq!(reader.value(binding), value.into());
498 assert_eq!(
499 reader.value(binding.with_mod_keys(ModKeys::SHIFT)),
500 Vec2::ZERO.into()
501 );
502
503 reader.consume::<PreUpdate>(binding);
504 assert_eq!(reader.value(binding), Vec2::ZERO.into());
505 }
506
507 #[test]
508 fn mouse_wheel() {
509 let (mut world, mut state) = init_world();
510
511 let value = Vec2::ONE;
512 world.insert_resource(AccumulatedMouseScroll {
513 unit: MouseScrollUnit::Line,
514 delta: value,
515 });
516
517 let binding = Binding::mouse_wheel();
518 let mut reader = state.get_mut(&mut world);
519 reader.clear_consumed::<PreUpdate>();
520 assert_eq!(reader.value(binding), value.into());
521 assert_eq!(
522 reader.value(binding.with_mod_keys(ModKeys::SUPER)),
523 Vec2::ZERO.into()
524 );
525
526 reader.consume::<PreUpdate>(binding);
527 assert_eq!(reader.value(binding), Vec2::ZERO.into());
528 }
529
530 #[test]
531 fn gamepad_button() {
532 let (mut world, mut state) = init_world();
533
534 let value = 1.0;
535 let button1 = GamepadButton::South;
536 let mut gamepad1 = Gamepad::default();
537 gamepad1.analog_mut().set(button1, value);
538 gamepad1.digital_mut().press(button1);
539 let gamepad_entity = world.spawn(gamepad1).id();
540
541 let button2 = GamepadButton::East;
542 let mut gamepad2 = Gamepad::default();
543 gamepad2.analog_mut().set(button2, value);
544 gamepad2.digital_mut().press(button2);
545 world.spawn(gamepad2);
546
547 let mut reader = state.get_mut(&mut world);
548 reader.set_gamepad(gamepad_entity);
549 assert_eq!(reader.value(button1), value.into());
550 assert_eq!(
551 reader.value(button2),
552 0.0.into(),
553 "should read only from `{gamepad_entity:?}`"
554 );
555 assert_eq!(reader.value(Binding::AnyKey), true.into());
556 assert_eq!(reader.value(GamepadButton::North), 0.0.into());
557
558 reader.consume::<PreUpdate>(button1);
559 assert_eq!(reader.value(button1), 0.0.into());
560 assert_eq!(reader.value(Binding::AnyKey), false.into());
561 }
562
563 #[test]
564 fn any_gamepad_button() {
565 let (mut world, mut state) = init_world();
566
567 let value = 1.0;
568 let button1 = GamepadButton::South;
569 let mut gamepad1 = Gamepad::default();
570 gamepad1.analog_mut().set(button1, value);
571 gamepad1.digital_mut().press(button1);
572 world.spawn(gamepad1);
573
574 let button2 = GamepadButton::East;
575 let mut gamepad2 = Gamepad::default();
576 gamepad2.analog_mut().set(button2, value);
577 gamepad2.digital_mut().press(button2);
578 world.spawn(gamepad2);
579
580 let mut reader = state.get_mut(&mut world);
581 assert_eq!(reader.value(button1), value.into());
582 assert_eq!(reader.value(button2), value.into());
583 assert_eq!(reader.value(Binding::AnyKey), true.into());
584 assert_eq!(reader.value(GamepadButton::North), 0.0.into());
585
586 reader.consume::<PreUpdate>(button1);
587 assert_eq!(reader.value(button1), 0.0.into());
588 assert_eq!(reader.value(Binding::AnyKey), true.into());
589
590 reader.consume::<PreUpdate>(button2);
591 assert_eq!(reader.value(button2), 0.0.into());
592 assert_eq!(reader.value(Binding::AnyKey), false.into());
593 }
594
595 #[test]
596 fn gamepad_axis() {
597 let (mut world, mut state) = init_world();
598
599 let value = 1.0;
600 let axis1 = GamepadAxis::LeftStickX;
601 let mut gamepad1 = Gamepad::default();
602 gamepad1.analog_mut().set(axis1, value);
603 let gamepad_entity = world.spawn(gamepad1).id();
604
605 let axis2 = GamepadAxis::LeftStickY;
606 let mut gamepad2 = Gamepad::default();
607 gamepad2.analog_mut().set(axis2, value);
608 world.spawn(gamepad2);
609
610 let mut reader = state.get_mut(&mut world);
611 reader.set_gamepad(gamepad_entity);
612 assert_eq!(reader.value(axis1), value.into());
613 assert_eq!(
614 reader.value(axis2),
615 0.0.into(),
616 "should read only from `{gamepad_entity:?}`"
617 );
618 assert_eq!(reader.value(GamepadAxis::RightStickX), 0.0.into());
619
620 reader.consume::<PreUpdate>(axis1);
621 assert_eq!(reader.value(axis1), 0.0.into());
622 }
623
624 #[test]
625 fn any_gamepad_axis() {
626 let (mut world, mut state) = init_world();
627
628 let value = 1.0;
629 let axis1 = GamepadAxis::LeftStickX;
630 let mut gamepad1 = Gamepad::default();
631 gamepad1.analog_mut().set(axis1, value);
632 world.spawn(gamepad1);
633
634 let axis2 = GamepadAxis::LeftStickY;
635 let mut gamepad2 = Gamepad::default();
636 gamepad2.analog_mut().set(axis2, value);
637 world.spawn(gamepad2);
638
639 let mut reader = state.get_mut(&mut world);
640 assert_eq!(reader.value(axis1), value.into());
641 assert_eq!(reader.value(axis2), value.into());
642 assert_eq!(reader.value(GamepadAxis::RightStickX), 0.0.into());
643
644 reader.consume::<PreUpdate>(axis1);
645 assert_eq!(reader.value(axis1), 0.0.into());
646
647 reader.consume::<PreUpdate>(axis2);
648 assert_eq!(reader.value(axis2), 0.0.into());
649 }
650
651 #[test]
652 fn no_gamepad() {
653 let (mut world, mut state) = init_world();
654
655 let value = 1.0;
656 let axis = GamepadAxis::LeftStickX;
657 let button = GamepadButton::South;
658 let mut gamepad = Gamepad::default();
659 gamepad.analog_mut().set(axis, value);
660 gamepad.analog_mut().set(button, value);
661 gamepad.digital_mut().press(button);
662 world.spawn(gamepad);
663
664 let mut reader = state.get_mut(&mut world);
665 reader.set_gamepad(None);
666 assert_eq!(reader.value(button), 0.0.into());
667 assert_eq!(reader.value(axis), 0.0.into());
668 assert_eq!(reader.value(Binding::AnyKey), false.into());
669 }
670
671 #[test]
672 fn any_gamepad_axis_sum() {
673 let (mut world, mut state) = init_world();
674
675 let axis = GamepadAxis::LeftStickX;
676 let mut gamepad1 = Gamepad::default();
677 gamepad1.analog_mut().set(axis, 0.001);
678 world.spawn(gamepad1);
679
680 let mut gamepad2 = Gamepad::default();
681 gamepad2.analog_mut().set(axis, 0.002);
682 world.spawn(gamepad2);
683
684 let mut reader = state.get_mut(&mut world);
685 assert_eq!(reader.value(axis), 0.003.into());
686 assert_eq!(reader.value(GamepadAxis::RightStickX), 0.0.into());
687
688 reader.consume::<PreUpdate>(axis);
689 assert_eq!(reader.value(axis), 0.0.into());
690 }
691
692 #[test]
693 fn keyboard_with_modifier() {
694 let (mut world, mut state) = init_world();
695
696 let key = KeyCode::Space;
697 let modifier = KeyCode::ControlLeft;
698 let mut keys = world.resource_mut::<ButtonInput<KeyCode>>();
699 keys.press(modifier);
700 keys.press(key);
701
702 let binding = key.with_mod_keys(modifier.into());
703 let mut reader = state.get_mut(&mut world);
704 assert_eq!(reader.value(binding), true.into());
705 assert_eq!(reader.value(key), true.into());
706 assert_eq!(reader.value(Binding::AnyKey), true.into());
707 assert_eq!(
708 reader.value(binding.with_mod_keys(ModKeys::ALT)),
709 false.into()
710 );
711 assert_eq!(
712 reader.value(binding.with_mod_keys(ModKeys::CONTROL | ModKeys::ALT)),
713 false.into()
714 );
715
716 reader.consume::<PreUpdate>(binding);
717 assert_eq!(reader.value(binding), false.into());
718 assert_eq!(
719 reader.value(Binding::AnyKey),
720 true.into(),
721 "should still be pressed due to modifier"
722 );
723
724 let other_key = KeyCode::Enter;
726 world
727 .resource_mut::<ButtonInput<KeyCode>>()
728 .press(other_key);
729 let other_input = other_key.with_mod_keys(modifier.into());
730 let reader = state.get_mut(&mut world);
731 assert_eq!(reader.value(other_input), false.into());
732 assert_eq!(reader.value(other_key), true.into());
733 }
734
735 #[test]
736 fn mouse_button_with_modifier() {
737 let (mut world, mut state) = init_world();
738
739 let button = MouseButton::Left;
740 let modifier = KeyCode::AltLeft;
741 world.resource_mut::<ButtonInput<KeyCode>>().press(modifier);
742 world
743 .resource_mut::<ButtonInput<MouseButton>>()
744 .press(button);
745
746 let binding = button.with_mod_keys(modifier.into());
747 let mut reader = state.get_mut(&mut world);
748 assert_eq!(reader.value(binding), true.into());
749 assert_eq!(reader.value(button), true.into());
750 assert_eq!(reader.value(Binding::AnyKey), true.into());
751 assert_eq!(
752 reader.value(binding.with_mod_keys(ModKeys::CONTROL)),
753 false.into()
754 );
755 assert_eq!(
756 reader.value(binding.with_mod_keys(ModKeys::CONTROL | ModKeys::ALT)),
757 false.into()
758 );
759
760 reader.consume::<PreUpdate>(binding);
761 assert_eq!(reader.value(binding), false.into());
762 assert_eq!(
763 reader.value(Binding::AnyKey),
764 true.into(),
765 "should still be pressed due to modifier"
766 );
767 }
768
769 #[test]
770 fn mouse_motion_with_modifier() {
771 let (mut world, mut state) = init_world();
772
773 let value = Vec2::ONE;
774 let modifier = KeyCode::ShiftLeft;
775 world.resource_mut::<ButtonInput<KeyCode>>().press(modifier);
776 world.insert_resource(AccumulatedMouseMotion { delta: value });
777
778 let binding = Binding::mouse_motion().with_mod_keys(modifier.into());
779 let mut reader = state.get_mut(&mut world);
780 reader.clear_consumed::<PreUpdate>();
781 assert_eq!(reader.value(binding), value.into());
782 assert_eq!(reader.value(binding.without_mod_keys()), value.into());
783 assert_eq!(
784 reader.value(binding.with_mod_keys(ModKeys::SUPER)),
785 Vec2::ZERO.into()
786 );
787 assert_eq!(
788 reader.value(binding.with_mod_keys(ModKeys::SHIFT | ModKeys::SUPER)),
789 Vec2::ZERO.into()
790 );
791
792 reader.consume::<PreUpdate>(binding);
793 assert_eq!(reader.value(binding), Vec2::ZERO.into());
794 }
795
796 #[test]
797 fn mouse_wheel_with_modifier() {
798 let (mut world, mut state) = init_world();
799
800 let value = Vec2::ONE;
801 let modifier = KeyCode::SuperLeft;
802 world.resource_mut::<ButtonInput<KeyCode>>().press(modifier);
803 world.insert_resource(AccumulatedMouseScroll {
804 unit: MouseScrollUnit::Line,
805 delta: value,
806 });
807
808 let binding = Binding::mouse_wheel().with_mod_keys(modifier.into());
809 let mut reader = state.get_mut(&mut world);
810 reader.clear_consumed::<PreUpdate>();
811 assert_eq!(reader.value(binding), value.into());
812 assert_eq!(reader.value(binding.without_mod_keys()), value.into());
813 assert_eq!(
814 reader.value(binding.with_mod_keys(ModKeys::SHIFT)),
815 Vec2::ZERO.into()
816 );
817 assert_eq!(
818 reader.value(binding.with_mod_keys(ModKeys::SHIFT | ModKeys::SUPER)),
819 Vec2::ZERO.into()
820 );
821
822 reader.consume::<PreUpdate>(binding);
823 assert_eq!(reader.value(binding), Vec2::ZERO.into());
824 }
825
826 #[test]
827 fn sources() {
828 let (mut world, mut state) = init_world();
829
830 let key = KeyCode::Space;
831 let mouse_button = MouseButton::Left;
832 let gamepad_button = GamepadButton::South;
833 let axis = GamepadAxis::LeftStickX;
834
835 world.resource_mut::<ButtonInput<KeyCode>>().press(key);
836 world
837 .resource_mut::<ButtonInput<MouseButton>>()
838 .press(mouse_button);
839
840 world.insert_resource(AccumulatedMouseMotion { delta: Vec2::ONE });
841 world.insert_resource(AccumulatedMouseScroll {
842 unit: MouseScrollUnit::Line,
843 delta: Vec2::ONE,
844 });
845
846 let mut gamepad = Gamepad::default();
847 gamepad.analog_mut().set(axis, 1.0);
848 gamepad.analog_mut().set(gamepad_button, 1.0);
849 world.spawn(gamepad);
850
851 let mut action_sources = world.resource_mut::<ActionSources>();
852 action_sources.keyboard = false;
853 action_sources.mouse_buttons = false;
854 action_sources.mouse_motion = false;
855 action_sources.mouse_wheel = false;
856 action_sources.gamepad_button = false;
857 action_sources.gamepad_axis = false;
858
859 let mut reader = state.get_mut(&mut world);
860 reader.clear_consumed::<PreUpdate>();
861
862 assert_eq!(reader.value(key), false.into());
863 assert_eq!(reader.value(mouse_button), false.into());
864 assert_eq!(reader.value(Binding::mouse_motion()), Vec2::ZERO.into());
865 assert_eq!(reader.value(Binding::mouse_wheel()), Vec2::ZERO.into());
866 assert_eq!(reader.value(gamepad_button), 0.0.into());
867 assert_eq!(reader.value(axis), 0.0.into());
868 }
869
870 fn init_world<'w, 's>() -> (World, SystemState<InputReader<'w, 's>>) {
871 let mut world = World::new();
872 world.init_resource::<ButtonInput<KeyCode>>();
873 world.init_resource::<ButtonInput<MouseButton>>();
874 world.init_resource::<Messages<MouseMotion>>();
875 world.init_resource::<Messages<MouseWheel>>();
876 world.init_resource::<ButtonInput<GamepadButton>>();
877 world.init_resource::<Axis<GamepadAxis>>();
878 world.init_resource::<AccumulatedMouseMotion>();
879 world.init_resource::<AccumulatedMouseScroll>();
880 world.init_resource::<ConsumedInputs>();
881 world.init_resource::<PendingBindings>();
882 world.init_resource::<ActionSources>();
883
884 let state = SystemState::<InputReader>::new(&mut world);
885
886 (world, state)
887 }
888}