bd595851e2
251 files: init, acpid, ipcd, netcfg, ihdgd, virtio-gpud, scheme-utils, inputd, block driver, ptyd, ramfs, randd, initfs bootstrap, path deps, version +rb0.3.1, author attribution
135 lines
3.9 KiB
Rust
135 lines
3.9 KiB
Rust
use std::collections::VecDeque;
|
|
|
|
use orbclient::{Event, EventOption};
|
|
use syscall::error::*;
|
|
|
|
use crate::display::Display;
|
|
use crate::keymap::Keymap;
|
|
|
|
pub struct TextScreen {
|
|
pub display: Display,
|
|
inner: console_draw::TextScreen,
|
|
ctrl: bool,
|
|
input: VecDeque<u8>,
|
|
pending_writes: Vec<Vec<u8>>,
|
|
/// Active keyboard layout. Defaults to US QWERTY.
|
|
pub keymap: Keymap,
|
|
}
|
|
|
|
impl TextScreen {
|
|
pub fn new(display: Display) -> TextScreen {
|
|
TextScreen {
|
|
display,
|
|
inner: console_draw::TextScreen::new(),
|
|
ctrl: false,
|
|
input: VecDeque::new(),
|
|
pending_writes: Vec::new(),
|
|
keymap: Keymap::us(),
|
|
}
|
|
}
|
|
|
|
pub fn handle_handoff(&mut self) {
|
|
log::info!("fbcond: Performing handoff");
|
|
self.display.reopen_for_handoff();
|
|
if self.display.map.is_some() {
|
|
self.flush_pending_writes();
|
|
}
|
|
}
|
|
|
|
pub fn input(&mut self, event: &Event) {
|
|
let mut buf = vec![];
|
|
|
|
match event.to_option() {
|
|
EventOption::Key(key_event) => {
|
|
if key_event.scancode == 0x1D {
|
|
self.ctrl = key_event.pressed;
|
|
} else if key_event.pressed {
|
|
let sc = key_event.scancode as u8;
|
|
if let Some(seq) = self.keymap.lookup(sc) {
|
|
buf.extend_from_slice(seq);
|
|
} else {
|
|
let c = match key_event.character {
|
|
c @ 'A'..='Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
|
|
c @ 'a'..='z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
|
|
c => c,
|
|
};
|
|
|
|
if c != '\0' {
|
|
let mut b = [0; 4];
|
|
buf.extend_from_slice(c.encode_utf8(&mut b).as_bytes());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_ => (), //TODO: Mouse in terminal
|
|
}
|
|
|
|
for &b in buf.iter() {
|
|
self.input.push_back(b);
|
|
}
|
|
}
|
|
|
|
pub fn can_read(&self) -> bool {
|
|
!self.input.is_empty()
|
|
}
|
|
}
|
|
|
|
impl TextScreen {
|
|
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
|
let mut i = 0;
|
|
|
|
while i < buf.len() && !self.input.is_empty() {
|
|
buf[i] = self.input.pop_front().unwrap();
|
|
i += 1;
|
|
}
|
|
|
|
Ok(i)
|
|
}
|
|
|
|
pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
if let Some(map) = &mut self.display.map {
|
|
Display::handle_resize(map, &mut self.inner);
|
|
|
|
let damage = self.inner.write(map, buf, &mut self.input);
|
|
|
|
self.display.sync_rect(damage);
|
|
} else {
|
|
log::warn!(
|
|
"fbcond: TextScreen::write() called while display map is None; \
|
|
buffering {} bytes ({} pending chunks). Will flush after handoff.",
|
|
buf.len(),
|
|
self.pending_writes.len() + 1,
|
|
);
|
|
self.pending_writes.push(buf.to_vec());
|
|
}
|
|
|
|
Ok(buf.len())
|
|
}
|
|
|
|
pub fn flush_pending_writes(&mut self) {
|
|
if self.pending_writes.is_empty() {
|
|
return;
|
|
}
|
|
|
|
let count = self.pending_writes.len();
|
|
log::info!(
|
|
"fbcond: Flushing {} pending write chunks after display handoff",
|
|
count,
|
|
);
|
|
|
|
if let Some(map) = &mut self.display.map {
|
|
for pending in self.pending_writes.drain(..) {
|
|
Display::handle_resize(map, &mut self.inner);
|
|
let damage = self.inner.write(map, &pending, &mut self.input);
|
|
map.dirty_fb(damage).unwrap();
|
|
}
|
|
} else {
|
|
log::error!(
|
|
"fbcond: flush_pending_writes called but display map is still None; \
|
|
keeping {} buffered chunks",
|
|
self.pending_writes.len(),
|
|
);
|
|
}
|
|
}
|
|
}
|