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) {
|
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' => {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
// @A–Z[\]^_`a–z{|}~
|
// @A–Z[\]^_`a–z{|}~
|
||||||
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 ¶m 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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user