152da9a59SGnoCiYeH use core::sync::atomic::{AtomicBool, AtomicIsize, Ordering}; 252da9a59SGnoCiYeH 352da9a59SGnoCiYeH use alloc::{ 452da9a59SGnoCiYeH sync::{Arc, Weak}, 552da9a59SGnoCiYeH vec::Vec, 652da9a59SGnoCiYeH }; 752da9a59SGnoCiYeH use bitmap::{traits::BitMapOps, StaticBitmap}; 852da9a59SGnoCiYeH 952da9a59SGnoCiYeH use crate::{ 1052da9a59SGnoCiYeH driver::tty::{console::ConsoleSwitch, ConsoleFont, KDMode}, 1152da9a59SGnoCiYeH libs::{font::FontDesc, rwlock::RwLock}, 1252da9a59SGnoCiYeH process::Pid, 1352da9a59SGnoCiYeH }; 1452da9a59SGnoCiYeH 1552da9a59SGnoCiYeH use super::{ 1652da9a59SGnoCiYeH console_map::{TranslationMap, TranslationMapType}, 1752da9a59SGnoCiYeH Color, DrawRegion, VtMode, VtModeData, COLOR_TABLE, DEFAULT_BLUE, DEFAULT_GREEN, DEFAULT_RED, 1852da9a59SGnoCiYeH }; 1952da9a59SGnoCiYeH 2052da9a59SGnoCiYeH pub(super) const NPAR: usize = 16; 2152da9a59SGnoCiYeH 2252da9a59SGnoCiYeH lazy_static! { 2352da9a59SGnoCiYeH /// 是否已经添加了软光标 2452da9a59SGnoCiYeH pub(super) static ref SOFTCURSOR_ORIGINAL: RwLock<Option<VcCursor>> = RwLock::new(None); 2552da9a59SGnoCiYeH 2652da9a59SGnoCiYeH pub static ref CURRENT_VCNUM: AtomicIsize = AtomicIsize::new(-1); 2752da9a59SGnoCiYeH 2852da9a59SGnoCiYeH pub static ref CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false); 2952da9a59SGnoCiYeH } 3052da9a59SGnoCiYeH 3152da9a59SGnoCiYeH /// ## 虚拟控制台的信息 3252da9a59SGnoCiYeH #[derive(Debug, Clone)] 3352da9a59SGnoCiYeH pub struct VirtualConsoleData { 3452da9a59SGnoCiYeH pub num: usize, 3552da9a59SGnoCiYeH pub state: VirtualConsoleInfo, 3652da9a59SGnoCiYeH pub saved_state: VirtualConsoleInfo, 3752da9a59SGnoCiYeH /// 最大列数 3852da9a59SGnoCiYeH pub cols: usize, 3952da9a59SGnoCiYeH /// 最大行数 4052da9a59SGnoCiYeH pub rows: usize, 4152da9a59SGnoCiYeH // /// 每行的字节数 4252da9a59SGnoCiYeH // pub bytes_per_row: usize, 4352da9a59SGnoCiYeH /// 扫描行数 4452da9a59SGnoCiYeH pub scan_lines: usize, 4552da9a59SGnoCiYeH /// 字符单元高度 4652da9a59SGnoCiYeH pub cell_height: u32, 4752da9a59SGnoCiYeH 4852da9a59SGnoCiYeH // /// 实际屏幕地址的开始 4952da9a59SGnoCiYeH // pub screen_base: VirtAddr, 5052da9a59SGnoCiYeH // /// 实际屏幕的结束 5152da9a59SGnoCiYeH // pub scr_end: u64, 5252da9a59SGnoCiYeH /// 可见窗口的开始 5352da9a59SGnoCiYeH pub visible_origin: usize, 5452da9a59SGnoCiYeH /// 滚动窗口的顶部 5552da9a59SGnoCiYeH pub top: usize, 5652da9a59SGnoCiYeH /// 滚动窗口的底部 5752da9a59SGnoCiYeH pub bottom: usize, 5852da9a59SGnoCiYeH /// 当前读取位置 5952da9a59SGnoCiYeH pub pos: usize, 6052da9a59SGnoCiYeH 6152da9a59SGnoCiYeH /// 颜色集合 6252da9a59SGnoCiYeH pub palette: [Color; 16], 6352da9a59SGnoCiYeH /// 默认颜色 6452da9a59SGnoCiYeH pub def_color: u8, 6552da9a59SGnoCiYeH /// 下划线颜色 6652da9a59SGnoCiYeH pub underline_color: u32, 6752da9a59SGnoCiYeH /// 斜体颜色 6852da9a59SGnoCiYeH pub italic_color: u32, 6952da9a59SGnoCiYeH /// 半强度颜色 7052da9a59SGnoCiYeH pub half_color: u32, 7152da9a59SGnoCiYeH 7252da9a59SGnoCiYeH pub mode: KDMode, 7352da9a59SGnoCiYeH pub vt_mode: VtModeData, 7452da9a59SGnoCiYeH 7552da9a59SGnoCiYeH /// 是否启用颜色 7652da9a59SGnoCiYeH pub color_mode: bool, 7752da9a59SGnoCiYeH 7852da9a59SGnoCiYeH // 字符 7952da9a59SGnoCiYeH pub hi_font_mask: u16, 8052da9a59SGnoCiYeH pub font: ConsoleFont, 8152da9a59SGnoCiYeH 8252da9a59SGnoCiYeH pub erase_char: u16, 8352da9a59SGnoCiYeH 8452da9a59SGnoCiYeH pub complement_mask: u16, 8552da9a59SGnoCiYeH pub s_complement_mask: u16, 8652da9a59SGnoCiYeH 8752da9a59SGnoCiYeH pub cursor_blink_ms: u16, 8852da9a59SGnoCiYeH 8952da9a59SGnoCiYeH pub pid: Option<Pid>, 9052da9a59SGnoCiYeH pub index: usize, 9152da9a59SGnoCiYeH 9252da9a59SGnoCiYeH pub vc_state: VirtualConsoleState, 9352da9a59SGnoCiYeH 9452da9a59SGnoCiYeH // 一些标志 9552da9a59SGnoCiYeH /// 指示是否显示 ASCII 字符小于 32 的控制字符(vc_disp_ctrl) 9652da9a59SGnoCiYeH pub display_ctrl: bool, 9752da9a59SGnoCiYeH /// 指示是否切换高位(meta)位。Meta 键是一个特殊的按键,用于扩展字符集。 9852da9a59SGnoCiYeH pub toggle_meta: bool, 9952da9a59SGnoCiYeH /// 表示屏幕模式(vc_decscnm) 10052da9a59SGnoCiYeH pub screen_mode: bool, 10152da9a59SGnoCiYeH /// 指定光标移动的起始位置,是相对于屏幕的左上角还是相对于当前页的左上角(vc_decom) 10252da9a59SGnoCiYeH pub origin_mode: bool, 10352da9a59SGnoCiYeH /// 控制光标到达行末时是否自动换行(vc_decawm) 10452da9a59SGnoCiYeH pub autowrap: bool, 10552da9a59SGnoCiYeH /// 控制光标的可见性(vc_deccm) 10652da9a59SGnoCiYeH pub cursor_visible: bool, 10752da9a59SGnoCiYeH /// 光标相关 10852da9a59SGnoCiYeH pub cursor_type: VcCursor, 10952da9a59SGnoCiYeH /// 控制插入或替换模式(vc_decim) 11052da9a59SGnoCiYeH pub insert_mode: bool, 11152da9a59SGnoCiYeH /// 表示一些私有模式或状态,通常由特定终端实现定义(vc_priv) 11252da9a59SGnoCiYeH pub private: Vt102_OP, 11352da9a59SGnoCiYeH /// 是否需要进行自动换行 11452da9a59SGnoCiYeH pub need_wrap: bool, 11552da9a59SGnoCiYeH /// 控制鼠标事件的报告方式 11652da9a59SGnoCiYeH pub report_mouse: u8, 11752da9a59SGnoCiYeH /// 指示终端是否使用 UTF-8 编码 11852da9a59SGnoCiYeH pub utf: bool, 11952da9a59SGnoCiYeH /// UTF-8 编码的字符计数,表示还需要多少个字节才能够构建完成 12052da9a59SGnoCiYeH pub utf_count: u8, 12152da9a59SGnoCiYeH /// UTF-8 编码的字符,表示正在构建的utf字符 12252da9a59SGnoCiYeH pub utf_char: u32, 12352da9a59SGnoCiYeH /// 构建utf时需要的参数,表示目前接收了多少个字节的数据来构建utf字符 12452da9a59SGnoCiYeH pub npar: u32, 12552da9a59SGnoCiYeH /// 12652da9a59SGnoCiYeH pub par: [u32; NPAR], 12752da9a59SGnoCiYeH 12852da9a59SGnoCiYeH /// 字符转换表 用于将输入字符映射到特定的字符 12952da9a59SGnoCiYeH pub translate: TranslationMap, 13052da9a59SGnoCiYeH 13152da9a59SGnoCiYeH pub tab_stop: StaticBitmap<256>, 13252da9a59SGnoCiYeH 13352da9a59SGnoCiYeH pub attr: u8, 13452da9a59SGnoCiYeH 13552da9a59SGnoCiYeH /// vc缓冲区 13652da9a59SGnoCiYeH pub screen_buf: Vec<u16>, 13752da9a59SGnoCiYeH 13852da9a59SGnoCiYeH /// 对应的Console Driver funcs 13952da9a59SGnoCiYeH driver_funcs: Option<Weak<dyn ConsoleSwitch>>, 14052da9a59SGnoCiYeH } 14152da9a59SGnoCiYeH 14252da9a59SGnoCiYeH impl VirtualConsoleData { 14352da9a59SGnoCiYeH pub fn new(num: usize) -> Self { 14452da9a59SGnoCiYeH Self { 14552da9a59SGnoCiYeH state: VirtualConsoleInfo::new(0, 0), 14652da9a59SGnoCiYeH saved_state: Default::default(), 14752da9a59SGnoCiYeH cols: Default::default(), 14852da9a59SGnoCiYeH rows: Default::default(), 14952da9a59SGnoCiYeH // bytes_per_row: Default::default(), 15052da9a59SGnoCiYeH scan_lines: Default::default(), 15152da9a59SGnoCiYeH cell_height: Default::default(), 15252da9a59SGnoCiYeH // origin: Default::default(), 15352da9a59SGnoCiYeH // scr_end: Default::default(), 15452da9a59SGnoCiYeH visible_origin: Default::default(), 15552da9a59SGnoCiYeH top: Default::default(), 15652da9a59SGnoCiYeH bottom: Default::default(), 15752da9a59SGnoCiYeH palette: [Default::default(); 16], 15852da9a59SGnoCiYeH def_color: Default::default(), 15952da9a59SGnoCiYeH underline_color: Default::default(), 16052da9a59SGnoCiYeH italic_color: Default::default(), 16152da9a59SGnoCiYeH half_color: Default::default(), 16252da9a59SGnoCiYeH mode: Default::default(), 16352da9a59SGnoCiYeH color_mode: Default::default(), 16452da9a59SGnoCiYeH hi_font_mask: Default::default(), 16552da9a59SGnoCiYeH erase_char: Default::default(), 16652da9a59SGnoCiYeH complement_mask: Default::default(), 16752da9a59SGnoCiYeH s_complement_mask: Default::default(), 16852da9a59SGnoCiYeH cursor_blink_ms: 200, 16952da9a59SGnoCiYeH pos: Default::default(), 17052da9a59SGnoCiYeH vt_mode: VtModeData { 17152da9a59SGnoCiYeH mode: VtMode::Auto, 17252da9a59SGnoCiYeH relsig: 0, 17352da9a59SGnoCiYeH acqsig: 0, 17452da9a59SGnoCiYeH }, 17552da9a59SGnoCiYeH pid: None, 17652da9a59SGnoCiYeH index: 0, 17752da9a59SGnoCiYeH font: Default::default(), 17852da9a59SGnoCiYeH vc_state: VirtualConsoleState::ESnormal, 17952da9a59SGnoCiYeH display_ctrl: Default::default(), 18052da9a59SGnoCiYeH toggle_meta: Default::default(), 18152da9a59SGnoCiYeH screen_mode: Default::default(), 18252da9a59SGnoCiYeH origin_mode: Default::default(), 18352da9a59SGnoCiYeH autowrap: Default::default(), 18452da9a59SGnoCiYeH cursor_visible: Default::default(), 18552da9a59SGnoCiYeH insert_mode: Default::default(), 18652da9a59SGnoCiYeH private: Vt102_OP::EPecma, 18752da9a59SGnoCiYeH need_wrap: Default::default(), 18852da9a59SGnoCiYeH report_mouse: Default::default(), 18952da9a59SGnoCiYeH utf: Default::default(), 19052da9a59SGnoCiYeH utf_count: Default::default(), 19152da9a59SGnoCiYeH utf_char: Default::default(), 19252da9a59SGnoCiYeH translate: TranslationMap::new(TranslationMapType::Lat1Map), 19352da9a59SGnoCiYeH npar: Default::default(), 19452da9a59SGnoCiYeH tab_stop: StaticBitmap::new(), 19552da9a59SGnoCiYeH par: [0; 16], 19652da9a59SGnoCiYeH attr: Default::default(), 19752da9a59SGnoCiYeH screen_buf: Default::default(), 19852da9a59SGnoCiYeH driver_funcs: None, 19952da9a59SGnoCiYeH cursor_type: VcCursor::empty(), 20052da9a59SGnoCiYeH num, 20152da9a59SGnoCiYeH } 20252da9a59SGnoCiYeH } 20352da9a59SGnoCiYeH 20452da9a59SGnoCiYeH pub(super) fn init(&mut self, rows: Option<usize>, cols: Option<usize>, clear: bool) { 20552da9a59SGnoCiYeH if rows.is_some() { 20652da9a59SGnoCiYeH self.rows = rows.unwrap(); 20752da9a59SGnoCiYeH } 20852da9a59SGnoCiYeH if cols.is_some() { 20952da9a59SGnoCiYeH self.cols = cols.unwrap(); 21052da9a59SGnoCiYeH } 21152da9a59SGnoCiYeH 21252da9a59SGnoCiYeH self.pos = self.cols * self.state.y + self.state.x; 21352da9a59SGnoCiYeH // self.bytes_per_row = self.cols << 1; 21452da9a59SGnoCiYeH 21552da9a59SGnoCiYeH self.def_color = 15; // white 21652da9a59SGnoCiYeH self.italic_color = 2; // green 21752da9a59SGnoCiYeH self.underline_color = 3; // cyan 21852da9a59SGnoCiYeH self.half_color = 0x08; // grey 21952da9a59SGnoCiYeH 22052da9a59SGnoCiYeH self.reset(clear); 22152da9a59SGnoCiYeH 22252da9a59SGnoCiYeH self.screen_buf.resize(self.cols * self.rows, 0); 22352da9a59SGnoCiYeH } 22452da9a59SGnoCiYeH 22552da9a59SGnoCiYeH pub fn should_update(&self) -> bool { 22652da9a59SGnoCiYeH self.is_visible() && !CONSOLE_BLANKED.load(Ordering::SeqCst) 22752da9a59SGnoCiYeH } 22852da9a59SGnoCiYeH 22952da9a59SGnoCiYeH pub fn is_visible(&self) -> bool { 23052da9a59SGnoCiYeH let cur_vc = CURRENT_VCNUM.load(Ordering::SeqCst); 23152da9a59SGnoCiYeH if cur_vc == -1 { 23252da9a59SGnoCiYeH return false; 23352da9a59SGnoCiYeH } 23452da9a59SGnoCiYeH 23552da9a59SGnoCiYeH cur_vc as usize == self.num 23652da9a59SGnoCiYeH } 23752da9a59SGnoCiYeH 23852da9a59SGnoCiYeH fn driver_funcs(&self) -> Arc<dyn ConsoleSwitch> { 23952da9a59SGnoCiYeH self.driver_funcs.as_ref().unwrap().upgrade().unwrap() 24052da9a59SGnoCiYeH } 24152da9a59SGnoCiYeH 24252da9a59SGnoCiYeH pub(super) fn set_driver_funcs(&mut self, func: Weak<dyn ConsoleSwitch>) { 24352da9a59SGnoCiYeH self.driver_funcs = Some(func); 24452da9a59SGnoCiYeH } 24552da9a59SGnoCiYeH 24652da9a59SGnoCiYeH pub(super) fn reset(&mut self, do_clear: bool) { 24752da9a59SGnoCiYeH self.mode = KDMode::KdText; 24852da9a59SGnoCiYeH // unicode? 24952da9a59SGnoCiYeH self.vt_mode.mode = VtMode::Auto; 25052da9a59SGnoCiYeH self.vt_mode.acqsig = 0; 25152da9a59SGnoCiYeH self.vt_mode.relsig = 0; 25252da9a59SGnoCiYeH self.display_ctrl = false; 25352da9a59SGnoCiYeH self.toggle_meta = false; 25452da9a59SGnoCiYeH self.screen_mode = false; 25552da9a59SGnoCiYeH self.origin_mode = false; 25652da9a59SGnoCiYeH self.autowrap = true; 25752da9a59SGnoCiYeH self.cursor_visible = true; 25852da9a59SGnoCiYeH self.insert_mode = false; 25952da9a59SGnoCiYeH self.need_wrap = false; 26052da9a59SGnoCiYeH self.report_mouse = 0; 26152da9a59SGnoCiYeH self.utf_count = 0; 26252da9a59SGnoCiYeH self.translate = TranslationMap::new(TranslationMapType::Lat1Map); 26352da9a59SGnoCiYeH self.utf = true; 26452da9a59SGnoCiYeH self.pid = None; 26552da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 26652da9a59SGnoCiYeH self.reset_palette(); 26752da9a59SGnoCiYeH self.cursor_type = VcCursor::CUR_UNDERLINE; 26852da9a59SGnoCiYeH 26952da9a59SGnoCiYeH self.default_attr(); 27052da9a59SGnoCiYeH self.update_attr(); 27152da9a59SGnoCiYeH 27252da9a59SGnoCiYeH self.tab_stop.set_all(false); 27352da9a59SGnoCiYeH 27452da9a59SGnoCiYeH for i in (0..256).step_by(8) { 27552da9a59SGnoCiYeH self.tab_stop.set(i, true); 27652da9a59SGnoCiYeH } 27752da9a59SGnoCiYeH 27852da9a59SGnoCiYeH self.state.x = 0; 27952da9a59SGnoCiYeH self.state.y = 0; 28052da9a59SGnoCiYeH self.pos = 0; 28152da9a59SGnoCiYeH 28252da9a59SGnoCiYeH if do_clear { 28352da9a59SGnoCiYeH self.csi_J(2); 28452da9a59SGnoCiYeH } 28552da9a59SGnoCiYeH } 28652da9a59SGnoCiYeH 28752da9a59SGnoCiYeH fn reset_palette(&mut self) { 28852da9a59SGnoCiYeH for (idx, color) in self.palette.iter_mut().enumerate() { 28952da9a59SGnoCiYeH color.red = DEFAULT_RED[idx]; 29052da9a59SGnoCiYeH color.green = DEFAULT_GREEN[idx]; 29152da9a59SGnoCiYeH color.blue = DEFAULT_BLUE[idx]; 29252da9a59SGnoCiYeH } 29352da9a59SGnoCiYeH 29452da9a59SGnoCiYeH self.set_palette(); 29552da9a59SGnoCiYeH } 29652da9a59SGnoCiYeH 29752da9a59SGnoCiYeH fn set_palette(&self) { 29852da9a59SGnoCiYeH if self.mode != KDMode::KdGraphics { 29952da9a59SGnoCiYeH // todo: 通知driver层的Console 30052da9a59SGnoCiYeH let _ = self.driver_funcs().con_set_palette(self, COLOR_TABLE); 30152da9a59SGnoCiYeH } 30252da9a59SGnoCiYeH } 30352da9a59SGnoCiYeH 30452da9a59SGnoCiYeH /// ## 翻译字符,将字符转换为终端控制符 30552da9a59SGnoCiYeH /// ### 参数 30652da9a59SGnoCiYeH /// 30752da9a59SGnoCiYeH /// ### c: 需要转换的字符 30852da9a59SGnoCiYeH /// 30952da9a59SGnoCiYeH /// ### 返回值 31052da9a59SGnoCiYeH /// ### (转换后的字符:i32,是否需要更多的数据才能进行转换:bool) 31152da9a59SGnoCiYeH pub(super) fn translate(&mut self, c: &mut u32) -> (Option<u32>, bool) { 31252da9a59SGnoCiYeH if self.vc_state != VirtualConsoleState::ESnormal { 31352da9a59SGnoCiYeH // 在控制字符状态下不需要翻译 31452da9a59SGnoCiYeH return (Some(*c), false); 31552da9a59SGnoCiYeH } 31652da9a59SGnoCiYeH if self.utf && !self.display_ctrl { 31752da9a59SGnoCiYeH // utf模式并且不显示控制字符 31852da9a59SGnoCiYeH let (ret, rescan) = self.translate_unicode(*c); 31952da9a59SGnoCiYeH if ret.is_some() { 32052da9a59SGnoCiYeH *c = ret.unwrap(); 32152da9a59SGnoCiYeH } 32252da9a59SGnoCiYeH return (ret, rescan); 32352da9a59SGnoCiYeH } 32452da9a59SGnoCiYeH 32552da9a59SGnoCiYeH return (Some(self.translate_ascii(*c)), false); 32652da9a59SGnoCiYeH } 32752da9a59SGnoCiYeH 32852da9a59SGnoCiYeH /// 该数组包含每个字节序列长度变化的阈值 32952da9a59SGnoCiYeH /// 即如果由两个字节组成的unicode字符,则长度应该在UTF8_LENGTH_CHANGES[0] ~ UTF8_LENGTH_CHANGES[1]之间 33052da9a59SGnoCiYeH const UTF8_LENGTH_CHANGES: &'static [u32] = &[ 33152da9a59SGnoCiYeH 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff, 33252da9a59SGnoCiYeH ]; 33352da9a59SGnoCiYeH 33452da9a59SGnoCiYeH /// ## 翻译字符,将UTF-8 编码的字符转换为 Unicode 编码 33552da9a59SGnoCiYeH /// ### 参数 33652da9a59SGnoCiYeH /// 33752da9a59SGnoCiYeH /// ### c: 需要转换的字符 33852da9a59SGnoCiYeH /// 33952da9a59SGnoCiYeH /// ### 返回值 34052da9a59SGnoCiYeH /// ### (转换后的字符:i32,是否需要重新传入该字符:bool) 34152da9a59SGnoCiYeH /// 34252da9a59SGnoCiYeH /// !!! 注意,该函数返回true时,元组的第一个数据是无效数据(未转换完成) 34352da9a59SGnoCiYeH fn translate_unicode(&mut self, c: u32) -> (Option<u32>, bool) { 34452da9a59SGnoCiYeH // 收到的字符不是首个 34552da9a59SGnoCiYeH if (c & 0xc8) == 0x80 { 34652da9a59SGnoCiYeH // 已经不需要继续的字符了,说明这个字符是非法的 34752da9a59SGnoCiYeH if self.utf_count == 0 { 34852da9a59SGnoCiYeH return (Some(0xfffd), false); 34952da9a59SGnoCiYeH } 35052da9a59SGnoCiYeH 35152da9a59SGnoCiYeH self.utf_char = (self.utf_char << 6) | (c & 0x3f); 35252da9a59SGnoCiYeH self.npar += 1; 35352da9a59SGnoCiYeH 35452da9a59SGnoCiYeH self.utf_count -= 1; 35552da9a59SGnoCiYeH if self.utf_count > 0 { 35652da9a59SGnoCiYeH // 表示需要更多字节 35752da9a59SGnoCiYeH return (None, false); 35852da9a59SGnoCiYeH } 35952da9a59SGnoCiYeH 36052da9a59SGnoCiYeH let c = self.utf_char; 36152da9a59SGnoCiYeH 36252da9a59SGnoCiYeH // 先检查一遍是否合格 36352da9a59SGnoCiYeH if c <= Self::UTF8_LENGTH_CHANGES[self.npar as usize - 1] 36452da9a59SGnoCiYeH || c > Self::UTF8_LENGTH_CHANGES[self.npar as usize] 36552da9a59SGnoCiYeH { 36652da9a59SGnoCiYeH return (Some(0xfffd), false); 36752da9a59SGnoCiYeH } 36852da9a59SGnoCiYeH 36952da9a59SGnoCiYeH return (Some(Self::sanitize_unicode(c)), false); 37052da9a59SGnoCiYeH } 37152da9a59SGnoCiYeH 37252da9a59SGnoCiYeH // 接收到单个ASCII字符或者一个序列的首字符,且上次的未处理完,则上一个字符视为无效,则需要重新传入该字符处理 37352da9a59SGnoCiYeH if self.utf_count > 0 { 37452da9a59SGnoCiYeH self.utf_count = 0; 37552da9a59SGnoCiYeH return (Some(0xfffd), true); 37652da9a59SGnoCiYeH } 37752da9a59SGnoCiYeH 37852da9a59SGnoCiYeH // ascii 37952da9a59SGnoCiYeH if c <= 0x7f { 38052da9a59SGnoCiYeH return (Some(c), false); 38152da9a59SGnoCiYeH } 38252da9a59SGnoCiYeH 38352da9a59SGnoCiYeH // 第一个字节 38452da9a59SGnoCiYeH self.npar = 0; 38552da9a59SGnoCiYeH if (c & 0xe0) == 0xc0 { 38652da9a59SGnoCiYeH self.utf_count = 1; 38752da9a59SGnoCiYeH self.utf_char = c & 0x1f; 38852da9a59SGnoCiYeH } else if (c & 0xf0) == 0xe0 { 38952da9a59SGnoCiYeH self.utf_count = 2; 39052da9a59SGnoCiYeH self.utf_char = c & 0x0f; 39152da9a59SGnoCiYeH } else if (c & 0xf8) == 0xf0 { 39252da9a59SGnoCiYeH self.utf_count = 3; 39352da9a59SGnoCiYeH self.utf_char = c & 0x07; 39452da9a59SGnoCiYeH } else if (c & 0xfc) == 0xf8 { 39552da9a59SGnoCiYeH self.utf_count = 4; 39652da9a59SGnoCiYeH self.utf_char = c & 0x03; 39752da9a59SGnoCiYeH } else if (c & 0xfe) == 0xfc { 39852da9a59SGnoCiYeH self.utf_count = 5; 39952da9a59SGnoCiYeH self.utf_char = c & 0x01; 40052da9a59SGnoCiYeH } else { 40152da9a59SGnoCiYeH /* 254 and 255 are invalid */ 40252da9a59SGnoCiYeH return (Some(0xfffd), false); 40352da9a59SGnoCiYeH } 40452da9a59SGnoCiYeH 40552da9a59SGnoCiYeH (None, false) 40652da9a59SGnoCiYeH } 40752da9a59SGnoCiYeH 40852da9a59SGnoCiYeH /// ## 翻译字符,将字符转换为Ascii 40952da9a59SGnoCiYeH fn translate_ascii(&self, c: u32) -> u32 { 41052da9a59SGnoCiYeH let mut c = c; 41152da9a59SGnoCiYeH if self.toggle_meta { 41252da9a59SGnoCiYeH c |= 0x80; 41352da9a59SGnoCiYeH } 41452da9a59SGnoCiYeH 41552da9a59SGnoCiYeH return self.translate.translate(c) as u32; 41652da9a59SGnoCiYeH } 41752da9a59SGnoCiYeH 41852da9a59SGnoCiYeH /// ## 用于替换无效的 Unicode 代码点(code points)。 41952da9a59SGnoCiYeH /// Unicode 代码点的范围是从 U+0000 到 U+10FFFF, 42052da9a59SGnoCiYeH /// 但是有一些特殊的代码点是无效的或者保留给特定用途的。 42152da9a59SGnoCiYeH /// 这个函数的主要目的是将无效的 Unicode 代码点替换为 U+FFFD,即 Unicode 替代字符。 42252da9a59SGnoCiYeH fn sanitize_unicode(c: u32) -> u32 { 42352da9a59SGnoCiYeH if (c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff { 42452da9a59SGnoCiYeH return 0xfffd; 42552da9a59SGnoCiYeH } 42652da9a59SGnoCiYeH return c; 42752da9a59SGnoCiYeH } 42852da9a59SGnoCiYeH 42952da9a59SGnoCiYeH /// 用于表示小于 32 的字符中,哪些字符对应的位被设置为 1, 43052da9a59SGnoCiYeH /// 表示这些字符会触发一些特殊的动作,比如光标移动等。 43152da9a59SGnoCiYeH /// 这些字符在 disp_ctrl 模式未开启时不应该被显示为图形符号 43252da9a59SGnoCiYeH const CTRL_ACTION: u32 = 0x0d00ff81; 43352da9a59SGnoCiYeH /// 用于表示哪些控制字符是始终显示的,即便 disp_ctrl 模式未开启。 43452da9a59SGnoCiYeH /// 这些字符对于终端来说是必要的,显示它们是为了保证终端正常工作。 43552da9a59SGnoCiYeH /// 这些字符在 disp_ctrl 模式开启或关闭时都应该显示为控制字符。 43652da9a59SGnoCiYeH const CTRL_ALWAYS: u32 = 0x0800f501; 43752da9a59SGnoCiYeH 43852da9a59SGnoCiYeH /// ## 用于判断tc(终端字符)在当前VC下是不是需要显示的控制字符 43952da9a59SGnoCiYeH pub(super) fn is_control(&self, tc: u32, c: u32) -> bool { 44052da9a59SGnoCiYeH // 当前vc状态机不在正常状态,即在接收特殊字符的状态,则是控制字符 44152da9a59SGnoCiYeH if self.vc_state != VirtualConsoleState::ESnormal { 44252da9a59SGnoCiYeH return true; 44352da9a59SGnoCiYeH } 44452da9a59SGnoCiYeH 44552da9a59SGnoCiYeH if tc == 0 { 44652da9a59SGnoCiYeH return true; 44752da9a59SGnoCiYeH } 44852da9a59SGnoCiYeH 44952da9a59SGnoCiYeH if c < 32 { 45052da9a59SGnoCiYeH if self.display_ctrl { 45152da9a59SGnoCiYeH // 查看在位图中是否有该字符 45252da9a59SGnoCiYeH return Self::CTRL_ALWAYS & (1 << c) != 0; 45352da9a59SGnoCiYeH } else { 45452da9a59SGnoCiYeH return self.utf || (Self::CTRL_ACTION & (1 << c) != 0); 45552da9a59SGnoCiYeH } 45652da9a59SGnoCiYeH } 45752da9a59SGnoCiYeH 45852da9a59SGnoCiYeH if c == 127 && !self.display_ctrl { 45952da9a59SGnoCiYeH return true; 46052da9a59SGnoCiYeH } 46152da9a59SGnoCiYeH 46252da9a59SGnoCiYeH if c == 128 + 27 { 46352da9a59SGnoCiYeH return true; 46452da9a59SGnoCiYeH } 46552da9a59SGnoCiYeH 46652da9a59SGnoCiYeH false 46752da9a59SGnoCiYeH } 46852da9a59SGnoCiYeH 46952da9a59SGnoCiYeH pub(super) fn set_cursor(&mut self) { 47052da9a59SGnoCiYeH if self.mode == KDMode::KdGraphics { 47152da9a59SGnoCiYeH return; 47252da9a59SGnoCiYeH } 47352da9a59SGnoCiYeH 47452da9a59SGnoCiYeH if self.cursor_visible { 47552da9a59SGnoCiYeH // TODO: 处理选择 47652da9a59SGnoCiYeH self.add_softcursor(); 47752da9a59SGnoCiYeH if self.cursor_type.cursor_size() != VcCursor::CUR_NONE { 47852da9a59SGnoCiYeH self.driver_funcs().con_cursor(self, CursorOperation::Draw); 47952da9a59SGnoCiYeH } 48052da9a59SGnoCiYeH } else { 48152da9a59SGnoCiYeH self.hide_cursor(); 48252da9a59SGnoCiYeH } 48352da9a59SGnoCiYeH } 48452da9a59SGnoCiYeH 48552da9a59SGnoCiYeH /// ## 添加软光标 48652da9a59SGnoCiYeH fn add_softcursor(&mut self) { 48752da9a59SGnoCiYeH let mut i = self.screen_buf[self.pos] as u32; 48852da9a59SGnoCiYeH let cursor_type = self.cursor_type; 48952da9a59SGnoCiYeH 49052da9a59SGnoCiYeH if !cursor_type.contains(VcCursor::CUR_SW) { 49152da9a59SGnoCiYeH return; 49252da9a59SGnoCiYeH } 49352da9a59SGnoCiYeH 49452da9a59SGnoCiYeH if SOFTCURSOR_ORIGINAL.read_irqsave().is_some() { 49552da9a59SGnoCiYeH // 已经设置了软光标 49652da9a59SGnoCiYeH return; 49752da9a59SGnoCiYeH } 49852da9a59SGnoCiYeH 49952da9a59SGnoCiYeH let mut soft_cursor_guard = SOFTCURSOR_ORIGINAL.write_irqsave(); 50052da9a59SGnoCiYeH *soft_cursor_guard = Some(unsafe { VcCursor::from_bits_unchecked(i as u32) }); 50152da9a59SGnoCiYeH 50252da9a59SGnoCiYeH let soft_cursor = soft_cursor_guard.unwrap(); 50352da9a59SGnoCiYeH 50452da9a59SGnoCiYeH i |= cursor_type.cursor_set(); 50552da9a59SGnoCiYeH i ^= cursor_type.cursor_change(); 50652da9a59SGnoCiYeH if cursor_type.contains(VcCursor::CUR_ALWAYS_BG) 50752da9a59SGnoCiYeH && ((soft_cursor.bits & VcCursor::CUR_BG.bits) == (i & VcCursor::CUR_BG.bits)) 50852da9a59SGnoCiYeH { 50952da9a59SGnoCiYeH i ^= VcCursor::CUR_BG.bits; 51052da9a59SGnoCiYeH } 51152da9a59SGnoCiYeH if cursor_type.contains(VcCursor::CUR_INVERT_FG_BG) 51252da9a59SGnoCiYeH && ((i & VcCursor::CUR_FG.bits) == ((i & VcCursor::CUR_BG.bits) >> 4)) 51352da9a59SGnoCiYeH { 51452da9a59SGnoCiYeH i ^= VcCursor::CUR_FG.bits; 51552da9a59SGnoCiYeH } 51652da9a59SGnoCiYeH 51752da9a59SGnoCiYeH self.screen_buf[self.pos] = i as u16; 51852da9a59SGnoCiYeH 51952da9a59SGnoCiYeH let _ = 52052da9a59SGnoCiYeH self.driver_funcs() 52152da9a59SGnoCiYeH .con_putc(&self, i as u16, self.state.y as u32, self.state.x as u32); 52252da9a59SGnoCiYeH } 52352da9a59SGnoCiYeH 52452da9a59SGnoCiYeH pub fn hide_cursor(&mut self) { 52552da9a59SGnoCiYeH // TODO: 处理选择 52652da9a59SGnoCiYeH 52752da9a59SGnoCiYeH self.driver_funcs().con_cursor(self, CursorOperation::Erase); 52852da9a59SGnoCiYeH self.hide_softcursor(); 52952da9a59SGnoCiYeH } 53052da9a59SGnoCiYeH 53152da9a59SGnoCiYeH fn hide_softcursor(&mut self) { 53252da9a59SGnoCiYeH let softcursor = SOFTCURSOR_ORIGINAL.upgradeable_read_irqsave(); 53352da9a59SGnoCiYeH if softcursor.is_some() { 53452da9a59SGnoCiYeH self.screen_buf[self.pos] = softcursor.unwrap().bits as u16; 53552da9a59SGnoCiYeH let _ = self.driver_funcs().con_putc( 53652da9a59SGnoCiYeH &self, 53752da9a59SGnoCiYeH softcursor.unwrap().bits as u16, 53852da9a59SGnoCiYeH self.state.y as u32, 53952da9a59SGnoCiYeH self.state.x as u32, 54052da9a59SGnoCiYeH ); 54152da9a59SGnoCiYeH 54252da9a59SGnoCiYeH *softcursor.upgrade() = None; 54352da9a59SGnoCiYeH } 54452da9a59SGnoCiYeH } 54552da9a59SGnoCiYeH 54652da9a59SGnoCiYeH fn gotoxay(&mut self, x: i32, y: i32) { 54752da9a59SGnoCiYeH if self.origin_mode { 54852da9a59SGnoCiYeH self.gotoxy(x, self.top as i32 + y); 54952da9a59SGnoCiYeH } else { 55052da9a59SGnoCiYeH self.gotoxy(x, y) 55152da9a59SGnoCiYeH } 55252da9a59SGnoCiYeH } 55352da9a59SGnoCiYeH 55452da9a59SGnoCiYeH // ## 将当前vc的光标移动到目标位置 55552da9a59SGnoCiYeH fn gotoxy(&mut self, x: i32, y: i32) { 55652da9a59SGnoCiYeH if x < 0 { 55752da9a59SGnoCiYeH self.state.x = 0; 55852da9a59SGnoCiYeH } else { 55952da9a59SGnoCiYeH if x as usize >= self.cols { 56052da9a59SGnoCiYeH self.state.x = self.cols - 1; 56152da9a59SGnoCiYeH } else { 56252da9a59SGnoCiYeH self.state.x = x as usize; 56352da9a59SGnoCiYeH } 56452da9a59SGnoCiYeH } 56552da9a59SGnoCiYeH 56652da9a59SGnoCiYeH let max_y; 56752da9a59SGnoCiYeH let min_y; 56852da9a59SGnoCiYeH if self.origin_mode { 56952da9a59SGnoCiYeH min_y = self.top; 57052da9a59SGnoCiYeH max_y = self.bottom; 57152da9a59SGnoCiYeH } else { 57252da9a59SGnoCiYeH min_y = 0; 57352da9a59SGnoCiYeH max_y = self.rows; 57452da9a59SGnoCiYeH } 57552da9a59SGnoCiYeH 57652da9a59SGnoCiYeH if y < min_y as i32 { 57752da9a59SGnoCiYeH self.state.y = min_y as usize; 57852da9a59SGnoCiYeH } else if y >= max_y as i32 { 57952da9a59SGnoCiYeH self.state.y = max_y as usize; 58052da9a59SGnoCiYeH } else { 58152da9a59SGnoCiYeH self.state.y = y as usize; 58252da9a59SGnoCiYeH } 58352da9a59SGnoCiYeH 584*be60c929SGnoCiYeH self.pos = self.state.y * self.cols + self.state.x; 58552da9a59SGnoCiYeH self.need_wrap = false; 58652da9a59SGnoCiYeH } 58752da9a59SGnoCiYeH 58852da9a59SGnoCiYeH fn scroll(&mut self, dir: ScrollDir, mut nr: usize) { 58952da9a59SGnoCiYeH // todo: uniscr_srceen 59052da9a59SGnoCiYeH if self.top + nr >= self.bottom { 59152da9a59SGnoCiYeH // 滚动超过一页,则按一页计算 59252da9a59SGnoCiYeH nr = self.bottom - self.top - 1; 59352da9a59SGnoCiYeH } 59452da9a59SGnoCiYeH 59552da9a59SGnoCiYeH if nr < 1 { 59652da9a59SGnoCiYeH return; 59752da9a59SGnoCiYeH } 59852da9a59SGnoCiYeH 59952da9a59SGnoCiYeH if self 60052da9a59SGnoCiYeH .driver_funcs() 60152da9a59SGnoCiYeH .con_scroll(self, self.top, self.bottom, dir, nr) 60252da9a59SGnoCiYeH { 60352da9a59SGnoCiYeH // 如果成功 60452da9a59SGnoCiYeH return; 60552da9a59SGnoCiYeH } 60652da9a59SGnoCiYeH 60752da9a59SGnoCiYeH // 调整screen_buf 60852da9a59SGnoCiYeH let count = nr * self.cols; 60952da9a59SGnoCiYeH if dir == ScrollDir::Up { 61052da9a59SGnoCiYeH for i in self.screen_buf[0..count].iter_mut() { 61152da9a59SGnoCiYeH *i = self.erase_char; 61252da9a59SGnoCiYeH } 61352da9a59SGnoCiYeH self.screen_buf.rotate_left(count); 61452da9a59SGnoCiYeH } else if dir == ScrollDir::Down { 61552da9a59SGnoCiYeH todo!(); 61652da9a59SGnoCiYeH } 61752da9a59SGnoCiYeH } 61852da9a59SGnoCiYeH 61952da9a59SGnoCiYeH /// ## 退格 62052da9a59SGnoCiYeH fn backspace(&mut self) { 62152da9a59SGnoCiYeH if self.state.x > 0 { 62252da9a59SGnoCiYeH self.pos -= 1; 62352da9a59SGnoCiYeH self.state.x -= 1; 62452da9a59SGnoCiYeH self.need_wrap = false; 62552da9a59SGnoCiYeH 62652da9a59SGnoCiYeH // TODO: notify 62752da9a59SGnoCiYeH } 62852da9a59SGnoCiYeH } 62952da9a59SGnoCiYeH 63052da9a59SGnoCiYeH /// ## 换行 63152da9a59SGnoCiYeH fn line_feed(&mut self) { 63252da9a59SGnoCiYeH if self.state.y + 1 == self.bottom as usize { 63352da9a59SGnoCiYeH self.scroll(ScrollDir::Up, 1); 63452da9a59SGnoCiYeH } else if self.state.y < self.rows - 1 { 63552da9a59SGnoCiYeH self.state.y += 1; 63652da9a59SGnoCiYeH self.pos += self.cols; 63752da9a59SGnoCiYeH } 63852da9a59SGnoCiYeH 63952da9a59SGnoCiYeH self.need_wrap = false; 64052da9a59SGnoCiYeH // TODO: Notify write 64152da9a59SGnoCiYeH } 64252da9a59SGnoCiYeH 64352da9a59SGnoCiYeH /// ## 回车 64452da9a59SGnoCiYeH fn carriage_return(&mut self) { 64552da9a59SGnoCiYeH // 写入位置回退到该行最前 64652da9a59SGnoCiYeH self.pos -= self.state.x; 64752da9a59SGnoCiYeH self.need_wrap = false; 64852da9a59SGnoCiYeH self.state.x = 0; 64952da9a59SGnoCiYeH } 65052da9a59SGnoCiYeH 65152da9a59SGnoCiYeH /// ## Del 65252da9a59SGnoCiYeH fn delete(&mut self) { 65352da9a59SGnoCiYeH // ignore 65452da9a59SGnoCiYeH } 65552da9a59SGnoCiYeH 65652da9a59SGnoCiYeH /// ## 向上滚动虚拟终端的内容,或者将光标上移一行 65752da9a59SGnoCiYeH fn reverse_index(&mut self) { 65852da9a59SGnoCiYeH if self.state.y == self.top as usize { 65952da9a59SGnoCiYeH self.scroll(ScrollDir::Down, 1); 66052da9a59SGnoCiYeH } else if self.state.y > 0 { 66152da9a59SGnoCiYeH self.state.y -= 1; 66252da9a59SGnoCiYeH self.pos -= self.cols; 66352da9a59SGnoCiYeH } 66452da9a59SGnoCiYeH self.need_wrap = false; 66552da9a59SGnoCiYeH } 66652da9a59SGnoCiYeH 66752da9a59SGnoCiYeH /// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/vt/vt.c#restore_cur 66852da9a59SGnoCiYeH fn restore_cursor(&mut self) { 66952da9a59SGnoCiYeH self.saved_state = self.state.clone(); 67052da9a59SGnoCiYeH 67152da9a59SGnoCiYeH self.gotoxy(self.state.x as i32, self.state.y as i32); 67252da9a59SGnoCiYeH 67352da9a59SGnoCiYeH // TODO Gx_charset 67452da9a59SGnoCiYeH 67552da9a59SGnoCiYeH self.update_attr(); 67652da9a59SGnoCiYeH self.need_wrap = false; 67752da9a59SGnoCiYeH todo!() 67852da9a59SGnoCiYeH } 67952da9a59SGnoCiYeH 68052da9a59SGnoCiYeH /// ## 设置当前vt的各项属性 68152da9a59SGnoCiYeH fn set_mode(&mut self, on_off: bool) { 68252da9a59SGnoCiYeH for i in 0..self.npar as usize { 68352da9a59SGnoCiYeH if self.private == Vt102_OP::EPdec { 68452da9a59SGnoCiYeH match self.par[i] { 68552da9a59SGnoCiYeH 1 => { 68652da9a59SGnoCiYeH todo!("kbd todo"); 68752da9a59SGnoCiYeH } 68852da9a59SGnoCiYeH 3 => { 68952da9a59SGnoCiYeH todo!("reisze todo"); 69052da9a59SGnoCiYeH } 69152da9a59SGnoCiYeH 5 => { 69252da9a59SGnoCiYeH todo!("invert_screen todo"); 69352da9a59SGnoCiYeH } 69452da9a59SGnoCiYeH 6 => { 69552da9a59SGnoCiYeH self.origin_mode = on_off; 69652da9a59SGnoCiYeH if on_off { 69752da9a59SGnoCiYeH self.gotoxy(0, self.top as i32); 69852da9a59SGnoCiYeH } else { 69952da9a59SGnoCiYeH self.gotoxy(0, 0); 70052da9a59SGnoCiYeH } 70152da9a59SGnoCiYeH } 70252da9a59SGnoCiYeH 7 => { 70352da9a59SGnoCiYeH self.autowrap = on_off; 70452da9a59SGnoCiYeH } 70552da9a59SGnoCiYeH 8 => { 70652da9a59SGnoCiYeH todo!("kbd todo"); 70752da9a59SGnoCiYeH } 70852da9a59SGnoCiYeH 9 => { 70952da9a59SGnoCiYeH todo!("report mouse todo"); 71052da9a59SGnoCiYeH } 71152da9a59SGnoCiYeH 25 => { 71252da9a59SGnoCiYeH self.cursor_visible = on_off; 71352da9a59SGnoCiYeH } 71452da9a59SGnoCiYeH 1000 => { 71552da9a59SGnoCiYeH todo!("report mouse todo"); 71652da9a59SGnoCiYeH } 71752da9a59SGnoCiYeH _ => {} 71852da9a59SGnoCiYeH } 71952da9a59SGnoCiYeH } else { 72052da9a59SGnoCiYeH match self.par[i] { 72152da9a59SGnoCiYeH 3 => { 72252da9a59SGnoCiYeH self.display_ctrl = on_off; 72352da9a59SGnoCiYeH } 72452da9a59SGnoCiYeH 4 => { 72552da9a59SGnoCiYeH self.insert_mode = on_off; 72652da9a59SGnoCiYeH } 72752da9a59SGnoCiYeH 20 => { 72852da9a59SGnoCiYeH todo!("kbd todo"); 72952da9a59SGnoCiYeH } 73052da9a59SGnoCiYeH _ => {} 73152da9a59SGnoCiYeH } 73252da9a59SGnoCiYeH } 73352da9a59SGnoCiYeH } 73452da9a59SGnoCiYeH } 73552da9a59SGnoCiYeH 73652da9a59SGnoCiYeH fn do_getpars(&mut self, c: char) { 73752da9a59SGnoCiYeH if c == ';' && self.npar < (NPAR - 1) as u32 { 73852da9a59SGnoCiYeH self.npar += 1; 73952da9a59SGnoCiYeH return; 74052da9a59SGnoCiYeH } 74152da9a59SGnoCiYeH 74252da9a59SGnoCiYeH if c >= '0' && c <= '9' { 74352da9a59SGnoCiYeH self.par[self.npar as usize] *= 10; 74452da9a59SGnoCiYeH self.par[self.npar as usize] += (c as u8 - '0' as u8) as u32; 74552da9a59SGnoCiYeH return; 74652da9a59SGnoCiYeH } 74752da9a59SGnoCiYeH 74852da9a59SGnoCiYeH if c as u8 >= 0x20 && c as u8 <= 0x3f { 74952da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::EScsiignore; 75052da9a59SGnoCiYeH return; 75152da9a59SGnoCiYeH } 75252da9a59SGnoCiYeH 75352da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 75452da9a59SGnoCiYeH 75552da9a59SGnoCiYeH match c { 75652da9a59SGnoCiYeH 'h' => { 75752da9a59SGnoCiYeH if self.private <= Vt102_OP::EPdec { 75852da9a59SGnoCiYeH self.set_mode(true); 75952da9a59SGnoCiYeH } 76052da9a59SGnoCiYeH return; 76152da9a59SGnoCiYeH } 76252da9a59SGnoCiYeH 'l' => { 76352da9a59SGnoCiYeH if self.private <= Vt102_OP::EPdec { 76452da9a59SGnoCiYeH self.set_mode(false); 76552da9a59SGnoCiYeH } 76652da9a59SGnoCiYeH return; 76752da9a59SGnoCiYeH } 76852da9a59SGnoCiYeH 'c' => { 76952da9a59SGnoCiYeH if self.private == Vt102_OP::EPdec { 77052da9a59SGnoCiYeH if self.par[0] != 0 { 77152da9a59SGnoCiYeH self.cursor_type = 77252da9a59SGnoCiYeH VcCursor::make_cursor(self.par[0], self.par[1], self.par[2]) 77352da9a59SGnoCiYeH } else { 77452da9a59SGnoCiYeH self.cursor_type = VcCursor::CUR_UNDERLINE; 77552da9a59SGnoCiYeH } 77652da9a59SGnoCiYeH return; 77752da9a59SGnoCiYeH } 77852da9a59SGnoCiYeH } 77952da9a59SGnoCiYeH 'm' => { 78052da9a59SGnoCiYeH if self.private == Vt102_OP::EPdec { 78152da9a59SGnoCiYeH if self.par[0] != 0 { 78252da9a59SGnoCiYeH self.complement_mask = (self.par[0] << 8 | self.par[1]) as u16; 78352da9a59SGnoCiYeH } else { 78452da9a59SGnoCiYeH self.complement_mask = self.s_complement_mask; 78552da9a59SGnoCiYeH } 78652da9a59SGnoCiYeH return; 78752da9a59SGnoCiYeH } 78852da9a59SGnoCiYeH } 78952da9a59SGnoCiYeH 'n' => { 79052da9a59SGnoCiYeH if self.private == Vt102_OP::EPecma { 79152da9a59SGnoCiYeH if self.par[0] == 5 { 79252da9a59SGnoCiYeH kwarn!("tty status report todo"); 79352da9a59SGnoCiYeH } else if self.par[0] == 6 { 79452da9a59SGnoCiYeH kwarn!("tty cursor report todo"); 79552da9a59SGnoCiYeH } 79652da9a59SGnoCiYeH } 79752da9a59SGnoCiYeH return; 79852da9a59SGnoCiYeH } 79952da9a59SGnoCiYeH _ => {} 80052da9a59SGnoCiYeH } 80152da9a59SGnoCiYeH 80252da9a59SGnoCiYeH if self.private != Vt102_OP::EPecma { 80352da9a59SGnoCiYeH self.private = Vt102_OP::EPecma; 80452da9a59SGnoCiYeH return; 80552da9a59SGnoCiYeH } 80652da9a59SGnoCiYeH 80752da9a59SGnoCiYeH match c { 80852da9a59SGnoCiYeH 'G' | '`' => { 80952da9a59SGnoCiYeH if self.par[0] != 0 { 81052da9a59SGnoCiYeH self.par[0] -= 1; 81152da9a59SGnoCiYeH } 81252da9a59SGnoCiYeH self.gotoxy(self.par[0] as i32, self.state.y as i32); 81352da9a59SGnoCiYeH return; 81452da9a59SGnoCiYeH } 81552da9a59SGnoCiYeH 'A' => { 81652da9a59SGnoCiYeH if self.par[0] == 0 { 81752da9a59SGnoCiYeH self.par[0] += 1; 81852da9a59SGnoCiYeH } 81952da9a59SGnoCiYeH self.gotoxy( 82052da9a59SGnoCiYeH self.state.x as i32, 82152da9a59SGnoCiYeH (self.state.y - self.par[0] as usize) as i32, 82252da9a59SGnoCiYeH ); 82352da9a59SGnoCiYeH return; 82452da9a59SGnoCiYeH } 82552da9a59SGnoCiYeH 'B' | 'e' => { 82652da9a59SGnoCiYeH if self.par[0] == 0 { 82752da9a59SGnoCiYeH self.par[0] += 1; 82852da9a59SGnoCiYeH } 82952da9a59SGnoCiYeH self.gotoxy( 83052da9a59SGnoCiYeH self.state.x as i32, 83152da9a59SGnoCiYeH (self.state.y + self.par[0] as usize) as i32, 83252da9a59SGnoCiYeH ); 83352da9a59SGnoCiYeH return; 83452da9a59SGnoCiYeH } 83552da9a59SGnoCiYeH 'C' | 'a' => { 83652da9a59SGnoCiYeH if self.par[0] == 0 { 83752da9a59SGnoCiYeH self.par[0] += 1; 83852da9a59SGnoCiYeH } 83952da9a59SGnoCiYeH self.gotoxy( 84052da9a59SGnoCiYeH (self.state.x + self.par[0] as usize) as i32, 84152da9a59SGnoCiYeH self.state.y as i32, 84252da9a59SGnoCiYeH ); 84352da9a59SGnoCiYeH return; 84452da9a59SGnoCiYeH } 84552da9a59SGnoCiYeH 'D' => { 84652da9a59SGnoCiYeH if self.par[0] == 0 { 84752da9a59SGnoCiYeH self.par[0] += 1; 84852da9a59SGnoCiYeH } 84952da9a59SGnoCiYeH self.gotoxy( 85052da9a59SGnoCiYeH (self.state.x - self.par[0] as usize) as i32, 85152da9a59SGnoCiYeH self.state.y as i32, 85252da9a59SGnoCiYeH ); 85352da9a59SGnoCiYeH return; 85452da9a59SGnoCiYeH } 85552da9a59SGnoCiYeH 'E' => { 85652da9a59SGnoCiYeH if self.par[0] == 0 { 85752da9a59SGnoCiYeH self.par[0] += 1; 85852da9a59SGnoCiYeH } 85952da9a59SGnoCiYeH self.gotoxy(0, (self.state.y + self.par[0] as usize) as i32); 86052da9a59SGnoCiYeH return; 86152da9a59SGnoCiYeH } 86252da9a59SGnoCiYeH 'F' => { 86352da9a59SGnoCiYeH if self.par[0] == 0 { 86452da9a59SGnoCiYeH self.par[0] += 1; 86552da9a59SGnoCiYeH } 86652da9a59SGnoCiYeH self.gotoxy(0, (self.state.y - self.par[0] as usize) as i32); 86752da9a59SGnoCiYeH return; 86852da9a59SGnoCiYeH } 86952da9a59SGnoCiYeH 'd' => { 87052da9a59SGnoCiYeH if self.par[0] != 0 { 87152da9a59SGnoCiYeH self.par[0] -= 1; 87252da9a59SGnoCiYeH } 87352da9a59SGnoCiYeH self.gotoxay(self.state.x as i32, self.par[0] as i32); 87452da9a59SGnoCiYeH return; 87552da9a59SGnoCiYeH } 87652da9a59SGnoCiYeH 'H' | 'f' => { 87752da9a59SGnoCiYeH if self.par[0] != 0 { 87852da9a59SGnoCiYeH self.par[0] -= 1; 87952da9a59SGnoCiYeH } 88052da9a59SGnoCiYeH if self.par[1] != 0 { 88152da9a59SGnoCiYeH self.par[1] -= 1; 88252da9a59SGnoCiYeH } 88352da9a59SGnoCiYeH self.gotoxay(self.par[1] as i32, self.par[0] as i32); 88452da9a59SGnoCiYeH return; 88552da9a59SGnoCiYeH } 88652da9a59SGnoCiYeH 'J' => { 88752da9a59SGnoCiYeH self.csi_J(self.par[0]); 88852da9a59SGnoCiYeH return; 88952da9a59SGnoCiYeH } 89052da9a59SGnoCiYeH 'K' => { 89152da9a59SGnoCiYeH self.csi_K(self.par[0]); 89252da9a59SGnoCiYeH return; 89352da9a59SGnoCiYeH } 89452da9a59SGnoCiYeH 'L' => { 89552da9a59SGnoCiYeH todo!("csi_L todo"); 89652da9a59SGnoCiYeH } 89752da9a59SGnoCiYeH 'M' => { 89852da9a59SGnoCiYeH todo!("csi_M todo"); 89952da9a59SGnoCiYeH } 90052da9a59SGnoCiYeH 'P' => { 90152da9a59SGnoCiYeH todo!("csi_P todo"); 90252da9a59SGnoCiYeH } 90352da9a59SGnoCiYeH 'c' => { 90452da9a59SGnoCiYeH if self.par[0] == 0 { 90552da9a59SGnoCiYeH kwarn!("respone ID todo"); 90652da9a59SGnoCiYeH } 90752da9a59SGnoCiYeH return; 90852da9a59SGnoCiYeH } 90952da9a59SGnoCiYeH 'g' => { 91052da9a59SGnoCiYeH if self.par[0] == 0 && self.state.x < 256 { 91152da9a59SGnoCiYeH self.tab_stop.set(self.state.x as usize, true); 91252da9a59SGnoCiYeH } else if self.par[0] == 3 { 91352da9a59SGnoCiYeH self.tab_stop.set_all(false); 91452da9a59SGnoCiYeH } 91552da9a59SGnoCiYeH return; 91652da9a59SGnoCiYeH } 91752da9a59SGnoCiYeH 'm' => { 91852da9a59SGnoCiYeH self.csi_m(); 91952da9a59SGnoCiYeH return; 92052da9a59SGnoCiYeH } 92152da9a59SGnoCiYeH 'q' => { 92252da9a59SGnoCiYeH if self.par[0] < 4 { 92352da9a59SGnoCiYeH todo!("vt set led state todo"); 92452da9a59SGnoCiYeH } 92552da9a59SGnoCiYeH return; 92652da9a59SGnoCiYeH } 92752da9a59SGnoCiYeH 'r' => { 92852da9a59SGnoCiYeH if self.par[0] == 0 { 92952da9a59SGnoCiYeH self.par[0] += 1; 93052da9a59SGnoCiYeH } 93152da9a59SGnoCiYeH if self.par[1] == 0 { 93252da9a59SGnoCiYeH self.par[1] = self.rows as u32; 93352da9a59SGnoCiYeH } 93452da9a59SGnoCiYeH if self.par[0] < self.par[1] && self.par[1] <= self.rows as u32 { 93552da9a59SGnoCiYeH self.top = self.par[0] as usize - 1; 93652da9a59SGnoCiYeH self.bottom = self.par[1] as usize; 93752da9a59SGnoCiYeH self.gotoxay(0, 0); 93852da9a59SGnoCiYeH } 93952da9a59SGnoCiYeH return; 94052da9a59SGnoCiYeH } 94152da9a59SGnoCiYeH 's' => { 94252da9a59SGnoCiYeH self.saved_state = self.state.clone(); 94352da9a59SGnoCiYeH return; 94452da9a59SGnoCiYeH } 94552da9a59SGnoCiYeH 'u' => { 94652da9a59SGnoCiYeH self.restore_cursor(); 94752da9a59SGnoCiYeH return; 94852da9a59SGnoCiYeH } 94952da9a59SGnoCiYeH '@' => { 95052da9a59SGnoCiYeH todo!("csi_at todo"); 95152da9a59SGnoCiYeH } 95252da9a59SGnoCiYeH ']' => { 95352da9a59SGnoCiYeH todo!("set termial command todo"); 95452da9a59SGnoCiYeH } 95552da9a59SGnoCiYeH _ => {} 95652da9a59SGnoCiYeH } 95752da9a59SGnoCiYeH } 95852da9a59SGnoCiYeH 95952da9a59SGnoCiYeH /// ## 处理Control Sequence Introducer(控制序列引导符) m字符 96052da9a59SGnoCiYeH fn csi_m(&mut self) { 96152da9a59SGnoCiYeH let mut i = 0; 96252da9a59SGnoCiYeH loop { 96352da9a59SGnoCiYeH if i > self.npar as usize { 96452da9a59SGnoCiYeH break; 96552da9a59SGnoCiYeH } 96652da9a59SGnoCiYeH match self.par[i] { 96752da9a59SGnoCiYeH 0 => { 96852da9a59SGnoCiYeH // 关闭所有属性 96952da9a59SGnoCiYeH self.default_attr(); 97052da9a59SGnoCiYeH } 97152da9a59SGnoCiYeH 97252da9a59SGnoCiYeH 1 => { 97352da9a59SGnoCiYeH // 设置粗体 97452da9a59SGnoCiYeH self.state.intensity = VirtualConsoleIntensity::VciBold; 97552da9a59SGnoCiYeH } 97652da9a59SGnoCiYeH 97752da9a59SGnoCiYeH 2 => { 97852da9a59SGnoCiYeH // 设置半亮度(半明显 97952da9a59SGnoCiYeH self.state.intensity = VirtualConsoleIntensity::VciHalfBright; 98052da9a59SGnoCiYeH } 98152da9a59SGnoCiYeH 98252da9a59SGnoCiYeH 3 => { 98352da9a59SGnoCiYeH // 斜体 98452da9a59SGnoCiYeH self.state.italic = true; 98552da9a59SGnoCiYeH } 98652da9a59SGnoCiYeH 98752da9a59SGnoCiYeH 4 | 21 => { 98852da9a59SGnoCiYeH // 下划线 98952da9a59SGnoCiYeH 99052da9a59SGnoCiYeH // 21是设置双下划线,但是不支持,就单下划线 99152da9a59SGnoCiYeH self.state.underline = true; 99252da9a59SGnoCiYeH } 99352da9a59SGnoCiYeH 99452da9a59SGnoCiYeH 5 => { 99552da9a59SGnoCiYeH // 设置闪烁 99652da9a59SGnoCiYeH self.state.blink = true; 99752da9a59SGnoCiYeH } 99852da9a59SGnoCiYeH 99952da9a59SGnoCiYeH 7 => { 100052da9a59SGnoCiYeH // 设置反显(前景色与背景色对调) 100152da9a59SGnoCiYeH self.state.reverse = true; 100252da9a59SGnoCiYeH } 100352da9a59SGnoCiYeH 100452da9a59SGnoCiYeH 10 => { 100552da9a59SGnoCiYeH // 选择主要字体 100652da9a59SGnoCiYeH todo!() 100752da9a59SGnoCiYeH } 100852da9a59SGnoCiYeH 100952da9a59SGnoCiYeH 11 => { 101052da9a59SGnoCiYeH // 选择第一个替代字体 101152da9a59SGnoCiYeH todo!() 101252da9a59SGnoCiYeH } 101352da9a59SGnoCiYeH 101452da9a59SGnoCiYeH 12 => { 101552da9a59SGnoCiYeH // 选择第二个替代字体 101652da9a59SGnoCiYeH todo!() 101752da9a59SGnoCiYeH } 101852da9a59SGnoCiYeH 101952da9a59SGnoCiYeH 22 => { 102052da9a59SGnoCiYeH // 关闭粗体和半亮度,恢复正常亮度 102152da9a59SGnoCiYeH self.state.intensity = VirtualConsoleIntensity::VciNormal; 102252da9a59SGnoCiYeH } 102352da9a59SGnoCiYeH 102452da9a59SGnoCiYeH 23 => { 102552da9a59SGnoCiYeH // 关闭斜体 102652da9a59SGnoCiYeH self.state.italic = false; 102752da9a59SGnoCiYeH } 102852da9a59SGnoCiYeH 102952da9a59SGnoCiYeH 24 => { 103052da9a59SGnoCiYeH // 关闭下划线 103152da9a59SGnoCiYeH self.state.underline = false; 103252da9a59SGnoCiYeH } 103352da9a59SGnoCiYeH 103452da9a59SGnoCiYeH 25 => { 103552da9a59SGnoCiYeH // 关闭字符闪烁 103652da9a59SGnoCiYeH self.state.blink = false; 103752da9a59SGnoCiYeH } 103852da9a59SGnoCiYeH 103952da9a59SGnoCiYeH 27 => { 104052da9a59SGnoCiYeH // 关闭反显 104152da9a59SGnoCiYeH self.state.reverse = false; 104252da9a59SGnoCiYeH } 104352da9a59SGnoCiYeH 104452da9a59SGnoCiYeH 38 => { 104552da9a59SGnoCiYeH // 设置前景色 104652da9a59SGnoCiYeH let (idx, color) = self.t416_color(i); 104752da9a59SGnoCiYeH i = idx; 104852da9a59SGnoCiYeH if color.is_some() { 104952da9a59SGnoCiYeH let color = color.unwrap(); 105052da9a59SGnoCiYeH let mut max = color.red.max(color.green); 105152da9a59SGnoCiYeH max = max.max(color.blue); 105252da9a59SGnoCiYeH 105352da9a59SGnoCiYeH let mut hue = 0; 105452da9a59SGnoCiYeH if color.red > max / 2 { 105552da9a59SGnoCiYeH hue |= 4; 105652da9a59SGnoCiYeH } 105752da9a59SGnoCiYeH if color.green > max / 2 { 105852da9a59SGnoCiYeH hue |= 2; 105952da9a59SGnoCiYeH } 106052da9a59SGnoCiYeH if color.blue > max / 2 { 106152da9a59SGnoCiYeH hue |= 1; 106252da9a59SGnoCiYeH } 106352da9a59SGnoCiYeH 106452da9a59SGnoCiYeH if hue == 7 && max <= 0x55 { 106552da9a59SGnoCiYeH hue = 0; 106652da9a59SGnoCiYeH self.state.intensity = VirtualConsoleIntensity::VciBold; 106752da9a59SGnoCiYeH } else if max > 0xaa { 106852da9a59SGnoCiYeH self.state.intensity = VirtualConsoleIntensity::VciBold; 106952da9a59SGnoCiYeH } else { 107052da9a59SGnoCiYeH self.state.intensity = VirtualConsoleIntensity::VciNormal; 107152da9a59SGnoCiYeH } 107252da9a59SGnoCiYeH 107352da9a59SGnoCiYeH self.state.color = (self.state.color & 0xf0) | hue; 107452da9a59SGnoCiYeH } 107552da9a59SGnoCiYeH } 107652da9a59SGnoCiYeH 107752da9a59SGnoCiYeH 48 => { 107852da9a59SGnoCiYeH // 设置背景色 107952da9a59SGnoCiYeH let (idx, color) = self.t416_color(i); 108052da9a59SGnoCiYeH i = idx; 108152da9a59SGnoCiYeH if color.is_some() { 108252da9a59SGnoCiYeH let color = color.unwrap(); 108352da9a59SGnoCiYeH self.state.color = (self.state.color & 0x0f) 108452da9a59SGnoCiYeH | ((color.red as u8 & 0x80) >> 1) 108552da9a59SGnoCiYeH | ((color.green as u8 & 0x80) >> 2) 108652da9a59SGnoCiYeH | ((color.blue as u8 & 0x80) >> 3); 108752da9a59SGnoCiYeH } 108852da9a59SGnoCiYeH } 108952da9a59SGnoCiYeH 109052da9a59SGnoCiYeH 39 => { 109152da9a59SGnoCiYeH // 恢复默认前景色 109252da9a59SGnoCiYeH self.state.color = (self.def_color & 0x0f) | (self.state.color & 0xf0); 109352da9a59SGnoCiYeH } 109452da9a59SGnoCiYeH 109552da9a59SGnoCiYeH 49 => { 109652da9a59SGnoCiYeH // 恢复默认背景色 109752da9a59SGnoCiYeH self.state.color = (self.def_color & 0xf0) | (self.state.color & 0x0f); 109852da9a59SGnoCiYeH } 109952da9a59SGnoCiYeH 110052da9a59SGnoCiYeH _ => { 110152da9a59SGnoCiYeH if self.par[i] >= 90 && self.par[i] <= 107 { 110252da9a59SGnoCiYeH if self.par[i] < 100 { 110352da9a59SGnoCiYeH self.state.intensity = VirtualConsoleIntensity::VciBold; 110452da9a59SGnoCiYeH } 110552da9a59SGnoCiYeH self.par[i] -= 60; 110652da9a59SGnoCiYeH } 110752da9a59SGnoCiYeH 110852da9a59SGnoCiYeH if self.par[i] >= 30 && self.par[i] <= 37 { 110952da9a59SGnoCiYeH self.state.color = 111052da9a59SGnoCiYeH COLOR_TABLE[self.par[i] as usize - 30] | self.state.color & 0xf0; 111152da9a59SGnoCiYeH } else if self.par[i] >= 40 && self.par[i] <= 47 { 111252da9a59SGnoCiYeH self.state.color = 111352da9a59SGnoCiYeH (COLOR_TABLE[self.par[i] as usize - 40] << 4) | self.state.color & 0xf0; 111452da9a59SGnoCiYeH } 111552da9a59SGnoCiYeH } 111652da9a59SGnoCiYeH } 111752da9a59SGnoCiYeH 111852da9a59SGnoCiYeH i += 1; 111952da9a59SGnoCiYeH } 112052da9a59SGnoCiYeH 112152da9a59SGnoCiYeH self.update_attr(); 112252da9a59SGnoCiYeH } 112352da9a59SGnoCiYeH 112452da9a59SGnoCiYeH /// ## 处理Control Sequence Introducer(控制序列引导符) J字符 112552da9a59SGnoCiYeH /// 该命令用于擦除终端显示区域的部分或全部内容。根据参数 vpar 的不同值,执行不同的擦除操作: 112652da9a59SGnoCiYeH /// - vpar 为 0 时,擦除从光标位置到显示区域末尾的内容; 112752da9a59SGnoCiYeH /// - vpar 为 1 时,擦除从显示区域起始位置到光标位置的内容; 112852da9a59SGnoCiYeH /// - vpar 为 2 或 3 时,分别表示擦除整个显示区域的内容,其中参数 3 还会清除回滚缓冲区的内容。 112952da9a59SGnoCiYeH #[allow(non_snake_case)] 113052da9a59SGnoCiYeH fn csi_J(&mut self, vpar: u32) { 113152da9a59SGnoCiYeH let count; 113252da9a59SGnoCiYeH let start; 113352da9a59SGnoCiYeH 113452da9a59SGnoCiYeH match vpar { 113552da9a59SGnoCiYeH 0 => { 113652da9a59SGnoCiYeH // 擦除从光标位置到显示区域末尾的内容 113752da9a59SGnoCiYeH count = self.screen_buf.len() - self.pos; 113852da9a59SGnoCiYeH start = self.pos; 113952da9a59SGnoCiYeH } 114052da9a59SGnoCiYeH 1 => { 114152da9a59SGnoCiYeH // 擦除从显示区域起始位置到光标位置的内容 114252da9a59SGnoCiYeH count = self.pos; 114352da9a59SGnoCiYeH start = 0; 114452da9a59SGnoCiYeH } 114552da9a59SGnoCiYeH 2 => { 114652da9a59SGnoCiYeH // 擦除整个显示区域的内容 114752da9a59SGnoCiYeH count = self.screen_buf.len(); 114852da9a59SGnoCiYeH start = 0; 114952da9a59SGnoCiYeH } 115052da9a59SGnoCiYeH 3 => { 115152da9a59SGnoCiYeH // 表示擦除整个显示区域的内容,还会清除回滚缓冲区的内容 115252da9a59SGnoCiYeH // TODO:当前未实现回滚缓冲 115352da9a59SGnoCiYeH count = self.screen_buf.len(); 115452da9a59SGnoCiYeH start = 0; 115552da9a59SGnoCiYeH } 115652da9a59SGnoCiYeH _ => { 115752da9a59SGnoCiYeH return; 115852da9a59SGnoCiYeH } 115952da9a59SGnoCiYeH } 116052da9a59SGnoCiYeH 116152da9a59SGnoCiYeH for i in self.screen_buf[start..(start + count)].iter_mut() { 116252da9a59SGnoCiYeH *i = self.erase_char; 116352da9a59SGnoCiYeH } 116452da9a59SGnoCiYeH 116552da9a59SGnoCiYeH if self.should_update() { 116652da9a59SGnoCiYeH self.do_update_region(start, count) 116752da9a59SGnoCiYeH } 116852da9a59SGnoCiYeH 116952da9a59SGnoCiYeH self.need_wrap = false; 117052da9a59SGnoCiYeH } 117152da9a59SGnoCiYeH 117252da9a59SGnoCiYeH /// ## 处理Control Sequence Introducer(控制序列引导符) K字符 117352da9a59SGnoCiYeH /// 该命令用于擦除终端当前行的部分或全部内容。根据参数 vpar 的不同值,执行不同的擦除操作: 117452da9a59SGnoCiYeH /// - vpar 为 0 时,擦除从光标位置到该行末尾的内容 117552da9a59SGnoCiYeH /// - vpar 为 1 时,擦除从该行起始位置到光标位置的内容 117652da9a59SGnoCiYeH /// - vpar 为 2 时,擦除整个行。 117752da9a59SGnoCiYeH #[allow(non_snake_case)] 117852da9a59SGnoCiYeH fn csi_K(&mut self, vpar: u32) { 117952da9a59SGnoCiYeH let count; 118052da9a59SGnoCiYeH let start; 118152da9a59SGnoCiYeH 118252da9a59SGnoCiYeH match vpar { 118352da9a59SGnoCiYeH 0 => { 118452da9a59SGnoCiYeH // 擦除从光标位置到该行末尾的内容 118552da9a59SGnoCiYeH count = self.cols - self.state.x; 118652da9a59SGnoCiYeH start = self.pos; 118752da9a59SGnoCiYeH } 118852da9a59SGnoCiYeH 1 => { 118952da9a59SGnoCiYeH // 擦除从该行起始位置到光标位置的内容 119052da9a59SGnoCiYeH count = self.state.x + 1; 119152da9a59SGnoCiYeH start = self.pos - self.state.x; 119252da9a59SGnoCiYeH } 119352da9a59SGnoCiYeH 2 => { 119452da9a59SGnoCiYeH // 擦除整个行 119552da9a59SGnoCiYeH count = self.cols; 119652da9a59SGnoCiYeH start = self.pos - self.state.x; 119752da9a59SGnoCiYeH } 119852da9a59SGnoCiYeH _ => { 119952da9a59SGnoCiYeH return; 120052da9a59SGnoCiYeH } 120152da9a59SGnoCiYeH } 120252da9a59SGnoCiYeH 1203*be60c929SGnoCiYeH let max_idx = self.screen_buf.len(); 1204*be60c929SGnoCiYeH for i in self.screen_buf[start..max_idx.min(start + count)].iter_mut() { 120552da9a59SGnoCiYeH *i = self.erase_char; 120652da9a59SGnoCiYeH } 120752da9a59SGnoCiYeH 120852da9a59SGnoCiYeH if self.should_update() { 1209*be60c929SGnoCiYeH self.do_update_region(start, count.min(max_idx - start)) 121052da9a59SGnoCiYeH } 121152da9a59SGnoCiYeH 121252da9a59SGnoCiYeH self.need_wrap = false; 121352da9a59SGnoCiYeH } 121452da9a59SGnoCiYeH 121552da9a59SGnoCiYeH fn t416_color(&mut self, mut idx: usize) -> (usize, Option<Color>) { 121652da9a59SGnoCiYeH idx += 1; 121752da9a59SGnoCiYeH if idx > self.npar as usize { 121852da9a59SGnoCiYeH return (idx, None); 121952da9a59SGnoCiYeH } 122052da9a59SGnoCiYeH 122152da9a59SGnoCiYeH if self.par[idx] == 5 && idx + 1 <= self.npar as usize { 122252da9a59SGnoCiYeH // 256色 122352da9a59SGnoCiYeH idx += 1; 122452da9a59SGnoCiYeH return (idx, Some(Color::from_256(self.par[idx]))); 122552da9a59SGnoCiYeH } else if self.par[idx] == 2 && idx + 3 <= self.npar as usize { 122652da9a59SGnoCiYeH // 24位 122752da9a59SGnoCiYeH let mut color = Color::default(); 122852da9a59SGnoCiYeH color.red = self.par[idx + 1] as u16; 122952da9a59SGnoCiYeH color.green = self.par[idx + 2] as u16; 123052da9a59SGnoCiYeH color.blue = self.par[idx + 3] as u16; 123152da9a59SGnoCiYeH idx += 3; 123252da9a59SGnoCiYeH return (idx, Some(color)); 123352da9a59SGnoCiYeH } else { 123452da9a59SGnoCiYeH return (idx, None); 123552da9a59SGnoCiYeH } 123652da9a59SGnoCiYeH } 123752da9a59SGnoCiYeH 123852da9a59SGnoCiYeH /// ## 处理终端控制字符 123952da9a59SGnoCiYeH pub(super) fn do_control(&mut self, ch: u32) { 124052da9a59SGnoCiYeH // 首先检查是否处于 ANSI 控制字符串状态 124152da9a59SGnoCiYeH if self.vc_state.is_ansi_control_string() && ch >= 8 && ch <= 13 { 124252da9a59SGnoCiYeH return; 124352da9a59SGnoCiYeH } 124452da9a59SGnoCiYeH 124552da9a59SGnoCiYeH match ch { 124652da9a59SGnoCiYeH 0 => { 124752da9a59SGnoCiYeH return; 124852da9a59SGnoCiYeH } 124952da9a59SGnoCiYeH 7 => { 125052da9a59SGnoCiYeH // BEL 125152da9a59SGnoCiYeH if self.vc_state.is_ansi_control_string() { 125252da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 125352da9a59SGnoCiYeH } 125452da9a59SGnoCiYeH // TODO: 发出声音? 125552da9a59SGnoCiYeH return; 125652da9a59SGnoCiYeH } 125752da9a59SGnoCiYeH 8 => { 125852da9a59SGnoCiYeH // BS backspace 125952da9a59SGnoCiYeH self.backspace(); 126052da9a59SGnoCiYeH return; 126152da9a59SGnoCiYeH } 126252da9a59SGnoCiYeH 9 => { 126352da9a59SGnoCiYeH // 水平制表符(Horizontal Tab) 126452da9a59SGnoCiYeH self.pos -= self.state.x; 126552da9a59SGnoCiYeH 126652da9a59SGnoCiYeH let ret = self.tab_stop.next_index(self.state.x + 1); 126752da9a59SGnoCiYeH 126852da9a59SGnoCiYeH if ret.is_none() { 126952da9a59SGnoCiYeH self.state.x = self.cols - 1; 127052da9a59SGnoCiYeH } else { 127152da9a59SGnoCiYeH self.state.x = ret.unwrap(); 127252da9a59SGnoCiYeH } 127352da9a59SGnoCiYeH 127452da9a59SGnoCiYeH self.pos += self.state.x; 127552da9a59SGnoCiYeH // TODO: notify 127652da9a59SGnoCiYeH return; 127752da9a59SGnoCiYeH } 127852da9a59SGnoCiYeH 10 | 11 | 12 => { 127952da9a59SGnoCiYeH // LD line feed 128052da9a59SGnoCiYeH self.line_feed(); 128152da9a59SGnoCiYeH // TODO: 检查键盘模式 128252da9a59SGnoCiYeH self.carriage_return(); 128352da9a59SGnoCiYeH return; 128452da9a59SGnoCiYeH } 128552da9a59SGnoCiYeH 13 => { 128652da9a59SGnoCiYeH // CR 回车符 128752da9a59SGnoCiYeH self.carriage_return(); 128852da9a59SGnoCiYeH return; 128952da9a59SGnoCiYeH } 129052da9a59SGnoCiYeH 14 => { 129152da9a59SGnoCiYeH todo!("Gx_charset todo!"); 129252da9a59SGnoCiYeH } 129352da9a59SGnoCiYeH 15 => { 129452da9a59SGnoCiYeH todo!("Gx_charset todo!"); 129552da9a59SGnoCiYeH } 129652da9a59SGnoCiYeH 24 | 26 => { 129752da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 129852da9a59SGnoCiYeH return; 129952da9a59SGnoCiYeH } 130052da9a59SGnoCiYeH 27 => { 130152da9a59SGnoCiYeH // esc 130252da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESesc; 130352da9a59SGnoCiYeH return; 130452da9a59SGnoCiYeH } 130552da9a59SGnoCiYeH 127 => { 130652da9a59SGnoCiYeH // delete 130752da9a59SGnoCiYeH self.delete(); 130852da9a59SGnoCiYeH return; 130952da9a59SGnoCiYeH } 131052da9a59SGnoCiYeH 155 => { 131152da9a59SGnoCiYeH // '[' 131252da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESsquare; 131352da9a59SGnoCiYeH return; 131452da9a59SGnoCiYeH } 131552da9a59SGnoCiYeH _ => {} 131652da9a59SGnoCiYeH } 131752da9a59SGnoCiYeH 131852da9a59SGnoCiYeH match self.vc_state { 131952da9a59SGnoCiYeH VirtualConsoleState::ESesc => { 132052da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 132152da9a59SGnoCiYeH match ch as u8 as char { 132252da9a59SGnoCiYeH '[' => { 132352da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESsquare; 132452da9a59SGnoCiYeH } 132552da9a59SGnoCiYeH ']' => { 132652da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnonstd; 132752da9a59SGnoCiYeH } 132852da9a59SGnoCiYeH '_' => { 132952da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESapc; 133052da9a59SGnoCiYeH } 133152da9a59SGnoCiYeH '^' => { 133252da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESpm; 133352da9a59SGnoCiYeH } 133452da9a59SGnoCiYeH '%' => { 133552da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESpercent; 133652da9a59SGnoCiYeH } 133752da9a59SGnoCiYeH 'E' => { 133852da9a59SGnoCiYeH self.carriage_return(); 133952da9a59SGnoCiYeH self.line_feed(); 134052da9a59SGnoCiYeH } 134152da9a59SGnoCiYeH 'M' => { 134252da9a59SGnoCiYeH self.reverse_index(); 134352da9a59SGnoCiYeH } 134452da9a59SGnoCiYeH 'D' => { 134552da9a59SGnoCiYeH self.line_feed(); 134652da9a59SGnoCiYeH } 134752da9a59SGnoCiYeH 'H' => { 134852da9a59SGnoCiYeH if self.state.x < 256 { 134952da9a59SGnoCiYeH self.tab_stop.set(self.state.x, true); 135052da9a59SGnoCiYeH } 135152da9a59SGnoCiYeH } 135252da9a59SGnoCiYeH 'P' => { 135352da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESdcs; 135452da9a59SGnoCiYeH } 135552da9a59SGnoCiYeH 'Z' => { 135652da9a59SGnoCiYeH todo!("Respond ID todo!"); 135752da9a59SGnoCiYeH } 135852da9a59SGnoCiYeH '7' => self.saved_state = self.state.clone(), 135952da9a59SGnoCiYeH '8' => self.restore_cursor(), 136052da9a59SGnoCiYeH '(' => { 136152da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESsetG0; 136252da9a59SGnoCiYeH } 136352da9a59SGnoCiYeH ')' => { 136452da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESsetG1; 136552da9a59SGnoCiYeH } 136652da9a59SGnoCiYeH '#' => { 136752da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::EShash; 136852da9a59SGnoCiYeH } 136952da9a59SGnoCiYeH 'c' => { 137052da9a59SGnoCiYeH self.reset(true); 137152da9a59SGnoCiYeH } 137252da9a59SGnoCiYeH '>' => { 137352da9a59SGnoCiYeH todo!("clr_kbd todo"); 137452da9a59SGnoCiYeH } 137552da9a59SGnoCiYeH '=' => { 137652da9a59SGnoCiYeH todo!("set_kbd todo"); 137752da9a59SGnoCiYeH } 137852da9a59SGnoCiYeH _ => {} 137952da9a59SGnoCiYeH } 138052da9a59SGnoCiYeH } 138152da9a59SGnoCiYeH VirtualConsoleState::ESsquare => { 138252da9a59SGnoCiYeH for i in self.par.iter_mut() { 138352da9a59SGnoCiYeH *i = 0; 138452da9a59SGnoCiYeH } 138552da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESgetpars; 138652da9a59SGnoCiYeH self.npar = 0; 138752da9a59SGnoCiYeH let c = ch as u8 as char; 138852da9a59SGnoCiYeH if c == '[' { 138952da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESfunckey; 139052da9a59SGnoCiYeH return; 139152da9a59SGnoCiYeH } 139252da9a59SGnoCiYeH 139352da9a59SGnoCiYeH match c { 139452da9a59SGnoCiYeH '?' => { 139552da9a59SGnoCiYeH self.private = Vt102_OP::EPdec; 139652da9a59SGnoCiYeH return; 139752da9a59SGnoCiYeH } 139852da9a59SGnoCiYeH '>' => { 139952da9a59SGnoCiYeH self.private = Vt102_OP::EPgt; 140052da9a59SGnoCiYeH return; 140152da9a59SGnoCiYeH } 140252da9a59SGnoCiYeH '=' => { 140352da9a59SGnoCiYeH self.private = Vt102_OP::EPeq; 140452da9a59SGnoCiYeH return; 140552da9a59SGnoCiYeH } 140652da9a59SGnoCiYeH '<' => { 140752da9a59SGnoCiYeH self.private = Vt102_OP::EPlt; 140852da9a59SGnoCiYeH return; 140952da9a59SGnoCiYeH } 141052da9a59SGnoCiYeH _ => {} 141152da9a59SGnoCiYeH } 141252da9a59SGnoCiYeH 141352da9a59SGnoCiYeH self.private = Vt102_OP::EPecma; 141452da9a59SGnoCiYeH self.do_getpars(c); 141552da9a59SGnoCiYeH } 141652da9a59SGnoCiYeH VirtualConsoleState::ESgetpars => { 141752da9a59SGnoCiYeH let c = ch as u8 as char; 141852da9a59SGnoCiYeH self.do_getpars(c); 141952da9a59SGnoCiYeH } 142052da9a59SGnoCiYeH VirtualConsoleState::ESfunckey => { 142152da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 142252da9a59SGnoCiYeH return; 142352da9a59SGnoCiYeH } 142452da9a59SGnoCiYeH VirtualConsoleState::EShash => { 142552da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 142652da9a59SGnoCiYeH if ch as u8 as char == '8' { 142752da9a59SGnoCiYeH self.erase_char = (self.erase_char & 0xff00) | 'E' as u16; 142852da9a59SGnoCiYeH self.csi_J(2); 142952da9a59SGnoCiYeH self.erase_char = (self.erase_char & 0xff00) | ' ' as u16; 143052da9a59SGnoCiYeH self.do_update_region(0, self.screen_buf.len()); 143152da9a59SGnoCiYeH } 143252da9a59SGnoCiYeH return; 143352da9a59SGnoCiYeH } 143452da9a59SGnoCiYeH VirtualConsoleState::ESsetG0 => { 143552da9a59SGnoCiYeH todo!("SetGx todo"); 143652da9a59SGnoCiYeH } 143752da9a59SGnoCiYeH VirtualConsoleState::ESsetG1 => { 143852da9a59SGnoCiYeH todo!("SetGx todo"); 143952da9a59SGnoCiYeH } 144052da9a59SGnoCiYeH VirtualConsoleState::ESpercent => { 144152da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 144252da9a59SGnoCiYeH let c = ch as u8 as char; 144352da9a59SGnoCiYeH match c { 144452da9a59SGnoCiYeH '@' => { 144552da9a59SGnoCiYeH self.utf = false; 144652da9a59SGnoCiYeH return; 144752da9a59SGnoCiYeH } 144852da9a59SGnoCiYeH 'G' | '8' => { 144952da9a59SGnoCiYeH self.utf = true; 145052da9a59SGnoCiYeH return; 145152da9a59SGnoCiYeH } 145252da9a59SGnoCiYeH _ => {} 145352da9a59SGnoCiYeH } 145452da9a59SGnoCiYeH return; 145552da9a59SGnoCiYeH } 145652da9a59SGnoCiYeH VirtualConsoleState::EScsiignore => { 145752da9a59SGnoCiYeH if ch >= 20 && ch <= 0x3f { 145852da9a59SGnoCiYeH return; 145952da9a59SGnoCiYeH } 146052da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 146152da9a59SGnoCiYeH return; 146252da9a59SGnoCiYeH } 146352da9a59SGnoCiYeH VirtualConsoleState::ESnonstd => { 146452da9a59SGnoCiYeH let c = ch as u8 as char; 146552da9a59SGnoCiYeH if c == 'P' { 146652da9a59SGnoCiYeH for i in self.par.iter_mut() { 146752da9a59SGnoCiYeH *i = 0; 146852da9a59SGnoCiYeH } 146952da9a59SGnoCiYeH self.npar = 0; 147052da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESpalette; 147152da9a59SGnoCiYeH return; 147252da9a59SGnoCiYeH } else if c == 'R' { 147352da9a59SGnoCiYeH self.reset_palette(); 147452da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 147552da9a59SGnoCiYeH } else if c >= '0' && c <= '9' { 147652da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESosc; 147752da9a59SGnoCiYeH } else { 147852da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 147952da9a59SGnoCiYeH } 148052da9a59SGnoCiYeH } 148152da9a59SGnoCiYeH VirtualConsoleState::ESpalette => { 148252da9a59SGnoCiYeH let c = ch as u8 as char; 148352da9a59SGnoCiYeH if c.is_digit(16) { 148452da9a59SGnoCiYeH self.npar += 1; 148552da9a59SGnoCiYeH self.par[self.npar as usize] = c.to_digit(16).unwrap(); 148652da9a59SGnoCiYeH 148752da9a59SGnoCiYeH if self.npar == 7 { 148852da9a59SGnoCiYeH let mut i = self.par[0] as usize; 148952da9a59SGnoCiYeH let mut j = 0; 149052da9a59SGnoCiYeH self.palette[i].red = self.par[j] as u16; 149152da9a59SGnoCiYeH j += 1; 149252da9a59SGnoCiYeH self.palette[i].green = self.par[j] as u16; 149352da9a59SGnoCiYeH j += 1; 149452da9a59SGnoCiYeH self.palette[i].blue = self.par[j] as u16; 149552da9a59SGnoCiYeH j += 1; 149652da9a59SGnoCiYeH i += 1; 149752da9a59SGnoCiYeH self.palette[i].red = self.par[j] as u16; 149852da9a59SGnoCiYeH j += 1; 149952da9a59SGnoCiYeH self.palette[i].green = self.par[j] as u16; 150052da9a59SGnoCiYeH j += 1; 150152da9a59SGnoCiYeH self.palette[i].blue = self.par[j] as u16; 150252da9a59SGnoCiYeH self.set_palette(); 150352da9a59SGnoCiYeH self.vc_state = VirtualConsoleState::ESnormal; 150452da9a59SGnoCiYeH } 150552da9a59SGnoCiYeH } 150652da9a59SGnoCiYeH } 150752da9a59SGnoCiYeH VirtualConsoleState::ESosc => {} 150852da9a59SGnoCiYeH VirtualConsoleState::ESapc => {} 150952da9a59SGnoCiYeH VirtualConsoleState::ESpm => {} 151052da9a59SGnoCiYeH VirtualConsoleState::ESdcs => {} 151152da9a59SGnoCiYeH VirtualConsoleState::ESnormal => {} 151252da9a59SGnoCiYeH } 151352da9a59SGnoCiYeH } 151452da9a59SGnoCiYeH 151552da9a59SGnoCiYeH pub(super) fn console_write_normal( 151652da9a59SGnoCiYeH &mut self, 151752da9a59SGnoCiYeH mut tc: u32, 151852da9a59SGnoCiYeH c: u32, 151952da9a59SGnoCiYeH draw: &mut DrawRegion, 152052da9a59SGnoCiYeH ) -> bool { 152152da9a59SGnoCiYeH let mut attr = self.attr; 152252da9a59SGnoCiYeH let himask = self.hi_font_mask; 152352da9a59SGnoCiYeH let charmask = if himask == 0 { 0xff } else { 0x1ff }; 152452da9a59SGnoCiYeH let mut width = 1; 152552da9a59SGnoCiYeH // 表示需不需要反转 152652da9a59SGnoCiYeH let mut invert = false; 152752da9a59SGnoCiYeH if self.utf && !self.display_ctrl { 152852da9a59SGnoCiYeH if FontDesc::is_double_width(c) { 152952da9a59SGnoCiYeH width = 2; 153052da9a59SGnoCiYeH } 153152da9a59SGnoCiYeH } 153252da9a59SGnoCiYeH 153352da9a59SGnoCiYeH let tmp = self.unicode_to_index(tc); 153452da9a59SGnoCiYeH if tmp & (!charmask as i32) != 0 { 153552da9a59SGnoCiYeH if tmp == -1 || tmp == -2 { 153652da9a59SGnoCiYeH return false; 153752da9a59SGnoCiYeH } 153852da9a59SGnoCiYeH 153952da9a59SGnoCiYeH // 未找到 154052da9a59SGnoCiYeH if (!self.utf || self.display_ctrl || c < 128) && c & !charmask == 0 { 154152da9a59SGnoCiYeH tc = c; 154252da9a59SGnoCiYeH } else { 154352da9a59SGnoCiYeH let tmp = self.unicode_to_index(0xfffd); 154452da9a59SGnoCiYeH if tmp < 0 { 154552da9a59SGnoCiYeH invert = true; 154652da9a59SGnoCiYeH let tmp = self.unicode_to_index('?' as u32); 154752da9a59SGnoCiYeH if tmp < 0 { 154852da9a59SGnoCiYeH tc = '?' as u32; 154952da9a59SGnoCiYeH } else { 155052da9a59SGnoCiYeH tc = tmp as u32; 155152da9a59SGnoCiYeH } 155252da9a59SGnoCiYeH 155352da9a59SGnoCiYeH attr = self.invert_attr(); 155452da9a59SGnoCiYeH self.flush(draw); 155552da9a59SGnoCiYeH } 155652da9a59SGnoCiYeH } 155752da9a59SGnoCiYeH } 155852da9a59SGnoCiYeH 155952da9a59SGnoCiYeH loop { 156052da9a59SGnoCiYeH if self.need_wrap || self.insert_mode { 156152da9a59SGnoCiYeH self.flush(draw); 156252da9a59SGnoCiYeH } 156352da9a59SGnoCiYeH if self.need_wrap { 156452da9a59SGnoCiYeH self.carriage_return(); 156552da9a59SGnoCiYeH self.line_feed(); 156652da9a59SGnoCiYeH } 156752da9a59SGnoCiYeH 156852da9a59SGnoCiYeH if self.insert_mode { 156952da9a59SGnoCiYeH self.insert_char(1); 157052da9a59SGnoCiYeH } 157152da9a59SGnoCiYeH 157252da9a59SGnoCiYeH // TODO: 处理unicode screen buf 157352da9a59SGnoCiYeH 157452da9a59SGnoCiYeH if himask != 0 { 157552da9a59SGnoCiYeH tc = ((if tc & 0x100 != 0 { himask as u32 } else { 0 }) | (tc & 0xff)) as u32; 157652da9a59SGnoCiYeH } 157752da9a59SGnoCiYeH 157852da9a59SGnoCiYeH tc |= ((attr as u32) << 8) & (!himask as u32); 157952da9a59SGnoCiYeH 158052da9a59SGnoCiYeH // kwarn!( 158152da9a59SGnoCiYeH // "ch {} pos {} x {} y {} cols {}", 158252da9a59SGnoCiYeH // c as u8 as char, 158352da9a59SGnoCiYeH // self.pos, 158452da9a59SGnoCiYeH // self.state.x, 158552da9a59SGnoCiYeH // self.state.y, 158652da9a59SGnoCiYeH // self.cols, 158752da9a59SGnoCiYeH // ); 158852da9a59SGnoCiYeH self.screen_buf[self.pos] = tc as u16; 158952da9a59SGnoCiYeH 159052da9a59SGnoCiYeH if draw.x.is_none() { 159152da9a59SGnoCiYeH // 设置draw参数 159252da9a59SGnoCiYeH draw.x = Some(self.state.x as u32); 159352da9a59SGnoCiYeH draw.offset = self.pos; 159452da9a59SGnoCiYeH } 159552da9a59SGnoCiYeH 159652da9a59SGnoCiYeH if self.state.x == self.cols - 1 { 159752da9a59SGnoCiYeH // 需要换行? 159852da9a59SGnoCiYeH self.need_wrap = self.autowrap; 159952da9a59SGnoCiYeH draw.size += 1; 160052da9a59SGnoCiYeH } else { 160152da9a59SGnoCiYeH self.state.x += 1; 160252da9a59SGnoCiYeH self.pos += 1; 160352da9a59SGnoCiYeH draw.size += 1; 160452da9a59SGnoCiYeH } 160552da9a59SGnoCiYeH 160652da9a59SGnoCiYeH width -= 1; 160752da9a59SGnoCiYeH if width == 0 { 160852da9a59SGnoCiYeH break; 160952da9a59SGnoCiYeH } 161052da9a59SGnoCiYeH let tmp = self.unicode_to_index(' ' as u32); 161152da9a59SGnoCiYeH tc = if tmp < 0 { ' ' as u32 } else { tmp as u32 }; 161252da9a59SGnoCiYeH } 161352da9a59SGnoCiYeH 161452da9a59SGnoCiYeH if invert { 161552da9a59SGnoCiYeH self.flush(draw); 161652da9a59SGnoCiYeH } 161752da9a59SGnoCiYeH 161852da9a59SGnoCiYeH true 161952da9a59SGnoCiYeH } 162052da9a59SGnoCiYeH 162152da9a59SGnoCiYeH /// ## 当前vc插入nr个字符 162252da9a59SGnoCiYeH fn insert_char(&mut self, nr: usize) { 162352da9a59SGnoCiYeH // TODO: 管理unicode屏幕信息 162452da9a59SGnoCiYeH 162552da9a59SGnoCiYeH let pos = self.pos; 162652da9a59SGnoCiYeH // 把当前位置以后得字符向后移动nr*2位 162752da9a59SGnoCiYeH self.screen_buf[pos..].rotate_right(nr * 2); 162852da9a59SGnoCiYeH 162952da9a59SGnoCiYeH // 把空出来的位置用erase_char填充 163052da9a59SGnoCiYeH for c in &mut self.screen_buf[pos..(pos + nr * 2)] { 163152da9a59SGnoCiYeH *c = self.erase_char 163252da9a59SGnoCiYeH } 163352da9a59SGnoCiYeH 163452da9a59SGnoCiYeH self.need_wrap = false; 163552da9a59SGnoCiYeH 163652da9a59SGnoCiYeH // 更新本行后面部分 163752da9a59SGnoCiYeH self.do_update_region(self.pos, self.cols - self.state.x); 163852da9a59SGnoCiYeH } 163952da9a59SGnoCiYeH 164052da9a59SGnoCiYeH /// ## 更新虚拟控制台指定区域的显示 164152da9a59SGnoCiYeH fn do_update_region(&self, mut start: usize, mut count: usize) { 164252da9a59SGnoCiYeH let ret = self.driver_funcs().con_getxy(self, start); 164352da9a59SGnoCiYeH let (mut x, mut y) = if ret.is_err() { 164452da9a59SGnoCiYeH let offset = start / 2; 164552da9a59SGnoCiYeH (offset % self.cols, offset / self.cols) 164652da9a59SGnoCiYeH } else { 164752da9a59SGnoCiYeH let (tmp_start, tmp_x, tmp_y) = ret.unwrap(); 164852da9a59SGnoCiYeH start = tmp_start; 164952da9a59SGnoCiYeH (tmp_x, tmp_y) 165052da9a59SGnoCiYeH }; 165152da9a59SGnoCiYeH 165252da9a59SGnoCiYeH loop { 165352da9a59SGnoCiYeH // 记录当前字符的属性 165452da9a59SGnoCiYeH let mut attr = self.screen_buf[start] & 0xff00; 165552da9a59SGnoCiYeH let mut startx = x; 165652da9a59SGnoCiYeH let mut size = 0; 165752da9a59SGnoCiYeH 165852da9a59SGnoCiYeH while count != 0 && x < self.cols { 165952da9a59SGnoCiYeH // 检查属性是否变化,如果属性变了,则将前一个字符先输出 166052da9a59SGnoCiYeH if attr != (self.screen_buf[start] & 0xff00) { 166152da9a59SGnoCiYeH if size > 0 { 166252da9a59SGnoCiYeH let _ = self.driver_funcs().con_putcs( 166352da9a59SGnoCiYeH self, 166452da9a59SGnoCiYeH &self.screen_buf[start..], 166552da9a59SGnoCiYeH size, 166652da9a59SGnoCiYeH y as u32, 166752da9a59SGnoCiYeH startx as u32, 166852da9a59SGnoCiYeH ); 166952da9a59SGnoCiYeH startx = x; 167052da9a59SGnoCiYeH start += size; 167152da9a59SGnoCiYeH size = 0; 167252da9a59SGnoCiYeH attr = self.screen_buf[start] & 0xff00; 167352da9a59SGnoCiYeH } 167452da9a59SGnoCiYeH } 167552da9a59SGnoCiYeH size += 1; 167652da9a59SGnoCiYeH x += 1; 167752da9a59SGnoCiYeH count -= 1; 167852da9a59SGnoCiYeH } 167952da9a59SGnoCiYeH 168052da9a59SGnoCiYeH if size > 0 { 168152da9a59SGnoCiYeH let _ = self.driver_funcs().con_putcs( 168252da9a59SGnoCiYeH self, 168352da9a59SGnoCiYeH &self.screen_buf[start..], 168452da9a59SGnoCiYeH size, 168552da9a59SGnoCiYeH y as u32, 168652da9a59SGnoCiYeH startx as u32, 168752da9a59SGnoCiYeH ); 168852da9a59SGnoCiYeH } 168952da9a59SGnoCiYeH if count == 0 { 169052da9a59SGnoCiYeH break; 169152da9a59SGnoCiYeH } 169252da9a59SGnoCiYeH 169352da9a59SGnoCiYeH // 一行 169452da9a59SGnoCiYeH x = 0; 169552da9a59SGnoCiYeH y += 1; 169652da9a59SGnoCiYeH 169752da9a59SGnoCiYeH let ret = self.driver_funcs().con_getxy(self, start); 169852da9a59SGnoCiYeH if ret.is_ok() { 169952da9a59SGnoCiYeH start = ret.unwrap().0; 170052da9a59SGnoCiYeH } 170152da9a59SGnoCiYeH } 170252da9a59SGnoCiYeH } 170352da9a59SGnoCiYeH 170452da9a59SGnoCiYeH const UNI_DIRECT_MAKS: u32 = 0x01ff; 170552da9a59SGnoCiYeH const UNI_DIRECT_BASE: u32 = 0xf000; 170652da9a59SGnoCiYeH /// ## unicode字符转对应的坐标,暂时这样写,还没有适配unicode 170752da9a59SGnoCiYeH /// 这里是糊代码的,后面重写 170852da9a59SGnoCiYeH fn unicode_to_index(&self, ch: u32) -> i32 { 170952da9a59SGnoCiYeH if ch > 0xfff { 171052da9a59SGnoCiYeH // 未找到 171152da9a59SGnoCiYeH return -4; 171252da9a59SGnoCiYeH } else if ch < 0x20 { 171352da9a59SGnoCiYeH // 不可打印 171452da9a59SGnoCiYeH return -1; 171552da9a59SGnoCiYeH } else if ch == 0xfeff || (ch >= 0x200b && ch <= 0x200f) { 171652da9a59SGnoCiYeH // 零长空格 171752da9a59SGnoCiYeH return -2; 171852da9a59SGnoCiYeH } else if (ch & !Self::UNI_DIRECT_MAKS) == Self::UNI_DIRECT_BASE { 171952da9a59SGnoCiYeH return (ch & Self::UNI_DIRECT_MAKS) as i32; 172052da9a59SGnoCiYeH } 172152da9a59SGnoCiYeH 172252da9a59SGnoCiYeH // TODO: 暂时这样写,表示不支持 172352da9a59SGnoCiYeH return -3; 172452da9a59SGnoCiYeH } 172552da9a59SGnoCiYeH 172652da9a59SGnoCiYeH fn invert_attr(&self) -> u8 { 172752da9a59SGnoCiYeH if !self.color_mode { 172852da9a59SGnoCiYeH return self.attr ^ 0x08; 172952da9a59SGnoCiYeH } 173052da9a59SGnoCiYeH 173152da9a59SGnoCiYeH if self.hi_font_mask == 0x100 { 173252da9a59SGnoCiYeH return (self.attr & 0x11) | ((self.attr & 0xe0) >> 4) | ((self.attr & 0x0e) << 4); 173352da9a59SGnoCiYeH } 173452da9a59SGnoCiYeH 173552da9a59SGnoCiYeH return (self.attr & 0x88) | ((self.attr & 0x70) >> 4) | ((self.attr & 0x07) << 4); 173652da9a59SGnoCiYeH } 173752da9a59SGnoCiYeH 173852da9a59SGnoCiYeH pub(super) fn flush(&self, draw: &mut DrawRegion) { 173952da9a59SGnoCiYeH if draw.x.is_none() { 174052da9a59SGnoCiYeH return; 174152da9a59SGnoCiYeH } 174252da9a59SGnoCiYeH 174352da9a59SGnoCiYeH let _ = self.driver_funcs().con_putcs( 174452da9a59SGnoCiYeH self, 174552da9a59SGnoCiYeH &self.screen_buf[draw.offset..draw.offset + draw.size], 174652da9a59SGnoCiYeH draw.size, 174752da9a59SGnoCiYeH self.state.y as u32, 174852da9a59SGnoCiYeH draw.x.unwrap() as u32, 174952da9a59SGnoCiYeH ); 175052da9a59SGnoCiYeH 175152da9a59SGnoCiYeH draw.x = None; 175252da9a59SGnoCiYeH draw.size = 0; 175352da9a59SGnoCiYeH } 175452da9a59SGnoCiYeH 175552da9a59SGnoCiYeH fn build_attr( 175652da9a59SGnoCiYeH &self, 175752da9a59SGnoCiYeH color: u8, 175852da9a59SGnoCiYeH intensity: VirtualConsoleIntensity, 175952da9a59SGnoCiYeH blink: bool, 176052da9a59SGnoCiYeH underline: bool, 176152da9a59SGnoCiYeH reverse: bool, 176252da9a59SGnoCiYeH italic: bool, 176352da9a59SGnoCiYeH ) -> u8 { 176452da9a59SGnoCiYeH let ret = self 176552da9a59SGnoCiYeH .driver_funcs() 176652da9a59SGnoCiYeH .con_build_attr(self, color, intensity, blink, underline, reverse, italic); 176752da9a59SGnoCiYeH 176852da9a59SGnoCiYeH if ret.is_ok() { 176952da9a59SGnoCiYeH return ret.unwrap(); 177052da9a59SGnoCiYeH } 177152da9a59SGnoCiYeH 177252da9a59SGnoCiYeH let mut ret = color; 177352da9a59SGnoCiYeH 177452da9a59SGnoCiYeH if !self.color_mode { 177552da9a59SGnoCiYeH return intensity as u8 177652da9a59SGnoCiYeH | (italic as u8) << 1 177752da9a59SGnoCiYeH | (underline as u8) << 2 177852da9a59SGnoCiYeH | (reverse as u8) << 3 177952da9a59SGnoCiYeH | (blink as u8) << 7; 178052da9a59SGnoCiYeH } 178152da9a59SGnoCiYeH 178252da9a59SGnoCiYeH if italic { 178352da9a59SGnoCiYeH ret = (ret & 0xf0) | self.italic_color as u8; 178452da9a59SGnoCiYeH } else if underline { 178552da9a59SGnoCiYeH ret = (ret & 0xf0) | self.underline_color as u8; 178652da9a59SGnoCiYeH } else if intensity == VirtualConsoleIntensity::VciHalfBright { 178752da9a59SGnoCiYeH ret = (ret & 0xf0) | self.half_color as u8; 178852da9a59SGnoCiYeH } 178952da9a59SGnoCiYeH 179052da9a59SGnoCiYeH if reverse { 179152da9a59SGnoCiYeH ret = (ret & 0x88) | (((ret >> 4) | (ret << 4)) & 0x77); 179252da9a59SGnoCiYeH } 179352da9a59SGnoCiYeH 179452da9a59SGnoCiYeH if blink { 179552da9a59SGnoCiYeH ret ^= 0x80; 179652da9a59SGnoCiYeH } 179752da9a59SGnoCiYeH 179852da9a59SGnoCiYeH if intensity == VirtualConsoleIntensity::VciBold { 179952da9a59SGnoCiYeH ret ^= 0x08; 180052da9a59SGnoCiYeH } 180152da9a59SGnoCiYeH 180252da9a59SGnoCiYeH if self.hi_font_mask == 0x100 { 180352da9a59SGnoCiYeH ret <<= 1; 180452da9a59SGnoCiYeH } 180552da9a59SGnoCiYeH 180652da9a59SGnoCiYeH ret 180752da9a59SGnoCiYeH } 180852da9a59SGnoCiYeH 180952da9a59SGnoCiYeH pub(super) fn update_attr(&mut self) { 181052da9a59SGnoCiYeH self.attr = self.build_attr( 181152da9a59SGnoCiYeH self.state.color, 181252da9a59SGnoCiYeH self.state.intensity, 181352da9a59SGnoCiYeH self.state.blink, 181452da9a59SGnoCiYeH self.state.underline, 181552da9a59SGnoCiYeH self.state.reverse ^ self.screen_mode, 181652da9a59SGnoCiYeH self.state.italic, 181752da9a59SGnoCiYeH ); 181852da9a59SGnoCiYeH 181952da9a59SGnoCiYeH self.erase_char = ' ' as u16 182052da9a59SGnoCiYeH | ((self.build_attr( 182152da9a59SGnoCiYeH self.state.color, 182252da9a59SGnoCiYeH VirtualConsoleIntensity::VciNormal, 182352da9a59SGnoCiYeH self.state.blink, 182452da9a59SGnoCiYeH false, 182552da9a59SGnoCiYeH self.screen_mode, 182652da9a59SGnoCiYeH false, 182752da9a59SGnoCiYeH ) as u16) 182852da9a59SGnoCiYeH << 8); 182952da9a59SGnoCiYeH } 183052da9a59SGnoCiYeH 183152da9a59SGnoCiYeH fn default_attr(&mut self) { 183252da9a59SGnoCiYeH self.state.intensity = VirtualConsoleIntensity::VciNormal; 183352da9a59SGnoCiYeH self.state.italic = false; 183452da9a59SGnoCiYeH self.state.underline = false; 183552da9a59SGnoCiYeH self.state.reverse = false; 183652da9a59SGnoCiYeH self.state.blink = false; 183752da9a59SGnoCiYeH self.state.color = self.def_color; 183852da9a59SGnoCiYeH } 183952da9a59SGnoCiYeH } 184052da9a59SGnoCiYeH 184152da9a59SGnoCiYeH /// ## 虚拟控制台的状态信息 184252da9a59SGnoCiYeH #[derive(Debug, Default, Clone)] 184352da9a59SGnoCiYeH pub struct VirtualConsoleInfo { 184452da9a59SGnoCiYeH // x,y表示光标坐标 184552da9a59SGnoCiYeH pub x: usize, 184652da9a59SGnoCiYeH pub y: usize, 184752da9a59SGnoCiYeH pub color: u8, 184852da9a59SGnoCiYeH 184952da9a59SGnoCiYeH /// 表示字符的强度 185052da9a59SGnoCiYeH intensity: VirtualConsoleIntensity, 185152da9a59SGnoCiYeH /// 斜体 185252da9a59SGnoCiYeH italic: bool, 185352da9a59SGnoCiYeH /// 下划线 185452da9a59SGnoCiYeH underline: bool, 185552da9a59SGnoCiYeH /// 字符闪烁 185652da9a59SGnoCiYeH blink: bool, 185752da9a59SGnoCiYeH /// 前景与背景色反转 185852da9a59SGnoCiYeH reverse: bool, 185952da9a59SGnoCiYeH } 186052da9a59SGnoCiYeH 186152da9a59SGnoCiYeH impl VirtualConsoleInfo { 186252da9a59SGnoCiYeH pub fn new(x: usize, y: usize) -> Self { 186352da9a59SGnoCiYeH Self { 186452da9a59SGnoCiYeH x, 186552da9a59SGnoCiYeH y, 186652da9a59SGnoCiYeH color: Default::default(), 186752da9a59SGnoCiYeH intensity: Default::default(), 186852da9a59SGnoCiYeH italic: Default::default(), 186952da9a59SGnoCiYeH underline: Default::default(), 187052da9a59SGnoCiYeH blink: Default::default(), 187152da9a59SGnoCiYeH reverse: Default::default(), 187252da9a59SGnoCiYeH } 187352da9a59SGnoCiYeH } 187452da9a59SGnoCiYeH } 187552da9a59SGnoCiYeH 187652da9a59SGnoCiYeH /// 字符强度 187752da9a59SGnoCiYeH #[derive(Debug, Clone, PartialEq, Copy)] 187852da9a59SGnoCiYeH pub enum VirtualConsoleIntensity { 187952da9a59SGnoCiYeH /// 暗淡 188052da9a59SGnoCiYeH VciHalfBright = 0, 188152da9a59SGnoCiYeH /// 正常 188252da9a59SGnoCiYeH VciNormal = 1, 188352da9a59SGnoCiYeH /// 粗体 188452da9a59SGnoCiYeH VciBold = 2, 188552da9a59SGnoCiYeH } 188652da9a59SGnoCiYeH 188752da9a59SGnoCiYeH impl Default for VirtualConsoleIntensity { 188852da9a59SGnoCiYeH fn default() -> Self { 188952da9a59SGnoCiYeH Self::VciNormal 189052da9a59SGnoCiYeH } 189152da9a59SGnoCiYeH } 189252da9a59SGnoCiYeH 189352da9a59SGnoCiYeH /// ## 虚拟控制台的状态 189452da9a59SGnoCiYeH /// 189552da9a59SGnoCiYeH /// 可以把VC的接收字符理解为一个状态机 189652da9a59SGnoCiYeH #[derive(Debug, PartialEq, Clone)] 189752da9a59SGnoCiYeH pub enum VirtualConsoleState { 189852da9a59SGnoCiYeH /// 正常状态 189952da9a59SGnoCiYeH ESnormal, 190052da9a59SGnoCiYeH /// 收到了转义字符 \e,即"Escape"字符 190152da9a59SGnoCiYeH ESesc, 190252da9a59SGnoCiYeH /// 收到了 "[" 字符,通常是 ANSI 控制序列的开始 190352da9a59SGnoCiYeH ESsquare, 190452da9a59SGnoCiYeH /// 解析参数状态 190552da9a59SGnoCiYeH ESgetpars, 190652da9a59SGnoCiYeH /// 功能键状态 190752da9a59SGnoCiYeH ESfunckey, 190852da9a59SGnoCiYeH /// 收到了 "#" 字符 190952da9a59SGnoCiYeH EShash, 191052da9a59SGnoCiYeH /// 设置 G0 字符集状态 191152da9a59SGnoCiYeH ESsetG0, 191252da9a59SGnoCiYeH /// 设置 G1 字符集状态 191352da9a59SGnoCiYeH ESsetG1, 191452da9a59SGnoCiYeH /// 收到了 "%" 字符 191552da9a59SGnoCiYeH ESpercent, 191652da9a59SGnoCiYeH /// 忽略 ANSI 控制序列状态 191752da9a59SGnoCiYeH EScsiignore, 191852da9a59SGnoCiYeH /// 非标准字符状态 191952da9a59SGnoCiYeH ESnonstd, 192052da9a59SGnoCiYeH /// 调色板状态 192152da9a59SGnoCiYeH ESpalette, 192252da9a59SGnoCiYeH /// Operating System Command (OSC) 状态 192352da9a59SGnoCiYeH ESosc, 192452da9a59SGnoCiYeH /// Application Program Command (APC) 状态 192552da9a59SGnoCiYeH ESapc, 192652da9a59SGnoCiYeH /// Privacy Message (PM) 状态 192752da9a59SGnoCiYeH ESpm, 192852da9a59SGnoCiYeH /// Device Control String (DCS) 状态 192952da9a59SGnoCiYeH ESdcs, 193052da9a59SGnoCiYeH } 193152da9a59SGnoCiYeH 193252da9a59SGnoCiYeH impl VirtualConsoleState { 193352da9a59SGnoCiYeH pub fn is_ansi_control_string(&self) -> bool { 193452da9a59SGnoCiYeH if *self == Self::ESosc 193552da9a59SGnoCiYeH || *self == Self::ESapc 193652da9a59SGnoCiYeH || *self == Self::ESpm 193752da9a59SGnoCiYeH || *self == Self::ESdcs 193852da9a59SGnoCiYeH { 193952da9a59SGnoCiYeH return true; 194052da9a59SGnoCiYeH } 194152da9a59SGnoCiYeH 194252da9a59SGnoCiYeH false 194352da9a59SGnoCiYeH } 194452da9a59SGnoCiYeH } 194552da9a59SGnoCiYeH 194652da9a59SGnoCiYeH #[derive(Debug, Clone, PartialEq, PartialOrd)] 194752da9a59SGnoCiYeH #[allow(non_camel_case_types)] 194852da9a59SGnoCiYeH pub enum Vt102_OP { 194952da9a59SGnoCiYeH EPecma, 195052da9a59SGnoCiYeH EPdec, 195152da9a59SGnoCiYeH EPeq, 195252da9a59SGnoCiYeH EPgt, 195352da9a59SGnoCiYeH EPlt, 195452da9a59SGnoCiYeH } 195552da9a59SGnoCiYeH 195652da9a59SGnoCiYeH bitflags! { 195752da9a59SGnoCiYeH #[derive(Default)] 195852da9a59SGnoCiYeH pub struct VcCursor: u32 { 195952da9a59SGnoCiYeH /// 默认 196052da9a59SGnoCiYeH const CUR_DEF = 0; 196152da9a59SGnoCiYeH /// 无光标 196252da9a59SGnoCiYeH const CUR_NONE = 1; 196352da9a59SGnoCiYeH /// 下划线形式 196452da9a59SGnoCiYeH const CUR_UNDERLINE = 2; 196552da9a59SGnoCiYeH /// 光标占据底部的三分之一 196652da9a59SGnoCiYeH const CUR_LOWER_THIRD = 3; 196752da9a59SGnoCiYeH /// 光标占据底部的一半 196852da9a59SGnoCiYeH const CUR_LOWER_HALF = 4; 196952da9a59SGnoCiYeH /// 光标占据底部的三分之二 197052da9a59SGnoCiYeH const CUR_TWO_THIRDS = 5; 197152da9a59SGnoCiYeH /// 光标为块状(方块)形式 197252da9a59SGnoCiYeH const CUR_BLOCK = 6; 197352da9a59SGnoCiYeH /// 光标属性,用于指示软件光标 197452da9a59SGnoCiYeH const CUR_SW = 0x000010; 197552da9a59SGnoCiYeH /// 光标属性,用于指示光标是否始终在背景上显示 197652da9a59SGnoCiYeH const CUR_ALWAYS_BG = 0x000020; 197752da9a59SGnoCiYeH /// 光标属性,用于指示前景和背景是否反转 197852da9a59SGnoCiYeH const CUR_INVERT_FG_BG = 0x000040; 197952da9a59SGnoCiYeH /// 光标前景色属性,用于指定光标的前景色 198052da9a59SGnoCiYeH const CUR_FG = 0x000700; 198152da9a59SGnoCiYeH /// 光标背景色属性,用于指定光标的背景色 198252da9a59SGnoCiYeH const CUR_BG = 0x007000; 198352da9a59SGnoCiYeH } 198452da9a59SGnoCiYeH } 198552da9a59SGnoCiYeH 198652da9a59SGnoCiYeH impl VcCursor { 198752da9a59SGnoCiYeH pub fn make_cursor(size: u32, change: u32, set: u32) -> Self { 198852da9a59SGnoCiYeH unsafe { Self::from_bits_unchecked(size | (change << 8) | (set << 16)) } 198952da9a59SGnoCiYeH } 199052da9a59SGnoCiYeH 199152da9a59SGnoCiYeH pub fn cursor_size(&self) -> Self { 199252da9a59SGnoCiYeH Self::from_bits_truncate(self.bits & 0x00000f) 199352da9a59SGnoCiYeH } 199452da9a59SGnoCiYeH 199552da9a59SGnoCiYeH pub fn cursor_set(&self) -> u32 { 199652da9a59SGnoCiYeH (self.bits & 0xff0000) >> 8 199752da9a59SGnoCiYeH } 199852da9a59SGnoCiYeH 199952da9a59SGnoCiYeH pub fn cursor_change(&self) -> u32 { 200052da9a59SGnoCiYeH self.bits & 0x00ff00 200152da9a59SGnoCiYeH } 200252da9a59SGnoCiYeH } 200352da9a59SGnoCiYeH 200452da9a59SGnoCiYeH #[derive(Debug, PartialEq)] 200552da9a59SGnoCiYeH #[allow(dead_code)] 200652da9a59SGnoCiYeH pub enum CursorOperation { 200752da9a59SGnoCiYeH Draw, 200852da9a59SGnoCiYeH Erase, 200952da9a59SGnoCiYeH Move, 201052da9a59SGnoCiYeH } 201152da9a59SGnoCiYeH 201252da9a59SGnoCiYeH #[derive(Debug, PartialEq, Clone, Copy)] 201352da9a59SGnoCiYeH pub enum ScrollDir { 201452da9a59SGnoCiYeH Up, 201552da9a59SGnoCiYeH Down, 201652da9a59SGnoCiYeH } 2017