Index: uspace/srv/kbd/ctl/gxe_fb.c
===================================================================
--- uspace/srv/kbd/ctl/gxe_fb.c	(revision 3f95377042657539cf9cca0cfec68cd3976ef5e0)
+++ uspace/srv/kbd/ctl/gxe_fb.c	(revision dc22844fb0d5ea9ccfad3f1097a7bf38da0c0ef9)
@@ -203,5 +203,5 @@
 	}
 
-	kbd_push_ev(KE_PRESS, KC_ESCAPE, 0);
+	kbd_push_ev(KE_PRESS, KC_ESCAPE);
 }
 
Index: uspace/srv/kbd/ctl/pc.c
===================================================================
--- uspace/srv/kbd/ctl/pc.c	(revision 3f95377042657539cf9cca0cfec68cd3976ef5e0)
+++ uspace/srv/kbd/ctl/pc.c	(revision dc22844fb0d5ea9ccfad3f1097a7bf38da0c0ef9)
@@ -60,5 +60,5 @@
 	key = scanmap_simple[scancode];
 	if (key != 0)
-		kbd_push_ev(type, key, 0);
+		kbd_push_ev(type, key);
 }
 
Index: uspace/srv/kbd/ctl/stty.c
===================================================================
--- uspace/srv/kbd/ctl/stty.c	(revision 3f95377042657539cf9cca0cfec68cd3976ef5e0)
+++ uspace/srv/kbd/ctl/stty.c	(revision dc22844fb0d5ea9ccfad3f1097a7bf38da0c0ef9)
@@ -213,5 +213,5 @@
 	}
 
-	kbd_push_ev(KE_PRESS, KC_ESCAPE, 0);
+	kbd_push_ev(KE_PRESS, KC_ESCAPE);
 }
 
@@ -253,5 +253,5 @@
 	key = map[scancode];
 	if (key != 0)
-		kbd_push_ev(KE_PRESS, key, 0);
+		kbd_push_ev(KE_PRESS, key);
 }
 
Index: uspace/srv/kbd/ctl/sun.c
===================================================================
--- uspace/srv/kbd/ctl/sun.c	(revision 3f95377042657539cf9cca0cfec68cd3976ef5e0)
+++ uspace/srv/kbd/ctl/sun.c	(revision dc22844fb0d5ea9ccfad3f1097a7bf38da0c0ef9)
@@ -66,5 +66,5 @@
 	key = scanmap_simple[scancode];
 	if (key != 0)
-		kbd_push_ev(type, key, 0);
+		kbd_push_ev(type, key);
 }
 
Index: uspace/srv/kbd/generic/kbd.c
===================================================================
--- uspace/srv/kbd/generic/kbd.c	(revision 3f95377042657539cf9cca0cfec68cd3976ef5e0)
+++ uspace/srv/kbd/generic/kbd.c	(revision dc22844fb0d5ea9ccfad3f1097a7bf38da0c0ef9)
@@ -58,5 +58,8 @@
 int cons_connected = 0;
 int phone2cons = -1;
-keybuffer_t keybuffer;	
+keybuffer_t keybuffer;
+
+/** Currently active modifiers. */
+static unsigned mods;
 
 void kbd_push_scancode(int scancode)
@@ -67,7 +70,35 @@
 
 #include <kbd/keycode.h>
-void kbd_push_ev(int type, unsigned int key, unsigned int mods)
+void kbd_push_ev(int type, unsigned int key)
 {
 	kbd_event_t ev;
+	unsigned mod_mask;
+
+	switch (key) {
+	case KC_LCTRL: mod_mask = KM_LCTRL; break;
+	case KC_RCTRL: mod_mask = KM_RCTRL; break;
+	case KC_LSHIFT: mod_mask = KM_LSHIFT; break;
+	case KC_RSHIFT: mod_mask = KM_RSHIFT; break;
+	case KC_LALT: mod_mask = KM_LALT; break;
+	case KC_RALT: mod_mask = KM_RALT; break;
+	default: mod_mask = 0; break;
+	}
+
+	if (mod_mask != 0) {
+		if (type == KE_PRESS)
+			mods = mods | mod_mask;
+		else
+			mods = mods & ~mod_mask;
+	}
+
+	switch (key) {
+	case KC_CAPS_LOCK: mod_mask = KM_CAPS_LOCK; break;
+	case KC_NUM_LOCK: mod_mask = KM_NUM_LOCK; break;
+	case KC_SCROLL_LOCK: mod_mask = KM_SCROLL_LOCK; break;
+	default: mod_mask = 0; break;
+	}
+
+	if (mod_mask != 0 && type == KE_PRESS)
+		mods = mods ^ mod_mask;
 
 	printf("type: %d\n", type);
@@ -83,25 +114,4 @@
 	async_msg_4(phone2cons, KBD_EVENT, ev.type, ev.key, ev.mods, ev.c);
 }
-
-//static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
-//{
-//	kbd_event_t ev;
-//
-//	kbd_arch_process(&keybuffer, call);
-//
-//	if (cons_connected && phone2cons != -1) {
-//		/*
-//		 * One interrupt can produce more than one event so the result
-//		 * is stored in a FIFO.
-//		 */
-//		while (!keybuffer_empty(&keybuffer)) {
-//			if (!keybuffer_pop(&keybuffer, &ev))
-//				break;
-//
-//			async_msg_4(phone2cons, KBD_EVENT, ev.type, ev.key,
-//			    ev.mods, ev.c);
-//		}
-//	}
-//}
 
 static void console_connection(ipc_callid_t iid, ipc_call_t *icall)
@@ -143,5 +153,4 @@
 
 
-
 int main(int argc, char **argv)
 {
Index: uspace/srv/kbd/include/kbd.h
===================================================================
--- uspace/srv/kbd/include/kbd.h	(revision 3f95377042657539cf9cca0cfec68cd3976ef5e0)
+++ uspace/srv/kbd/include/kbd.h	(revision dc22844fb0d5ea9ccfad3f1097a7bf38da0c0ef9)
@@ -47,5 +47,5 @@
 
 extern void kbd_push_scancode(int);
-extern void kbd_push_ev(int, unsigned int, unsigned int);
+extern void kbd_push_ev(int, unsigned int);
 
 #endif
Index: uspace/srv/kbd/layout/us_dvorak.c
===================================================================
--- uspace/srv/kbd/layout/us_dvorak.c	(revision 3f95377042657539cf9cca0cfec68cd3976ef5e0)
+++ uspace/srv/kbd/layout/us_dvorak.c	(revision dc22844fb0d5ea9ccfad3f1097a7bf38da0c0ef9)
@@ -37,5 +37,71 @@
 #include <layout.h>
 
-static int map_normal[] = {
+static char map_lcase[] = {
+	[KC_R] = 'p',
+	[KC_T] = 'y',
+	[KC_Y] = 'f',
+	[KC_U] = 'g',
+	[KC_I] = 'c',
+	[KC_O] = 'r',
+	[KC_P] = 'l',
+
+	[KC_A] = 'a',
+	[KC_S] = 'o',
+	[KC_D] = 'e',
+	[KC_F] = 'u',
+	[KC_G] = 'i',
+	[KC_H] = 'd',
+	[KC_J] = 'h',
+	[KC_K] = 't',
+	[KC_L] = 'n',
+
+	[KC_SEMICOLON] = 's',
+
+	[KC_X] = 'q',
+	[KC_C] = 'j',
+	[KC_V] = 'k',
+	[KC_B] = 'x',
+	[KC_N] = 'b',
+	[KC_M] = 'm',
+
+	[KC_COMMA] = 'w',
+	[KC_PERIOD] = 'v',
+	[KC_SLASH] = 'z',
+};
+
+static char map_ucase[] = {
+	[KC_R] = 'P',
+	[KC_T] = 'Y',
+	[KC_Y] = 'F',
+	[KC_U] = 'G',
+	[KC_I] = 'C',
+	[KC_O] = 'R',
+	[KC_P] = 'L',
+
+	[KC_A] = 'A',
+	[KC_S] = 'O',
+	[KC_D] = 'E',
+	[KC_F] = 'U',
+	[KC_G] = 'I',
+	[KC_H] = 'D',
+	[KC_J] = 'H',
+	[KC_K] = 'T',
+	[KC_L] = 'N',
+
+	[KC_SEMICOLON] = 'S',
+
+	[KC_X] = 'Q',
+	[KC_C] = 'J',
+	[KC_V] = 'K',
+	[KC_B] = 'X',
+	[KC_N] = 'B',
+	[KC_M] = 'M',
+
+	[KC_COMMA] = 'W',
+	[KC_PERIOD] = 'V',
+	[KC_SLASH] = 'Z',
+};
+
+static char map_not_shifted[] = {
 	[KC_BACKTICK] = '`',
 
@@ -53,58 +119,87 @@
 	[KC_MINUS] = '[',
 	[KC_EQUALS] = ']',
-	[KC_BACKSPACE] = '\b',
-
-	[KC_TAB] = '\t',
 
 	[KC_Q] = '\'',
 	[KC_W] = ',',
 	[KC_E] = '.',
-	[KC_R] = 'p',
-	[KC_T] = 'y',
-	[KC_Y] = 'f',
-	[KC_U] = 'g',
-	[KC_I] = 'c',
-	[KC_O] = 'r',
-	[KC_P] = 'l',
 
 	[KC_LBRACKET] = '/',
 	[KC_RBRACKET] = '=',
 
-	[KC_A] = 'a',
-	[KC_S] = 'o',
-	[KC_D] = 'e',
-	[KC_F] = 'u',
-	[KC_G] = 'i',
-	[KC_H] = 'd',
-	[KC_J] = 'h',
-	[KC_K] = 't',
-	[KC_L] = 'n',
-
-	[KC_SEMICOLON] = 's',
 	[KC_QUOTE] = '-',
 	[KC_BACKSLASH] = '\\',
 
 	[KC_Z] = ';',
-	[KC_X] = 'q',
-	[KC_C] = 'j',
-	[KC_V] = 'k',
-	[KC_B] = 'x',
-	[KC_N] = 'b',
-	[KC_M] = 'm',
-
-	[KC_COMMA] = 'w',
-	[KC_PERIOD] = 'v',
-	[KC_SLASH] = 'z',
-
+};
+
+static char map_shifted[] = {
+	[KC_BACKTICK] = '~',
+
+	[KC_1] = '!',
+	[KC_2] = '@',
+	[KC_3] = '#',
+	[KC_4] = '$',
+	[KC_5] = '%',
+	[KC_6] = '^',
+	[KC_7] = '&',
+	[KC_8] = '*',
+	[KC_9] = '(',
+	[KC_0] = ')',
+
+	[KC_MINUS] = '{',
+	[KC_EQUALS] = '}',
+
+	[KC_Q] = '"',
+	[KC_W] = '<',
+	[KC_E] = '>',
+
+	[KC_LBRACKET] = '?',
+	[KC_RBRACKET] = '+',
+
+	[KC_QUOTE] = '_',
+	[KC_BACKSLASH] = '|',
+
+	[KC_Z] = ':',
+};
+
+static char map_neutral[] = {
+	[KC_BACKSPACE] = '\b',
+	[KC_TAB] = '\t',
 	[KC_ENTER] = '\n'
 };
+
+static int translate(unsigned int key, char *map, size_t map_length)
+{
+	if (key >= map_length) return 0;
+	return map[key];	
+}
 
 char layout_parse_ev(kbd_event_t *ev)
 {
-	if (ev->key >= sizeof(map_normal) / sizeof(int))
+	char c;
+
+	/* Produce no characters when Ctrl or Alt is pressed. */
+	if ((ev->mods & (KM_CTRL | KM_ALT)) != 0)
 		return 0;
 
-	return map_normal[ev->key];
+	c = translate(ev->key, map_neutral, sizeof(map_neutral) / sizeof(char));
+	if (c != 0) return c;
+
+	if (((ev->mods & KM_SHIFT) != 0) ^ ((ev->mods & KM_CAPS_LOCK) != 0))
+		c = translate(ev->key, map_ucase, sizeof(map_ucase) / sizeof(char));
+	else
+		c = translate(ev->key, map_lcase, sizeof(map_lcase) / sizeof(char));
+
+	if (c != 0) return c;
+
+	if ((ev->mods & KM_SHIFT) != 0)
+		c = translate(ev->key, map_shifted, sizeof(map_shifted) / sizeof(char));
+	else
+		c = translate(ev->key, map_not_shifted, sizeof(map_not_shifted) / sizeof(char));
+
+	if (c != 0 ) return c;
+
 }
+
 
 /**
Index: uspace/srv/kbd/layout/us_qwerty.c
===================================================================
--- uspace/srv/kbd/layout/us_qwerty.c	(revision 3f95377042657539cf9cca0cfec68cd3976ef5e0)
+++ uspace/srv/kbd/layout/us_qwerty.c	(revision dc22844fb0d5ea9ccfad3f1097a7bf38da0c0ef9)
@@ -37,5 +37,67 @@
 #include <layout.h>
 
-static int map_normal[] = {
+static char map_lcase[] = {
+	[KC_Q] = 'q',
+	[KC_W] = 'w',
+	[KC_E] = 'e',
+	[KC_R] = 'r',
+	[KC_T] = 't',
+	[KC_Y] = 'y',
+	[KC_U] = 'u',
+	[KC_I] = 'i',
+	[KC_O] = 'o',
+	[KC_P] = 'p',
+
+	[KC_A] = 'a',
+	[KC_S] = 's',
+	[KC_D] = 'd',
+	[KC_F] = 'f',
+	[KC_G] = 'g',
+	[KC_H] = 'h',
+	[KC_J] = 'j',
+	[KC_K] = 'k',
+	[KC_L] = 'l',
+
+	[KC_Z] = 'z',
+	[KC_X] = 'x',
+	[KC_C] = 'c',
+	[KC_V] = 'v',
+	[KC_B] = 'b',
+	[KC_N] = 'n',
+	[KC_M] = 'm',
+};
+
+static char map_ucase[] = {
+	[KC_Q] = 'Q',
+	[KC_W] = 'W',
+	[KC_E] = 'E',
+	[KC_R] = 'R',
+	[KC_T] = 'T',
+	[KC_Y] = 'Y',
+	[KC_U] = 'U',
+	[KC_I] = 'I',
+	[KC_O] = 'O',
+	[KC_P] = 'P',
+
+	[KC_A] = 'A',
+	[KC_S] = 'S',
+	[KC_D] = 'D',
+	[KC_F] = 'F',
+	[KC_G] = 'G',
+	[KC_H] = 'H',
+	[KC_J] = 'J',
+	[KC_K] = 'K',
+	[KC_L] = 'L',
+
+	[KC_Z] = 'Z',
+	[KC_X] = 'X',
+	[KC_C] = 'C',
+	[KC_V] = 'V',
+	[KC_B] = 'B',
+	[KC_N] = 'N',
+	[KC_M] = 'M',
+};
+
+static char map_not_shifted[] = {
 	[KC_BACKTICK] = '`',
 
@@ -53,58 +115,84 @@
 	[KC_MINUS] = '-',
 	[KC_EQUALS] = '=',
-	[KC_BACKSPACE] = '\b',
-
-	[KC_TAB] = '\t',
-
-	[KC_Q] = 'q',
-	[KC_W] = 'w',
-	[KC_E] = 'e',
-	[KC_R] = 'r',
-	[KC_T] = 't',
-	[KC_Y] = 'y',
-	[KC_U] = 'u',
-	[KC_I] = 'i',
-	[KC_O] = 'o',
-	[KC_P] = 'p',
 
 	[KC_LBRACKET] = '[',
 	[KC_RBRACKET] = ']',
-
-	[KC_A] = 'a',
-	[KC_S] = 's',
-	[KC_D] = 'd',
-	[KC_F] = 'f',
-	[KC_G] = 'g',
-	[KC_H] = 'h',
-	[KC_J] = 'j',
-	[KC_K] = 'k',
-	[KC_L] = 'l',
 
 	[KC_SEMICOLON] = ';',
 	[KC_QUOTE] = '\'',
 	[KC_BACKSLASH] = '\\',
-	[KC_ENTER] = '\n',
-
-	[KC_Z] = 'z',
-	[KC_X] = 'x',
-	[KC_C] = 'c',
-	[KC_V] = 'v',
-	[KC_B] = 'b',
-	[KC_N] = 'n',
-	[KC_M] = 'm',
 
 	[KC_COMMA] = ',',
 	[KC_PERIOD] = '.',
 	[KC_SLASH] = '/',
-
+};
+
+static char map_shifted[] = {
+	[KC_BACKTICK] = '~',
+
+	[KC_1] = '!',
+	[KC_2] = '@',
+	[KC_3] = '#',
+	[KC_4] = '$',
+	[KC_5] = '%',
+	[KC_6] = '^',
+	[KC_7] = '&',
+	[KC_8] = '*',
+	[KC_9] = '(',
+	[KC_0] = ')',
+
+	[KC_MINUS] = '_',
+	[KC_EQUALS] = '+',
+
+	[KC_LBRACKET] = '{',
+	[KC_RBRACKET] = '}',
+
+	[KC_SEMICOLON] = ':',
+	[KC_QUOTE] = '"',
+	[KC_BACKSLASH] = '|',
+
+	[KC_COMMA] = '<',
+	[KC_PERIOD] = '>',
+	[KC_SLASH] = '?',
+};
+
+static char map_neutral[] = {
+	[KC_BACKSPACE] = '\b',
+	[KC_TAB] = '\t',
+	[KC_ENTER] = '\n',
 	[KC_SPACE] = ' '
 };
+
+static int translate(unsigned int key, char *map, size_t map_length)
+{
+	if (key >= map_length) return 0;
+	return map[key];	
+}
 
 char layout_parse_ev(kbd_event_t *ev)
 {
-	if (ev->key >= sizeof(map_normal) / sizeof(int))
+	char c;
+
+	/* Produce no characters when Ctrl or Alt is pressed. */
+	if ((ev->mods & (KM_CTRL | KM_ALT)) != 0)
 		return 0;
 
-	return map_normal[ev->key];
+	c = translate(ev->key, map_neutral, sizeof(map_neutral) / sizeof(char));
+	if (c != 0) return c;
+
+	if (((ev->mods & KM_SHIFT) != 0) ^ ((ev->mods & KM_CAPS_LOCK) != 0))
+		c = translate(ev->key, map_ucase, sizeof(map_ucase) / sizeof(char));
+	else
+		c = translate(ev->key, map_lcase, sizeof(map_lcase) / sizeof(char));
+
+	if (c != 0) return c;
+
+	if ((ev->mods & KM_SHIFT) != 0)
+		c = translate(ev->key, map_shifted, sizeof(map_shifted) / sizeof(char));
+	else
+		c = translate(ev->key, map_not_shifted, sizeof(map_not_shifted) / sizeof(char));
+
+	if (c != 0 ) return c;
+
 }
 
