diff --git a/Makefile b/Makefile
index 5ab6f56..d8b498d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
-CCFLAGS := -Wall -Wextra -Wpedantic -Werror -std=c99 -D_DEFAULT_SOURCE
+CFLAGS := -Wall -Wextra -Wpedantic -Werror -std=c99
 
 kilo: kilo.c
-	$(CC) $(CCFLAGS) kilo.c -o kilo
+	$(CC) $(CFLAGS) kilo.c -o kilo
 
 clean:
 	rm -f ./kilo
diff --git a/kilo.c b/kilo.c
index e4165b8..c05c5ba 100644
--- a/kilo.c
+++ b/kilo.c
@@ -1,6 +1,11 @@
+#define _BSD_SOURCE
+#define _DEFAULT_SOURCE
+#define _GNU_SOURCE
+
 #include <ctype.h>
 #include <errno.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -12,12 +17,17 @@
 
 /*****************************************************************************/
 
+struct screen_buf;
+struct input_buf;
+
+typedef uint16_t KEY;
+
 struct {
     struct termios orig_termios;
-    int rows;
-    int cols;
-    int cx, cy;
     struct input_buf *ib;
+    int screenrows, screencols;
+    int cx, cy;
+    bool running;
 } E;
 
 enum keys {
@@ -33,16 +43,24 @@ enum keys {
     NOP
 };
 
-struct screen_buf;
-struct input_buf;
-
 /*****************************************************************************/
 
 void editor_init();
 void editor_redraw_screen();
 void editor_draw_rows(struct screen_buf *);
 void editor_process_key();
-int editor_read_key();
+void editor_free();
+
+struct screen_buf *sb_init();
+void sb_append(struct screen_buf *, const char *);
+void sb_write(struct screen_buf *);
+void sb_free(struct screen_buf *);
+
+struct input_buf *ib_init(size_t);
+KEY ib_read(struct input_buf *);
+void ib_write(struct input_buf *, KEY);
+bool ib_empty(struct input_buf *);
+void ib_free(struct input_buf *);
 
 int term_enable_raw();
 void term_disable_raw();
@@ -51,17 +69,8 @@ int term_cursor_hidden(bool);
 int term_get_win_size(int *, int *);
 int term_get_cursor_pos(int *, int *);
 int term_set_cursor_pos(int, int);
+KEY term_read_key();
 
-struct screen_buf *sb_init();
-void sb_append(struct screen_buf *, const char *);
-void sb_free(struct screen_buf *);
-void sb_write(struct screen_buf *);
-
-struct input_buf *ib_init(size_t);
-int ib_read(struct input_buf *);
-void ib_write(struct input_buf *, int);
-bool ib_empty(struct input_buf *);
-void ib_free(struct input_buf *);
 
 void die(const char *);
 
@@ -70,11 +79,12 @@ void die(const char *);
 int main() {
     editor_init();
 
-    while (1) {
+    while (E.running) {
         editor_redraw_screen();
         editor_process_key();
     }
 
+    editor_free();
     return 0;
 }
 
@@ -87,10 +97,12 @@ void editor_init() {
     }
 
     if (term_enable_raw() == -1) die("term_enable_raw");
-    if (term_get_win_size(&E.rows, &E.cols) == -1) die("term_get_win_size");
+
+    if (term_get_win_size(&E.screenrows, &E.screencols) == -1) die("term_get_win_size");
 
     E.cx = E.cy = 0;
     E.ib = ib_init(128);
+    E.running = true;
 }
 
 void editor_redraw_screen() {
@@ -108,92 +120,133 @@ void editor_redraw_screen() {
 void editor_draw_rows(struct screen_buf *sb) {
     term_set_cursor_pos(1, 1);
 
-    for (int y = 0; y < E.rows; y++) {
+    for (int y = 0; y < E.screenrows; y++) {
         sb_append(sb, "~");
 
         sb_append(sb, "\x1b[K"); // Clear rest of the line
-        if (y < E.rows - 1) sb_append(sb, "\r\n");
+        if (y < E.screenrows - 1) sb_append(sb, "\r\n");
     }
 }
 
 
 void editor_process_key() {
-    int c = editor_read_key();
+    KEY c = ib_read(E.ib);
 
     switch (c) {
-        case CTRL_KEY('Q'):
-            term_clear();
-            exit(0);
-            break;
-
         case ARROW_LEFT:
             if (E.cx > 0) E.cx--;
             break;
         case ARROW_DOWN:
-            if (E.cy < E.rows - 1) E.cy++;
+            if (E.cy < E.screenrows - 1) E.cy++;
             break;
         case ARROW_UP:
             if (E.cy > 0) E.cy--;
             break;
         case ARROW_RIGHT:
-            if (E.cx < E.cols - 1) E.cx++;
+            if (E.cx < E.screencols - 1) E.cx++;
+            break;
+
+        case HOME:
+            E.cx = 0;
+            break;
+        case END:
+            E.cx = E.screencols - 1;
+            break;
+
+        case PG_UP:
+        case PG_DOWN:
+            for (int i = 0; i < E.screenrows; i++)
+                 ib_write(E.ib, (c == PG_UP ? ARROW_UP : ARROW_DOWN));
+            break;
+
+        case CTRL_KEY('Q'):
+            E.running = false;
             break;
     }
 }
 
-int editor_read_key() {
-    // TODO: There's better ways to do this.
-    // Somehow make everything go through the input buffer
-    if (!ib_empty(E.ib))
-        return ib_read(E.ib);
+void editor_free() {
+    term_clear();
+    ib_free(E.ib);
+}
 
-    char c;
-    while (read(STDIN_FILENO, &c, 1) == 0);
+/*****************************************************************************/
 
-    if (c == '\x1b') {
-        char buf[8];
+struct screen_buf {
+    char *s;
+    size_t size;
+};
 
-        for (size_t i = 0; i < sizeof(buf); i++) {
-            if (read(STDIN_FILENO, buf+i, 1) == 0) {
-                buf[i] = '\0';
-                break;
-            }
-        }
+struct screen_buf *sb_init() {
+    struct screen_buf *sb = (struct screen_buf *) malloc(sizeof(struct screen_buf));
 
-        char escape_char;
-        if (sscanf(buf, "[%c~", &escape_char) != EOF) {
-            switch (escape_char) {
-                case 'A': return ARROW_UP;
-                case 'B': return ARROW_DOWN;
-                case 'C': return ARROW_RIGHT;
-                case 'D': return ARROW_LEFT;
-                case 'H': return HOME;
-                case 'F': return END;
-            }
-        }
+    sb->s = NULL;
+    sb->size = 0;
 
-        int escape_int;
-        if (sscanf(buf, "[%d~", &escape_int) != EOF) {
-            switch (escape_int) {
-                case 1:
-                case 7:
-                    return HOME;
-                case 3:
-                    return DEL;
-                case 4:
-                case 8:
-                    return END;
-                case 5:
-                    return PG_UP;
-                case 6:
-                    return PG_DOWN;
-            }
-        }
+    return sb;
+}
 
-        return NOP;
-    }
+void sb_append(struct screen_buf *sb, const char *s) {
+    int size = strlen(s);
 
-    return (int) c;
+    sb->s = realloc(sb->s, sb->size + size);
+    memcpy(sb->s + sb->size, s, size);
+
+    sb->size += size;
+}
+
+void sb_write(struct screen_buf *sb) {
+    write(STDOUT_FILENO, sb->s, sb->size);
+}
+
+void sb_free(struct screen_buf *sb) {
+    free(sb->s);
+    free(sb);
+}
+
+
+struct input_buf {
+    KEY *carr; // Circular array
+    int read_i;
+    int write_i;
+    size_t capacity; // Actual capacity is one less
+};
+
+struct input_buf *ib_init(size_t capacity) {
+    struct input_buf *ib = (struct input_buf *) malloc(sizeof(struct input_buf));
+
+    ib->carr = (KEY *) malloc(sizeof(KEY) * capacity);
+    ib->write_i = 0;
+    ib->read_i  = 0;
+    ib->capacity = capacity;
+
+    return ib;
+}
+
+void ib_write(struct input_buf *ib, KEY key) {
+    if ((ib->write_i + 1) % (int) ib->capacity == ib->read_i) // Buffer full
+        die("ib_write");
+
+    ib->carr[ib->write_i] = key;
+    ib->write_i = (ib->write_i + 1) % ib->capacity;
+}
+
+KEY ib_read(struct input_buf *ib) {
+    if (ib_empty(ib)) ib_write(ib, term_read_key());
+
+    KEY key = ib->carr[ib->read_i];
+    ib->read_i = (ib->read_i + 1) % ib->capacity;
+
+    return key;
+}
+
+bool ib_empty(struct input_buf *ib) {
+    return ib->write_i == ib->read_i;
+}
+
+void ib_free(struct input_buf *ib) {
+    free(ib->carr);
+    free(ib);
 }
 
 /*****************************************************************************/
@@ -206,7 +259,7 @@ int term_enable_raw() {
     cfmakeraw(&raw);
 
     raw.c_cc[VMIN]  = 0;
-    raw.c_cc[VTIME] = 1;
+    raw.c_cc[VTIME] = 10;
 
     if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) == -1) return -1;
 
@@ -275,83 +328,52 @@ int term_set_cursor_pos(int row, int col) {
     return 0;
 }
 
-/*****************************************************************************/
+KEY term_read_key() {
+    char c;
+    while (read(STDIN_FILENO, &c, 1) == 0);
 
-struct screen_buf {
-    char *s;
-    size_t size;
-};
+    if (c == '\x1b') {
+        char buf[8] = { '\0' };
 
-struct screen_buf *sb_init() {
-    struct screen_buf *sb = (struct screen_buf *) malloc(sizeof(struct screen_buf));
+        // Inefficient but I like the way it looks
+        for (size_t i = 0; i < sizeof(buf); i++) {
+            if (read(STDIN_FILENO, buf+i, 1) == 0) break;
 
-    sb->s = NULL;
-    sb->size = 0;
+            char escape_char;
+            if (sscanf(buf, "[%c~", &escape_char) != EOF) {
+                switch (escape_char) {
+                    case 'A': return ARROW_UP;
+                    case 'B': return ARROW_DOWN;
+                    case 'C': return ARROW_RIGHT;
+                    case 'D': return ARROW_LEFT;
+                    case 'H': return HOME;
+                    case 'F': return END;
+                }
+            }
 
-    return sb;
-}
+            int escape_int;
+            if (sscanf(buf, "[%d~", &escape_int) != EOF) {
+                switch (escape_int) {
+                    case 1:
+                    case 7:
+                        return HOME;
+                    case 3:
+                        return DEL;
+                    case 4:
+                    case 8:
+                        return END;
+                    case 5:
+                        return PG_UP;
+                    case 6:
+                        return PG_DOWN;
+                }
+            }
+        }
 
-void sb_append(struct screen_buf *sb, const char *s) {
-    int size = strlen(s);
+        return NOP;
+    }
 
-    sb->s = realloc(sb->s, sb->size + size);
-    memcpy(sb->s + sb->size, s, size);
-
-    sb->size += size;
-}
-
-void sb_write(struct screen_buf *sb) {
-    write(STDOUT_FILENO, sb->s, sb->size);
-}
-
-void sb_free(struct screen_buf *sb) {
-    free(sb->s);
-    free(sb);
-}
-
-
-struct input_buf {
-    int *carr; // Circular array
-    int read_i;
-    int write_i;
-    size_t capacity; // Actual capacity is one less
-};
-
-struct input_buf *ib_init(size_t capacity) {
-    struct input_buf *ib = (struct input_buf *) malloc(sizeof(struct input_buf));
-
-    ib->carr = (int *) malloc(sizeof(int) * capacity);
-    ib->write_i = 0;
-    ib->read_i  = 0;
-    ib->capacity = capacity;
-
-    return ib;
-}
-
-void ib_write(struct input_buf *ib, int key) {
-    if ((ib->write_i + 1) % (int) ib->capacity == ib->read_i) // Buffer full
-        die("ib_write");
-
-    ib->carr[ib->write_i] = key;
-    ib->write_i = (ib->write_i + 1) % ib->capacity;
-}
-
-int ib_read(struct input_buf *ib) {
-    if (ib_empty(ib)) die("ib_read");
-
-    int key = ib->carr[ib->read_i];
-    ib->read_i = (ib->read_i + 1) % ib->capacity;
-
-    return key;
-}
-
-bool ib_empty(struct input_buf *ib) {
-    return ib->write_i == ib->read_i;
-}
-
-void ib_free(struct input_buf *ib) {
-    free(ib->carr);
-    free(ib);
+    return (KEY) c;
 }
 
 /*****************************************************************************/