Add keyboard input to terminal.
diff --git a/terminal.c b/terminal.c
index acd4f2b..f0cf76d 100644
--- a/terminal.c
+++ b/terminal.c
@@ -31,6 +31,7 @@
 #include <pty.h>
 #include <cairo.h>
 #include <glib.h>
+#include <linux/input.h>
 
 #include <GL/gl.h>
 #include <eagle.h>
@@ -44,15 +45,20 @@
 static const char gem_device[] = "/dev/dri/card0";
 static const char socket_name[] = "\0wayland";
 
+#define MOD_SHIFT	0x01
+#define MOD_ALT		0x02
+#define MOD_CTRL	0x04
+
 struct terminal {
 	struct window *window;
 	struct wl_display *display;
 	int resize_scheduled;
 	char *data;
 	int width, height, tail, row, column;
-	int fd;
+	int fd, master;
 	struct buffer *buffer;
 	GIOChannel *channel;
+	uint32_t modifiers;
 };
 
 static void
@@ -118,25 +124,6 @@
 }
 
 static void
-resize_handler(struct window *window, int32_t width, int32_t height, void *data)
-{
-	struct terminal *terminal = data;
-
-	if (!terminal->resize_scheduled) {
-		g_idle_add(idle_redraw, terminal);
-		terminal->resize_scheduled = 1;
-	}
-}
-
-static void
-acknowledge_handler(struct window *window, uint32_t key, void *data)
-{
-	struct terminal *terminal = data;
-
-	terminal->resize_scheduled = 0;
-}
-
-static void
 terminal_data(struct terminal *terminal, const char *data, size_t length)
 {
 	int i;
@@ -166,6 +153,134 @@
 	}
 }
 
+static void
+resize_handler(struct window *window, int32_t width, int32_t height, void *data)
+{
+	struct terminal *terminal = data;
+
+	if (!terminal->resize_scheduled) {
+		g_idle_add(idle_redraw, terminal);
+		terminal->resize_scheduled = 1;
+	}
+}
+
+static void
+acknowledge_handler(struct window *window, uint32_t key, void *data)
+{
+	struct terminal *terminal = data;
+
+	terminal->resize_scheduled = 0;
+}
+
+struct key {
+	int code[2];
+} evdev_keymap[] = {
+	{ { 0, 0 } },		/* 0 */
+	{ { 0x1b, 0x1b } },
+	{ { '1', '!' } },
+	{ { '2', '@' } },
+	{ { '3', '#' } },
+	{ { '4', '$' } },
+	{ { '5', '%' } },
+	{ { '6', '^' } },
+	{ { '7', '&' } },
+	{ { '8', '*' } },
+	{ { '9', '(' } },
+	{ { '0', ')' } },
+	{ { '-', '_' } },
+	{ { '=', '+' } },
+	{ { '\b', '\b' } },
+	{ { '\t', '\t' } },
+
+	{ { 'q', 'Q' } },		/* 16 */
+	{ { 'w', 'W' } },
+	{ { 'e', 'E' } },
+	{ { 'r', 'R' } },
+	{ { 't', 'T' } },
+	{ { 'y', 'Y' } },
+	{ { 'u', 'U' } },
+	{ { 'i', 'I' } },
+	{ { 'o', 'O' } },
+	{ { 'p', 'P' } },
+	{ { '[', '{' } },
+	{ { ']', '}' } },
+	{ { '\n', '\n' } },
+	{ { 0, 0 } },
+	{ { 'a', 'A' } },
+	{ { 's', 'S' } },
+
+	{ { 'd', 'D' } },		/* 32 */
+	{ { 'f', 'F' } },
+	{ { 'g', 'G' } },
+	{ { 'h', 'H' } },
+	{ { 'j', 'J' } },
+	{ { 'k', 'K' } },
+	{ { 'l', 'L' } },
+	{ { ';', ':' } },
+	{ { '\'', '"' } },
+	{ { '`', '~' } },
+	{ { 0, 0 } },
+	{ { '\\', '|' } },
+	{ { 'z', 'Z' } },
+	{ { 'x', 'X' } },
+	{ { 'c', 'C' } },
+	{ { 'v', 'V' } },
+
+	{ { 'b', 'B' } },		/* 48 */
+	{ { 'n', 'N' } },
+	{ { 'm', 'M' } },
+	{ { ',', '<' } },
+	{ { '.', '>' } },
+	{ { '/', '?' } },
+	{ { 0, 0 } },
+	{ { '*', '*' } },
+	{ { 0, 0 } },
+	{ { ' ', ' ' } },
+	{ { 0, 0 } }
+
+	/* 59 */
+};
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+static void
+key_handler(struct window *window, uint32_t key, uint32_t state, void *data)
+{
+	struct terminal *terminal = data;
+	uint32_t mod = 0;
+	char c;
+
+	switch (key) {
+	case KEY_LEFTSHIFT:
+	case KEY_RIGHTSHIFT:
+		mod = MOD_SHIFT;
+		break;
+	case KEY_LEFTCTRL:
+	case KEY_RIGHTCTRL:
+		mod = MOD_CTRL;
+		break;
+	case KEY_LEFTALT:
+	case KEY_RIGHTALT:
+		mod = MOD_ALT;
+		break;
+	default:
+		if (key < ARRAY_LENGTH(evdev_keymap)) {
+			if (terminal->modifiers & MOD_SHIFT)
+				c = evdev_keymap[key].code[1];
+			else
+				c = evdev_keymap[key].code[0];
+			if (state && c)
+				write(terminal->master, &c, 1);
+		}
+		break;
+	}
+
+	if (state)
+		terminal->modifiers |= mod;
+	else
+		terminal->modifiers &= ~mod;
+}
+
 static struct terminal *
 terminal_create(struct wl_display *display, int fd)
 {
@@ -190,6 +305,7 @@
 
 	window_set_resize_handler(terminal->window, resize_handler, terminal);
 	window_set_acknowledge_handler(terminal->window, acknowledge_handler, terminal);
+	window_set_key_handler(terminal->window, key_handler, terminal);
 
 	return terminal;
 }
@@ -206,7 +322,6 @@
 
 	g_io_channel_read_chars(source, buffer, sizeof buffer,
 				&bytes_read, &error);
-	printf("got data: %.*s\n", bytes_read, buffer);
 
 	terminal_data(terminal, buffer, bytes_read);
 
@@ -234,6 +349,7 @@
 	}
 
 	close(slave);
+	terminal->master = master;
 	terminal->channel = g_io_channel_unix_new(master);
 	fcntl(master, F_SETFL, O_NONBLOCK);
 	g_io_add_watch(terminal->channel, G_IO_IN,