refactor mega-commit.
- reorganised the entire project so that the entire kernel is a single codebase rather than a kernel and a libk.
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user