1 //! Managing raw mode. 2 //! 3 //! Raw mode is a particular state a TTY can have. It signifies that: 4 //! 5 //! 1. No line buffering (the input is given byte-by-byte). 6 //! 2. The input is not written out, instead it has to be done manually by the programmer. 7 //! 3. The output is not canonicalized (for example, `\n` means "go one line down", not "line 8 //! break"). 9 //! 10 //! It is essential to design terminal programs. 11 //! 12 //! # Example 13 //! 14 //! ```rust,no_run 15 //! use termion::raw::IntoRawMode; 16 //! use std::io::{Write, stdout}; 17 //! 18 //! fn main() { 19 //! let mut stdout = stdout().into_raw_mode().unwrap(); 20 //! 21 //! write!(stdout, "Hey there.").unwrap(); 22 //! } 23 //! ``` 24 25 use std::io::{self, Write}; 26 use std::ops; 27 28 use sys::Termios; 29 use sys::attr::{get_terminal_attr, raw_terminal_attr, set_terminal_attr}; 30 31 /// The timeout of an escape code control sequence, in milliseconds. 32 pub const CONTROL_SEQUENCE_TIMEOUT: u64 = 100; 33 34 /// A terminal restorer, which keeps the previous state of the terminal, and restores it, when 35 /// dropped. 36 /// 37 /// Restoring will entirely bring back the old TTY state. 38 pub struct RawTerminal<W: Write> { 39 prev_ios: Termios, 40 output: W, 41 } 42 43 impl<W: Write> Drop for RawTerminal<W> { drop(&mut self)44 fn drop(&mut self) { 45 set_terminal_attr(&self.prev_ios).unwrap(); 46 } 47 } 48 49 impl<W: Write> ops::Deref for RawTerminal<W> { 50 type Target = W; 51 deref(&self) -> &W52 fn deref(&self) -> &W { 53 &self.output 54 } 55 } 56 57 impl<W: Write> ops::DerefMut for RawTerminal<W> { deref_mut(&mut self) -> &mut W58 fn deref_mut(&mut self) -> &mut W { 59 &mut self.output 60 } 61 } 62 63 impl<W: Write> Write for RawTerminal<W> { write(&mut self, buf: &[u8]) -> io::Result<usize>64 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 65 self.output.write(buf) 66 } 67 flush(&mut self) -> io::Result<()>68 fn flush(&mut self) -> io::Result<()> { 69 self.output.flush() 70 } 71 } 72 73 /// Types which can be converted into "raw mode". 74 /// 75 /// # Why is this type defined on writers and not readers? 76 /// 77 /// TTYs has their state controlled by the writer, not the reader. You use the writer to clear the 78 /// screen, move the cursor and so on, so naturally you use the writer to change the mode as well. 79 pub trait IntoRawMode: Write + Sized { 80 /// Switch to raw mode. 81 /// 82 /// Raw mode means that stdin won't be printed (it will instead have to be written manually by 83 /// the program). Furthermore, the input isn't canonicalised or buffered (that is, you can 84 /// read from stdin one byte of a time). The output is neither modified in any way. into_raw_mode(self) -> io::Result<RawTerminal<Self>>85 fn into_raw_mode(self) -> io::Result<RawTerminal<Self>>; 86 } 87 88 impl<W: Write> IntoRawMode for W { into_raw_mode(self) -> io::Result<RawTerminal<W>>89 fn into_raw_mode(self) -> io::Result<RawTerminal<W>> { 90 let mut ios = get_terminal_attr()?; 91 let prev_ios = ios; 92 93 raw_terminal_attr(&mut ios); 94 95 set_terminal_attr(&ios)?; 96 97 Ok(RawTerminal { 98 prev_ios: prev_ios, 99 output: self, 100 }) 101 } 102 } 103 104 impl<W: Write> RawTerminal<W> { 105 /// Temporarily switch to original mode suspend_raw_mode(&self) -> io::Result<()>106 pub fn suspend_raw_mode(&self) -> io::Result<()> { 107 set_terminal_attr(&self.prev_ios)?; 108 Ok(()) 109 } 110 111 /// Temporarily switch to raw mode activate_raw_mode(&self) -> io::Result<()>112 pub fn activate_raw_mode(&self) -> io::Result<()> { 113 let mut ios = get_terminal_attr()?; 114 raw_terminal_attr(&mut ios); 115 set_terminal_attr(&ios)?; 116 Ok(()) 117 } 118 } 119 120 #[cfg(test)] 121 mod test { 122 use super::*; 123 use std::io::{Write, stdout}; 124 125 #[test] test_into_raw_mode()126 fn test_into_raw_mode() { 127 let mut out = stdout().into_raw_mode().unwrap(); 128 129 out.write_all(b"this is a test, muahhahahah\r\n").unwrap(); 130 131 drop(out); 132 } 133 } 134