-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Handle
Ctrl+C
in the terminal properly (#14001)
# Objective Fixes #13995. ## Solution Override the default `Ctrl+C` handler with one that sends `AppExit` event to every app with `TerminalCtrlCHandlerPlugin`. ## Testing Tested by running the `3d_scene` example and hitting `Ctrl+C` in the terminal. --- ## Changelog Handles `Ctrl+C` in the terminal gracefully. ## Migration Guide If you are overriding the `Ctrl+C` handler then you should call `TerminalCtrlCHandlerPlugin::gracefully_exit` from your handler. It will tell the app to exit.
- Loading branch information
1 parent
cb4fe4e
commit f607be8
Showing
4 changed files
with
85 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
use std::sync::atomic::{AtomicBool, Ordering}; | ||
|
||
use bevy_ecs::event::EventWriter; | ||
|
||
use crate::{App, AppExit, Plugin, Update}; | ||
|
||
pub use ctrlc; | ||
|
||
/// Indicates that all [`App`]'s should exit. | ||
static SHOULD_EXIT: AtomicBool = AtomicBool::new(false); | ||
|
||
/// Gracefully handles `Ctrl+C` by emitting a [`AppExit`] event. This plugin is part of the `DefaultPlugins`. | ||
/// | ||
/// ```no_run | ||
/// # use bevy_app::{App, NoopPluginGroup as MinimalPlugins, PluginGroup, TerminalCtrlCHandlerPlugin}; | ||
/// fn main() { | ||
/// App::new() | ||
/// .add_plugins(MinimalPlugins) | ||
/// .add_plugins(TerminalCtrlCHandlerPlugin) | ||
/// .run(); | ||
/// } | ||
/// ``` | ||
/// | ||
/// If you want to setup your own `Ctrl+C` handler, you should call the | ||
/// [`TerminalCtrlCHandlerPlugin::gracefully_exit`] function in your handler if you want bevy to gracefully exit. | ||
/// ```no_run | ||
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, TerminalCtrlCHandlerPlugin, ctrlc}; | ||
/// fn main() { | ||
/// // Your own `Ctrl+C` handler | ||
/// ctrlc::set_handler(move || { | ||
/// // Other clean up code ... | ||
/// | ||
/// TerminalCtrlCHandlerPlugin::gracefully_exit(); | ||
/// }); | ||
/// | ||
/// App::new() | ||
/// .add_plugins(DefaultPlugins) | ||
/// .run(); | ||
/// } | ||
/// ``` | ||
#[derive(Default)] | ||
pub struct TerminalCtrlCHandlerPlugin; | ||
|
||
impl TerminalCtrlCHandlerPlugin { | ||
/// Sends the [`AppExit`] event to all apps using this plugin to make them gracefully exit. | ||
pub fn gracefully_exit() { | ||
SHOULD_EXIT.store(true, Ordering::Relaxed); | ||
} | ||
|
||
/// Sends a [`AppExit`] event when the user presses `Ctrl+C` on the terminal. | ||
fn exit_on_flag(mut events: EventWriter<AppExit>) { | ||
if SHOULD_EXIT.load(Ordering::Relaxed) { | ||
events.send(AppExit::from_code(130)); | ||
} | ||
} | ||
} | ||
|
||
impl Plugin for TerminalCtrlCHandlerPlugin { | ||
fn build(&self, app: &mut App) { | ||
let result = ctrlc::try_set_handler(move || { | ||
Self::gracefully_exit(); | ||
}); | ||
match result { | ||
Ok(()) => {} | ||
Err(ctrlc::Error::MultipleHandlers) => { | ||
bevy_utils::tracing::info!("Skipping installing `Ctrl+C` handler as one was already installed. Please call `TerminalCtrlCHandlerPlugin::gracefully_exit` in your own `Ctrl+C` handler if you want Bevy to gracefully exit on `Ctrl+C`."); | ||
} | ||
Err(err) => bevy_utils::tracing::warn!("Failed to set `Ctrl+C` handler: {err}"), | ||
} | ||
|
||
app.add_systems(Update, TerminalCtrlCHandlerPlugin::exit_on_flag); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters