1 use std::borrow::ToOwned; 2 use std::io::{self, Error, Result}; 3 use std::str; 4 5 use winapi::ctypes::c_void; 6 use winapi::shared::minwindef::DWORD; 7 use winapi::shared::ntdef::NULL; 8 use winapi::um::consoleapi::{GetNumberOfConsoleInputEvents, ReadConsoleInputW, WriteConsoleW}; 9 use winapi::um::wincon::{ 10 FillConsoleOutputAttribute, FillConsoleOutputCharacterA, GetLargestConsoleWindowSize, 11 SetConsoleTextAttribute, SetConsoleWindowInfo, COORD, INPUT_RECORD, SMALL_RECT, 12 }; 13 14 use super::{is_true, Coord, Handle, HandleType, InputRecord, WindowPositions}; 15 16 /// Could be used to do some basic things with the console. 17 pub struct Console { 18 handle: Handle, 19 } 20 21 impl Console { 22 /// Create new instance of `Console`. 23 /// 24 /// This created instance will use the default output handle (STD_OUTPUT_HANDLE) as handle for the function call it wraps. output() -> Result<Console>25 pub fn output() -> Result<Console> { 26 Ok(Console { 27 handle: Handle::new(HandleType::OutputHandle)?, 28 }) 29 } 30 31 /// Sets the attributes of characters written to the console screen buffer by the WriteFile or WriteConsole function, or echoed by the ReadFile or ReadConsole function. 32 /// This function affects text written after the function call. 33 /// 34 /// parameter: [wAttributes] 35 /// Wraps the underlying function call: [SetConsoleTextAttribute] 36 /// link: [https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute] set_text_attribute(&self, value: u16) -> Result<()>37 pub fn set_text_attribute(&self, value: u16) -> Result<()> { 38 unsafe { 39 if !is_true(SetConsoleTextAttribute(*self.handle, value)) { 40 return Err(Error::last_os_error()); 41 } 42 } 43 Ok(()) 44 } 45 46 /// Sets the current size and position of a console screen buffer's window. 47 /// 48 /// Wraps the underlying function call: [SetConsoleTextAttribute] 49 /// link: [https://docs.microsoft.com/en-us/windows/console/setconsoletextattribute] set_console_info(&self, absolute: bool, rect: WindowPositions) -> Result<()>50 pub fn set_console_info(&self, absolute: bool, rect: WindowPositions) -> Result<()> { 51 let absolute = match absolute { 52 true => 1, 53 false => 0, 54 }; 55 let a = SMALL_RECT::from(rect); 56 57 unsafe { 58 if !is_true(SetConsoleWindowInfo(*self.handle, absolute, &a)) { 59 return Err(Error::last_os_error()); 60 } 61 } 62 63 Ok(()) 64 } 65 66 /// Writes a character to the console screen buffer a specified number of times, beginning at the specified coordinates 67 /// 68 /// Wraps the underlying function call: [FillConsoleOutputCharacterA] 69 /// link: [https://docs.microsoft.com/en-us/windows/console/fillconsoleoutputcharacter] fill_whit_character( &self, start_location: Coord, cells_to_write: u32, filling_char: char, ) -> Result<u32>70 pub fn fill_whit_character( 71 &self, 72 start_location: Coord, 73 cells_to_write: u32, 74 filling_char: char, 75 ) -> Result<u32> { 76 let mut chars_written = 0; 77 unsafe { 78 // fill the cells in console with blanks 79 if !is_true(FillConsoleOutputCharacterA( 80 *self.handle, 81 filling_char as i8, 82 cells_to_write, 83 COORD::from(start_location), 84 &mut chars_written, 85 )) { 86 return Err(Error::last_os_error()); 87 } 88 89 Ok(chars_written) 90 } 91 } 92 93 /// Sets the character attributes for a specified number of character cells, beginning at the specified coordinates in a screen buffer. 94 /// 95 /// Wraps the underlying function call: [FillConsoleOutputAttribute] 96 /// link: [https://docs.microsoft.com/en-us/windows/console/fillconsoleoutputattribute] fill_whit_attribute( &self, start_location: Coord, cells_to_write: u32, dw_attribute: u16, ) -> Result<u32>97 pub fn fill_whit_attribute( 98 &self, 99 start_location: Coord, 100 cells_to_write: u32, 101 dw_attribute: u16, 102 ) -> Result<u32> { 103 let mut cells_written = 0; 104 // Get the position of the current console window 105 unsafe { 106 if !is_true(FillConsoleOutputAttribute( 107 *self.handle, 108 dw_attribute, 109 cells_to_write, 110 COORD::from(start_location), 111 &mut cells_written, 112 )) { 113 return Err(Error::last_os_error()); 114 } 115 } 116 117 Ok(cells_written) 118 } 119 120 /// Retrieves the size of the largest possible console window, based on the current text and the size of the display. 121 /// 122 /// Wraps the underlying function call: [GetLargestConsoleWindowSize] 123 /// link: [https://docs.microsoft.com/en-us/windows/console/getlargestconsolewindowsize] largest_window_size(&self) -> Coord124 pub fn largest_window_size(&self) -> Coord { 125 Coord::from(unsafe { GetLargestConsoleWindowSize(*self.handle) }) 126 } 127 128 /// Writes a character string to a console screen buffer beginning at the current cursor location. 129 /// 130 /// Wraps the underlying function call: [WriteConsoleW] 131 /// link: [https://docs.microsoft.com/en-us/windows/console/writeconsole] write_char_buffer(&self, buf: &[u8]) -> Result<usize>132 pub fn write_char_buffer(&self, buf: &[u8]) -> Result<usize> { 133 // get string from u8[] and parse it to an c_str 134 let utf8 = match str::from_utf8(buf) { 135 Ok(string) => string, 136 Err(_) => { 137 return Err(io::Error::new( 138 io::ErrorKind::Other, 139 "Could not parse to utf8 string", 140 )); 141 } 142 }; 143 144 let utf16: Vec<u16> = utf8.encode_utf16().collect(); 145 let utf16_ptr: *const c_void = utf16.as_ptr() as *const _ as *const c_void; 146 147 let mut cells_written: u32 = 0; 148 // write to console 149 unsafe { 150 if !is_true(WriteConsoleW( 151 *self.handle, 152 utf16_ptr, 153 utf16.len() as u32, 154 &mut cells_written, 155 NULL, 156 )) { 157 return Err(io::Error::last_os_error()); 158 } 159 } 160 Ok(utf8.as_bytes().len()) 161 } 162 read_single_input_event(&self) -> Result<InputRecord>163 pub fn read_single_input_event(&self) -> Result<InputRecord> { 164 let mut buf: Vec<INPUT_RECORD> = Vec::with_capacity(1); 165 let mut size = 0; 166 167 return Ok(self.read_input(&mut buf, 1, &mut size)?.1[0].to_owned()); 168 } 169 read_console_input(&self) -> Result<(u32, Vec<InputRecord>)>170 pub fn read_console_input(&self) -> Result<(u32, Vec<InputRecord>)> { 171 let buf_len = self.number_of_console_input_events()?; 172 173 // Fast-skipping all the code below if there is nothing to read at all 174 if buf_len == 0 { 175 return Ok((0, vec![])); 176 } 177 178 let mut buf: Vec<INPUT_RECORD> = Vec::with_capacity(buf_len as usize); 179 let mut size = 0; 180 181 self.read_input(&mut buf, buf_len, &mut size) 182 } 183 number_of_console_input_events(&self) -> Result<u32>184 pub fn number_of_console_input_events(&self) -> Result<u32> { 185 let mut buf_len: DWORD = 0; 186 if !is_true(unsafe { GetNumberOfConsoleInputEvents(*self.handle, &mut buf_len) }) { 187 return Err(Error::last_os_error()); 188 } 189 190 Ok(buf_len) 191 } 192 read_input( &self, buf: &mut Vec<INPUT_RECORD>, buf_len: u32, bytes_written: &mut u32, ) -> Result<(u32, Vec<InputRecord>)>193 fn read_input( 194 &self, 195 buf: &mut Vec<INPUT_RECORD>, 196 buf_len: u32, 197 bytes_written: &mut u32, 198 ) -> Result<(u32, Vec<InputRecord>)> { 199 if !is_true(unsafe { 200 ReadConsoleInputW(*self.handle, buf.as_mut_ptr(), buf_len, bytes_written) 201 }) { 202 return Err(Error::last_os_error()); 203 } else { 204 unsafe { 205 buf.set_len(buf_len as usize); 206 } 207 } 208 209 Ok(( 210 buf_len, 211 buf[..(buf_len as usize)] 212 .iter() 213 .map(|x| InputRecord::from(*x)) 214 .collect::<Vec<InputRecord>>(), 215 )) 216 } 217 } 218 219 impl From<Handle> for Console { 220 /// Create a `Console` instance who's functions will be executed on the the given `Handle` from(handle: Handle) -> Self221 fn from(handle: Handle) -> Self { 222 Console { handle } 223 } 224 } 225