use bevy_input_sequence::{key, KeyChord}; #[test] fn keychord_display() { let keychord = KeyChord::from(key!(ctrl - A)); assert_eq!(format!("{}", keychord), "ctrl-A"); let keychord = KeyChord::from(key!(ctrl - 1)); assert_eq!(format!("{}", keychord), "ctrl-1"); let keychord = KeyChord::from(key!(1)); assert_eq!(format!("{}", keychord), "1"); } mod simulate_app { use bevy::{ app::{App, PostUpdate}, ecs::{ component::Component, event::{Event, EventReader}, system::{ //commands::Commands, Query, }, world::{Command, World}, }, input::{ gamepad::{ Gamepad, GamepadAxis, GamepadButton, GamepadButtonType, GamepadConnection, GamepadConnectionEvent, GamepadInfo, Gamepads, }, keyboard::KeyCode, Axis, ButtonInput as Input, }, prelude::Commands, MinimalPlugins, }; use bevy_input_sequence::prelude::*; #[derive(Event, Clone)] struct MyEvent; #[derive(Component)] struct EventSent(u8); trait AddCommand { fn add(&mut self, command: impl Command); } impl AddCommand for World { fn add(&mut self, command: impl Command) { command.apply(self); } } #[test] fn one_key() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [(Modifiers::empty(), KeyCode::KeyA)], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn two_components_one_event() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert_eq!( app.world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .count(), 1 ); } #[test] fn two_presses_two_events() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyB], )); press_key(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyB); app.update(); assert_eq!( app.world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .count(), 2 ); } #[test] fn two_keycodes_match_first() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyC], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn match_short_seq() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB, KeyCode::KeyC], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyB); app.update(); assert_eq!( app.world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .map(|x| x.0) .unwrap(), 1 // .is_some() ); clear_just_pressed(&mut app, KeyCode::KeyB); press_key(&mut app, KeyCode::KeyC); app.update(); assert_eq!( app.world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .map(|x| x.0) .unwrap(), 2 // .is_some() ); clear_just_pressed(&mut app, KeyCode::KeyC); press_key(&mut app, KeyCode::KeyD); app.update(); assert_eq!( app.world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .map(|x| x.0) .unwrap(), 2 ); } #[test] fn two_keycodes_match_second() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyC], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyC); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn two_any_patterns() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyC], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyD], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn two_any_patterns_match_2nd() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyC], )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyD], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyD); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn two_keycodes() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn delete_sequences_if_pressed_incorrect_key() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB, KeyCode::KeyC], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyB); press_key(&mut app, KeyCode::KeyD); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); } #[test] fn game_pad_button() { let mut app = new_app(); app.world_mut().send_event(GamepadConnectionEvent::new( Gamepad::new(1), GamepadConnection::Connected(GamepadInfo { name: "".to_string(), }), )); app.world_mut().add(ButtonSequence::new( action::send_event_with_input(|_: Gamepad| MyEvent), [ GamepadButtonType::North, GamepadButtonType::East, GamepadButtonType::South, ], )); app.update(); press_pad_button(&mut app, GamepadButtonType::North); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed_pad_button(&mut app, GamepadButtonType::North); press_pad_button(&mut app, GamepadButtonType::East); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed_pad_button(&mut app, GamepadButtonType::East); press_pad_button(&mut app, GamepadButtonType::South); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn multiple_inputs() { let mut app = new_app(); app.world_mut().send_event(GamepadConnectionEvent::new( Gamepad::new(1), GamepadConnection::Connected(GamepadInfo { name: "".to_string(), }), )); // This is no longer possible right now. We could introduce a // KeyButtonSequence mixture struct would allow it. // app.world_mut().add(KeySequence::new( // action::send_event(MyEvent), // [ // (KeyCode::KeyA), // (KeyCode::KeyB), // (KeyCode::KeyC) | Act::PadButton(GamepadButtonType::North.into()), // (GamepadButtonType::C.into()), // ], // )); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB, KeyCode::KeyX], )); app.world_mut().add(ButtonSequence::new( action::send_event_with_input(|_: Gamepad| MyEvent), [GamepadButtonType::North, GamepadButtonType::C], )); app.update(); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyB); press_pad_button(&mut app, GamepadButtonType::North); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed_pad_button(&mut app, GamepadButtonType::North); press_pad_button(&mut app, GamepadButtonType::C); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn timeout_1frame() { let mut app = new_app(); app.world_mut().add( KeySequence::new(action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB]) .time_limit(TimeLimit::Frames(1)), ); // eprintln!("t0"); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); // eprintln!("t1"); clear_just_pressed(&mut app, KeyCode::KeyA); app.update(); // eprintln!("t2"); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); } #[test] fn test_modifier() { let mut app = new_app(); app.world_mut().add(KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB], )); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); app.update(); press_key(&mut app, KeyCode::ControlLeft); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); release(&mut app, KeyCode::ControlLeft); app.update(); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn no_timeout_1frame() { let mut app = new_app(); app.world_mut().add( KeySequence::new(action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB]) .time_limit(TimeLimit::Frames(2)), ); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); app.update(); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_some()); } #[test] fn timeout_3frames() { let mut app = new_app(); app.world_mut().add( KeySequence::new( action::send_event(MyEvent), [KeyCode::KeyA, KeyCode::KeyB, KeyCode::KeyC], ) .time_limit(TimeLimit::Frames(2)), ); press_key(&mut app, KeyCode::KeyA); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyA); app.update(); press_key(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); clear_just_pressed(&mut app, KeyCode::KeyB); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); app.update(); assert!(app .world_mut() .query::<&EventSent>() .iter(&app.world_mut()) .next() .is_none()); } fn press_key(app: &mut App, key: KeyCode) { app.world_mut().resource_mut::>().press(key); } fn clear_just_pressed(app: &mut App, key: KeyCode) { app.world_mut() .resource_mut::>() .clear_just_pressed(key); } fn release(app: &mut App, key: KeyCode) { app.world_mut() .resource_mut::>() .release(key); } fn press_pad_button(app: &mut App, game_button: GamepadButtonType) { app.world_mut() .resource_mut::>() .press(GamepadButton::new(Gamepad::new(1), game_button)) } fn clear_just_pressed_pad_button(app: &mut App, game_button: GamepadButtonType) { app.world_mut() .resource_mut::>() .clear_just_pressed(GamepadButton::new(Gamepad::new(1), game_button)); } fn read( mut commands: Commands, mut er: EventReader, mut query: Query<&mut EventSent>, ) { for _ in er.read() { match query.get_single_mut() { Ok(ref mut event_sent) => { event_sent.0 += 1; } _ => { commands.spawn(EventSent(1)); } } } } fn new_app() -> App { let mut app = App::new(); app.add_plugins(MinimalPlugins); // app.add_plugins(DefaultPlugins); app.add_plugins( InputSequencePlugin::default() .match_key(true) .match_button(true), ); app.add_systems(PostUpdate, read); app.add_event::(); app.init_resource::(); app.init_resource::>(); app.init_resource::>(); app.init_resource::>(); app.init_resource::>(); app.init_resource::>(); app } }