d53661b9a0
I will start working on stack traces tonight and tomorrow. We need to be able to 'unwind' by finding calling functions.
210 lines
5.4 KiB
Rust
210 lines
5.4 KiB
Rust
use core::{
|
|
pin::Pin,
|
|
task::{Context, Poll},
|
|
};
|
|
|
|
use crate::println;
|
|
use crossbeam::queue::ArrayQueue;
|
|
use futures_util::{Stream, StreamExt, task::AtomicWaker};
|
|
use pc_keyboard::{
|
|
DecodedKey, HandleControl, KeyCode, Keyboard, ScancodeSet1,
|
|
layouts::Uk105Key,
|
|
};
|
|
use spin::{Lazy, Mutex, Once};
|
|
|
|
static KBD_QUEUE: Once<ArrayQueue<u8>> = Once::new();
|
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
|
|
|
pub static KEYBOARD: Lazy<Mutex<Keyboard<Uk105Key, ScancodeSet1>>> =
|
|
Lazy::new(|| {
|
|
Mutex::new(Keyboard::new(
|
|
ScancodeSet1::new(),
|
|
// TODO: Expose an API to change the default KB layout.
|
|
Uk105Key,
|
|
HandleControl::Ignore,
|
|
))
|
|
});
|
|
pub static SCANCODE_STREAM: Lazy<Mutex<ScancodeStream>> =
|
|
Lazy::new(|| Mutex::new(ScancodeStream::new()));
|
|
|
|
pub fn add_scancode(scancode: u8) {
|
|
if let Some(queue) = KBD_QUEUE.get() {
|
|
if queue.push(scancode).is_err() {
|
|
println!("WARNING: scancode queue full; dropping keyboard input");
|
|
} else {
|
|
WAKER.wake();
|
|
}
|
|
} else {
|
|
println!("WARNING: scancode queue not initialized");
|
|
}
|
|
}
|
|
|
|
pub struct ScancodeStream {
|
|
_private: (),
|
|
}
|
|
|
|
impl ScancodeStream {
|
|
pub fn new() -> Self {
|
|
KBD_QUEUE.call_once(|| ArrayQueue::new(5));
|
|
Self { _private: () }
|
|
}
|
|
|
|
pub fn try_next(&mut self) -> Option<u8> {
|
|
KBD_QUEUE.get().and_then(|queue| queue.pop())
|
|
}
|
|
}
|
|
|
|
impl Default for ScancodeStream {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl Stream for ScancodeStream {
|
|
type Item = u8;
|
|
|
|
fn poll_next(
|
|
self: Pin<&mut Self>,
|
|
cx: &mut Context<'_>,
|
|
) -> Poll<Option<Self::Item>> {
|
|
let queue = KBD_QUEUE.get().unwrap();
|
|
|
|
if let Some(scancode) = queue.pop() {
|
|
return Poll::Ready(Some(scancode));
|
|
}
|
|
|
|
WAKER.register(cx.waker());
|
|
WAKER.register(cx.waker());
|
|
|
|
queue.pop().map_or(Poll::Pending, |scancode| {
|
|
WAKER.take();
|
|
Poll::Ready(Some(scancode))
|
|
})
|
|
}
|
|
}
|
|
|
|
pub async fn get_keystroke_async() -> KeyStroke {
|
|
loop {
|
|
if let Some(scancode) = SCANCODE_STREAM.lock().next().await {
|
|
if let Ok(keystroke) = KeyStroke::try_from(scancode) {
|
|
return keystroke;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn get_keystroke_optional() -> Option<KeyStroke> {
|
|
if let Some(scancode) = SCANCODE_STREAM.lock().try_next() {
|
|
if let Ok(keystroke) = KeyStroke::try_from(scancode) {
|
|
return Some(keystroke);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub enum KeyStroke {
|
|
Char(char),
|
|
Ctrl,
|
|
RCtrl,
|
|
Alt,
|
|
RAlt,
|
|
Shift,
|
|
RShift,
|
|
Meta,
|
|
RMeta,
|
|
Backspace,
|
|
Left,
|
|
Right,
|
|
Up,
|
|
Down,
|
|
None,
|
|
Enter,
|
|
Escape,
|
|
Del,
|
|
}
|
|
|
|
impl KeyStroke {
|
|
pub const fn from_keycode(key: KeyCode) -> Self {
|
|
match key {
|
|
KeyCode::LControl => Self::Ctrl,
|
|
KeyCode::RControl => Self::RCtrl,
|
|
KeyCode::LAlt => Self::Alt,
|
|
KeyCode::RAlt2 => Self::RAlt,
|
|
KeyCode::LShift => Self::Shift,
|
|
KeyCode::RShift => Self::RShift,
|
|
KeyCode::LWin => Self::Meta,
|
|
KeyCode::RWin => Self::RMeta,
|
|
KeyCode::Backspace => Self::Backspace,
|
|
KeyCode::ArrowLeft => Self::Left,
|
|
KeyCode::ArrowRight => Self::Right,
|
|
KeyCode::ArrowUp => Self::Up,
|
|
KeyCode::ArrowDown => Self::Down,
|
|
KeyCode::Return => Self::Enter,
|
|
KeyCode::Escape => Self::Escape,
|
|
KeyCode::Delete => Self::Del,
|
|
_ => Self::None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<u8> for KeyStroke {
|
|
type Error = ();
|
|
|
|
fn try_from(code: u8) -> Result<Self, Self::Error> {
|
|
let mut keyboard = KEYBOARD.lock();
|
|
|
|
let key = match keyboard.add_byte(code) {
|
|
Ok(Some(event)) => match keyboard.process_keyevent(event) {
|
|
Some(key) => key,
|
|
_ => return Err(()),
|
|
},
|
|
_ => return Err(()),
|
|
};
|
|
|
|
match key {
|
|
DecodedKey::Unicode(ch) => Ok(Self::Char(ch)),
|
|
DecodedKey::RawKey(key) => match Self::from_keycode(key) {
|
|
Self::None => Err(()),
|
|
key => Ok(key),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryInto<char> for KeyStroke {
|
|
type Error = ();
|
|
|
|
fn try_into(self) -> Result<char, Self::Error> {
|
|
match self {
|
|
Self::Char(c) => Ok(c),
|
|
_ => Err(()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl core::fmt::Display for KeyStroke {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
match self {
|
|
Self::Char(c) => write!(f, "{}", c),
|
|
Self::Ctrl => write!(f, "CTRL"),
|
|
Self::RCtrl => write!(f, "RCtrl"),
|
|
Self::Alt => write!(f, "ALT"),
|
|
Self::RAlt => write!(f, "RAlt"),
|
|
Self::Shift => write!(f, "SHIFT"),
|
|
Self::RShift => write!(f, "RShift"),
|
|
Self::Meta => write!(f, "META"),
|
|
Self::RMeta => write!(f, "RMeta"),
|
|
Self::Backspace => write!(f, "BACKSPACE"),
|
|
Self::Left => write!(f, "LEFT"),
|
|
Self::Right => write!(f, "RIGHT"),
|
|
Self::Up => write!(f, "UP"),
|
|
Self::Down => write!(f, "DOWN"),
|
|
Self::Enter => write!(f, "ENTER"),
|
|
Self::Escape => write!(f, "ESCAPE"),
|
|
Self::None => write!(f, "NONE"),
|
|
Self::Del => write!(f, "DEL"),
|
|
}
|
|
}
|
|
}
|