1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
#![no_std] #[macro_use] extern crate bitflags; extern crate cursebox; extern crate libc; use core::char; use core::marker::PhantomData; use core::mem; use cursebox::*; use libc::c_int; #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Key { Tab, Enter, Esc, Backspace, Right, Left, Up, Down, Delete, Insert, Home, End, PgUp, PgDn, Char(char), Ctrl(char), F(u16), } impl Key { pub fn from_code(code: u16) -> Option<Key> { use Key::*; match code { 8 => Some(Backspace), 9 => Some(Tab), 13 => Some(Enter), 1...26 => Some(Ctrl(unsafe { char::from_u32_unchecked('`' as u32 + code as u32) })), 27 => Some(Esc), 28 => Some(Ctrl('\\')), 29 => Some(Ctrl(']')), 30 => Some(Ctrl('6')), 31 => Some(Ctrl('/')), 32 => Some(Char(' ')), 127 => Some(Backspace), TB_KEY_ARROW_LEFT => Some(Left), TB_KEY_ARROW_RIGHT => Some(Right), TB_KEY_ARROW_UP => Some(Up), TB_KEY_ARROW_DOWN => Some(Down), TB_KEY_INSERT => Some(Insert), TB_KEY_DELETE => Some(Delete), TB_KEY_HOME => Some(Home), TB_KEY_END => Some(End), TB_KEY_PGUP => Some(PgUp), TB_KEY_PGDN => Some(PgDn), TB_KEY_F1 => Some(F( 1)), TB_KEY_F2 => Some(F( 2)), TB_KEY_F3 => Some(F( 3)), TB_KEY_F4 => Some(F( 4)), TB_KEY_F5 => Some(F( 5)), TB_KEY_F6 => Some(F( 6)), TB_KEY_F7 => Some(F( 7)), TB_KEY_F8 => Some(F( 8)), TB_KEY_F9 => Some(F( 9)), TB_KEY_F10 => Some(F(10)), TB_KEY_F11 => Some(F(11)), TB_KEY_F12 => Some(F(12)), _ => None, } } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[repr(C, u16)] pub enum Color { Black = 0x00, Red = 0x01, Green = 0x02, Yellow = 0x03, Blue = 0x04, Magenta = 0x05, Cyan = 0x06, White = 0x07, Default = 0x0F, } bitflags! { #[repr(C)] pub flags Face: u8 { const BOLD = 0x10, const UNDERLINE = 0x20, const REVERSE = 0x40, } } #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Event { Key(Key), Resize(u32, u32), } #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub enum Failure { Unknown, UnsupportedTerminal, FailedToOpenTty, PipeTrapError, } pub struct Term(PhantomData<*mut ()>); impl Term { pub fn init() -> Result<Self, Failure> { let c = unsafe { tb_init() }; if c >= 0 { Ok(Term(PhantomData)) } else { use Failure::*; Err(match c { TB_EUNSUPPORTED_TERMINAL => UnsupportedTerminal, TB_EFAILED_TO_OPEN_TTY => FailedToOpenTty, TB_EPIPE_TRAP_ERROR => PipeTrapError, _ => Unknown, }) } } pub fn width(&self) -> usize { unsafe { tb_width() as usize } } pub fn height(&self) -> usize { unsafe { tb_height() as usize } } pub fn clear(&mut self) { unsafe { tb_clear() } } pub fn freshen(&mut self) { unsafe { tb_present() } } pub fn print_char(&mut self, x_pos: usize, y_pos: usize, face: Face, fg: Color, bg: Color, x: char) { unsafe { tb_change_cell(x_pos as c_int, y_pos as c_int, x as u32, fg as u16 | ((face.bits as u16) << 8), bg as u16) }; } pub fn next_event(&mut self, timeout: Option<u32>) -> Result<Option<Event>, ()> { unsafe { let mut ev: RawEvent = mem::uninitialized(); let c = match timeout { Some(t_msec) => tb_peek_event(&mut ev, t_msec as c_int), None => tb_poll_event(&mut ev), }; if c < 0 { return Err(()) }; match c as u8 { 0 => Ok(None), TB_EVENT_KEY => Ok(if ev.key == 0 { char::from_u32(ev.ch).map(Key::Char) } else { Key::from_code(ev.key) }.map(Event::Key)), TB_EVENT_RESIZE => Ok(Some(Event::Resize(ev.w as u32, ev.h as u32))), _ => Err(()), } } } pub fn set_cursor(&mut self, x: usize, y: usize) { unsafe { tb_set_cursor(x as c_int, y as c_int) } } } impl Drop for Term { #[inline] fn drop(&mut self) { unsafe { tb_shutdown() }; } }