I want to know if there is any way I can read user input in UEFI using the uefi-rs Rust wrapper. (or possibly any other way I can gather user input in UEFI with Rust)
I have tried many different approaches with read_key, the key event, and one didn't even compile and the other one only printed zeros. I have also scavenged through dozens of GitHub repositories, but seemingly none of those used these methods.
The first method (read key):
let bs = st.boot_services();
let read_key = st.stdin().read_key();
let unwrap = read_key.unwrap();
if unwrap.is_some() {
st.stdout().write_str(&unwrap.expect("Error").fmt(&mut fmt::Formatter).to_string()).expect("Failed to write to the console.");
}
And the second method (wait for event):
let mut binding = st.unsafe_clone();
key_event = binding.stdin().wait_for_key_event();
let result = bs.wait_for_event(&mut [key_event.unsafe_clone()]);
let usize = result.unwrap();
st.stdout().write_str(&usize.to_string()).expect("Failed to write to the console.");
There are probably many beginner mistakes in there because I am not extremely experienced with Rust. I did a few projects and now I found this, so I wanted to try it. User input is a thing that is comparably easy in Assembly. (from what I've experienced with Rust so far)
If anyone knows a repository I could check or knows the answer, please help. Have been working on this for hours now.
Link to the crate docs: https://docs.rs/uefi/latest/uefi/ Source code: https://github.com/rust-osdev/uefi-rs
CodePudding user response:
Here is a short example to read input until the user presses 'ESC'.
#![no_main]
#![no_std]
#![feature(abi_efiapi)]
use core::fmt::{Write};
use uefi::{prelude::*, proto::console::text::ScanCode, Char16};
#[entry]
fn main(_handle: Handle, mut st: SystemTable<Boot>) -> Status {
uefi_services::init(&mut st).unwrap();
let mut exit_flag = false;
while !exit_flag {
let key = st.stdin().read_key().expect("Expected input");
let _ = match key {
Some(k) => {
match k {
uefi::proto::console::text::Key::Printable(p) => {
write!(st.stdout(), "A printable key was entered: {:?}\r\n", p).expect("Write failed");
if p == Char16::try_from(27u16).expect("Unable to convert the ESC ascii code to Char16") {
exit_flag = true;
}
}
uefi::proto::console::text::Key::Special(s) => {
write!(st.stdout(), "A special key was entered: {:?}\r\n", s).expect("Write failed");
if s == ScanCode::ESCAPE {
exit_flag = true;
}
}
};
},
None => {}
};
}
Status::SUCCESS
}
I have never used uefi-rs before, there may be better solutions to handle input with this crate.
Take the template as starting point and replace main.rs.
Build with: cargo nightly build --target x86_64-unknown-uefi