// Copyright 2023 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::io::Stdin;56use winapi::shared::minwindef::DWORD;7use winapi::um::consoleapi::GetConsoleMode;8use winapi::um::consoleapi::SetConsoleMode;9use winapi::um::wincon::ENABLE_ECHO_INPUT;10use winapi::um::wincon::ENABLE_LINE_INPUT;11use winapi::um::wincon::ENABLE_PROCESSED_INPUT;12use winapi::um::wincon::ENABLE_VIRTUAL_TERMINAL_INPUT;1314use crate::AsRawDescriptor;15use crate::Error;16use crate::RawDescriptor;17use crate::Result;1819/// Trait for file descriptors that are terminals.20///21/// # Safety22/// This is marked unsafe because the implementation must promise that the returned RawDescriptor is23/// a valid descriptor and that the lifetime of the returned descriptor is at least that of the24/// trait object.25pub unsafe trait Terminal {26/// Gets the file descriptor of the terminal.27fn terminal_descriptor(&self) -> RawDescriptor;2829/// Set this terminal's mode to raw mode.30///31/// Returns the original mode, which can be passed to `restore_mode()` to reset the terminal to32/// its previous state.33fn set_raw_mode(&self) -> Result<DWORD> {34let descriptor = self.terminal_descriptor();35let mut orig_mode = 0;3637// SAFETY:38// Safe because we provide a valid descriptor and pointer and we check the return result.39if unsafe { GetConsoleMode(descriptor, &mut orig_mode) } == 0 {40return Err(Error::last());41}4243let new_mode = (orig_mode | ENABLE_VIRTUAL_TERMINAL_INPUT)44& !(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);4546// SAFETY:47// Safe because the syscall will only read the extent of mode and we check the return48// result.49if unsafe { SetConsoleMode(descriptor, new_mode) } == 0 {50return Err(Error::last());51}5253Ok(orig_mode)54}5556/// Set this terminal's mode to a previous state returned by `set_raw_mode()`.57fn restore_mode(&self, mode: DWORD) -> Result<()> {58// SAFETY:59// Safe because the syscall will only read the extent of mode and we check the return60// result.61if unsafe { SetConsoleMode(self.terminal_descriptor(), mode) } == 0 {62Err(Error::last())63} else {64Ok(())65}66}67}6869// SAFETY:70// Safe because we return a genuine terminal descriptor that never changes and shares our lifetime.71unsafe impl Terminal for Stdin {72fn terminal_descriptor(&self) -> RawDescriptor {73self.as_raw_descriptor()74}75}767778