From bbda2e5a83972e876dcd74e77ed04b0a5a23956e Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sat, 23 Nov 2024 07:09:22 -0500 Subject: [PATCH 01/17] feature: Add trigger actions. --- src/action.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/action.rs b/src/action.rs index 7dfc22b..9475591 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,5 +1,7 @@ //! Common actions to do on key sequence matches use bevy::ecs::{ + prelude::{Commands}, + observer::TriggerTargets, event::{Event, EventWriter}, system::In, }; @@ -25,6 +27,20 @@ pub fn send_event(event: E) -> impl FnMut(EventWriter) { } } +/// Trigger and event. +pub fn trigger(event: E) -> impl FnMut(Commands) { + move |mut commands: Commands| { + commands.trigger(event.clone()); + } +} + +/// Trigger and event with targets. +pub fn trigger_targets(event: E, targets: T) -> impl FnMut(Commands) { + move |mut commands: Commands| { + commands.trigger_targets(event.clone(), targets.clone()); + } +} + /// Sends an event with input, .e.g, [ButtonSequence](crate::input_sequence::ButtonSequence) provides a [Gamepad](bevy::input::gamepad::Gamepad) identifier. pub fn send_event_with_input E>( mut f: F, From fbb12c644fa0ead16240ae05c4973635fbc71cc7 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sat, 23 Nov 2024 16:06:42 -0500 Subject: [PATCH 02/17] feature: Bump keyseq 0.4.0. Use caps 'Ctrl-A'. --- Cargo.toml | 2 +- README.md | 12 ++--- examples/keymod.rs | 4 +- tests/act.rs | 106 ++++++++++++++++++++++----------------------- tests/macros.rs | 8 ++-- tests/simulated.rs | 8 ++-- 6 files changed, 70 insertions(+), 70 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16515a0..a78aa82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ path = "examples/multiple_input.rs" [dependencies] bevy = { version = "0.14", default-features = false, features = [] } trie-rs = { version = "0.4" } -keyseq = { version = "0.3.0", features = [ "bevy" ] } +keyseq = { version = "0.4.0", features = [ "bevy" ] } [dev-dependencies] bevy = "0.14" diff --git a/README.md b/README.md index 5da2b3e..e670507 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ fn main() { fn setup(mut commands: Commands) { commands.add( KeySequence::new(action::send_event(MyEvent), - keyseq! { ctrl-E L M }) + keyseq! { Ctrl-E L M }) ); } @@ -147,7 +147,7 @@ struct MyEvent; fn create_key_sequence(mut commands: Commands) { commands.add(KeySequence::new( action::send_event(bevy::app::AppExit::default()), - keyseq! { ctrl-E L M } + keyseq! { Ctrl-E L M } )); } @@ -155,12 +155,12 @@ fn create_key_sequence_and_add_it_to_an_entity(mut commands: Commands) { let parent = commands.spawn_empty().id(); commands.entity(parent).add(KeySequence::new( action::send_event(MyEvent), - keyseq! { ctrl-E L M } + keyseq! { Ctrl-E L M } )); // OR commands.spawn_empty().add(KeySequence::new( action::send_event(MyEvent), - keyseq! { ctrl-E L M } + keyseq! { Ctrl-E L M } )); } ``` @@ -178,7 +178,7 @@ fn create_key_sequence_within_command(mut commands: Commands) { commands.add(|world: &mut World| { let builder = KeySequence::new( move || { info!("got it"); }, - keyseq! { ctrl-E L M } + keyseq! { Ctrl-E L M } ); let key_sequence: KeySequence = builder.build(world); // And then put it somewhere? It ought to go as a component. @@ -199,7 +199,7 @@ cargo run --example keycode ## keymod -The `keymod` example recognizes `ctrl-W ctrl-D ctrl-S ctrl-A` and fires an event. +The `keymod` example recognizes `Ctrl-W Ctrl-D Ctrl-S Ctrl-A` and fires an event. ``` sh cargo run --example keymod diff --git a/examples/keymod.rs b/examples/keymod.rs index fcc8a45..48e63f8 100644 --- a/examples/keymod.rs +++ b/examples/keymod.rs @@ -18,11 +18,11 @@ fn setup(mut commands: Commands) { commands.add( KeySequence::new( action::send_event(MyEvent), - keyseq!(ctrl-W ctrl-D ctrl-S ctrl-A), + keyseq!(Ctrl-W Ctrl-D Ctrl-S Ctrl-A), ) .time_limit(Duration::from_secs(1)), ); - println!("Press ctrl-W ctrl-D ctrl-S ctrl-A to emit event."); + println!("Press Ctrl-W Ctrl-D Ctrl-S Ctrl-A to emit event."); } fn input_sequence_event_system(mut er: EventReader) { diff --git a/tests/act.rs b/tests/act.rs index fec7e27..cceb1b8 100644 --- a/tests/act.rs +++ b/tests/act.rs @@ -33,131 +33,131 @@ fn eq_if_contains_key_in_lhs() { // #[test] // fn test_shifted_key_macro() { -// assert_eq!((Modifiers::CONTROL, KeyCode::KeyB), key! { ctrl-* }); +// assert_eq!((Modifiers::CONTROL, KeyCode::KeyB), key! { Ctrl-* }); // } /// XXX: This doc test isn't working. /// /// ```compile_fail -/// assert_eq!((Modifiers::CONTROL, KeyCode::F2), key!{ ctrl-f2 }); +/// assert_eq!((Modifiers::CONTROL, KeyCode::F2), key!{ Ctrl-f2 }); /// ``` /// /// ``` -/// let _ = key! { ctrl-* }); +/// let _ = key! { Ctrl-* }); /// ``` #[allow(unused_must_use)] #[test] fn test_key_macro() { - assert_eq!((Modifiers::CONTROL, KeyCode::KeyB), key! { ctrl-B }); - assert_eq!((Modifiers::CONTROL, KeyCode::Digit1), key! { ctrl-1 }); - assert_eq!((Modifiers::CONTROL, KeyCode::Digit2), key! { ctrl-2 }); - assert_eq!((Modifiers::CONTROL, KeyCode::F2), key! { ctrl-F2 }); - // assert_eq!((Modifiers::CONTROL, KeyCode::F2), key!{ ctrl-f2 }); - assert_eq!((Modifiers::CONTROL, KeyCode::Semicolon), key! { ctrl-; }); - // assert_eq!((Modifiers::CONTROL, KeyCode::Caret), key! { ctrl-^ }); - // assert_eq!((Modifiers::CONTROL, KeyCode::Colon), key! { ctrl-: }); - assert_eq!((Modifiers::CONTROL, KeyCode::Equal), key! { ctrl-= }); - assert_eq!((Modifiers::CONTROL, KeyCode::Comma), key! { ctrl-, }); - assert_eq!((Modifiers::CONTROL, KeyCode::Period), key! { ctrl-. }); - assert_eq!((Modifiers::CONTROL, KeyCode::Slash), key! { ctrl-/ }); - assert_eq!((Modifiers::CONTROL, KeyCode::Enter), key! { ctrl-Enter }); - assert_eq!((Modifiers::CONTROL, KeyCode::Space), key! { ctrl-Space }); - assert_eq!((Modifiers::CONTROL, KeyCode::Tab), key! { ctrl-Tab }); - assert_eq!((Modifiers::CONTROL, KeyCode::Delete), key! { ctrl-Delete }); - assert_eq!((Modifiers::CONTROL, KeyCode::Minus), key! { ctrl-- }); + assert_eq!((Modifiers::CONTROL, KeyCode::KeyB), key! { Ctrl-B }); + assert_eq!((Modifiers::CONTROL, KeyCode::Digit1), key! { Ctrl-1 }); + assert_eq!((Modifiers::CONTROL, KeyCode::Digit2), key! { Ctrl-2 }); + assert_eq!((Modifiers::CONTROL, KeyCode::F2), key! { Ctrl-F2 }); + // assert_eq!((Modifiers::CONTROL, KeyCode::F2), key!{ Ctrl-f2 }); + assert_eq!((Modifiers::CONTROL, KeyCode::Semicolon), key! { Ctrl-; }); + // assert_eq!((Modifiers::CONTROL, KeyCode::Caret), key! { Ctrl-^ }); + // assert_eq!((Modifiers::CONTROL, KeyCode::Colon), key! { Ctrl-: }); + assert_eq!((Modifiers::CONTROL, KeyCode::Equal), key! { Ctrl-= }); + assert_eq!((Modifiers::CONTROL, KeyCode::Comma), key! { Ctrl-, }); + assert_eq!((Modifiers::CONTROL, KeyCode::Period), key! { Ctrl-. }); + assert_eq!((Modifiers::CONTROL, KeyCode::Slash), key! { Ctrl-/ }); + assert_eq!((Modifiers::CONTROL, KeyCode::Enter), key! { Ctrl-Enter }); + assert_eq!((Modifiers::CONTROL, KeyCode::Space), key! { Ctrl-Space }); + assert_eq!((Modifiers::CONTROL, KeyCode::Tab), key! { Ctrl-Tab }); + assert_eq!((Modifiers::CONTROL, KeyCode::Delete), key! { Ctrl-Delete }); + assert_eq!((Modifiers::CONTROL, KeyCode::Minus), key! { Ctrl-- }); assert_eq!( (Modifiers::CONTROL | Modifiers::SHIFT, KeyCode::Minus), - key! { ctrl-shift-- } + key! { Ctrl-Shift-- } ); - // assert_eq!((Modifiers::CONTROL, KeyCode::Underline), key! { ctrl-_ }); + // assert_eq!((Modifiers::CONTROL, KeyCode::Underline), key! { Ctrl-_ }); // No colon key. - // assert_eq!((Modifiers::CONTROL, KeyCode::Colon), key! { ctrl-: }); + // assert_eq!((Modifiers::CONTROL, KeyCode::Colon), key! { Ctrl-: }); assert_eq!( (Modifiers::CONTROL | Modifiers::SHIFT, KeyCode::Semicolon), - key! { ctrl-shift-; } + key! { Ctrl-Shift-; } ); - assert_eq!((Modifiers::CONTROL, KeyCode::Quote), key! { ctrl-'\'' }); + assert_eq!((Modifiers::CONTROL, KeyCode::Quote), key! { Ctrl-'\'' }); assert_eq!( (Modifiers::CONTROL | Modifiers::SHIFT, KeyCode::KeyA), - key! { ctrl-shift-A } + key! { Ctrl-Shift-A } ); - // assert_eq!((Modifiers::CONTROL, KeyCode::KeyA), key!{ ctrl-A }); - assert_eq!((Modifiers::SUPER, KeyCode::KeyA), key! { super-A }); - assert_eq!((Modifiers::CONTROL, KeyCode::KeyA), key! { ctrl-A }); // Allow lowercase or demand lowercase? + // assert_eq!((Modifiers::CONTROL, KeyCode::KeyA), key!{ Ctrl-A }); + assert_eq!((Modifiers::SUPER, KeyCode::KeyA), key! { Super-A }); + assert_eq!((Modifiers::CONTROL, KeyCode::KeyA), key! { Ctrl-A }); // Allow lowercase or demand lowercase? assert_eq!((Modifiers::empty(), KeyCode::KeyA), key! { A }); let k = (Modifiers::empty(), KeyCode::KeyA); assert_eq!(k, key! { A }); // assert_eq!( // (Modifiers::CONTROL, KeyCode::Asterisk), - // key! { ctrl-Asterisk } + // key! { Ctrl-Asterisk } // ); assert_eq!( (Modifiers::CONTROL | Modifiers::SHIFT, KeyCode::Digit8), - key! { ctrl-shift-8 } + key! { Ctrl-Shift-8 } ); assert_eq!( (Modifiers::CONTROL | Modifiers::SHIFT, KeyCode::Digit8), - key! { ctrl-shift-Digit8 } + key! { Ctrl-Shift-Digit8 } ); // All bevy KeyCode names work. - // assert_eq!((Modifiers::CONTROL, KeyCode::Asterisk), key! { ctrl-* }); // with some short hand. + // assert_eq!((Modifiers::CONTROL, KeyCode::Asterisk), key! { Ctrl-* }); // with some short hand. - // assert_eq!((Modifiers::CONTROL, KeyCode::Plus), key! { ctrl-+ }); + // assert_eq!((Modifiers::CONTROL, KeyCode::Plus), key! { Ctrl-+ }); assert_eq!( (Modifiers::CONTROL | Modifiers::SHIFT, KeyCode::Equal), - key! { ctrl-shift-= } + key! { Ctrl-Shift-= } ); - // assert_eq!((Modifiers::CONTROL, KeyCode::At), key! { ctrl-@ }); + // assert_eq!((Modifiers::CONTROL, KeyCode::At), key! { Ctrl-@ }); assert_eq!( (Modifiers::CONTROL, KeyCode::BracketLeft), - key! { ctrl-'[' } + key! { Ctrl-'[' } ); assert_eq!( (Modifiers::CONTROL, KeyCode::BracketRight), - key! { ctrl-']' } + key! { Ctrl-']' } ); assert_eq!( (Modifiers::CONTROL, KeyCode::BracketRight), - key! { ctrl-']' } + key! { Ctrl-']' } ); - assert_eq!((Modifiers::CONTROL, KeyCode::Backquote), key! { ctrl-'`' }); - assert_eq!((Modifiers::CONTROL, KeyCode::Backslash), key! { ctrl-'\\' }); - assert_eq!((Modifiers::CONTROL, KeyCode::Escape), key! { ctrl-Escape }); - // assert_eq!((Modifiers::CONTROL, KeyCode::Escape), key!{ ctrl-Esc }); + assert_eq!((Modifiers::CONTROL, KeyCode::Backquote), key! { Ctrl-'`' }); + assert_eq!((Modifiers::CONTROL, KeyCode::Backslash), key! { Ctrl-'\\' }); + assert_eq!((Modifiers::CONTROL, KeyCode::Escape), key! { Ctrl-Escape }); + // assert_eq!((Modifiers::CONTROL, KeyCode::Escape), key!{ Ctrl-Esc }); assert_eq!( (Modifiers::CONTROL | Modifiers::ALT, KeyCode::KeyA), - key! { ctrl-alt-A } + key! { Ctrl-Alt-A } ); assert_eq!((Modifiers::empty(), KeyCode::KeyA), key! { A }); assert_eq!( (Modifiers::CONTROL | Modifiers::ALT, KeyCode::KeyA), - key! { ctrl-alt-A } + key! { Ctrl-Alt-A } ); assert_eq!( (Modifiers::CONTROL | Modifiers::ALT, KeyCode::KeyA), - key! { ctrl-alt-A } + key! { Ctrl-Alt-A } ); assert_eq!( (Modifiers::CONTROL | Modifiers::ALT, KeyCode::Semicolon), - key! { ctrl-alt-Semicolon } + key! { Ctrl-Alt-Semicolon } ); assert_eq!( (Modifiers::CONTROL | Modifiers::ALT, KeyCode::Semicolon), - key! { ctrl-alt-; } + key! { Ctrl-Alt-; } ); assert_eq!( ( Modifiers::CONTROL | Modifiers::ALT | Modifiers::SHIFT, KeyCode::Semicolon ), - key! { ctrl-alt-shift-; } // ctrl-alt-: + key! { Ctrl-Alt-Shift-; } // Ctrl-Alt-: ); assert_eq!( (Modifiers::CONTROL | Modifiers::ALT, KeyCode::Slash), - key! { ctrl-alt-/ } + key! { Ctrl-Alt-/ } ); } @@ -166,18 +166,18 @@ fn test_key_macro() { fn test_keyseq() { assert_eq!( vec![(Modifiers::CONTROL, KeyCode::KeyA)], - keyseq! { ctrl-A } + keyseq! { Ctrl-A } ); assert_eq!( vec![(Modifiers::CONTROL, KeyCode::KeyA)], - keyseq! { ctrl-ctrl-A } + keyseq! { Ctrl-Ctrl-A } ); assert_eq!( vec![ (Modifiers::CONTROL, KeyCode::KeyA), (Modifiers::ALT, KeyCode::KeyB) ], - keyseq! { ctrl-A alt-B } + keyseq! { Ctrl-A Alt-B } ); assert_eq!( diff --git a/tests/macros.rs b/tests/macros.rs index 8af3c13..5abf67e 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -11,25 +11,25 @@ fn test_keyseq_doc() { ] ); assert_eq!( - keyseq! { ctrl-A B }, + keyseq! { Ctrl-A B }, [ (Modifiers::CONTROL, KeyCode::KeyA), (Modifiers::empty(), KeyCode::KeyB) ] ); assert_eq!( - keyseq! { ctrl-alt-A Escape }, + keyseq! { Ctrl-Alt-A Escape }, [ (Modifiers::ALT | Modifiers::CONTROL, KeyCode::KeyA), (Modifiers::empty(), KeyCode::Escape) ] ); assert_eq!( - keyseq! { ctrl-; }, + keyseq! { Ctrl-; }, [(Modifiers::CONTROL, KeyCode::Semicolon)] ); assert_eq!( - keyseq! { ctrl-Semicolon }, + keyseq! { Ctrl-Semicolon }, [(Modifiers::CONTROL, KeyCode::Semicolon)] ); } diff --git a/tests/simulated.rs b/tests/simulated.rs index 06529ba..74f2b03 100644 --- a/tests/simulated.rs +++ b/tests/simulated.rs @@ -2,10 +2,10 @@ 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!(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"); } From 2ca3f5520cf88861973e51001f1787f1acff2e7d Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 24 Nov 2024 00:50:49 -0500 Subject: [PATCH 03/17] doc: Bump to 0.6.0. --- CHANGELOG.md | 5 ++++- Cargo.toml | 11 +++++------ README.md | 54 +++++++++++++++++++++++++++++++++++++++++++--------- src/lib.rs | 2 +- 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 197b8d5..a4b20e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ All notable changes to this project will be documented in this file. -## [0.4.0] - 2024-04-23 +## [0.5.0] - 2024-04-23 + +### Features +- Optimize look ups to incrementally search using O(log n) instead of O(m^2 log n). See [PR #7](https://github.com/not-elm/bevy-input-sequence/pull/7) for more details. ## [0.4.0] - 2024-04-23 diff --git a/Cargo.toml b/Cargo.toml index a78aa82..e120e43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bevy-input-sequence" -description = "Recognizes input sequences and send events" -version = "0.5.0" +description = "Recognizes and acts on input sequences" +version = "0.6.0" edition = "2021" authors = ["elm", "Shane Celis "] keywords = [ @@ -18,22 +18,18 @@ readme = "README.md" license = "MIT OR Apache-2.0" repository = "https://github.com/elm-register/bevy-input-sequence" - [[example]] name = "keycode" path = "examples/keycode.rs" - [[example]] name = "gamepad_button" path = "examples/gamepad_button.rs" - [[example]] name = "multiple_input" path = "examples/multiple_input.rs" - [dependencies] bevy = { version = "0.14", default-features = false, features = [] } trie-rs = { version = "0.4" } @@ -43,3 +39,6 @@ keyseq = { version = "0.4.0", features = [ "bevy" ] } bevy = "0.14" trybuild = "1.0" version-sync = "0.9" + +[patch.crates-io] +keyseq = { path = "../keyseq" } diff --git a/README.md b/README.md index e670507..fe3da51 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # bevy-input-sequence -Detect input sequences from the keyboard or a gamepad. +Recognizes and acts on input sequences from the keyboard or a gamepad. # Use Cases @@ -42,6 +42,7 @@ fn main() { } fn setup(mut commands: Commands) { + // Add key sequence. commands.add( KeySequence::new(say_hello, keyseq! { H I }) @@ -63,11 +64,11 @@ with `action::send_event()`. use bevy::prelude::*; use bevy_input_sequence::prelude::*; -// Define an event +/// Define an event. #[derive(Event, Clone, Debug)] struct MyEvent; -// Add event as an key sequence +/// Add event as an key sequence. fn main() { App::new() .add_plugins(MinimalPlugins) @@ -101,11 +102,11 @@ take an input of `Gamepad`. use bevy::prelude::*; use bevy_input_sequence::prelude::*; -// Define an event +/// Define an event. #[derive(Event, Clone, Debug)] struct MyEvent(Gamepad); -// Add event as an key sequence +/// Add event as an key sequence. fn main() { App::new() .add_plugins(MinimalPlugins) @@ -132,6 +133,41 @@ fn check_events(mut events: EventReader) { } ``` +## Trigger an Event on Key Sequence + +You can also trigger an event with `action::trigger()` or `action::trigger_targets()`. + +```rust +use bevy::prelude::*; +use bevy_input_sequence::prelude::*; + +/// Define an event. +#[derive(Event, Clone, Debug)] +struct MyEvent; + +/// Add event as an key sequence. +fn main() { + App::new() + .add_plugins(MinimalPlugins) + .add_plugins(InputSequencePlugin::default()) + .add_event::() + .add_systems(Startup, setup) + .observe(check_trigger) + .update(); // Normally you'd run it here. +} + +fn setup(mut commands: Commands) { + commands.add( + KeySequence::new(action::trigger(MyEvent), + keyseq! { Ctrl-E L M }) + ); +} + +fn check_trigger(mut trigger: Trigger) { + info!("got event {:?}", trigger.event()); +} +``` + ## KeySequence Creation Patterns `KeySequence::new` now returns `KeySequenceBuilder`, which implements `Command`. @@ -152,8 +188,8 @@ fn create_key_sequence(mut commands: Commands) { } fn create_key_sequence_and_add_it_to_an_entity(mut commands: Commands) { - let parent = commands.spawn_empty().id(); - commands.entity(parent).add(KeySequence::new( + let id = commands.spawn_empty().id(); + commands.entity(id).add(KeySequence::new( action::send_event(MyEvent), keyseq! { Ctrl-E L M } )); @@ -254,8 +290,8 @@ cargo run --example run_if | bevy-input-sequence | bevy | |---------------------|------| -| 0.5 | 0.14 | -| 0.3 ~ 0.4.0 | 0.13 | +| 0.5 ~ 0.6 | 0.14 | +| 0.3 ~ 0.4 | 0.13 | | 0.2 | 0.12 | | 0.1 | 0.11 | diff --git a/src/lib.rs b/src/lib.rs index a157c96..2b7884b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://docs.rs/bevy-input-sequence/0.5.0")] +#![doc(html_root_url = "https://docs.rs/bevy-input-sequence/0.6.0")] #![doc = include_str!("../README.md")] #![forbid(missing_docs)] From c184021fa55a6a96cf3272aed60406d629f1d039 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 24 Nov 2024 14:57:21 -0500 Subject: [PATCH 04/17] chore: Update to Modifier::From. --- src/cond_system.rs | 2 +- src/plugin.rs | 2 +- tests/simulated.rs | 76 +++++++++++++++++++++++----------------------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/cond_system.rs b/src/cond_system.rs index 271858f..1f813b5 100644 --- a/src/cond_system.rs +++ b/src/cond_system.rs @@ -34,7 +34,7 @@ pub trait IntoCondSystem: IntoSystem { } } -impl IntoCondSystem for T where T: IntoSystem + ?Sized {} +impl IntoCondSystem for T where T: IntoSystem {} /// A one-shot conditional system comprised of consequent `SystemA` and /// conditional `SystemB`. diff --git a/src/plugin.rs b/src/plugin.rs index bf5659f..1fb7cb4 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -234,7 +234,7 @@ fn key_sequence_matcher( frame_count: Res, mut commands: Commands, ) { - let mods = Modifiers::from_input(&keys); + let mods = Modifiers::from(&keys); let now = FrameTime { frame: frame_count.0, time: time.elapsed_seconds(), diff --git a/tests/simulated.rs b/tests/simulated.rs index 74f2b03..1d832db 100644 --- a/tests/simulated.rs +++ b/tests/simulated.rs @@ -64,7 +64,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -86,7 +86,7 @@ mod simulate_app { assert_eq!( app.world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .count(), 1 ); @@ -110,7 +110,7 @@ mod simulate_app { assert_eq!( app.world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .count(), 2 ); @@ -134,7 +134,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -144,7 +144,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -167,7 +167,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -177,7 +177,7 @@ mod simulate_app { assert_eq!( app.world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .map(|x| x.0) .unwrap(), @@ -190,7 +190,7 @@ mod simulate_app { assert_eq!( app.world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .map(|x| x.0) .unwrap(), @@ -203,7 +203,7 @@ mod simulate_app { assert_eq!( app.world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .map(|x| x.0) .unwrap(), @@ -229,7 +229,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -239,7 +239,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -265,7 +265,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -275,7 +275,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -301,7 +301,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -311,7 +311,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -330,7 +330,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -340,7 +340,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -359,7 +359,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -369,7 +369,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -379,7 +379,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); } @@ -409,7 +409,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -419,7 +419,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -429,7 +429,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -470,7 +470,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -480,7 +480,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -490,7 +490,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -500,7 +500,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -520,7 +520,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -534,7 +534,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); } @@ -553,7 +553,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -565,7 +565,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); release(&mut app, KeyCode::ControlLeft); @@ -576,7 +576,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -595,7 +595,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -607,7 +607,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_some()); } @@ -629,7 +629,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -641,7 +641,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -650,7 +650,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); @@ -658,7 +658,7 @@ mod simulate_app { assert!(app .world_mut() .query::<&EventSent>() - .iter(&app.world_mut()) + .iter(app.world_mut()) .next() .is_none()); } From 428e21649d9016d0393e5a314d1ba1883dbeebcf Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 24 Nov 2024 23:42:24 -0500 Subject: [PATCH 05/17] doc: Update changelog. --- CHANGELOG.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4b20e2..083637d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,18 @@ All notable changes to this project will be documented in this file. -## [0.5.0] - 2024-04-23 +## [unreleased] + +## [0.6.0] - 2024-11-24 + +## [0.5.0] - 2024-06-05 ### Features - Optimize look ups to incrementally search using O(log n) instead of O(m^2 log n). See [PR #7](https://github.com/not-elm/bevy-input-sequence/pull/7) for more details. +### Bugs +- Fix bug where "W A S D" and "A S" sequences would match the latter pattern when "W A S P" was typed. + ## [0.4.0] - 2024-04-23 ### Features @@ -15,7 +22,7 @@ All notable changes to this project will be documented in this file. - Use plugin. - Can configure schedule and system set. - Remove `GamepadEvent`; use system with input `In`. -- Add `IntoCondSystem` that adds `only_if()` conditions to `IntoSystems`. +- Add `IntoCondSystem` that adds `only_if()` conditi:ons to `IntoSystems`. - Add `only_if` example. - Add `prelude` module for glob imports. From afd2b6d3a05134cb3f60de7fa9bef42e3ffb8218 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Thu, 28 Nov 2024 05:48:59 -0500 Subject: [PATCH 06/17] excise: Remove patch; keyseq now published. --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e120e43..f082316 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,3 @@ keyseq = { version = "0.4.0", features = [ "bevy" ] } bevy = "0.14" trybuild = "1.0" version-sync = "0.9" - -[patch.crates-io] -keyseq = { path = "../keyseq" } From 212549b946ee9693291e7ec0dfd1913c14b9400f Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Thu, 28 Nov 2024 05:49:43 -0500 Subject: [PATCH 07/17] style: Cargo fmt. --- src/action.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/action.rs b/src/action.rs index 9475591..1b0cc38 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,8 +1,8 @@ //! Common actions to do on key sequence matches use bevy::ecs::{ - prelude::{Commands}, - observer::TriggerTargets, event::{Event, EventWriter}, + observer::TriggerTargets, + prelude::Commands, system::In, }; @@ -35,7 +35,10 @@ pub fn trigger(event: E) -> impl FnMut(Commands) { } /// Trigger and event with targets. -pub fn trigger_targets(event: E, targets: T) -> impl FnMut(Commands) { +pub fn trigger_targets( + event: E, + targets: T, +) -> impl FnMut(Commands) { move |mut commands: Commands| { commands.trigger_targets(event.clone(), targets.clone()); } From fbec223236f655c2100304bbee8958400f653dbc Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Thu, 28 Nov 2024 05:54:00 -0500 Subject: [PATCH 08/17] doc: Fix typo. --- src/action.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/action.rs b/src/action.rs index 1b0cc38..6da5e91 100644 --- a/src/action.rs +++ b/src/action.rs @@ -27,14 +27,14 @@ pub fn send_event(event: E) -> impl FnMut(EventWriter) { } } -/// Trigger and event. +/// Trigger an event. pub fn trigger(event: E) -> impl FnMut(Commands) { move |mut commands: Commands| { commands.trigger(event.clone()); } } -/// Trigger and event with targets. +/// Trigger an event with targets. pub fn trigger_targets( event: E, targets: T, From df8a7a8c964a56fe8b007a1e6a516ea8f3019e3c Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sat, 30 Nov 2024 01:41:11 -0500 Subject: [PATCH 09/17] doc: Update changelog. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 083637d..cd963c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ All notable changes to this project will be documented in this file. ## [0.6.0] - 2024-11-24 +- Add `action::trigger` and `action::trigger_targets` convenience systems. +- Bump keyseq to 0.4.0, which changes notation to be more standard: `Ctrl-A` + instead of `ctrl-A`. + ## [0.5.0] - 2024-06-05 ### Features From 3da846c98fd1712408ec882c23f0125333a6d93f Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sat, 30 Nov 2024 22:16:42 -0500 Subject: [PATCH 10/17] test: Start of test. --- tests/simulated.rs | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/simulated.rs b/tests/simulated.rs index 1d832db..c46f65f 100644 --- a/tests/simulated.rs +++ b/tests/simulated.rs @@ -243,6 +243,41 @@ mod simulate_app { .next() .is_some()); } + #[test] + fn match_ab_and_c() { + let mut app = new_app(); + + app.world_mut().add(KeySequence::new( + action::send_event(EventSent(0)), + [KeyCode::KeyA, KeyCode::KeyB], + )); + app.world_mut().add(KeySequence::new( + action::send_event(EventSent(1)), + [KeyCode::KeyA], + )); + app.world_mut().add(KeySequence::new( + action::send_event(EventSent(2)), + [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() + .map(|x| x.0 == 0).unwrap_or(false)); + } #[test] fn two_any_patterns() { From 21b90a27ede360a7730cc4c114ebdd0ec7046927 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 1 Dec 2024 06:37:05 -0500 Subject: [PATCH 11/17] test: Finish test for correct behavior. Test fails but that's ok. --- tests/simulated.rs | 47 +++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/tests/simulated.rs b/tests/simulated.rs index c46f65f..bd8efa3 100644 --- a/tests/simulated.rs +++ b/tests/simulated.rs @@ -30,7 +30,7 @@ mod simulate_app { keyboard::KeyCode, Axis, ButtonInput as Input, }, - prelude::Commands, + prelude::{Resource, Commands, ResMut}, MinimalPlugins, }; use bevy_input_sequence::prelude::*; @@ -51,6 +51,19 @@ mod simulate_app { } } + #[derive(Resource, Default)] + struct R(u8); + + fn set(x: u8) -> impl Fn(ResMut) { + move |mut r: ResMut| { + r.0 = x; + } + } + + fn get(world: &World) -> u8 { + world.resource::().0 + } + #[test] fn one_key() { let mut app = new_app(); @@ -243,40 +256,31 @@ mod simulate_app { .next() .is_some()); } + #[test] - fn match_ab_and_c() { + fn match_a_and_c() { let mut app = new_app(); app.world_mut().add(KeySequence::new( - action::send_event(EventSent(0)), - [KeyCode::KeyA, KeyCode::KeyB], + set(1), + [KeyCode::KeyA], )); app.world_mut().add(KeySequence::new( - action::send_event(EventSent(1)), - [KeyCode::KeyA], + set(2), + [KeyCode::KeyA, KeyCode::KeyB], )); app.world_mut().add(KeySequence::new( - action::send_event(EventSent(2)), + set(3), [KeyCode::KeyC], )); + assert_eq!(get(app.world()), 0); press_key(&mut app, KeyCode::KeyA); app.update(); - assert!(app - .world_mut() - .query::<&EventSent>() - .iter(app.world_mut()) - .next() - .is_none()); - + assert_eq!(get(app.world()), 1); clear_just_pressed(&mut app, KeyCode::KeyA); - press_key(&mut app, KeyCode::KeyB); + press_key(&mut app, KeyCode::KeyC); app.update(); - assert!(app - .world_mut() - .query::<&EventSent>() - .iter(app.world_mut()) - .next() - .map(|x| x.0 == 0).unwrap_or(false)); + assert_eq!(get(app.world()), 3); } #[test] @@ -754,6 +758,7 @@ mod simulate_app { ); app.add_systems(PostUpdate, read); app.add_event::(); + app.init_resource::(); app.init_resource::(); app.init_resource::>(); app.init_resource::>(); From 7acecd2c996f287f5fade3edb0804055a00dd2a2 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 1 Dec 2024 06:37:39 -0500 Subject: [PATCH 12/17] feature: Add manual Debug impl for InputSequence. --- src/input_sequence.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/input_sequence.rs b/src/input_sequence.rs index 5d444e1..8dca74d 100644 --- a/src/input_sequence.rs +++ b/src/input_sequence.rs @@ -1,5 +1,6 @@ //! Input sequences for keys and gamepad buttons use crate::{cond_system::IntoCondSystem, time_limit::TimeLimit, KeyChord}; +use std::fmt; use bevy::{ ecs::{ @@ -26,6 +27,26 @@ pub struct InputSequence { pub time_limit: Option, } +impl fmt::Debug for InputSequence { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + #[derive(Debug)] + #[allow(dead_code)] + struct InputSequence<'a, Act> { + // system_id: SystemId, + acts: &'a Vec, + time_limit: &'a Option, + } + + let Self { + acts, + time_limit, + system_id: _, + } = self; + + fmt::Debug::fmt(&InputSequence { acts, time_limit }, f) + } +} + /// An input sequence builder. pub struct InputSequenceBuilder { /// The action when to run when sequence matches From 98610676b0b959868768a1ebc3274b0872392fbf Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 1 Dec 2024 06:38:53 -0500 Subject: [PATCH 13/17] bug: Fix the match & prefix match bug. When the last keychord fails to match, we should check if it itself matches something. --- src/chord.rs | 12 +++++++++--- src/lib.rs | 11 +++++------ src/plugin.rs | 28 +++++++++++++++++++++------- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/src/chord.rs b/src/chord.rs index e1c4428..5e0da45 100644 --- a/src/chord.rs +++ b/src/chord.rs @@ -1,9 +1,8 @@ use bevy::{ - input::keyboard::KeyCode, - reflect::{Enum, Reflect}, + input::keyboard::KeyCode, prelude::{Deref, DerefMut, Resource}, reflect::{Enum, Reflect} }; -use std::fmt; +use std::{collections::VecDeque, fmt}; use keyseq::Modifiers; @@ -56,3 +55,10 @@ impl From for KeyChord { pub(crate) fn is_modifier(key: KeyCode) -> bool { !Modifiers::from(key).is_empty() } + +/// Manually add key chords to be processed as through they were pressed by the +/// user. +/// +/// Normally this does not need to be manipulated. It is a kind of escape hatch. +#[derive(Resource, Debug, Deref, DerefMut, Default)] +pub struct KeyChordQueue(pub VecDeque); diff --git a/src/lib.rs b/src/lib.rs index 2b7884b..6cf22a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,6 @@ #![doc = include_str!("../README.md")] #![forbid(missing_docs)] -pub use chord::KeyChord; -pub use plugin::InputSequencePlugin; -pub use time_limit::TimeLimit; - pub mod action; pub mod cache; mod chord; @@ -15,6 +11,10 @@ pub mod input_sequence; mod plugin; mod time_limit; +pub use chord::{KeyChord, KeyChordQueue}; +pub use plugin::{InputSequencePlugin}; +pub use time_limit::TimeLimit; + pub use keyseq::{ bevy::{pkey as key, pkeyseq as keyseq}, Modifiers, @@ -24,8 +24,7 @@ pub use keyseq::{ pub mod prelude { pub use super::input_sequence::{ButtonSequence, InputSequence, KeySequence}; pub use super::{action, keyseq, InputSequencePlugin, Modifiers, TimeLimit}; - - pub use super::chord::KeyChord; + pub use super::{KeyChordQueue, KeyChord}; pub use super::cond_system::IntoCondSystem; pub use std::time::Duration; } diff --git a/src/plugin.rs b/src/plugin.rs index 1fb7cb4..510bd5c 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -20,7 +20,7 @@ use std::collections::{HashMap, VecDeque}; use crate::{ cache::InputSequenceCache, - chord::is_modifier, + chord::{KeyChordQueue, is_modifier}, frame_time::FrameTime, input_sequence::{ButtonSequence, InputSequence, KeySequence}, KeyChord, Modifiers, @@ -53,6 +53,7 @@ impl Plugin for InputSequencePlugin { { // Add key sequence. app.init_resource::>(); + app.init_resource::(); for (schedule, set) in &self.schedules { if let Some(set) = set { @@ -233,6 +234,7 @@ fn key_sequence_matcher( mut cache: ResMut>, frame_count: Res, mut commands: Commands, + mut keychord_queue: ResMut, ) { let mods = Modifiers::from(&keys); let now = FrameTime { @@ -240,14 +242,15 @@ fn key_sequence_matcher( time: time.elapsed_seconds(), }; let maybe_start = last_times.front().cloned(); - let mut input = keys + let mut input = keychord_queue.drain(..).chain( + keys .get_just_pressed() .filter(|k| !is_modifier(**k)) .map(|k| { let chord = KeyChord(mods, *k); last_times.push_back(now.clone()); chord - }) + })) .peekable(); if input.peek().is_none() { return; @@ -297,11 +300,22 @@ where None => { search.reset(); // This could be the start of a new sequence. - if search.query(&k).is_none() { - // This may not be necessary. - search.reset(); + // + // Let's check it. + match search.query(&k) { + Some(Answer::Match) => { + let result = Some(search.value().unwrap()); + search.reset(); + result + } + Some(Answer::PrefixAndMatch) => Some(search.value().unwrap()), + Some(Answer::Prefix) => None, + None => { + // This may not be necessary. + search.reset(); + None + } } - None } } }) From cf89e1bf4205a6d90f1d2ceea98fd5468bd8d93f Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 1 Dec 2024 06:41:09 -0500 Subject: [PATCH 14/17] style: Cargo fmt. --- src/chord.rs | 4 +++- src/lib.rs | 6 +++--- src/plugin.rs | 22 ++++++++++++---------- tests/simulated.rs | 20 +++++++------------- 4 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/chord.rs b/src/chord.rs index 5e0da45..e72f76a 100644 --- a/src/chord.rs +++ b/src/chord.rs @@ -1,5 +1,7 @@ use bevy::{ - input::keyboard::KeyCode, prelude::{Deref, DerefMut, Resource}, reflect::{Enum, Reflect} + input::keyboard::KeyCode, + prelude::{Deref, DerefMut, Resource}, + reflect::{Enum, Reflect}, }; use std::{collections::VecDeque, fmt}; diff --git a/src/lib.rs b/src/lib.rs index 6cf22a5..e67b258 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,7 +12,7 @@ mod plugin; mod time_limit; pub use chord::{KeyChord, KeyChordQueue}; -pub use plugin::{InputSequencePlugin}; +pub use plugin::InputSequencePlugin; pub use time_limit::TimeLimit; pub use keyseq::{ @@ -22,9 +22,9 @@ pub use keyseq::{ /// Convenient glob import pub mod prelude { + pub use super::cond_system::IntoCondSystem; pub use super::input_sequence::{ButtonSequence, InputSequence, KeySequence}; pub use super::{action, keyseq, InputSequencePlugin, Modifiers, TimeLimit}; - pub use super::{KeyChordQueue, KeyChord}; - pub use super::cond_system::IntoCondSystem; + pub use super::{KeyChord, KeyChordQueue}; pub use std::time::Duration; } diff --git a/src/plugin.rs b/src/plugin.rs index 510bd5c..7672758 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -20,7 +20,7 @@ use std::collections::{HashMap, VecDeque}; use crate::{ cache::InputSequenceCache, - chord::{KeyChordQueue, is_modifier}, + chord::{is_modifier, KeyChordQueue}, frame_time::FrameTime, input_sequence::{ButtonSequence, InputSequence, KeySequence}, KeyChord, Modifiers, @@ -242,15 +242,17 @@ fn key_sequence_matcher( time: time.elapsed_seconds(), }; let maybe_start = last_times.front().cloned(); - let mut input = keychord_queue.drain(..).chain( - keys - .get_just_pressed() - .filter(|k| !is_modifier(**k)) - .map(|k| { - let chord = KeyChord(mods, *k); - last_times.push_back(now.clone()); - chord - })) + let mut input = keychord_queue + .drain(..) + .chain( + keys.get_just_pressed() + .filter(|k| !is_modifier(**k)) + .map(|k| { + let chord = KeyChord(mods, *k); + last_times.push_back(now.clone()); + chord + }), + ) .peekable(); if input.peek().is_none() { return; diff --git a/tests/simulated.rs b/tests/simulated.rs index bd8efa3..c32f321 100644 --- a/tests/simulated.rs +++ b/tests/simulated.rs @@ -30,7 +30,7 @@ mod simulate_app { keyboard::KeyCode, Axis, ButtonInput as Input, }, - prelude::{Resource, Commands, ResMut}, + prelude::{Commands, ResMut, Resource}, MinimalPlugins, }; use bevy_input_sequence::prelude::*; @@ -261,18 +261,12 @@ mod simulate_app { fn match_a_and_c() { let mut app = new_app(); - app.world_mut().add(KeySequence::new( - set(1), - [KeyCode::KeyA], - )); - app.world_mut().add(KeySequence::new( - set(2), - [KeyCode::KeyA, KeyCode::KeyB], - )); - app.world_mut().add(KeySequence::new( - set(3), - [KeyCode::KeyC], - )); + app.world_mut() + .add(KeySequence::new(set(1), [KeyCode::KeyA])); + app.world_mut() + .add(KeySequence::new(set(2), [KeyCode::KeyA, KeyCode::KeyB])); + app.world_mut() + .add(KeySequence::new(set(3), [KeyCode::KeyC])); assert_eq!(get(app.world()), 0); press_key(&mut app, KeyCode::KeyA); app.update(); From 810ddd1219a9b0e086379b7aca93850f206c90a8 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 8 Dec 2024 00:40:13 -0500 Subject: [PATCH 15/17] test: Test macro delimiter reformatting. --- tests/macros.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/macros.rs b/tests/macros.rs index 5abf67e..80d49a6 100644 --- a/tests/macros.rs +++ b/tests/macros.rs @@ -1,6 +1,62 @@ use bevy::prelude::*; use bevy_input_sequence::*; +#[rustfmt::skip] +#[test] +fn before_cargo_format() { + assert_eq!( + [key![Ctrl-A], + key! [Ctrl-A], + key! [ Ctrl-A ], + key!{Ctrl-A}, + key! {Ctrl-A}, + key! { Ctrl-A }, + key!(Ctrl-A), + key! (Ctrl-A), + key! ( Ctrl-A ), + ], + [ + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + ] + ); +} + +#[test] +fn after_cargo_format() { + assert_eq!( + [ + key![Ctrl - A], + key![Ctrl - A], + key![Ctrl - A], + key! {Ctrl-A}, + key! {Ctrl-A}, + key! { Ctrl-A }, + key!(Ctrl - A), + key!(Ctrl - A), + key!(Ctrl - A), + ], + [ + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + (Modifiers::CONTROL, KeyCode::KeyA), + ] + ); +} + #[test] fn test_keyseq_doc() { assert_eq!( From 2e1c64b091f3675bc75bbeca1481e3cf95c50835 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 8 Dec 2024 00:40:32 -0500 Subject: [PATCH 16/17] chore: Bump keyseq version. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f082316..55ec8ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ path = "examples/multiple_input.rs" [dependencies] bevy = { version = "0.14", default-features = false, features = [] } trie-rs = { version = "0.4" } -keyseq = { version = "0.4.0", features = [ "bevy" ] } +keyseq = { version = "0.4.1", features = [ "bevy" ] } [dev-dependencies] bevy = "0.14" From 96ff8512272089581940737ce3b4ce512924bc58 Mon Sep 17 00:00:00 2001 From: Shane Celis Date: Sun, 8 Dec 2024 02:08:40 -0500 Subject: [PATCH 17/17] style: Switch to curly braces for macro. --- examples/keycode.rs | 2 +- examples/keymod.rs | 2 +- examples/multiple_input.rs | 4 ++-- examples/only_if.rs | 4 ++-- examples/run_if.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/keycode.rs b/examples/keycode.rs index 76a3d87..34ed33b 100644 --- a/examples/keycode.rs +++ b/examples/keycode.rs @@ -39,7 +39,7 @@ fn setup(mut commands: Commands) { commands.add( KeySequence::new( action::send_event(MyEvent(Direction::CounterClockwise)), - keyseq!(W A S D), + keyseq!{ W A S D }, ) .time_limit(Duration::from_secs(1)), ); diff --git a/examples/keymod.rs b/examples/keymod.rs index 48e63f8..07f3e11 100644 --- a/examples/keymod.rs +++ b/examples/keymod.rs @@ -18,7 +18,7 @@ fn setup(mut commands: Commands) { commands.add( KeySequence::new( action::send_event(MyEvent), - keyseq!(Ctrl-W Ctrl-D Ctrl-S Ctrl-A), + keyseq! { Ctrl-W Ctrl-D Ctrl-S Ctrl-A }, ) .time_limit(Duration::from_secs(1)), ); diff --git a/examples/multiple_input.rs b/examples/multiple_input.rs index c88b65b..1e03974 100644 --- a/examples/multiple_input.rs +++ b/examples/multiple_input.rs @@ -17,7 +17,7 @@ fn main() { fn setup(mut commands: Commands) { commands.add( - KeySequence::new(action::send_event(MyEvent(1, None)), keyseq!(W D S A)) + KeySequence::new(action::send_event(MyEvent(1, None)), keyseq! { W D S A }) .time_limit(Duration::from_secs(5)), ); @@ -35,7 +35,7 @@ fn setup(mut commands: Commands) { ); commands.add( - KeySequence::new(action::send_event(MyEvent(3, None)), keyseq!(W A S D)) + KeySequence::new(action::send_event(MyEvent(3, None)), keyseq! { W A S D }) .time_limit(Duration::from_secs(5)), ); diff --git a/examples/only_if.rs b/examples/only_if.rs index 54884da..9a3370f 100644 --- a/examples/only_if.rs +++ b/examples/only_if.rs @@ -30,12 +30,12 @@ fn main() { fn setup(mut commands: Commands) { commands.add(KeySequence::new( action::send_event(GlobalEvent), - keyseq!(Escape), + keyseq! { Escape }, )); commands.add( KeySequence::new( action::send_event(MyEvent).only_if(in_state(AppState::Game)), - keyseq!(Space), + keyseq! { Space }, ) .time_limit(Duration::from_secs(1)), ); diff --git a/examples/run_if.rs b/examples/run_if.rs index e27641b..ef94af3 100644 --- a/examples/run_if.rs +++ b/examples/run_if.rs @@ -31,7 +31,7 @@ fn setup(mut commands: Commands) { commands.add( KeySequence::new( action::send_event(MyEvent).only_if(in_state(AppState::Game)), - keyseq!(Space), + keyseq! { Space }, ) .time_limit(Duration::from_secs(1)), );