uefi_input2/
input.rs

1use core::ffi::c_void;
2use core::ptr::addr_of_mut;
3use uefi::{Event, Result, StatusExt};
4use uefi::proto::unsafe_protocol;
5use crate::key_data::KeyData;
6use crate::simple_text_input_ex::{KeyNotifyFunction, KeyToggleState,
7                                  RawKeyData, SimpleTextInputExProtocol, Boolean};
8
9/// safety wrapper for SimpleTextInputExProtocol
10#[derive(Debug)]
11#[repr(transparent)]
12#[unsafe_protocol(SimpleTextInputExProtocol::GUID)]
13pub struct Input(SimpleTextInputExProtocol);
14
15impl Input {
16    /// clear keyboard cache
17    #[inline]
18    pub fn reset(&mut self, extended_verification: bool) -> Result {
19        let this = addr_of_mut!(self.0);
20        unsafe {
21            (self.0.reset)(this, Boolean::from(extended_verification)).to_result()
22        }
23    }
24
25    /// non-blocking keyboard read
26    #[inline]
27    pub fn read_key_stroke_ex(&mut self) -> Option<KeyData> {
28        let mut raw = RawKeyData::default();
29        let this = addr_of_mut!(self.0);
30
31        let status = unsafe {
32            // FFI binding
33            (self.0.read_key_stroke_ex)(this, &mut raw)
34        };
35
36        // Convert to Rust high-level type
37        status.is_success().then_some(KeyData::from(raw))
38    }
39
40    /// Returns an event that is signaled when a key is pressed.
41    ///
42    /// This allows the caller to wait for input without polling in a busy loop,
43    /// or to use it in `wait_for_event` along with other events (like timers).
44    #[inline]
45    pub fn wait_for_key_event(&self) -> Option<Event> {
46        unsafe { Event::from_ptr(self.0.wait_for_key_ex) }
47    }
48
49    /// only set toggle state
50    #[inline]
51    pub fn set_state(&mut self, mut state: KeyToggleState) -> Result {
52        let this = addr_of_mut!(self.0);
53        unsafe {
54            (self.0.set_state)(this, &mut state).to_result()
55        }
56    }
57
58    /// Register a callback function to be invoked when a key is pressed.
59    /// #### Usage
60    /// 1. Prepare callback function
61    /// ```rust,no_run
62    /// extern "efiapi" fn listener(_key_data: *mut uefi_input2::simple_text_input_ex::RawKeyData) -> Status {
63    ///     if _key_data.is_null() { return Status::INVALID_PARAMETER; }
64    ///     let data = unsafe { *_key_data };
65    ///     let data = KeyData::from(data);
66    ///     uefi::println!("{:?}{:08X}", data.key, data.key_state.key_shift_state);
67    ///     Status::SUCCESS
68    /// }
69    /// ```
70    /// 2. Register callback function
71    /// ```rust,no_run
72    /// uefi_input2::with_stdin(|input| {
73    ///     let trigger_key = KeyData::new('b')?;
74    ///     let _listener = input.on_key_callback(&trigger_key, listener)?;
75    ///     loop { core::hint::spin_loop() }
76    ///     Ok(())
77    ///  }).unwrap();
78    /// ```
79    pub fn on_key_callback(
80        &mut self,
81        key_data: &KeyData,
82        notification_function: KeyNotifyFunction,
83    ) -> Result<KeyNotifyHandle<'_>> {
84        let this = addr_of_mut!(self.0);
85
86        let mut handle = core::ptr::null_mut();
87        let mut raw_data = RawKeyData::from(*key_data);
88
89        unsafe {
90            ((*this).register_key_notify)(
91                this,
92                &mut raw_data,
93                notification_function,
94                &mut handle,
95            )
96                .to_result_with_val(|| KeyNotifyHandle {
97                    // the pointer needs to be cast back to a reference and stored in the Handle.
98                    // ensure that the Handle can safety borrow the origin protocol.
99                    proto: &mut *this,
100                    handle,
101                })
102        }
103    }
104
105    /// Register a callback function to be invoked when a key is pressed.
106    /// (need manual unregister)
107    pub unsafe fn register_key_notify(
108        &mut self,
109        key_data: &KeyData,
110        notification_function: KeyNotifyFunction,
111    ) -> Result<ManualKeyNotifyHandle> {
112        let this = addr_of_mut!(self.0);
113        let mut handle = core::ptr::null_mut();
114        let mut raw_data = RawKeyData::from(*key_data);
115
116        unsafe {
117            ((*this).register_key_notify)(
118                this,
119                &mut raw_data,
120                notification_function,
121                &mut handle,
122            ).to_result_with_val(|| handle)
123        }
124    }
125
126    /// Unregister a callback function
127    pub unsafe fn unregister_key_notify(
128        &mut self,
129        handle: ManualKeyNotifyHandle,
130    ) -> Result {
131        let this = addr_of_mut!(self.0);
132        unsafe {
133            ((*this).unregister_key_notify)(this, handle).to_result()
134        }
135    }
136}
137
138/// Keyboard notification handle(RAII)
139pub struct KeyNotifyHandle<'a> {
140    /// Referencing the original agreement ensures that the agreement remains valid upon cancellation.
141    proto: &'a mut SimpleTextInputExProtocol,
142    /// The unique handle generated by UEFI
143    handle: *mut c_void,
144}
145
146impl Drop for KeyNotifyHandle<'_> {
147    /// Automatically unregister the handle when the user no longer needs it
148    /// (e.g. when the variable goes out of scope).
149    fn drop(&mut self) {
150        let this = addr_of_mut!(*self.proto);
151        unsafe {
152            let _ = ((*this).unregister_key_notify)(this, self.handle);
153        }
154    }
155}
156
157/// unsafe Keyboard notification handle
158pub type ManualKeyNotifyHandle = *mut c_void;