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