RichoDemus/bevy-console

Input event still passed down to the game when I type inside the console.

zsdominik opened this issue · 6 comments

Hi. I was able to smack this bad boy into my game and it is working correctly. My problem is that if I have controls assigned to certain characters for example 'A', 'D' etc.. The game still registers this.

Is that possible to block the capturing of the input events to the game when the terminal is up?

I don't actually now, if you could figure that out I can fix it, or you can open a PR yourself :)

mwcz commented

If anyone else comes across this, I worked around this in my game by handling input only if the console is closed, like this:

fn handle_input(
    mut events: EventReader<KeyboardInput>,
    console_open: Res<ConsoleOpen>,
) {
    if !console_open.open {
        for event in events.iter() {
            if let ElementState::Pressed = event.state {
                if let Some(KeyCode::T) = event.key_code {
                    // handle pressing T
                }
            }
        }
    }
}

I quickly checked to see if this method could also work with leafwing-input-manager, and my best guess at how to temporarily disable the input manager is release_all, though I haven't tested it.

Okay I think a possible solution would be creating a system which users can opt-in for which "consumes" all keyboard events after the console_ui system runs. (I believe egui processes inputs on PreUpdate, so the console input still should work, and since it would run after console_ui it would be possible to change console state)

i.e.:

pub fn block_inputs_on_console_focus(
    mut events: ResMut<Events<KeyboardInput>>, 
    console_open: Res<ConsoleOpen>
){
   if console_open.open {
      events.drain().for_each(drop)
   }
}

I don't think we should make this a default though since removing all keyboard inputs downstream is very imposing,

@brandon-reinhart what do you think ?

I quickly checked to see if this method could also work with leafwing-input-manager, and my best guess at how to temporarily disable the input manager is release_all, though I haven't tested it.

Can confirm that release_all() is a valid approach for preventing game input while the console is open, assuming your main game input is routed through leafwing_input_manager:

I have a plugin that adds the console plugin and custom commands, and clears input before CoreStage::Update:

pub struct ConsoleCommandsPlugin;

/// This stage runs at before Update, and clears out the leafwing ActionState to prevent character/game input while the console is open.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(StageLabel)]
struct ConsoleClearLeafwingInputStage;

impl Plugin for ConsoleCommandsPlugin {
    fn build(&self, app: &mut App) {
        app
            .add_plugin(bevy_console::ConsolePlugin)

            // Add a system that consumes keyboard input while the console is open.
            // It occurs before Update to ensure it happens before Leafwing input is consumed.
            .add_stage_before(CoreStage::Update, ConsoleClearLeafwingInputStage, SystemStage::parallel())
            .add_system_to_stage(ConsoleClearLeafwingInputStage, clear_leafwing_input)
            
            .add_console_command::<LogCommand, _, _>(log_command) // etc.
        ;
    }
}

fn clear_leafwing_input(
    mut query_actions: Query<&mut leafwing_input_manager::prelude::ActionState::<
        crate::main_game::input_leafwing::Action> // (this type would need to be your own game's Action type)
    >,
    console_open: Res<ConsoleOpen>
) {
    if console_open.open {
        for mut leafwing_action_state in query_actions.iter_mut() {
            leafwing_action_state.release_all();
        }
    }
}

Adding my two cents on input exclusivity, dedicated ad-hoc solutions (such as the release_all() strategy when using leafwing-input-manager) might be necessary for any project that grows large enough, but @makspll's suggestion to drain keyboard events as a non-default ConsoleConfiguration option seems like a great option for covering the needs of new projects.

FWIW, leafwing-input-manager has an optional feature egui that provides this functionality. All you have to do is opt-in in Cargo.toml and leafwing will ignore input whenever an egui window (like bevy_console's) is open. Obviously that doesn't solve this issue for all input managers, but I'm commenting here for visibility.

Edit: I've just noted a regression where the feature flag no longer works to prevent this behavior. I'll update this comment if I discover a fix.

Kromey commented

You should be able to handle this in your own input handling by simply checking wants_keyboard_input, although I haven't yet tried this myself. IMO this shouldn't be something that bevy-console should be asked to handle for you, but (assuming this works) it would be good to call out in the docs.