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;