diff --git a/Cargo.lock b/Cargo.lock
index ce0b4d0056ed5ab3ceadc477f63fa2dc6728fa59..e3d3a4409e4fbd07382d1ddb4bed662c0bc87e65 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,9 +1,9 @@
 [root]
 name = "orbutils"
-version = "0.1.4"
+version = "0.1.5"
 dependencies = [
- "orbclient 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "orbtk 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "orbclient 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "orbtk 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -32,7 +32,7 @@ dependencies = [
 
 [[package]]
 name = "orbclient"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "sdl2 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -40,10 +40,10 @@ dependencies = [
 
 [[package]]
 name = "orbtk"
-version = "0.1.0"
+version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "orbclient 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "orbclient 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 54e12f6d2523895f0ce756bf1cff086f85abb8be..9da4efb95a13dcbabe06f98035c3013bba1bbbf8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,7 +2,7 @@
 name = "orbutils"
 description = "The Orbital Utilities"
 repository = "https://github.com/redox-os/orbutils"
-version = "0.1.5"
+version = "0.1.6"
 license-file = "LICENSE"
 readme = "README.md"
 authors = ["Jeremy Soller <jackpot51@gmail.com>"]
diff --git a/src/launcher/main.rs b/src/launcher/main.rs
index e030c13209a25b512c9b8e49786b7b9a92fcf18c..c476d2ac0f6614f9319a77148742bf3a783f1314 100644
--- a/src/launcher/main.rs
+++ b/src/launcher/main.rs
@@ -174,7 +174,7 @@ fn main() {
             println!("launcher: failed to read shutdown icon");
         }
 
-        let mut window = Window::new(0, 600 - 48, 800, 48, "").unwrap();
+        let mut window = Window::new(0, 768 - 48, 1024, 48, "").unwrap();
 
         draw(&mut window, &packages, &shutdown, -1, -1);
         'running: loop {
diff --git a/src/terminal/console.rs b/src/terminal/console.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5de32e47302feef3566efc9a8f14412476ed1bfb
--- /dev/null
+++ b/src/terminal/console.rs
@@ -0,0 +1,223 @@
+use std::mem;
+
+use orbclient::{Color, Event, EventOption, Window};
+use orbclient::event;
+
+const BLACK: Color = Color::rgb(0, 0, 0);
+const RED: Color = Color::rgb(194, 54, 33);
+const GREEN: Color = Color::rgb(37, 188, 36);
+const YELLOW: Color = Color::rgb(173, 173, 39);
+const BLUE: Color = Color::rgb(73, 46, 225);
+const MAGENTA: Color = Color::rgb(211, 56, 211);
+const CYAN: Color = Color::rgb(51, 187, 200);
+const WHITE: Color = Color::rgb(203, 204, 205);
+
+pub struct Console {
+    pub window: Box<Window>,
+    pub point_x: i32,
+    pub point_y: i32,
+    pub foreground: Color,
+    pub background: Color,
+    pub redraw: bool,
+    pub command: String,
+    pub escape: bool,
+    pub escape_sequence: bool,
+    pub sequence: Vec<String>,
+}
+
+impl Console {
+    pub fn new() -> Console {
+        let mut window = Window::new(-1, -1, 640, 480, "Terminal").unwrap();
+        window.sync();
+        Console {
+            window: window,
+            point_x: 0,
+            point_y: 0,
+            foreground: WHITE,
+            background: BLACK,
+            redraw: true,
+            command: String::new(),
+            escape: false,
+            escape_sequence: false,
+            sequence: Vec::new(),
+        }
+    }
+
+    pub fn code(&mut self, c: char) {
+        if self.escape_sequence {
+            if c >= '0' && c <= '9' {
+                // Add a number to the sequence list
+                if let Some(mut value) = self.sequence.last_mut() {
+                    value.push(c);
+                }
+            } else if c == ';' {
+                // Split sequence into list
+                self.sequence.push(String::new());
+            } else if c == 'm' {
+                // Display attributes
+                for value in self.sequence.iter() {
+                    if value == "0" {
+                        // Reset all
+                        self.foreground = WHITE;
+                        self.background = BLACK;
+                    } else if value == "30" {
+                        self.foreground = BLACK;
+                    } else if value == "31" {
+                        self.foreground = RED;
+                    } else if value == "32" {
+                        self.foreground = GREEN;
+                    } else if value == "33" {
+                        self.foreground = YELLOW;
+                    } else if value == "34" {
+                        self.foreground = BLUE;
+                    } else if value == "35" {
+                        self.foreground = MAGENTA;
+                    } else if value == "36" {
+                        self.foreground = CYAN;
+                    } else if value == "37" {
+                        self.foreground = WHITE;
+                    } else if value == "40" {
+                        self.background = BLACK;
+                    } else if value == "41" {
+                        self.background = RED;
+                    } else if value == "42" {
+                        self.background = GREEN;
+                    } else if value == "43" {
+                        self.background = YELLOW;
+                    } else if value == "44" {
+                        self.background = BLUE;
+                    } else if value == "45" {
+                        self.background = MAGENTA;
+                    } else if value == "46" {
+                        self.background = CYAN;
+                    } else if value == "47" {
+                        self.background = WHITE;
+                    }
+                }
+
+                self.escape_sequence = false;
+            } else {
+                self.escape_sequence = false;
+            }
+
+            if !self.escape_sequence {
+                self.sequence.clear();
+                self.escape = false;
+            }
+        } else if c == '[' {
+            // Control sequence initiator
+
+            self.escape_sequence = true;
+            self.sequence.push(String::new());
+        } else if c == 'c' {
+            // Reset
+            self.point_x = 0;
+            self.point_y = 0;
+            self.foreground = WHITE;
+            self.background = BLACK;
+            self.window.set(self.background);
+            self.redraw = true;
+
+            self.escape = false;
+        } else {
+            // Unknown escape character
+
+            self.escape = false;
+        }
+    }
+
+    pub fn scroll(&mut self, rows: usize) {
+        if rows > 0 && rows < self.window.height() as usize {
+            let offset = rows * self.window.width() as usize;
+            let data = self.window.data_mut();
+            for i in 0..data.len() - offset {
+                let color = data[i + offset];
+                data[i] = color;
+            }
+            for i in data.len() - offset..data.len() {
+                data[i] = self.background;
+            }
+        }
+    }
+
+    pub fn character(&mut self, c: char) {
+        self.window.rect(self.point_x, self.point_y, 8, 16, self.background);
+        if c == '\x00' {
+            // Ignore null character
+        } else if c == '\x1B' {
+            self.escape = true;
+        } else if c == '\n' {
+            self.point_x = 0;
+            self.point_y += 16;
+        } else if c == '\t' {
+            self.point_x = ((self.point_x / 64) + 1) * 64;
+        } else if c == '\x08' {
+            self.point_x -= 8;
+            if self.point_x < 0 {
+                self.point_x = 0
+            }
+            self.window.rect(self.point_x, self.point_y, 8, 16, self.background);
+        } else {
+            self.window.char(self.point_x, self.point_y, c, self.foreground);
+            self.point_x += 8;
+        }
+        if self.point_x >= self.window.width() as i32 {
+            self.point_x = 0;
+            self.point_y += 16;
+        }
+        while self.point_y + 16 > self.window.height() as i32 {
+            self.scroll(16);
+            self.point_y -= 16;
+        }
+        self.window.rect(self.point_x, self.point_y, 8, 16, self.foreground);
+        self.redraw = true;
+    }
+
+    pub fn event(&mut self, event: Event) -> Option<String> {
+        match event.to_option() {
+            EventOption::Key(key_event) => {
+                if key_event.pressed {
+                    match key_event.scancode {
+                        event::K_BKSP => if ! self.command.is_empty() {
+                            self.write(&[8]);
+                            self.command.pop();
+                        },
+                        _ => match key_event.character {
+                            '\0' => (),
+                            c => {
+                                self.command.push(c);
+                                self.write(&[c as u8]);
+
+                                if c == '\n' {
+                                    let mut command = String::new();
+                                    mem::swap(&mut self.command, &mut command);
+                                    return Some(command);
+                                }
+                            }
+                        },
+                    }
+                }
+            },
+            _ => (),
+        }
+
+        None
+    }
+
+    pub fn write(&mut self, bytes: &[u8]) {
+        for byte in bytes.iter() {
+            let c = *byte as char;
+
+            if self.escape {
+                self.code(c);
+            } else {
+                self.character(c);
+            }
+        }
+
+        if self.redraw {
+            self.redraw = false;
+            self.window.sync();
+        }
+    }
+}
diff --git a/src/terminal/main.rs b/src/terminal/main.rs
index 85ddec6637c8707b50bd040b8a8a58b98380116d..16e15ccefbc3a898c6900b36e84a47690aadae70 100644
--- a/src/terminal/main.rs
+++ b/src/terminal/main.rs
@@ -1,6 +1,8 @@
+#![feature(const_fn)]
+
 extern crate orbclient;
 
-use orbclient::Color;
+use orbclient::event;
 
 use std::env;
 use std::io::{self, Read, Write};
@@ -8,9 +10,9 @@ use std::process::{Command, Stdio};
 use std::sync::{Arc, Mutex};
 use std::thread;
 
-use window::{ConsoleEvent, ConsoleWindow};
+use console::Console;
 
-mod window;
+mod console;
 
 fn main() {
     let shell = env::args().nth(1).unwrap_or("sh".to_string());
@@ -76,15 +78,14 @@ fn main() {
             }
 
             let mut stdin = process.stdin.unwrap();
-            let mut window = ConsoleWindow::new(-1, -1, 576, 400, "Terminal");
+            let mut console = Console::new();
             'events: loop {
                 match output_mutex.lock() {
                     Ok(mut output) => {
-                        let mut string = String::new();
-                        for byte in output.drain(..) {
-                            string.push(byte as char);
+                        if ! output.is_empty() {
+                            console.write(&output);
+                            output.clear();
                         }
-                        window.print(&string, Color::rgb(255, 255, 255));
                     },
                     Err(_) => {
                         println!("failed to lock print output mutex");
@@ -92,10 +93,12 @@ fn main() {
                     }
                 }
 
-                for console_event in window.read() {
-                    match console_event {
-                        ConsoleEvent::Line(mut line) => {
-                            line.push('\n');
+                for event in console.window.events_no_wait() {
+                    if event.code == event::EVENT_QUIT {
+                        break 'events;
+                    }
+                    match console.event(event) {
+                        Some(line) => {
                             match stdin.write(&line.as_bytes()) {
                                 Ok(_) => (),
                                 Err(err) => {
@@ -104,7 +107,7 @@ fn main() {
                                 }
                             }
                         },
-                        ConsoleEvent::Quit => break 'events
+                        None => ()
                     }
                 }
 
diff --git a/src/terminal/window.rs b/src/terminal/window.rs
deleted file mode 100644
index 00ead957fb1e2aa156909bc790eb4d8e186c68c0..0000000000000000000000000000000000000000
--- a/src/terminal/window.rs
+++ /dev/null
@@ -1,229 +0,0 @@
-
-use orbclient::*;
-
-/// A console char
-pub struct ConsoleChar {
-    /// The char
-    character: char,
-    /// The color
-    color: Color,
-}
-
-/// A console event
-pub enum ConsoleEvent {
-    Line(String),
-    Quit
-}
-
-/// A console window
-pub struct ConsoleWindow {
-    /// The window
-    pub window: Box<Window>,
-    /// The char buffer
-    pub output: Vec<ConsoleChar>,
-    /// Previous commands
-    pub history: Vec<String>,
-    /// History index
-    pub history_i: u32,
-    /// Offset
-    pub offset: usize,
-    /// Scroll distance x
-    pub scroll_x: i32,
-    /// Scroll distance y
-    pub scroll_y: i32,
-    /// Wrap the text, if true
-    pub wrap: bool,
-}
-
-impl ConsoleWindow {
-    /// Create a new console window
-    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Box<Self> {
-        Box::new(ConsoleWindow {
-            window: Window::new(x, y, w, h, title).unwrap(),
-            output: Vec::new(),
-            history: vec!["".to_string()],
-            history_i: 0,
-            offset: 0,
-            scroll_x: 0,
-            scroll_y: 0,
-            wrap: true,
-        })
-    }
-
-    /// Print to the window
-    pub fn print(&mut self, string: &str, color: Color) {
-        for c in string.chars() {
-            self.output.push(ConsoleChar {
-                character: c,
-                color: color,
-            });
-        }
-        self.sync();
-    }
-
-    /// Read input
-    pub fn read(&mut self) -> Vec<ConsoleEvent> {
-        let mut console_events = Vec::new();
-
-        for event in self.window.events_no_wait() {
-            match event.to_option() {
-                EventOption::Key(key_event) => {
-                    if key_event.pressed {
-                        match key_event.scancode {
-                            K_BKSP => {
-                                if self.offset > 0 {
-                                    self.history[self.history_i as usize] =
-                                        self.history[self.history_i as usize][0..self.offset - 1]
-                                            .to_string() +
-                                        &self.history[self.history_i as usize][self.offset..];
-                                    self.offset -= 1;
-                                }
-                            }
-                            K_DEL => {
-                                if (self.offset) < self.history[self.history_i as usize].len() {
-                                    self.history[self.history_i as usize] =
-                                self.history[self.history_i as usize][0..self.offset].to_string() +
-                                &self.history[self.history_i as usize][self.offset + 1..self.history[self.history_i as usize].len() - 1];
-                                }
-                            }
-                            K_HOME => self.offset = 0,
-                            K_UP => {
-                                if self.history_i as usize + 1 < self.history.len() {
-                                    self.history_i += 1;
-                                }
-                                self.offset = self.history[self.history_i as usize].len();
-                            }
-                            K_LEFT => {
-                                if self.offset > 0 {
-                                    self.offset -= 1;
-                                }
-                            }
-                            K_RIGHT => {
-                                if (self.offset) < self.history[self.history_i as usize].len() {
-                                    self.offset += 1;
-                                }
-                            }
-                            K_END => self.offset = self.history[self.history_i as usize].len(),
-                            K_DOWN => {
-                                if self.history_i > 0 {
-                                    self.history_i -= 1;
-                                }
-                                self.offset = self.history[self.history_i as usize].len();
-                            }
-                            _ => {
-                                match key_event.character {
-                                    '\x00' => (),
-                                    '\n' => {
-                                        let command = self.history[self.history_i as usize].clone();
-                                        self.offset = 0;
-                                        self.history_i = 0;
-                                        if !self.history[0].is_empty() {
-                                            self.history.insert(0, "".to_string());
-                                        }
-                                        while self.history.len() > 1000 {
-                                            self.history.pop();
-                                        }
-                                        self.print(&command, Color::rgb(255, 255, 255));
-                                        self.print("\n", Color::rgb(255, 255, 255));
-                                        console_events.push(ConsoleEvent::Line(command));
-                                    }
-                                    '\x1B' => (),
-                                    _ => {
-                                        self.history[self.history_i as usize] =
-                                            self.history[self.history_i as usize][0..self.offset]
-                                                .to_string() +
-                                            &key_event.character.to_string() +
-                                            &self.history[self.history_i as usize][self.offset..];
-                                        self.offset += 1;
-                                    }
-                                }
-                            }
-                        }
-                        self.sync();
-                    }
-                }
-                EventOption::Quit(_quit_event) => console_events.push(ConsoleEvent::Quit),
-                _ => (),
-            }
-        }
-
-        console_events
-    }
-
-    /// Redraw the window
-    pub fn sync(&mut self) {
-        let scroll_x = self.scroll_x;
-        let scroll_y = self.scroll_y;
-
-        let mut col = -scroll_x;
-        let cols = self.window.width() as i32 / 8;
-        let mut row = -scroll_y;
-        let rows = self.window.height() as i32 / 16;
-
-        {
-            self.window.set(Color::rgb(0, 0, 0));
-
-            for c in self.output.iter() {
-                if self.wrap && col >= cols {
-                    col = -scroll_x;
-                    row += 1;
-                }
-
-                if c.character == '\n' {
-                    col = -scroll_x;
-                    row += 1;
-                } else if c.character == '\t' {
-                    col += 8 - col % 8;
-                } else {
-                    if col >= 0 && col < cols && row >= 0 && row < rows {
-                        self.window.char(8 * col, 16 * row, c.character, c.color);
-                    }
-                    col += 1;
-                }
-            }
-
-            let mut i = 0;
-            for c in self.history[self.history_i as usize].chars() {
-                if self.wrap && col >= cols {
-                    col = -scroll_x;
-                    row += 1;
-                }
-
-                if self.offset == i && col >= 0 && col < cols && row >= 0 && row < rows {
-                    self.window.char(8 * col, 16 * row, '_', Color::rgb(255, 255, 255));
-                }
-
-                if c == '\n' {
-                    col = -scroll_x;
-                    row += 1;
-                } else if c == '\t' {
-                    col += 8 - col % 8;
-                } else {
-                    if col >= 0 && col < cols && row >= 0 && row < rows {
-                        self.window.char(8 * col, 16 * row, c, Color::rgb(255, 255, 255));
-                    }
-                    col += 1;
-                }
-
-                i += 1;
-            }
-
-            if self.wrap && col >= cols {
-                col = -scroll_x;
-                row += 1;
-            }
-
-            if self.offset == i && col >= 0 && col < cols && row >= 0 && row < rows {
-                self.window.char(8 * col, 16 * row, '_', Color::rgb(255, 255, 255));
-            }
-        }
-
-        self.window.sync();
-
-        if row >= rows {
-            self.scroll_y += row - rows + 1;
-
-            self.sync();
-        }
-    }
-}