diff --git a/Cargo.lock b/Cargo.lock index 417a31e3..bd76e38c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1843,6 +1843,7 @@ dependencies = [ "toml", "walkdir", "which", + "winapi 0.3.9", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0c4281f6..f6dd03b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ self_update_crate = { version = "0.19.0", optional = true, package = "self_upda [target.'cfg(windows)'.dependencies] self_update_crate = { version = "0.19.0", optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate"] } +winapi = "0.3.9" [target.'cfg(target_os = "linux")'.dependencies] rust-ini = "0.15.0" diff --git a/src/ctrlc/interrupted.rs b/src/ctrlc/interrupted.rs new file mode 100644 index 00000000..5322d9bb --- /dev/null +++ b/src/ctrlc/interrupted.rs @@ -0,0 +1,22 @@ +use lazy_static::lazy_static; +use std::sync::atomic::{AtomicBool, Ordering}; + +lazy_static! { + /// A global variable telling whether the application has been interrupted. + static ref INTERRUPTED: AtomicBool = AtomicBool::new(false); +} + +/// Tells whether the program has been interrupted +pub fn interrupted() -> bool { + INTERRUPTED.load(Ordering::SeqCst) +} + +/// Clears the interrupted flag +pub fn unset_interrupted() { + debug_assert!(INTERRUPTED.load(Ordering::SeqCst)); + INTERRUPTED.store(false, Ordering::SeqCst) +} + +pub fn set_interrupted() { + INTERRUPTED.store(true, Ordering::SeqCst) +} diff --git a/src/ctrlc/mod.rs b/src/ctrlc/mod.rs index 4284cd92..75c669aa 100644 --- a/src/ctrlc/mod.rs +++ b/src/ctrlc/mod.rs @@ -1,11 +1,13 @@ -//! Provides handling for process interruption. -//! There's no actual handling for Windows at the moment. +mod interrupted; + #[cfg(unix)] mod unix; #[cfg(unix)] -pub use self::unix::*; +pub use self::unix::set_handler; #[cfg(windows)] mod windows; #[cfg(windows)] -pub use self::windows::*; +pub use self::windows::set_handler; + +pub use self::interrupted::*; diff --git a/src/ctrlc/unix.rs b/src/ctrlc/unix.rs index d63eca81..e8e4a29f 100644 --- a/src/ctrlc/unix.rs +++ b/src/ctrlc/unix.rs @@ -1,27 +1,10 @@ //! SIGINT handling in Unix systems. -use lazy_static::lazy_static; +use crate::ctrlc::interrupted::set_interrupted; use nix::sys::signal; -use std::sync::atomic::{AtomicBool, Ordering}; - -lazy_static! { - /// A global variable telling whether the application has been interrupted. - static ref INTERRUPTED: AtomicBool = AtomicBool::new(false); -} - -/// Tells whether the program has been interrupted -pub fn interrupted() -> bool { - INTERRUPTED.load(Ordering::SeqCst) -} - -/// Clears the interrupted flag -pub fn unset_interrupted() { - debug_assert!(INTERRUPTED.load(Ordering::SeqCst)); - INTERRUPTED.store(false, Ordering::SeqCst) -} /// Handle SIGINT. Set the interruption flag. extern "C" fn handle_sigint(_: i32) { - INTERRUPTED.store(true, Ordering::SeqCst) + set_interrupted() } /// Set the necessary signal handlers. diff --git a/src/ctrlc/windows.rs b/src/ctrlc/windows.rs index 65ac4ef9..b5148ee7 100644 --- a/src/ctrlc/windows.rs +++ b/src/ctrlc/windows.rs @@ -1,9 +1,21 @@ //! A stub for Ctrl + C handling. +use crate::ctrlc::interrupted::set_interrupted; +use winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE}; +use winapi::um::consoleapi::SetConsoleCtrlHandler; +use winapi::um::wincon::CTRL_C_EVENT; -pub fn interrupted() -> bool { - false +extern "system" fn handler(ctrl_type: DWORD) -> BOOL { + match ctrl_type { + CTRL_C_EVENT => { + set_interrupted(); + TRUE + } + _ => FALSE, + } } -pub fn unset_interrupted() {} - -pub fn set_handler() {} +pub fn set_handler() { + if 0 == unsafe { SetConsoleCtrlHandler(Some(handler), TRUE) } { + log::error!("Cannot set a control C handler") + } +} diff --git a/src/terminal.rs b/src/terminal.rs index da58aea0..3465d1e6 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -211,13 +211,9 @@ impl Terminal { .write_fmt(format_args!( "\n{}", style(format!( - "{}Retry? (y)es/(N)o/(s)hell {}", + "{}Retry? (y)es/(N)o/(s)hell{}", self.prefix, - if interrupted { - "(Press Ctrl+C again to stop Topgrade) " - } else { - "" - } + if interrupted { "/(q)uit" } else { "" } )) .yellow() .bold() @@ -233,7 +229,8 @@ impl Terminal { break Ok(true); } 'n' | 'N' | '\r' | '\n' => break Ok(false), - _ => (), + 'q' | 'Q' => return Err(io::Error::from(io::ErrorKind::Interrupted)), + _ => println!("hi"), } };