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