diff --git a/src/terminal.rs b/src/terminal.rs index ef5b293..2676d3b 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -98,6 +98,21 @@ use crate::{csi, impl_display, Result}; pub(crate) mod sys; +/// Tells whether the raw mode is enabled. +/// +/// Please have a look at the [raw mode](./#raw-mode) section. +pub fn is_raw_mode_enabled() -> Result { + #[cfg(unix)] + { + Ok(sys::is_raw_mode_enabled()) + } + + #[cfg(windows)] + { + sys::is_raw_mode_enabled() + } +} + /// Enables raw mode. /// /// Please have a look at the [raw mode](./#raw-mode) section. @@ -372,7 +387,7 @@ mod tests { use crate::execute; - use super::{size, SetSize}; + use super::*; // Test is disabled, because it's failing on Travis CI #[test] @@ -395,4 +410,29 @@ mod tests { assert_eq!((width, height), size().unwrap()); } + + #[test] + fn test_raw_mode() { + // check we start from normal mode (may fail on some test harnesses) + assert_eq!(is_raw_mode_enabled().unwrap(), false); + + // enable the raw mode + enable_raw_mode().unwrap(); + + // check it worked (on unix it doesn't really check the underlying + // tty but rather check that the code is consistent) + assert_eq!(is_raw_mode_enabled().unwrap(), true); + + // enable it again, this should not change anything + enable_raw_mode().unwrap(); + + // check we're still in raw mode + assert_eq!(is_raw_mode_enabled().unwrap(), true); + + // now let's disable it + disable_raw_mode().unwrap(); + + // check we're back to normal mode + assert_eq!(is_raw_mode_enabled().unwrap(), false); + } } diff --git a/src/terminal/sys.rs b/src/terminal/sys.rs index 89fd923..0c09fb4 100644 --- a/src/terminal/sys.rs +++ b/src/terminal/sys.rs @@ -4,8 +4,8 @@ pub(crate) use self::unix::{disable_raw_mode, enable_raw_mode, is_raw_mode_enabled, size}; #[cfg(windows)] pub(crate) use self::windows::{ - clear, disable_raw_mode, enable_raw_mode, scroll_down, scroll_up, set_size, set_window_title, - size, + clear, disable_raw_mode, enable_raw_mode, is_raw_mode_enabled, scroll_down, scroll_up, + set_size, set_window_title, size, }; #[cfg(windows)] diff --git a/src/terminal/sys/unix.rs b/src/terminal/sys/unix.rs index ecf4bff..b651d90 100644 --- a/src/terminal/sys/unix.rs +++ b/src/terminal/sys/unix.rs @@ -67,6 +67,11 @@ pub(crate) fn enable_raw_mode() -> Result<()> { Ok(()) } +/// Reset the raw mode. +/// +/// More precisely, reset the whole termios mode to what it was before the first call +/// to [enable_raw_mode]. If you don't mess with termios outside of crossterm, it's +/// effectively disabling the raw mode and doing nothing else. pub(crate) fn disable_raw_mode() -> Result<()> { let mut original_mode = TERMINAL_MODE_PRIOR_RAW_MODE.lock(); diff --git a/src/terminal/sys/windows.rs b/src/terminal/sys/windows.rs index 33bb422..d948b50 100644 --- a/src/terminal/sys/windows.rs +++ b/src/terminal/sys/windows.rs @@ -11,14 +11,26 @@ use winapi::{ use crate::{cursor, terminal::ClearType, ErrorKind, Result}; -const RAW_MODE_MASK: DWORD = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT; +/// bits which can't be set in raw mode +const NOT_RAW_MODE_MASK: DWORD = ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT; + +pub(crate) fn is_raw_mode_enabled() -> Result { + let console_mode = ConsoleMode::from(Handle::current_in_handle()?); + + let dw_mode = console_mode.mode()?; + + Ok( + // check none of the "not raw" bits is set + dw_mode & NOT_RAW_MODE_MASK == 0, + ) +} pub(crate) fn enable_raw_mode() -> Result<()> { let console_mode = ConsoleMode::from(Handle::current_in_handle()?); let dw_mode = console_mode.mode()?; - let new_mode = dw_mode & !RAW_MODE_MASK; + let new_mode = dw_mode & !NOT_RAW_MODE_MASK; console_mode.set_mode(new_mode)?; @@ -30,7 +42,7 @@ pub(crate) fn disable_raw_mode() -> Result<()> { let dw_mode = console_mode.mode()?; - let new_mode = dw_mode | RAW_MODE_MASK; + let new_mode = dw_mode | NOT_RAW_MODE_MASK; console_mode.set_mode(new_mode)?;