xref: /aosp_15_r20/external/crosvm/base/src/sys/windows/terminal.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Stdin;
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use winapi::shared::minwindef::DWORD;
8*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::consoleapi::GetConsoleMode;
9*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::consoleapi::SetConsoleMode;
10*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::wincon::ENABLE_ECHO_INPUT;
11*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::wincon::ENABLE_LINE_INPUT;
12*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::wincon::ENABLE_PROCESSED_INPUT;
13*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::wincon::ENABLE_VIRTUAL_TERMINAL_INPUT;
14*bb4ee6a4SAndroid Build Coastguard Worker 
15*bb4ee6a4SAndroid Build Coastguard Worker use crate::AsRawDescriptor;
16*bb4ee6a4SAndroid Build Coastguard Worker use crate::Error;
17*bb4ee6a4SAndroid Build Coastguard Worker use crate::RawDescriptor;
18*bb4ee6a4SAndroid Build Coastguard Worker use crate::Result;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker /// Trait for file descriptors that are terminals.
21*bb4ee6a4SAndroid Build Coastguard Worker ///
22*bb4ee6a4SAndroid Build Coastguard Worker /// # Safety
23*bb4ee6a4SAndroid Build Coastguard Worker /// This is marked unsafe because the implementation must promise that the returned RawDescriptor is
24*bb4ee6a4SAndroid Build Coastguard Worker /// a valid descriptor and that the lifetime of the returned descriptor is at least that of the
25*bb4ee6a4SAndroid Build Coastguard Worker /// trait object.
26*bb4ee6a4SAndroid Build Coastguard Worker pub unsafe trait Terminal {
27*bb4ee6a4SAndroid Build Coastguard Worker     /// Gets the file descriptor of the terminal.
terminal_descriptor(&self) -> RawDescriptor28*bb4ee6a4SAndroid Build Coastguard Worker     fn terminal_descriptor(&self) -> RawDescriptor;
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker     /// Set this terminal's mode to raw mode.
31*bb4ee6a4SAndroid Build Coastguard Worker     ///
32*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns the original mode, which can be passed to `restore_mode()` to reset the terminal to
33*bb4ee6a4SAndroid Build Coastguard Worker     /// its previous state.
set_raw_mode(&self) -> Result<DWORD>34*bb4ee6a4SAndroid Build Coastguard Worker     fn set_raw_mode(&self) -> Result<DWORD> {
35*bb4ee6a4SAndroid Build Coastguard Worker         let descriptor = self.terminal_descriptor();
36*bb4ee6a4SAndroid Build Coastguard Worker         let mut orig_mode = 0;
37*bb4ee6a4SAndroid Build Coastguard Worker 
38*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
39*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because we provide a valid descriptor and pointer and we check the return result.
40*bb4ee6a4SAndroid Build Coastguard Worker         if unsafe { GetConsoleMode(descriptor, &mut orig_mode) } == 0 {
41*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::last());
42*bb4ee6a4SAndroid Build Coastguard Worker         }
43*bb4ee6a4SAndroid Build Coastguard Worker 
44*bb4ee6a4SAndroid Build Coastguard Worker         let new_mode = (orig_mode | ENABLE_VIRTUAL_TERMINAL_INPUT)
45*bb4ee6a4SAndroid Build Coastguard Worker             & !(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
46*bb4ee6a4SAndroid Build Coastguard Worker 
47*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
48*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because the syscall will only read the extent of mode and we check the return
49*bb4ee6a4SAndroid Build Coastguard Worker         // result.
50*bb4ee6a4SAndroid Build Coastguard Worker         if unsafe { SetConsoleMode(descriptor, new_mode) } == 0 {
51*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::last());
52*bb4ee6a4SAndroid Build Coastguard Worker         }
53*bb4ee6a4SAndroid Build Coastguard Worker 
54*bb4ee6a4SAndroid Build Coastguard Worker         Ok(orig_mode)
55*bb4ee6a4SAndroid Build Coastguard Worker     }
56*bb4ee6a4SAndroid Build Coastguard Worker 
57*bb4ee6a4SAndroid Build Coastguard Worker     /// Set this terminal's mode to a previous state returned by `set_raw_mode()`.
restore_mode(&self, mode: DWORD) -> Result<()>58*bb4ee6a4SAndroid Build Coastguard Worker     fn restore_mode(&self, mode: DWORD) -> Result<()> {
59*bb4ee6a4SAndroid Build Coastguard Worker         // SAFETY:
60*bb4ee6a4SAndroid Build Coastguard Worker         // Safe because the syscall will only read the extent of mode and we check the return
61*bb4ee6a4SAndroid Build Coastguard Worker         // result.
62*bb4ee6a4SAndroid Build Coastguard Worker         if unsafe { SetConsoleMode(self.terminal_descriptor(), mode) } == 0 {
63*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::last())
64*bb4ee6a4SAndroid Build Coastguard Worker         } else {
65*bb4ee6a4SAndroid Build Coastguard Worker             Ok(())
66*bb4ee6a4SAndroid Build Coastguard Worker         }
67*bb4ee6a4SAndroid Build Coastguard Worker     }
68*bb4ee6a4SAndroid Build Coastguard Worker }
69*bb4ee6a4SAndroid Build Coastguard Worker 
70*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
71*bb4ee6a4SAndroid Build Coastguard Worker // Safe because we return a genuine terminal descriptor that never changes and shares our lifetime.
72*bb4ee6a4SAndroid Build Coastguard Worker unsafe impl Terminal for Stdin {
terminal_descriptor(&self) -> RawDescriptor73*bb4ee6a4SAndroid Build Coastguard Worker     fn terminal_descriptor(&self) -> RawDescriptor {
74*bb4ee6a4SAndroid Build Coastguard Worker         self.as_raw_descriptor()
75*bb4ee6a4SAndroid Build Coastguard Worker     }
76*bb4ee6a4SAndroid Build Coastguard Worker }
77