summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wio/src/console.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wio/src/console.rs')
-rw-r--r--third_party/rust/wio/src/console.rs270
1 files changed, 270 insertions, 0 deletions
diff --git a/third_party/rust/wio/src/console.rs b/third_party/rust/wio/src/console.rs
new file mode 100644
index 0000000000..a7d9fa7989
--- /dev/null
+++ b/third_party/rust/wio/src/console.rs
@@ -0,0 +1,270 @@
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// All files in the project carrying such notice may not be copied, modified, or distributed
+// except according to those terms.
+use error::{Error, Result};
+use handle::Handle;
+use std::{
+ mem::{size_of_val, zeroed},
+ os::windows::io::FromRawHandle,
+ ptr::{null, null_mut},
+};
+use wide::ToWide;
+use winapi::{
+ um::{
+ consoleapi::{AllocConsole, GetConsoleCP, GetConsoleOutputCP, GetNumberOfConsoleInputEvents, ReadConsoleInputW},
+ fileapi::{CreateFileW, OPEN_EXISTING},
+ handleapi::INVALID_HANDLE_VALUE,
+ wincon::{AttachConsole, CHAR_INFO, CONSOLE_FONT_INFOEX, CONSOLE_SCREEN_BUFFER_INFO, CONSOLE_SCREEN_BUFFER_INFOEX, CONSOLE_TEXTMODE_BUFFER, COORD, CreateConsoleScreenBuffer, FlushConsoleInputBuffer, FOCUS_EVENT, FreeConsole, GetConsoleScreenBufferInfo, GetConsoleScreenBufferInfoEx, GetCurrentConsoleFont, INPUT_RECORD, KEY_EVENT, MENU_EVENT, MOUSE_EVENT, SetConsoleActiveScreenBuffer, SetConsoleCP, SetConsoleOutputCP, SetConsoleScreenBufferInfoEx, SMALL_RECT, WINDOW_BUFFER_SIZE_EVENT, WriteConsoleOutputW},
+ winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE},
+ },
+ shared::minwindef::{DWORD, FALSE},
+};
+
+pub struct ScreenBuffer(Handle);
+impl ScreenBuffer {
+ pub fn new() -> Result<ScreenBuffer> {
+ let handle = unsafe { CreateConsoleScreenBuffer(
+ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ null(), CONSOLE_TEXTMODE_BUFFER, null_mut(),
+ )};
+ if handle == INVALID_HANDLE_VALUE { return Error::last() }
+ unsafe { Ok(ScreenBuffer(Handle::new(handle))) }
+ }
+ /// Gets the actual active console screen buffer
+ pub fn from_conout() -> Result<ScreenBuffer> {
+ let handle = unsafe { CreateFileW(
+ "CONOUT$".to_wide_null().as_ptr(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ, null_mut(), OPEN_EXISTING,
+ 0, null_mut(),
+ )};
+ if handle == INVALID_HANDLE_VALUE { return Error::last() }
+ unsafe { Ok(ScreenBuffer(Handle::new(handle))) }
+ }
+ pub fn set_active(&self) -> Result<()> {
+ let res = unsafe { SetConsoleActiveScreenBuffer(*self.0) };
+ if res == 0 { return Error::last() }
+ Ok(())
+ }
+ pub fn info(&self) -> Result<ScreenBufferInfo> {
+ let mut info = ScreenBufferInfo(unsafe { zeroed() });
+ let res = unsafe { GetConsoleScreenBufferInfo(*self.0, &mut info.0) };
+ if res == 0 { return Error::last() }
+ Ok(info)
+ }
+ pub fn info_ex(&self) -> Result<ScreenBufferInfoEx> {
+ let mut info: CONSOLE_SCREEN_BUFFER_INFOEX = unsafe { zeroed() };
+ info.cbSize = size_of_val(&info) as u32;
+ let res = unsafe { GetConsoleScreenBufferInfoEx(*self.0, &mut info) };
+ if res == 0 { return Error::last() }
+ // Yes, this is important
+ info.srWindow.Right += 1;
+ info.srWindow.Bottom += 1;
+ Ok(ScreenBufferInfoEx(info))
+ }
+ pub fn set_info_ex(&self, mut info: ScreenBufferInfoEx) -> Result<()> {
+ let res = unsafe { SetConsoleScreenBufferInfoEx(*self.0, &mut info.0) };
+ if res == 0 { return Error::last() }
+ Ok(())
+ }
+ // pub fn font_ex(&self) -> Result<FontEx> {
+ // unsafe {
+ // let mut info = zeroed();
+ // info.cbSize = size_of_val(&info);
+ // let res = GetCurrentConsoleFontEx(*self.0, w::FALSE, &mut info);
+ // if res == 0 { return Error::last() }
+ // Ok(FontEx(info))
+ // }
+ // }
+ pub fn write_output(&self, buf: &[CharInfo], size: (i16, i16), pos: (i16, i16)) -> Result<()> {
+ assert!(buf.len() == (size.0 as usize) * (size.1 as usize));
+ let mut rect = SMALL_RECT {
+ Left: pos.0,
+ Top: pos.1,
+ Right: pos.0 + size.0,
+ Bottom: pos.1 + size.1,
+ };
+ let size = COORD { X: size.0, Y: size.1 };
+ let pos = COORD { X: 0, Y: 0 };
+ let res = unsafe { WriteConsoleOutputW(
+ *self.0, buf.as_ptr() as *const CHAR_INFO, size, pos, &mut rect
+ )};
+ if res == 0 { return Error::last() }
+ Ok(())
+ }
+ pub fn font_size(&self) -> Result<(i16, i16)> {
+ unsafe {
+ let mut font = zeroed();
+ let res = GetCurrentConsoleFont(*self.0, FALSE, &mut font);
+ if res == 0 { return Error::last() }
+ Ok((font.dwFontSize.X, font.dwFontSize.Y))
+ }
+ }
+}
+impl FromRawHandle for ScreenBuffer {
+ unsafe fn from_raw_handle(handle: HANDLE) -> ScreenBuffer {
+ ScreenBuffer(Handle::new(handle))
+ }
+}
+pub struct InputBuffer(Handle);
+impl InputBuffer {
+ /// Gets the actual active console input buffer
+ pub fn from_conin() -> Result<InputBuffer> {
+ let handle = unsafe { CreateFileW(
+ "CONIN$".to_wide_null().as_ptr(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, null_mut(), OPEN_EXISTING,
+ 0, null_mut(),
+ )};
+ if handle == INVALID_HANDLE_VALUE { Error::last() }
+ else { unsafe { Ok(InputBuffer::from_raw_handle(handle)) } }
+ }
+ /// The number of input that is available to read
+ pub fn available_input(&self) -> Result<u32> {
+ let mut num = 0;
+ let res = unsafe { GetNumberOfConsoleInputEvents(*self.0, &mut num) };
+ if res == 0 { return Error::last() }
+ Ok(num)
+ }
+ /// Reads a bunch of input events
+ pub fn read_input(&self) -> Result<Vec<Input>> {
+ let mut buf: [INPUT_RECORD; 0x1000] = unsafe { zeroed() };
+ let mut size = 0;
+ let res = unsafe { ReadConsoleInputW(
+ *self.0, buf.as_mut_ptr(), buf.len() as DWORD, &mut size,
+ )};
+ if res == 0 { return Error::last() }
+ Ok(buf[..(size as usize)].iter().map(|input| {
+ unsafe { match input.EventType {
+ KEY_EVENT => {
+ let e = input.Event.KeyEvent();
+ Input::Key {
+ key_down: e.bKeyDown != 0,
+ repeat_count: e.wRepeatCount,
+ key_code: e.wVirtualKeyCode,
+ scan_code: e.wVirtualScanCode,
+ wide_char: *e.uChar.UnicodeChar(),
+ control_key_state: e.dwControlKeyState,
+ }
+ },
+ MOUSE_EVENT => {
+ let e = input.Event.MouseEvent();
+ Input::Mouse {
+ position: (e.dwMousePosition.X, e.dwMousePosition.Y),
+ button_state: e.dwButtonState,
+ control_key_state: e.dwControlKeyState,
+ event_flags: e.dwEventFlags,
+ }
+ },
+ WINDOW_BUFFER_SIZE_EVENT => {
+ let s = input.Event.WindowBufferSizeEvent().dwSize;
+ Input::WindowBufferSize(s.X, s.Y)
+ },
+ MENU_EVENT => Input::Menu(input.Event.MenuEvent().dwCommandId),
+ FOCUS_EVENT => Input::Focus(input.Event.FocusEvent().bSetFocus != 0),
+ e => unreachable!("invalid event type: {}", e),
+ } }
+ }).collect())
+ }
+ /// Clears all pending input
+ pub fn flush_input(&self) -> Result<()> {
+ let res = unsafe { FlushConsoleInputBuffer(*self.0) };
+ if res == 0 { return Error::last() }
+ Ok(())
+ }
+}
+impl FromRawHandle for InputBuffer {
+ unsafe fn from_raw_handle(handle: HANDLE) -> InputBuffer {
+ InputBuffer(Handle::from_raw_handle(handle))
+ }
+}
+#[repr(transparent)] #[derive(Copy, Clone)]
+pub struct ScreenBufferInfo(CONSOLE_SCREEN_BUFFER_INFO);
+impl ScreenBufferInfo {
+ pub fn size(&self) -> (i16, i16) {
+ (self.0.dwSize.X, self.0.dwSize.Y)
+ }
+}
+#[repr(transparent)] #[derive(Copy, Clone)]
+pub struct ScreenBufferInfoEx(CONSOLE_SCREEN_BUFFER_INFOEX);
+impl ScreenBufferInfoEx {
+ pub fn raw_mut(&mut self) -> &mut CONSOLE_SCREEN_BUFFER_INFOEX {
+ &mut self.0
+ }
+}
+#[repr(transparent)] #[derive(Copy, Clone)]
+pub struct FontInfoEx(CONSOLE_FONT_INFOEX);
+#[derive(Copy, Clone)]
+pub enum Input {
+ Key {
+ key_down: bool,
+ repeat_count: u16,
+ key_code: u16,
+ scan_code: u16,
+ wide_char: u16,
+ control_key_state: u32,
+ },
+ Mouse {
+ position: (i16, i16),
+ button_state: u32,
+ control_key_state: u32,
+ event_flags: u32,
+ },
+ WindowBufferSize(i16, i16),
+ Menu(u32),
+ Focus(bool),
+}
+#[repr(transparent)] #[derive(Copy, Clone)]
+pub struct CharInfo(CHAR_INFO);
+impl CharInfo {
+ pub fn new(ch: u16, attr: u16) -> CharInfo {
+ let mut ci: CHAR_INFO = unsafe { zeroed() };
+ unsafe { *ci.Char.UnicodeChar_mut() = ch };
+ ci.Attributes = attr;
+ CharInfo(ci)
+ }
+ pub fn character(&self) -> u16 { unsafe { *self.0.Char.UnicodeChar() } }
+ pub fn attributes(&self) -> u16 { self.0.Attributes }
+}
+/// Allocates a console if the process does not already have a console.
+pub fn alloc() -> Result<()> {
+ match unsafe { AllocConsole() } {
+ 0 => Error::last(),
+ _ => Ok(()),
+ }
+}
+/// Detaches the process from its current console.
+pub fn free() -> Result<()> {
+ match unsafe { FreeConsole() } {
+ 0 => Error::last(),
+ _ => Ok(()),
+ }
+}
+/// Attaches the process to the console of the specified process.
+/// Pass None to attach to the console of the parent process.
+pub fn attach(processid: Option<u32>) -> Result<()> {
+ match unsafe { AttachConsole(processid.unwrap_or(-1i32 as u32)) } {
+ 0 => Error::last(),
+ _ => Ok(()),
+ }
+}
+/// Gets the current input code page
+pub fn input_code_page() -> u32 {
+ unsafe { GetConsoleCP() }
+}
+/// Gets the current output code page
+pub fn output_code_page() -> u32 {
+ unsafe { GetConsoleOutputCP() }
+}
+/// Sets the current input code page
+pub fn set_input_code_page(code: u32) -> Result<()> {
+ let res = unsafe { SetConsoleCP(code) };
+ if res == 0 { return Error::last() }
+ Ok(())
+}
+/// Sets the current output code page
+pub fn set_output_code_page(code: u32) -> Result<()> {
+ let res = unsafe { SetConsoleOutputCP(code) };
+ if res == 0 { return Error::last() }
+ Ok(())
+}