uefi_input2/
key_data.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 uefi::{Char16, Status, Result};
8use uefi::boot::ScopedProtocol;
9use uefi::proto::console::text::Key;
10use uefi_raw::protocol::console::InputKey;
11use crate::input::Input;
12use crate::simple_text_input_ex::*;
13
14/// height-level key data wrapper
15#[derive(Debug, Copy, Clone)]
16pub struct KeyData {
17    pub key: Key,
18    pub key_state: KeyState,
19}
20
21/// reverse conversion to C struct
22impl From<KeyData> for RawKeyData {
23    fn from(value: KeyData) -> Self {
24        let input_key = match value.key {
25            Key::Printable(c) => InputKey {
26                scan_code: 0,
27                unicode_char: u16::from(c),
28            },
29            Key::Special(code) => InputKey {
30                scan_code: code.0,
31                unicode_char: 0,
32            },
33        };
34
35        Self {
36            key: input_key,
37            key_state: value.key_state,
38        }
39    }
40}
41
42/// forward conversion to Rust struct
43impl From<RawKeyData> for KeyData {
44    fn from(raw: RawKeyData) -> Self {
45        Self {
46            key: Key::from(raw.key),
47            key_state: raw.key_state,
48        }
49    }
50}
51
52impl KeyData {
53    /// Create key data from char
54    pub fn new(c: char) -> Result<Self> {
55        let c = Char16::try_from(c).map_err(|_| Status::INVALID_PARAMETER)?;
56
57        Ok(Self {
58            key: Key::Printable(c),
59            key_state: KeyState::default(),
60        })
61    }
62
63    /// check if the modifier key is supported.
64    #[inline(always)]
65    pub fn supports_modifiers(&self) -> bool {
66        (self.key_state.key_shift_state & SHIFT_STATE_VALID) != 0
67    }
68
69    /// check if the right shift is pressed.
70    #[inline(always)]
71    pub fn r_shift(&self) -> bool { (self.key_state.key_shift_state & RIGHT_SHIFT_PRESSED) != 0 }
72
73    ///  check if the left shift is pressed.
74    #[inline(always)]
75    pub fn l_shift(&self) -> bool { (self.key_state.key_shift_state & LEFT_SHIFT_PRESSED) != 0 }
76
77    /// check if any shift is pressed.
78    #[inline(always)]
79     pub fn shift(&self) -> bool {
80        const SHIFT_MASK: u32 = LEFT_SHIFT_PRESSED | RIGHT_SHIFT_PRESSED;
81        (self.key_state.key_shift_state & SHIFT_MASK) != 0
82    }
83
84    /// check if the right control is pressed.
85    #[inline(always)]
86    pub fn r_ctrl(&self) -> bool { (self.key_state.key_shift_state & RIGHT_CONTROL_PRESSED) != 0 }
87
88    /// check if the left control is pressed.
89    #[inline(always)]
90    pub fn l_ctrl(&self) -> bool { (self.key_state.key_shift_state & LEFT_CONTROL_PRESSED) != 0 }
91
92    /// check if any control is pressed.
93    #[inline(always)]
94    pub fn ctrl(&self) -> bool {
95        const CTRL_MASK: u32 = LEFT_CONTROL_PRESSED | RIGHT_CONTROL_PRESSED;
96        (self.key_state.key_shift_state & CTRL_MASK) != 0
97    }
98
99    /// check if the right alt is pressed.
100    #[inline(always)]
101    pub fn r_alt(&self) -> bool { (self.key_state.key_shift_state & RIGHT_ALT_PRESSED) != 0 }
102
103    /// check if the left alt is pressed.
104    #[inline(always)]
105    pub fn l_alt(&self) -> bool { (self.key_state.key_shift_state & LEFT_ALT_PRESSED) != 0 }
106
107    /// check if any alt is pressed.
108    #[inline(always)]
109    pub fn alt(&self) -> bool {
110        const ALT_MASK: u32 = LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED;
111        (self.key_state.key_shift_state & ALT_MASK) != 0
112    }
113
114    /// check if the right logo is pressed.
115    #[inline(always)]
116    pub fn r_logo(&self) -> bool { (self.key_state.key_shift_state & RIGHT_LOGO_PRESSED) != 0 }
117
118    /// check if the left logo is pressed.
119    #[inline(always)]
120    pub fn l_logo(&self) -> bool { (self.key_state.key_shift_state & LEFT_LOGO_PRESSED) != 0 }
121
122    /// check if any logo is pressed.
123    #[inline(always)]
124    pub fn logo(&self) -> bool {
125        const LOGO_MASK: u32 = LEFT_LOGO_PRESSED | RIGHT_LOGO_PRESSED;
126        (self.key_state.key_shift_state & LOGO_MASK) != 0
127    }
128
129    /// check if the menu is pressed.
130    #[inline(always)]
131    pub fn menu(&self) -> bool { (self.key_state.key_shift_state & MENU_KEY_PRESSED) != 0 }
132
133    /// check if the sys req is pressed.
134    #[inline(always)]
135    pub fn sys_req(&self) -> bool { (self.key_state.key_shift_state & SYS_REQ_PRESSED) != 0 }
136
137    /// check if the toggle state is supported.
138    #[inline(always)]
139    pub fn supports_toggles(&self) -> bool {
140        (self.key_state.key_toggle_state & TOGGLE_STATE_VALID) != 0
141    }
142
143    /// check if realtime mode is active.
144    /// but inconsistent keyboard input behavior across different vendors :(
145    #[inline(always)]
146    pub fn is_realtime_mode(&self) -> bool {
147        (self.key_state.key_toggle_state & KEY_STATE_EXPOSED) != 0
148    }
149
150    /// check if the scroll lock is active.
151    #[inline(always)]
152    pub fn scroll_lock(&self) -> bool {
153        (self.key_state.key_toggle_state & SCROLL_LOCK_ACTIVE) != 0
154    }
155
156    /// check if the num lock is active.
157    #[inline(always)]
158    pub fn num_lock(&self) -> bool { (self.key_state.key_toggle_state & NUM_LOCK_ACTIVE) != 0 }
159
160    /// check if the caps lock is active.
161    #[inline(always)]
162    pub fn caps_lock(&self) -> bool { (self.key_state.key_toggle_state & CAPS_LOCK_ACTIVE) != 0 }
163
164    /// initialize realtime mode.
165    /// warn: this init function could overwrite the existing toggle state.
166    /// warn: it is recommended to call this function at program startup.
167    #[inline]
168    pub fn realtime_init(stdin: &mut ScopedProtocol<Input>, enable: bool) -> Result {
169        // #define EFI_KEY_STATE_EXPOSED 0x40 <= UEFI Spec V2.8
170        let state_bits = TOGGLE_STATE_VALID | ((enable as u8) << 6);
171        stdin.set_state(state_bits)
172    }
173}