mirror of
https://github.com/rcore-os/rCore.git
synced 2024-11-23 00:16:17 +04:00
fix VGA and support keyboard escape char for rust/sh
This commit is contained in:
parent
23b4c39ec7
commit
5a619825bc
@ -171,9 +171,8 @@ impl<F: Font> Console<F> {
|
||||
|
||||
fn write_byte(&mut self, byte: u8) {
|
||||
if self.parser.is_parsing() {
|
||||
if self.parser.parse(byte) {
|
||||
return;
|
||||
}
|
||||
self.parser.parse(byte);
|
||||
return;
|
||||
}
|
||||
match byte {
|
||||
b'\x7f' => {
|
||||
|
@ -11,7 +11,7 @@ pub fn init() {
|
||||
|
||||
/// Receive character from keyboard
|
||||
/// Should be called on every interrupt
|
||||
pub fn receive() -> Option<char> {
|
||||
pub fn receive() -> Option<DecodedKey> {
|
||||
lazy_static! {
|
||||
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
|
||||
Mutex::new(Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore));
|
||||
@ -25,12 +25,7 @@ pub fn receive() -> Option<char> {
|
||||
if unsafe { status_port.read() } & (1 << 0) != 0 {
|
||||
let scancode = unsafe { data_port.read() };
|
||||
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
|
||||
if let Some(key) = keyboard.process_keyevent(key_event) {
|
||||
match key {
|
||||
DecodedKey::Unicode(character) => return Some(character),
|
||||
DecodedKey::RawKey(_key) => {}, // TODO: handle RawKey from keyboard
|
||||
}
|
||||
}
|
||||
return keyboard.process_keyevent(key_event);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -8,7 +8,7 @@ use x86_64::instructions::port::Port;
|
||||
|
||||
use crate::consts::KERNEL_OFFSET;
|
||||
use crate::util::color::ConsoleColor;
|
||||
use crate::util::escape_parser::EscapeParser;
|
||||
use crate::util::escape_parser::{EscapeParser, CSI};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct ColorCode(u8);
|
||||
@ -131,7 +131,9 @@ impl BaseConsole for VgaWriter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_pos(&mut self, pos: Position) -> Result<(), Self::Error> {
|
||||
fn set_pos(&mut self, mut pos: Position) -> Result<(), Self::Error> {
|
||||
pos.row.bound(self.get_height());
|
||||
pos.col.bound(self.get_width());
|
||||
self.pos = pos;
|
||||
self.buffer.set_cursor_at(pos.row.0 as usize, pos.col.0 as usize);
|
||||
Ok(())
|
||||
@ -186,13 +188,45 @@ impl AsciiConsole for VgaWriter {
|
||||
if escaped_char == b'[' {
|
||||
self.escape_parser.start_parse();
|
||||
}
|
||||
self.escape_parser.parse(escaped_char);
|
||||
let end = escaped_char == b'm';
|
||||
if end {
|
||||
let attr = self.escape_parser.char_attribute();
|
||||
self.color_code = ColorCode::new(attr.foreground, attr.background);
|
||||
let csi = match self.escape_parser.parse(escaped_char) {
|
||||
Some(csi) => csi,
|
||||
None => return false,
|
||||
};
|
||||
match csi {
|
||||
CSI::SGR => {
|
||||
let attr = self.escape_parser.char_attribute();
|
||||
self.color_code = ColorCode::new(attr.foreground, attr.background);
|
||||
}
|
||||
CSI::CursorMove(dx, dy) => {
|
||||
let x = (self.pos.row.0 as i8 + dx).max(0) as u8;
|
||||
let y = (self.pos.col.0 as i8 + dy).max(0) as u8;
|
||||
self.set_pos(Position::new(Row(x), Col(y)));
|
||||
}
|
||||
CSI::CursorMoveLine(dx) => {
|
||||
let x = (self.pos.row.0 as i8 + dx).max(0) as u8;
|
||||
self.set_pos(Position::new(Row(x), Col(0)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Check if an 8-bit char is special
|
||||
fn is_special(&self, ch: u8) -> Option<SpecialChar> {
|
||||
match self.get_control_char_mode() {
|
||||
ControlCharMode::Interpret => match ch {
|
||||
b'\n' => Some(SpecialChar::Linefeed),
|
||||
b'\r' => Some(SpecialChar::CarriageReturn),
|
||||
b'\t' => Some(SpecialChar::Tab),
|
||||
0x1b => Some(SpecialChar::Escape),
|
||||
0x7f => Some(SpecialChar::Delete),
|
||||
0x08 => Some(SpecialChar::Backspace),
|
||||
_ if !(ch.is_ascii_graphic() || ch == b' ')
|
||||
=> Some(SpecialChar::Delete), // ignore non-graphic ascii
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
end
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,9 +142,24 @@ fn page_fault(tf: &mut TrapFrame) {
|
||||
|
||||
fn keyboard() {
|
||||
use crate::arch::driver::keyboard;
|
||||
use pc_keyboard::{DecodedKey, KeyCode};
|
||||
trace!("\nInterupt: Keyboard");
|
||||
if let Some(c) = keyboard::receive() {
|
||||
crate::trap::serial(c);
|
||||
if let Some(key) = keyboard::receive() {
|
||||
match key {
|
||||
DecodedKey::Unicode(c) => crate::trap::serial(c),
|
||||
DecodedKey::RawKey(code) => {
|
||||
let s = match code {
|
||||
KeyCode::ArrowUp => "\u{1b}[A",
|
||||
KeyCode::ArrowDown => "\u{1b}[B",
|
||||
KeyCode::ArrowRight => "\u{1b}[C",
|
||||
KeyCode::ArrowLeft => "\u{1b}[D",
|
||||
_ => "",
|
||||
};
|
||||
for c in s.chars() {
|
||||
crate::trap::serial(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ impl From<Level> for ConsoleColor {
|
||||
fn from(level: Level) -> Self {
|
||||
match level {
|
||||
Level::Error => ConsoleColor::Red,
|
||||
Level::Warn => ConsoleColor::Yellow,
|
||||
Level::Warn => ConsoleColor::BrightYellow,
|
||||
Level::Info => ConsoleColor::Blue,
|
||||
Level::Debug => ConsoleColor::Green,
|
||||
Level::Trace => ConsoleColor::BrightBlack,
|
||||
|
@ -32,6 +32,24 @@ impl Default for CharacterAttribute {
|
||||
}
|
||||
}
|
||||
|
||||
impl CharacterAttribute {
|
||||
/// Parse and apply SGR (Select Graphic Rendition) parameters.
|
||||
fn apply_sgr(&mut self, code: u8) {
|
||||
match code {
|
||||
0 => *self = CharacterAttribute::default(),
|
||||
4 => self.underline = true,
|
||||
7 => self.reverse = true,
|
||||
9 => self.strikethrough = true,
|
||||
24 => self.underline = false,
|
||||
27 => self.reverse = false,
|
||||
29 => self.strikethrough = false,
|
||||
30...37 | 90...97 => self.foreground = ConsoleColor::from_console_code(code).unwrap(),
|
||||
40...47 | 100...107 => self.background = ConsoleColor::from_console_code(code - 10).unwrap(),
|
||||
_ => { /* unimplemented!() */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum ParseStatus {
|
||||
/// The last character is `ESC`, start parsing the escape sequence.
|
||||
@ -46,6 +64,30 @@ enum ParseStatus {
|
||||
Text,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum CSI {
|
||||
CursorMove(i8, i8),
|
||||
CursorMoveLine(i8),
|
||||
SGR,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl CSI {
|
||||
fn new(final_byte: u8, params: &[u8]) -> CSI {
|
||||
let n = *params.get(0).unwrap_or(&1) as i8;
|
||||
match final_byte {
|
||||
b'A' => CSI::CursorMove(-n, 0),
|
||||
b'B' => CSI::CursorMove(n, 0),
|
||||
b'C' => CSI::CursorMove(0, n),
|
||||
b'D' => CSI::CursorMove(0, -n),
|
||||
b'E' => CSI::CursorMoveLine(n),
|
||||
b'F' => CSI::CursorMoveLine(-n),
|
||||
b'm' => CSI::SGR,
|
||||
_ => CSI::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct EscapeParser {
|
||||
status: ParseStatus,
|
||||
@ -75,66 +117,49 @@ impl EscapeParser {
|
||||
self.current_param = None;
|
||||
}
|
||||
|
||||
//// Parse SGR (Select Graphic Rendition) parameters.
|
||||
fn parse_sgr_params(&mut self) {
|
||||
for param in &self.params {
|
||||
match param {
|
||||
0 => self.char_attr = CharacterAttribute::default(),
|
||||
4 => self.char_attr.underline = true,
|
||||
7 => self.char_attr.reverse = true,
|
||||
9 => self.char_attr.strikethrough = true,
|
||||
24 => self.char_attr.underline = false,
|
||||
27 => self.char_attr.reverse = false,
|
||||
29 => self.char_attr.strikethrough = false,
|
||||
30...37 | 90...97 => self.char_attr.foreground = ConsoleColor::from_console_code(*param).unwrap(),
|
||||
40...47 | 100...107 => self.char_attr.background = ConsoleColor::from_console_code(*param - 10).unwrap(),
|
||||
_ => { /* unimplemented!() */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See a character during parsing.
|
||||
pub fn parse(&mut self, byte: u8) -> bool {
|
||||
/// Return `Some(csi)` if parse end, else `None`.
|
||||
pub fn parse(&mut self, byte: u8) -> Option<CSI> {
|
||||
assert_ne!(self.status, ParseStatus::Text);
|
||||
match self.status {
|
||||
ParseStatus::BeginEscapeSequence => match byte {
|
||||
b'[' => {
|
||||
self.status = ParseStatus::ParsingCSI;
|
||||
self.current_param = Some(0);
|
||||
self.current_param = None;
|
||||
self.params.clear();
|
||||
return true;
|
||||
return None;
|
||||
}
|
||||
_ => { /* unimplemented!() */ }
|
||||
},
|
||||
ParseStatus::ParsingCSI => match byte {
|
||||
b'0'...b'9' => {
|
||||
let digit = (byte - b'0') as u32;
|
||||
if let Some(param) = self.current_param {
|
||||
let res: u32 = param as u32 * 10 + digit;
|
||||
self.current_param = if res <= 0xFF { Some(res as u8) } else { None };
|
||||
}
|
||||
return true;
|
||||
let param = self.current_param.unwrap_or(0) as u32;
|
||||
let res = param * 10 + digit;
|
||||
self.current_param = if res <= 0xFF { Some(res as u8) } else { None };
|
||||
return None;
|
||||
}
|
||||
b';' => {
|
||||
if let Some(param) = self.current_param {
|
||||
self.params.push(param).unwrap();
|
||||
}
|
||||
let param = self.current_param.unwrap_or(0);
|
||||
self.params.push(param).unwrap();
|
||||
self.current_param = Some(0);
|
||||
return true;
|
||||
return None;
|
||||
}
|
||||
// @A–Z[\]^_`a–z{|}~
|
||||
0x40...0x7E => {
|
||||
if let Some(param) = self.current_param {
|
||||
self.params.push(param).unwrap();
|
||||
}
|
||||
match byte {
|
||||
b'm' => self.parse_sgr_params(),
|
||||
_ => { /* unimplemented!() */ }
|
||||
let csi = CSI::new(byte, &self.params);
|
||||
if csi == CSI::SGR {
|
||||
for ¶m in self.params.iter() {
|
||||
self.char_attr.apply_sgr(param);
|
||||
}
|
||||
}
|
||||
self.status = ParseStatus::Text;
|
||||
self.current_param = None;
|
||||
self.params.clear();
|
||||
return true;
|
||||
return Some(csi);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
@ -143,7 +168,7 @@ impl EscapeParser {
|
||||
self.status = ParseStatus::Text;
|
||||
self.current_param = None;
|
||||
self.params.clear();
|
||||
false
|
||||
None
|
||||
}
|
||||
|
||||
pub fn char_attribute(&self) -> CharacterAttribute {
|
||||
|
Loading…
Reference in New Issue
Block a user