1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-23 08:26:17 +04:00

fix VGA and support keyboard escape char for rust/sh

This commit is contained in:
WangRunji 2019-03-17 13:32:03 +08:00
parent 23b4c39ec7
commit 5a619825bc
6 changed files with 124 additions and 56 deletions

View File

@ -171,9 +171,8 @@ impl<F: Font> Console<F> {
fn write_byte(&mut self, byte: u8) { fn write_byte(&mut self, byte: u8) {
if self.parser.is_parsing() { if self.parser.is_parsing() {
if self.parser.parse(byte) { self.parser.parse(byte);
return; return;
}
} }
match byte { match byte {
b'\x7f' => { b'\x7f' => {

View File

@ -11,7 +11,7 @@ pub fn init() {
/// Receive character from keyboard /// Receive character from keyboard
/// Should be called on every interrupt /// Should be called on every interrupt
pub fn receive() -> Option<char> { pub fn receive() -> Option<DecodedKey> {
lazy_static! { lazy_static! {
static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> = static ref KEYBOARD: Mutex<Keyboard<layouts::Us104Key, ScancodeSet1>> =
Mutex::new(Keyboard::new(layouts::Us104Key, ScancodeSet1, HandleControl::Ignore)); 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 { if unsafe { status_port.read() } & (1 << 0) != 0 {
let scancode = unsafe { data_port.read() }; let scancode = unsafe { data_port.read() };
if let Ok(Some(key_event)) = keyboard.add_byte(scancode) { if let Ok(Some(key_event)) = keyboard.add_byte(scancode) {
if let Some(key) = keyboard.process_keyevent(key_event) { return keyboard.process_keyevent(key_event);
match key {
DecodedKey::Unicode(character) => return Some(character),
DecodedKey::RawKey(_key) => {}, // TODO: handle RawKey from keyboard
}
}
} }
} }
None None

View File

@ -8,7 +8,7 @@ use x86_64::instructions::port::Port;
use crate::consts::KERNEL_OFFSET; use crate::consts::KERNEL_OFFSET;
use crate::util::color::ConsoleColor; use crate::util::color::ConsoleColor;
use crate::util::escape_parser::EscapeParser; use crate::util::escape_parser::{EscapeParser, CSI};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
struct ColorCode(u8); struct ColorCode(u8);
@ -131,7 +131,9 @@ impl BaseConsole for VgaWriter {
Ok(()) 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.pos = pos;
self.buffer.set_cursor_at(pos.row.0 as usize, pos.col.0 as usize); self.buffer.set_cursor_at(pos.row.0 as usize, pos.col.0 as usize);
Ok(()) Ok(())
@ -186,13 +188,45 @@ impl AsciiConsole for VgaWriter {
if escaped_char == b'[' { if escaped_char == b'[' {
self.escape_parser.start_parse(); self.escape_parser.start_parse();
} }
self.escape_parser.parse(escaped_char); let csi = match self.escape_parser.parse(escaped_char) {
let end = escaped_char == b'm'; Some(csi) => csi,
if end { None => return false,
let attr = self.escape_parser.char_attribute(); };
self.color_code = ColorCode::new(attr.foreground, attr.background); 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
} }
} }

View File

@ -142,9 +142,24 @@ fn page_fault(tf: &mut TrapFrame) {
fn keyboard() { fn keyboard() {
use crate::arch::driver::keyboard; use crate::arch::driver::keyboard;
use pc_keyboard::{DecodedKey, KeyCode};
trace!("\nInterupt: Keyboard"); trace!("\nInterupt: Keyboard");
if let Some(c) = keyboard::receive() { if let Some(key) = keyboard::receive() {
crate::trap::serial(c); 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);
}
}
}
} }
} }

View File

@ -79,7 +79,7 @@ impl From<Level> for ConsoleColor {
fn from(level: Level) -> Self { fn from(level: Level) -> Self {
match level { match level {
Level::Error => ConsoleColor::Red, Level::Error => ConsoleColor::Red,
Level::Warn => ConsoleColor::Yellow, Level::Warn => ConsoleColor::BrightYellow,
Level::Info => ConsoleColor::Blue, Level::Info => ConsoleColor::Blue,
Level::Debug => ConsoleColor::Green, Level::Debug => ConsoleColor::Green,
Level::Trace => ConsoleColor::BrightBlack, Level::Trace => ConsoleColor::BrightBlack,

View File

@ -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)] #[derive(Debug, PartialEq)]
enum ParseStatus { enum ParseStatus {
/// The last character is `ESC`, start parsing the escape sequence. /// The last character is `ESC`, start parsing the escape sequence.
@ -46,6 +64,30 @@ enum ParseStatus {
Text, 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)] #[derive(Debug)]
pub struct EscapeParser { pub struct EscapeParser {
status: ParseStatus, status: ParseStatus,
@ -75,66 +117,49 @@ impl EscapeParser {
self.current_param = None; 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. /// 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); assert_ne!(self.status, ParseStatus::Text);
match self.status { match self.status {
ParseStatus::BeginEscapeSequence => match byte { ParseStatus::BeginEscapeSequence => match byte {
b'[' => { b'[' => {
self.status = ParseStatus::ParsingCSI; self.status = ParseStatus::ParsingCSI;
self.current_param = Some(0); self.current_param = None;
self.params.clear(); self.params.clear();
return true; return None;
} }
_ => { /* unimplemented!() */ } _ => { /* unimplemented!() */ }
}, },
ParseStatus::ParsingCSI => match byte { ParseStatus::ParsingCSI => match byte {
b'0'...b'9' => { b'0'...b'9' => {
let digit = (byte - b'0') as u32; let digit = (byte - b'0') as u32;
if let Some(param) = self.current_param { let param = self.current_param.unwrap_or(0) as u32;
let res: u32 = param as u32 * 10 + digit; let res = param * 10 + digit;
self.current_param = if res <= 0xFF { Some(res as u8) } else { None }; self.current_param = if res <= 0xFF { Some(res as u8) } else { None };
} return None;
return true;
} }
b';' => { b';' => {
if let Some(param) = self.current_param { let param = self.current_param.unwrap_or(0);
self.params.push(param).unwrap(); self.params.push(param).unwrap();
}
self.current_param = Some(0); self.current_param = Some(0);
return true; return None;
} }
// @AZ[\]^_`az{|}~ // @AZ[\]^_`az{|}~
0x40...0x7E => { 0x40...0x7E => {
if let Some(param) = self.current_param { if let Some(param) = self.current_param {
self.params.push(param).unwrap(); self.params.push(param).unwrap();
} }
match byte { let csi = CSI::new(byte, &self.params);
b'm' => self.parse_sgr_params(), if csi == CSI::SGR {
_ => { /* unimplemented!() */ } for &param in self.params.iter() {
self.char_attr.apply_sgr(param);
}
} }
self.status = ParseStatus::Text; self.status = ParseStatus::Text;
self.current_param = None; self.current_param = None;
self.params.clear(); self.params.clear();
return true; return Some(csi);
} }
_ => {} _ => {}
}, },
@ -143,7 +168,7 @@ impl EscapeParser {
self.status = ParseStatus::Text; self.status = ParseStatus::Text;
self.current_param = None; self.current_param = None;
self.params.clear(); self.params.clear();
false None
} }
pub fn char_attribute(&self) -> CharacterAttribute { pub fn char_attribute(&self) -> CharacterAttribute {