uefi_input2/
input.rs

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