1 use crate::proto::unsafe_protocol;
2 use crate::{Char16, Event, Result, Status, StatusExt};
3 use core::mem::MaybeUninit;
4 use uefi_raw::protocol::console::{InputKey, SimpleTextInputProtocol};
5 
6 /// Interface for text-based input devices.
7 #[derive(Debug)]
8 #[repr(transparent)]
9 #[unsafe_protocol(SimpleTextInputProtocol::GUID)]
10 pub struct Input(SimpleTextInputProtocol);
11 
12 impl Input {
13     /// Resets the input device hardware.
14     ///
15     /// The `extended_verification` parameter is used to request that UEFI
16     /// performs an extended check and reset of the input device.
17     ///
18     /// # Errors
19     ///
20     /// - `DeviceError` if the device is malfunctioning and cannot be reset.
reset(&mut self, extended_verification: bool) -> Result21     pub fn reset(&mut self, extended_verification: bool) -> Result {
22         unsafe { (self.0.reset)(&mut self.0, extended_verification) }.to_result()
23     }
24 
25     /// Reads the next keystroke from the input device, if any.
26     ///
27     /// Use [`wait_for_key_event`] with the [`boot::wait_for_event`]
28     /// interface in order to wait for a key to be pressed.
29     ///
30     /// [`boot::wait_for_event`]: crate::boot::wait_for_event
31     /// [`wait_for_key_event`]: Self::wait_for_key_event
32     ///
33     /// # Errors
34     ///
35     /// - [`Status::DEVICE_ERROR`] if there was an issue with the input device
36     ///
37     /// # Examples
38     ///
39     /// ```
40     /// use log::info;
41     /// use uefi::proto::console::text::{Input, Key, ScanCode};
42     /// use uefi::{boot, Char16, Result, ResultExt};
43     ///
44     /// fn read_keyboard_events(input: &mut Input) -> Result {
45     ///     loop {
46     ///         // Pause until a keyboard event occurs.
47     ///         let mut events = unsafe { [input.wait_for_key_event().unwrap()] };
48     ///         boot::wait_for_event(&mut events).discard_errdata()?;
49     ///
50     ///         let u_key = Char16::try_from('u').unwrap();
51     ///         match input.read_key()? {
52     ///             // Example of handling a printable key: print a message when
53     ///             // the 'u' key is pressed.
54     ///             Some(Key::Printable(key)) if key == u_key => {
55     ///                 info!("the 'u' key was pressed");
56     ///             }
57     ///
58     ///             // Example of handling a special key: exit the loop when the
59     ///             // escape key is pressed.
60     ///             Some(Key::Special(ScanCode::ESCAPE)) => {
61     ///                 break;
62     ///             }
63     ///             _ => {}
64     ///         }
65     ///     }
66     ///
67     ///     Ok(())
68     /// }
69     /// ```
read_key(&mut self) -> Result<Option<Key>>70     pub fn read_key(&mut self) -> Result<Option<Key>> {
71         let mut key = MaybeUninit::<InputKey>::uninit();
72 
73         match unsafe { (self.0.read_key_stroke)(&mut self.0, key.as_mut_ptr()) } {
74             Status::NOT_READY => Ok(None),
75             other => other.to_result_with_val(|| Some(unsafe { key.assume_init() }.into())),
76         }
77     }
78 
79     /// Event to be used with [`boot::wait_for_event`] in order to wait
80     /// for a key to be available
81     ///
82     /// [`boot::wait_for_event`]: crate::boot::wait_for_event
83     #[must_use]
wait_for_key_event(&self) -> Option<Event>84     pub fn wait_for_key_event(&self) -> Option<Event> {
85         unsafe { Event::from_ptr(self.0.wait_for_key) }
86     }
87 }
88 
89 /// A key read from the console (high-level version)
90 #[derive(Debug, Copy, Clone, Eq, PartialEq)]
91 pub enum Key {
92     /// The key is associated with a printable Unicode character
93     Printable(Char16),
94 
95     /// The key is special (arrow, function, multimedia...)
96     Special(ScanCode),
97 }
98 
99 impl From<InputKey> for Key {
from(k: InputKey) -> Self100     fn from(k: InputKey) -> Self {
101         if k.scan_code == ScanCode::NULL.0 {
102             Self::Printable(Char16::try_from(k.unicode_char).unwrap())
103         } else {
104             Self::Special(ScanCode(k.scan_code))
105         }
106     }
107 }
108 
109 newtype_enum! {
110 /// A keyboard scan code
111 ///
112 /// Codes 0x8000 -> 0xFFFF are reserved for future OEM extensibility, therefore
113 /// this C enum is _not_ safe to model as a Rust enum (where the compiler must
114 /// know about all variants at compile time).
115 pub enum ScanCode: u16 => #[allow(missing_docs)] {
116     /// Null scan code, indicates that the Unicode character should be used.
117     NULL        = 0x00,
118     /// Move cursor up 1 row.
119     UP          = 0x01,
120     /// Move cursor down 1 row.
121     DOWN        = 0x02,
122     /// Move cursor right 1 column.
123     RIGHT       = 0x03,
124     /// Move cursor left 1 column.
125     LEFT        = 0x04,
126     HOME        = 0x05,
127     END         = 0x06,
128     INSERT      = 0x07,
129     DELETE      = 0x08,
130     PAGE_UP     = 0x09,
131     PAGE_DOWN   = 0x0A,
132     FUNCTION_1  = 0x0B,
133     FUNCTION_2  = 0x0C,
134     FUNCTION_3  = 0x0D,
135     FUNCTION_4  = 0x0E,
136     FUNCTION_5  = 0x0F,
137     FUNCTION_6  = 0x10,
138     FUNCTION_7  = 0x11,
139     FUNCTION_8  = 0x12,
140     FUNCTION_9  = 0x13,
141     FUNCTION_10 = 0x14,
142     FUNCTION_11 = 0x15,
143     FUNCTION_12 = 0x16,
144     ESCAPE      = 0x17,
145 
146     FUNCTION_13 = 0x68,
147     FUNCTION_14 = 0x69,
148     FUNCTION_15 = 0x6A,
149     FUNCTION_16 = 0x6B,
150     FUNCTION_17 = 0x6C,
151     FUNCTION_18 = 0x6D,
152     FUNCTION_19 = 0x6E,
153     FUNCTION_20 = 0x6F,
154     FUNCTION_21 = 0x70,
155     FUNCTION_22 = 0x71,
156     FUNCTION_23 = 0x72,
157     FUNCTION_24 = 0x73,
158 
159     MUTE        = 0x7F,
160     VOLUME_UP   = 0x80,
161     VOLUME_DOWN = 0x81,
162 
163     BRIGHTNESS_UP   = 0x100,
164     BRIGHTNESS_DOWN = 0x101,
165     SUSPEND         = 0x102,
166     HIBERNATE       = 0x103,
167     TOGGLE_DISPLAY  = 0x104,
168     RECOVERY        = 0x105,
169     EJECT           = 0x106,
170 }}
171