1 //! This contains the logic for working with the console buffer. 2 3 use std::io::Result; 4 use std::mem::size_of; 5 6 use winapi::{ 7 shared::minwindef::TRUE, 8 shared::ntdef::NULL, 9 um::{ 10 minwinbase::SECURITY_ATTRIBUTES, 11 wincon::{ 12 CreateConsoleScreenBuffer, GetConsoleScreenBufferInfo, SetConsoleActiveScreenBuffer, 13 SetConsoleScreenBufferSize, CONSOLE_TEXTMODE_BUFFER, COORD, 14 }, 15 winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE}, 16 }, 17 }; 18 19 use super::{handle_result, result, Handle, HandleType, ScreenBufferInfo}; 20 21 /// A wrapper around a screen buffer. 22 #[derive(Clone, Debug)] 23 pub struct ScreenBuffer { 24 handle: Handle, 25 } 26 27 impl ScreenBuffer { 28 /// Create a wrapper around a screen buffer from its handle. new(handle: Handle) -> Self29 pub fn new(handle: Handle) -> Self { 30 Self { handle } 31 } 32 33 /// Get the current console screen buffer current() -> Result<ScreenBuffer>34 pub fn current() -> Result<ScreenBuffer> { 35 Ok(ScreenBuffer { 36 handle: Handle::new(HandleType::CurrentOutputHandle)?, 37 }) 38 } 39 40 /// Create new console screen buffer. 41 /// 42 /// This wraps 43 /// [`CreateConsoleScreenBuffer`](https://docs.microsoft.com/en-us/windows/console/createconsolescreenbuffer) create() -> Result<ScreenBuffer>44 pub fn create() -> Result<ScreenBuffer> { 45 let security_attr: SECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES { 46 nLength: size_of::<SECURITY_ATTRIBUTES>() as u32, 47 lpSecurityDescriptor: NULL, 48 bInheritHandle: TRUE, 49 }; 50 51 let new_screen_buffer = handle_result(unsafe { 52 CreateConsoleScreenBuffer( 53 GENERIC_READ | // read/write access 54 GENERIC_WRITE, 55 FILE_SHARE_READ | FILE_SHARE_WRITE, // shared 56 &security_attr, // default security attributes 57 CONSOLE_TEXTMODE_BUFFER, // must be TEXTMODE 58 NULL, 59 ) 60 })?; 61 Ok(ScreenBuffer { 62 handle: unsafe { Handle::from_raw(new_screen_buffer) }, 63 }) 64 } 65 66 /// Set this screen buffer to the current one. 67 /// 68 /// This wraps 69 /// [`SetConsoleActiveScreenBuffer`](https://docs.microsoft.com/en-us/windows/console/setconsoleactivescreenbuffer). show(&self) -> Result<()>70 pub fn show(&self) -> Result<()> { 71 result(unsafe { SetConsoleActiveScreenBuffer(*self.handle) }) 72 } 73 74 /// Get the screen buffer information like terminal size, cursor position, buffer size. 75 /// 76 /// This wraps 77 /// [`GetConsoleScreenBufferInfo`](https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo). info(&self) -> Result<ScreenBufferInfo>78 pub fn info(&self) -> Result<ScreenBufferInfo> { 79 let mut csbi = ScreenBufferInfo::new(); 80 result(unsafe { GetConsoleScreenBufferInfo(*self.handle, &mut csbi.0) })?; 81 Ok(csbi) 82 } 83 84 /// Set the console screen buffer size to the given size. 85 /// 86 /// This wraps 87 /// [`SetConsoleScreenBufferSize`](https://docs.microsoft.com/en-us/windows/console/setconsolescreenbuffersize). set_size(&self, x: i16, y: i16) -> Result<()>88 pub fn set_size(&self, x: i16, y: i16) -> Result<()> { 89 result(unsafe { SetConsoleScreenBufferSize(*self.handle, COORD { X: x, Y: y }) }) 90 } 91 92 /// Get the underlying raw `HANDLE` used by this type to execute with. handle(&self) -> &Handle93 pub fn handle(&self) -> &Handle { 94 &self.handle 95 } 96 } 97 98 impl From<Handle> for ScreenBuffer { from(handle: Handle) -> Self99 fn from(handle: Handle) -> Self { 100 ScreenBuffer { handle } 101 } 102 } 103 104 #[cfg(test)] 105 mod tests { 106 use super::ScreenBuffer; 107 108 #[test] test_screen_buffer_info()109 fn test_screen_buffer_info() { 110 let buffer = ScreenBuffer::current().unwrap(); 111 let info = buffer.info().unwrap(); 112 info.terminal_size(); 113 info.terminal_window(); 114 info.attributes(); 115 info.cursor_pos(); 116 } 117 } 118