Index: uspace/app/tetris/input.c
===================================================================
--- uspace/app/tetris/input.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/app/tetris/input.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -115,5 +115,5 @@
 			cons_phone = get_cons_phone();
 			getchar_inprog = async_send_2(cons_phone,
-			    CONSOLE_GETCHAR, 0, 0, &charcall);
+			    CONSOLE_GETKEY, 0, 0, &charcall);
 		}
 		if (!s) 
@@ -128,5 +128,5 @@
 			stop("end of file, help");
 		}
-		lastchar = IPC_GET_ARG1(charcall);
+		lastchar = IPC_GET_ARG4(charcall);
 	}
 	if (tvp) {
Index: uspace/app/trace/trace.c
===================================================================
--- uspace/app/trace/trace.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/app/trace/trace.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -624,5 +624,5 @@
 		V_INTEGER,
 		V_INTEGER,
-		V_INTEGER		
+		V_INTEGER
 	};
 
@@ -659,7 +659,8 @@
 
 	p = proto_new("console");
-	resp_def[0] = V_CHAR;
-	o = oper_new("getchar", 0, arg_def, V_INTEGER, 2, resp_def);
-	proto_add_oper(p, CONSOLE_GETCHAR, o);
+	resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER;
+	resp_def[2] = V_INTEGER; resp_def[3] = V_CHAR;
+	o = oper_new("getkey", 0, arg_def, V_ERRNO, 4, resp_def);
+	proto_add_oper(p, CONSOLE_GETKEY, o);
 
 	arg_def[0] = V_CHAR;
Index: uspace/lib/libc/Makefile
===================================================================
--- uspace/lib/libc/Makefile	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/lib/libc/Makefile	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -80,4 +80,5 @@
 	generic/err.c \
 	generic/stdlib.c \
+	generic/kbd.c \
 	generic/mman.c \
 	generic/udebug.c \
Index: uspace/lib/libc/generic/io/stream.c
===================================================================
--- uspace/lib/libc/generic/io/stream.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/lib/libc/generic/io/stream.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -44,4 +44,5 @@
 #include <ipc/services.h>
 #include <ipc/console.h>
+#include <kbd/kbd.h>
 #include <unistd.h>
 #include <async.h>
@@ -59,11 +60,15 @@
 	open_console();
 	if (console_phone >= 0) {
-		ipcarg_t r0, r1;
+		kbd_event_t ev;
+		int rc;
 		size_t i = 0;
 	
 		while (i < count) {
-			if (async_req_0_2(console_phone, CONSOLE_GETCHAR, &r0, &r1) < 0)
-				return -1;
-			((char *) buf)[i++] = r0;
+			do {
+				rc = kbd_get_event(&ev);
+				if (rc < 0) return -1;
+			} while (ev.c == 0);
+
+			((char *) buf)[i++] = ev.c;
 		}
 		return i;
Index: uspace/lib/libc/generic/kbd.c
===================================================================
--- uspace/lib/libc/generic/kbd.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
+++ uspace/lib/libc/generic/kbd.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{
+ */
+/** @file
+ */ 
+
+#include <stdio.h>
+#include <io/stream.h>
+#include <kbd/kbd.h>
+#include <ipc/ipc.h>
+#include <ipc/console.h>
+#include <async.h>
+
+int kbd_get_event(kbd_event_t *ev)
+{
+	int console_phone = get_cons_phone();
+	ipcarg_t r0, r1, r2, r3;
+	int rc;
+
+	rc = async_req_0_4(console_phone, CONSOLE_GETKEY, &r0, &r1, &r2, &r3);
+	if (rc < 0)
+		return -1;
+
+	ev->type = r0;
+	ev->c = r1;
+	ev->key = r2;
+	ev->mods = r3;
+
+	return 0;
+}
+
+/** @}
+ */
Index: uspace/lib/libc/include/ipc/console.h
===================================================================
--- uspace/lib/libc/include/ipc/console.h	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/lib/libc/include/ipc/console.h	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -39,5 +39,5 @@
 
 typedef enum {
-	CONSOLE_GETCHAR = IPC_FIRST_USER_METHOD,
+	CONSOLE_GETKEY = IPC_FIRST_USER_METHOD,
 	CONSOLE_PUTCHAR,
 	CONSOLE_CLEAR,
Index: uspace/lib/libc/include/kbd/kbd.h
===================================================================
--- uspace/lib/libc/include/kbd/kbd.h	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
+++ uspace/lib/libc/include/kbd/kbd.h	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{ 
+ */
+/** @file
+ */
+
+#ifndef LIBC_KBD_H_
+#define LIBC_KBD_H_
+
+typedef enum kbd_ev_type {
+	KE_PRESS,
+	KE_RELEASE
+} kbd_ev_type_t;
+
+/** Keyboard event structure. */
+typedef struct {
+	/** Press or release event. */
+	kbd_ev_type_t type;
+
+	/** Keycode of the key that was pressed or released. */
+	unsigned int key;
+
+	/** Bitmask of modifiers held. */
+	unsigned int mods;
+
+	/** The character that was generated or '\0' for none. */
+	char c;
+} kbd_event_t;
+
+extern int kbd_get_event(kbd_event_t *);
+
+#endif
+ 
+/** @}
+ */
Index: uspace/lib/libc/include/kbd/keycode.h
===================================================================
--- uspace/lib/libc/include/kbd/keycode.h	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
+++ uspace/lib/libc/include/kbd/keycode.h	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libc
+ * @{ 
+ */
+/** @file
+ */
+
+#ifndef LIBC_KBD_KEYCODE_H_
+#define LIBC_KBD_KEYCODE_H_
+
+/** Keycode definitions.
+ *
+ * A keycode identifies a key by its position on the keyboard, rather
+ * than by its label. For human readability, key positions are noted
+ * with the key label on a keyboard with US layout. This label has
+ * nothing to do with the character, that the key produces
+ * -- this is determined by the keymap.
+ *
+ * The keyboard model reflects a standard PC keyboard layout.
+ * Non-standard keyboards need to be mapped to this model in some
+ * logical way. Scancodes are mapped to keycodes with a scanmap.
+ *
+ * For easier mapping to the model and to emphasize the nature of keycodes,
+ * they really are organized here by position, rather than by label.
+ */
+enum keycode {
+
+	/* Main block row 1 */
+
+	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_BACKSPACE,
+
+	/* Main block row 2 */
+
+	KC_TAB,
+
+	KC_Q,
+	KC_W,
+	KC_E,
+	KC_R,
+	KC_T,
+	KC_Y,
+	KC_U,
+	KC_I,
+	KC_O,
+	KC_P,
+
+	KC_LBRACKET,
+	KC_RBRACKET,
+
+	/* Main block row 3 */
+
+	KC_CAPS_LOCK,
+	
+	KC_A,
+	KC_S,
+	KC_D,
+	KC_F,
+	KC_G,
+	KC_H,
+	KC_J,
+	KC_K,
+	KC_L,
+
+	KC_SEMICOLON,
+	KC_QUOTE,
+	KC_BACKSLASH,
+
+	KC_ENTER,
+
+	/* Main block row 4 */
+
+	KC_LSHIFT,
+
+	KC_Z,
+	KC_X,
+	KC_C,
+	KC_V,
+	KC_B,
+	KC_N,
+	KC_M,
+
+	KC_COMMA,
+	KC_PERIOD,
+	KC_SLASH,
+
+	KC_RSHIFT,
+
+	/* Main block row 5 */
+
+	KC_LCTRL,
+	KC_LALT,
+	KC_SPACE,
+	KC_RALT,
+	KC_RCTRL,
+
+	/* Function keys block */
+
+	KC_ESCAPE,
+
+	KC_F1,
+	KC_F2,
+	KC_F3,
+	KC_F4,
+	KC_F5,
+	KC_F6,
+	KC_F7,
+	KC_F8,
+	KC_F9,
+	KC_F10,
+	KC_F11,
+	KC_F12,
+
+	KC_PRTSCR,
+	KC_SCROLL_LOCK,
+	KC_PAUSE,
+
+	/* Cursor keys block */
+
+	KC_INSERT,
+	KC_HOME,
+	KC_PAGE_UP,
+
+	KC_DELETE,
+	KC_END,
+	KC_PAGE_DOWN,
+
+	KC_UP,
+	KC_LEFT,
+	KC_DOWN,
+	KC_RIGHT,
+
+	/* Numeric block */
+
+	KC_NUM_LOCK,
+	KC_NSLASH,
+	KC_NTIMES,
+	KC_NMINUS,
+
+	KC_NPLUS,
+	KC_NENTER,
+
+	KC_N7,
+	KC_N8,
+	KC_N9,
+
+	KC_N4,
+	KC_N5,
+	KC_N6,
+
+	KC_N1,
+	KC_N2,
+	KC_N3,
+
+	KC_N0,
+	KC_NPERIOD
+	
+} keycode_t;
+
+enum keymod {
+	KM_SHIFT	= 0x01,
+	KM_CTRL		= 0x02,
+	KM_ALT		= 0x04
+} keymod_t;
+
+#endif
+ 
+/** @}
+ */
Index: uspace/srv/console/console.c
===================================================================
--- uspace/srv/console/console.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/console/console.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -298,5 +298,5 @@
 	ipc_call_t call;
 	int retval;
-	int c;
+	kbd_event_t ev;
 	connection_t *conn;
 	int newcon;
@@ -320,20 +320,22 @@
 			retval = 0;
 			break;
-		case KBD_PUSHCHAR:
-			/* got key from keyboard driver */
+		case KBD_EVENT:
+			/* Got event from keyboard driver. */
 			retval = 0;
-			c = IPC_GET_ARG1(call);
+			ev.type = IPC_GET_ARG1(call);
+			ev.key = IPC_GET_ARG2(call);
+			ev.mods = IPC_GET_ARG3(call);
+			ev.c = IPC_GET_ARG4(call);
+			
 			/* switch to another virtual console */
 			
 			conn = &connections[active_console];
-/*
- *			if ((c >= KBD_KEY_F1) && (c < KBD_KEY_F1 +
- *				CONSOLE_COUNT)) {
- */
-			if ((c >= 0x101) && (c < 0x101 + CONSOLE_COUNT)) {
-				if (c == 0x112)
+
+			if ((ev.key >= 0x101) && (ev.key < 0x101 +
+			    CONSOLE_COUNT)) {
+				if (ev.key == 0x112)
 					change_console(KERNEL_CONSOLE);
 				else
-					change_console(c - 0x101);
+					change_console(ev.key - 0x101);
 				break;
 			}
@@ -342,12 +344,12 @@
 			if (conn->keyrequest_counter > 0) {		
 				conn->keyrequest_counter--;
-				ipc_answer_1(fifo_pop(conn->keyrequests), EOK,
-				    c);
+				ipc_answer_4(fifo_pop(conn->keyrequests), EOK,
+				    ev.type, ev.key, ev.mods, ev.c);
 				break;
 			}
-			
-			keybuffer_push(&conn->keybuffer, c);
+
+			keybuffer_push(&conn->keybuffer, &ev);
 			retval = 0;
-			
+
 			break;
 		default:
@@ -364,5 +366,5 @@
 	ipc_call_t call;
 	int consnum;
-	ipcarg_t arg1, arg2, arg3;
+	ipcarg_t arg1, arg2, arg3, arg4;
 	connection_t *conn;
 	
@@ -389,4 +391,7 @@
 		arg1 = 0;
 		arg2 = 0;
+		arg3 = 0;
+		arg4 = 0;
+
 		switch (IPC_GET_METHOD(call)) {
 		case IPC_M_PHONE_HUNGUP:
@@ -459,5 +464,5 @@
 				curs_visibility(arg1);
 			break;
-		case CONSOLE_GETCHAR:
+		case CONSOLE_GETKEY:
 			if (keybuffer_empty(&conn->keybuffer)) {
 				/* buffer is empty -> store request */
@@ -475,10 +480,13 @@
 				continue;
 			}
-			int ch;
-			keybuffer_pop(&conn->keybuffer, &ch);
-			arg1 = ch;
+			kbd_event_t ev;
+			keybuffer_pop(&conn->keybuffer, &ev);
+			arg1 = ev.type;
+			arg2 = ev.key;
+			arg3 = ev.mods;
+			arg4 = ev.c;
 			break;
 		}
-		ipc_answer_2(callid, EOK, arg1, arg2);
+		ipc_answer_4(callid, EOK, arg1, arg2, arg3, arg4);
 	}
 }
Index: uspace/srv/kbd/arch/arm32/src/kbd_gxemul.c
===================================================================
--- uspace/srv/kbd/arch/arm32/src/kbd_gxemul.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/arch/arm32/src/kbd_gxemul.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -123,8 +123,8 @@
 	/*
 	// Preserve for detecting scan codes. 
-	keybuffer_push(keybuffer, to_hex((scan_code>>4)&0xf));
-	keybuffer_push(keybuffer, to_hex(scan_code&0xf));
-	keybuffer_push(keybuffer, 'X');
-	keybuffer_push(keybuffer, 'Y');
+	keybuffer_push0(keybuffer, to_hex((scan_code>>4)&0xf));
+	keybuffer_push0(keybuffer, to_hex(scan_code&0xf));
+	keybuffer_push0(keybuffer, 'X');
+	keybuffer_push0(keybuffer, 'Y');
 	return 1;
 	*/
@@ -137,41 +137,41 @@
 		switch (buf) {
 		case GXEMUL_KEY_F5:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 5);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 5);
 			buf = count = 0;
 			return 1;
 		case GXEMUL_KEY_F6:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 6);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 6);
 			buf = count = 0;
 			return 1;
 		case GXEMUL_KEY_F7:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 7);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 7);
 			buf = count = 0;
 			return 1;
 		case GXEMUL_KEY_F8:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 8);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 8);
 			buf = count = 0;
 			return 1;
 		case GXEMUL_KEY_F9:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 9);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 9);
 			buf = count = 0;
 			return 1;
 		case GXEMUL_KEY_F10:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 10);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 10);
 			buf = count = 0;
 			return 1;
 		case GXEMUL_KEY_F11:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 11);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 11);
 			buf = count = 0;
 			return 1;
 		case GXEMUL_KEY_F12:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 12);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 12);
 			buf = count = 0;
 			return 1;
 		default:
-			keybuffer_push(keybuffer, buf & 0xff);
-			keybuffer_push(keybuffer, (buf >> 8)  & 0xff);
-			keybuffer_push(keybuffer, (buf >> 16) & 0xff);
-			keybuffer_push(keybuffer, (buf >> 24) & 0xff);
-			keybuffer_push(keybuffer, scan_code);
+			keybuffer_push0(keybuffer, buf & 0xff);
+			keybuffer_push0(keybuffer, (buf >> 8)  & 0xff);
+			keybuffer_push0(keybuffer, (buf >> 16) & 0xff);
+			keybuffer_push0(keybuffer, (buf >> 24) & 0xff);
+			keybuffer_push0(keybuffer, scan_code);
 			buf = count = 0;
 			return 1;
@@ -183,5 +183,5 @@
 	
 	if ((buf & 0xff) != (GXEMUL_KEY_F1 & 0xff)) {
-		keybuffer_push(keybuffer, buf);
+		keybuffer_push0(keybuffer, buf);
 		buf = count = 0;
 		return 1;
@@ -195,6 +195,6 @@
 		&& (buf & 0xffff) != (GXEMUL_KEY_F5 & 0xffff) ) {
 
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff);
 		buf = count = 0;
 		return 1;
@@ -207,17 +207,17 @@
 	switch (buf) {
 	case GXEMUL_KEY_F1:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 1);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 1);
 		buf = count = 0;
 		return 1;
 	case GXEMUL_KEY_F2:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 2);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 2);
 		buf = count = 0;
 		return 1;
 	case GXEMUL_KEY_F3:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 3);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 3);
 		buf = count = 0;
 		return 1;
 	case GXEMUL_KEY_F4:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 4);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 4);
 		buf = count = 0;
 		return 1;
@@ -228,7 +228,7 @@
 		&& (buf & 0xffffff) != (GXEMUL_KEY_F9 & 0xffffff)) {
 
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) & 0xff);
-		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) & 0xff);
 		buf = count = 0;
 		return 1;
@@ -250,8 +250,8 @@
 		return 1;
 	default:
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8)  & 0xff);
-		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
-		keybuffer_push(keybuffer, (buf >> 24) & 0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8)  & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 24) & 0xff);
 		buf = count = 0;
 		return 1;
@@ -279,8 +279,8 @@
 	/*
 	// Please preserve this code (it can be used to determine scancodes)
-	keybuffer_push(keybuffer, to_hex((scan_code>>4)&0xf));
-	keybuffer_push(keybuffer, to_hex(scan_code&0xf));
-	keybuffer_push(keybuffer, ' ');
-	keybuffer_push(keybuffer, ' ');
+	keybuffer_push0(keybuffer, to_hex((scan_code>>4)&0xf));
+	keybuffer_push0(keybuffer, to_hex(scan_code&0xf));
+	keybuffer_push0(keybuffer, ' ');
+	keybuffer_push0(keybuffer, ' ');
 	return 1;
 	*/
@@ -295,5 +295,5 @@
 	
 	if ((buf & 0xff) != (GXEMUL_FB_KEY_F1 & 0xff)) {
-		keybuffer_push(keybuffer, buf);
+		keybuffer_push0(keybuffer, buf);
 		buf = count = 0;
 		return 1;
@@ -305,6 +305,6 @@
 
 	if ((buf & 0xffff) != (GXEMUL_FB_KEY_F1 & 0xffff)) {
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff);
 		buf = count = 0;
 		return 1;
@@ -319,7 +319,7 @@
 		&& (buf & 0xffffff) != (GXEMUL_FB_KEY_F9 & 0xffffff)) {
 
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) & 0xff);
-		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) & 0xff);
 		buf = count = 0;
 		return 1;
@@ -332,56 +332,56 @@
 	switch (buf) {
 	case GXEMUL_FB_KEY_F1:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 1 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 1 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F2:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 2 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 2 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F3:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 3 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 3 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F4:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 4 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 4 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F5:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 5 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 5 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F6:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 6 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 6 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F7:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 7 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 7 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F8:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 8 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 8 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F9:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 9 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 9 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F10:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 10 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 10 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F11:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 11 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 11 );
 		buf = count = 0;
 		return 1;
 	case GXEMUL_FB_KEY_F12:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 12 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 12 );
 		buf = count = 0;
 		return 1;
 	default:
-		keybuffer_push(keybuffer, buf & 0xff );
-		keybuffer_push(keybuffer, (buf >> 8)  & 0xff);
-		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
-		keybuffer_push(keybuffer, (buf >> 24) & 0xff);
+		keybuffer_push0(keybuffer, buf & 0xff );
+		keybuffer_push0(keybuffer, (buf >> 8)  & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 24) & 0xff);
 		buf = count = 0;
 		return 1;
Index: uspace/srv/kbd/arch/ia64/src/kbd.c
===================================================================
--- uspace/srv/kbd/arch/ia64/src/kbd.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/arch/ia64/src/kbd.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -179,37 +179,37 @@
 		switch (buf) {
 		case NSKEY_F6:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 6);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 6);
 			buf = count = 0;
 			return 1;
 		case NSKEY_F7:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 7);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 7);
 			buf = count = 0;
 			return 1;
 		case NSKEY_F8:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 8);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 8);
 			buf = count = 0;
 			return 1;
 		case NSKEY_F9:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 9);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 9);
 			buf = count = 0;
 			return 1;
 		case NSKEY_F10:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 10);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 10);
 			buf = count = 0;
 			return 1;
 		case NSKEY_F11:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 11);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 11);
 			buf = count = 0;
 			return 1;
 		case NSKEY_F12:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 12);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 12);
 			buf = count = 0;
 			return 1;
 		default:
-			keybuffer_push(keybuffer, buf & 0xff);
-			keybuffer_push(keybuffer, (buf >> 8) &0xff);
-			keybuffer_push(keybuffer, (buf >> 16) &0xff);
-			keybuffer_push(keybuffer, (buf >> 24) &0xff);
-			keybuffer_push(keybuffer, scan_code);
+			keybuffer_push0(keybuffer, buf & 0xff);
+			keybuffer_push0(keybuffer, (buf >> 8) &0xff);
+			keybuffer_push0(keybuffer, (buf >> 16) &0xff);
+			keybuffer_push0(keybuffer, (buf >> 24) &0xff);
+			keybuffer_push0(keybuffer, scan_code);
 			buf = count = 0;
 			return 1;
@@ -220,5 +220,5 @@
 	
 	if((buf & 0xff) != (NSKEY_F1 & 0xff)) {
-		keybuffer_push(keybuffer, buf);
+		keybuffer_push0(keybuffer, buf);
 		buf = count = 0;
 		return 1;
@@ -230,6 +230,6 @@
 	if ((buf & 0xffff) != (NSKEY_F1 & 0xffff))  {
 
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff);
 		buf = count = 0;
 		return 1;
@@ -244,7 +244,7 @@
 		&& (buf & 0xffffff) != (NSKEY_F9 & 0xffffff) ) {
 
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
-		keybuffer_push(keybuffer, (buf >> 16) &0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) &0xff);
 		buf = count = 0;
 		return 1;
@@ -256,21 +256,21 @@
 	switch (buf) {
 	case NSKEY_F1:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 1);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 1);
 		buf = count = 0;
 		return 1;
 	case NSKEY_F2:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 2);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 2);
 		buf = count = 0;
 		return 1;
 	case NSKEY_F3:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 3);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 3);
 		buf = count = 0;
 		return 1;
 	case NSKEY_F4:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 4);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 4);
 		buf = count = 0;
 		return 1;
 	case NSKEY_F5:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 5);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 5);
 		buf = count = 0;
 		return 1;
@@ -289,8 +289,8 @@
 		return 1;
 	default:
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
-		keybuffer_push(keybuffer, (buf >> 16) &0xff);
-		keybuffer_push(keybuffer, (buf >> 24) &0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) &0xff);
+		keybuffer_push0(keybuffer, (buf >> 24) &0xff);
 		buf = count = 0;
 		return 1;
@@ -309,8 +309,8 @@
 	 * Please preserve this code (it can be used to determine scancodes)
 	 */
-	//keybuffer_push(keybuffer, to_hex((scan_code>>4)&0xf));
-	//keybuffer_push(keybuffer, to_hex(scan_code&0xf));
-	//keybuffer_push(keybuffer, ' ');
-	//keybuffer_push(keybuffer, ' ');
+	//keybuffer_push0(keybuffer, to_hex((scan_code>>4)&0xf));
+	//keybuffer_push0(keybuffer, to_hex(scan_code&0xf));
+	//keybuffer_push0(keybuffer, ' ');
+	//keybuffer_push0(keybuffer, ' ');
 	//*/
 	
@@ -329,42 +329,42 @@
 	
 		if (!(buf & 0xff00)) {
-			keybuffer_push(keybuffer, buf);
+			keybuffer_push0(keybuffer, buf);
 		} else {
 			switch (buf) {
 			case KEY_F1:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 1);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 1);
 				break;
 			case KEY_F2:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 2);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 2);
 				break;
 			case KEY_F3:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 3);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 3);
 				break;
 			case KEY_F4:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 4);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 4);
 				break;
 			case KEY_F5:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 5);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 5);
 				break;
 			case KEY_F6:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 6);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 6);
 				break;
 			case KEY_F7:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 7);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 7);
 				break;
 			case KEY_F8:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 8);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 8);
 				break;
 			case KEY_F9:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 9);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 9);
 				break;
 			case KEY_F10:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 10);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 10);
 				break;
 			case KEY_F11:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 11);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 11);
 				break;
 			case KEY_F12:
-				keybuffer_push(keybuffer, FUNCTION_KEYS | 12);
+				keybuffer_push0(keybuffer, FUNCTION_KEYS | 12);
 				break;
 			}
Index: uspace/srv/kbd/arch/mips32/src/kbd.c
===================================================================
--- uspace/srv/kbd/arch/mips32/src/kbd.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/arch/mips32/src/kbd.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -108,8 +108,8 @@
 	/* Please preserve this code (it can be used to determine scancodes)
 	
-	keybuffer_push(keybuffer, to_hex((scan_code>>4)&0xf));
-	keybuffer_push(keybuffer, to_hex(scan_code&0xf));
-	keybuffer_push(keybuffer, ' ');
-	keybuffer_push(keybuffer, ' ');
+	keybuffer_push0(keybuffer, to_hex((scan_code>>4)&0xf));
+	keybuffer_push0(keybuffer, to_hex(scan_code&0xf));
+	keybuffer_push0(keybuffer, ' ');
+	keybuffer_push0(keybuffer, ' ');
 	
 	return 1;
@@ -123,5 +123,5 @@
 	
 	if ((buf & 0xff) != (GXEMUL_KEY_F1 & 0xff)) {
-		keybuffer_push(keybuffer, buf);
+		keybuffer_push0(keybuffer, buf);
 		buf = count = 0;
 		return 1;
@@ -132,6 +132,6 @@
 
 	if ((buf & 0xffff) != (GXEMUL_KEY_F1 & 0xffff)) {
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff);
 		buf = count = 0;
 		return 1;
@@ -146,7 +146,7 @@
 		&& (buf & 0xffffff) != (GXEMUL_KEY_F9 & 0xffffff)) {
 
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) & 0xff);
-		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) & 0xff);
 		buf = count = 0;
 		return 1;
@@ -159,56 +159,56 @@
 	switch (buf) {
 	case GXEMUL_KEY_F1:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 1 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 1 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F2:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 2 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 2 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F3:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 3 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 3 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F4:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 4 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 4 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F5:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 5 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 5 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F6:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 6 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 6 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F7:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 7 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 7 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F8:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 8 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 8 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F9:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 9 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 9 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F10:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 10 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 10 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F11:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 11 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 11 );
 		buf=count=0;
 		return 1;
 	case GXEMUL_KEY_F12:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 12 );
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 12 );
 		buf=count=0;
 		return 1;
 	default:
-		keybuffer_push(keybuffer, buf & 0xff );
-		keybuffer_push(keybuffer, (buf >> 8) &0xff );
-		keybuffer_push(keybuffer, (buf >> 16) &0xff );
-		keybuffer_push(keybuffer, (buf >> 24) &0xff );
+		keybuffer_push0(keybuffer, buf & 0xff );
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff );
+		keybuffer_push0(keybuffer, (buf >> 16) &0xff );
+		keybuffer_push0(keybuffer, (buf >> 24) &0xff );
 		buf=count=0;
 		return 1;
Index: uspace/srv/kbd/arch/ppc32/src/kbd.c
===================================================================
--- uspace/srv/kbd/arch/ppc32/src/kbd.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/arch/ppc32/src/kbd.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -193,5 +193,5 @@
 			
 			if (key != SPECIAL)
-				keybuffer_push(keybuffer, key);
+				keybuffer_push0(keybuffer, key);
 		}
 	}
Index: uspace/srv/kbd/genarch/src/kbd.c
===================================================================
--- uspace/srv/kbd/genarch/src/kbd.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/genarch/src/kbd.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -74,4 +74,5 @@
 	int shift, capslock;
 	int letter = 0;
+	kbd_event_t ev;
 
 	static int esc_count = 0;
@@ -103,6 +104,10 @@
 		if (shift)
 			map = sc_secondary_map;
-		if (map[key] != SPECIAL)
-			keybuffer_push(keybuffer, map[key]);	
+		if (map[key] != SPECIAL) {
+			ev.key = map[key];
+			ev.mods = 0;
+			ev.c = map[key];
+			keybuffer_push(keybuffer, &ev);
+		}
 		break;
 	}
Index: uspace/srv/kbd/genarch/src/nofb.c
===================================================================
--- uspace/srv/kbd/genarch/src/nofb.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/genarch/src/nofb.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -67,41 +67,41 @@
 		switch (buf) {
 		case KEY_F5:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 5);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 5);
 			buf = count = 0;
 			return 1;
 		case KEY_F6:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 6);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 6);
 			buf = count = 0;
 			return 1;
 		case KEY_F7:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 7);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 7);
 			buf = count = 0;
 			return 1;
 		case KEY_F8:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 8);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 8);
 			buf = count = 0;
 			return 1;
 		case KEY_F9:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 9);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 9);
 			buf = count = 0;
 			return 1;
 		case KEY_F10:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 10);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 10);
 			buf = count = 0;
 			return 1;
 		case KEY_F11:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 11);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 11);
 			buf = count = 0;
 			return 1;
 		case KEY_F12:
-			keybuffer_push(keybuffer,FUNCTION_KEYS | 12);
+			keybuffer_push0(keybuffer,FUNCTION_KEYS | 12);
 			buf = count = 0;
 			return 1;
 		default:
-			keybuffer_push(keybuffer, buf & 0xff);
-			keybuffer_push(keybuffer, (buf >> 8) &0xff);
-			keybuffer_push(keybuffer, (buf >> 16) &0xff);
-			keybuffer_push(keybuffer, (buf >> 24) &0xff);
-			keybuffer_push(keybuffer, scan_code);
+			keybuffer_push0(keybuffer, buf & 0xff);
+			keybuffer_push0(keybuffer, (buf >> 8) &0xff);
+			keybuffer_push0(keybuffer, (buf >> 16) &0xff);
+			keybuffer_push0(keybuffer, (buf >> 24) &0xff);
+			keybuffer_push0(keybuffer, scan_code);
 			buf = count = 0;
 			return 1;
@@ -112,5 +112,5 @@
 	
 	if((buf & 0xff) != (KEY_F1 & 0xff)) {
-		keybuffer_push(keybuffer, buf);
+		keybuffer_push0(keybuffer, buf);
 		buf = count = 0;
 		return 1;
@@ -123,6 +123,6 @@
 		&& (buf & 0xffff) != (KEY_F5 & 0xffff) ) {
 
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff);
 		buf = count = 0;
 		return 1;
@@ -134,17 +134,17 @@
 	switch (buf) {
 	case KEY_F1:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 1);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 1);
 		buf = count = 0;
 		return 1;
 	case KEY_F2:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 2);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 2);
 		buf = count = 0;
 		return 1;
 	case KEY_F3:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 3);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 3);
 		buf = count = 0;
 		return 1;
 	case KEY_F4:
-		keybuffer_push(keybuffer,FUNCTION_KEYS | 4);
+		keybuffer_push0(keybuffer,FUNCTION_KEYS | 4);
 		buf = count = 0;
 		return 1;
@@ -155,7 +155,7 @@
 		&& (buf & 0xffffff) != (KEY_F9 & 0xffffff)) {
 
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) & 0xff);
-		keybuffer_push(keybuffer, (buf >> 16) & 0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) & 0xff);
 		buf=count=0;
 		return 1;
@@ -176,8 +176,8 @@
 		return 1;
 	default:
-		keybuffer_push(keybuffer, buf & 0xff);
-		keybuffer_push(keybuffer, (buf >> 8) &0xff);
-		keybuffer_push(keybuffer, (buf >> 16) &0xff);
-		keybuffer_push(keybuffer, (buf >> 24) &0xff);
+		keybuffer_push0(keybuffer, buf & 0xff);
+		keybuffer_push0(keybuffer, (buf >> 8) &0xff);
+		keybuffer_push0(keybuffer, (buf >> 16) &0xff);
+		keybuffer_push0(keybuffer, (buf >> 24) &0xff);
 		buf = count = 0;
 		return 1;
Index: uspace/srv/kbd/generic/kbd.c
===================================================================
--- uspace/srv/kbd/generic/kbd.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/generic/kbd.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -43,10 +43,12 @@
 #include <stdio.h>
 #include <ipc/ns.h>
+#include <async.h>
 #include <errno.h>
+#include <libadt/fifo.h>
+#include <kbd/kbd.h>
+
 #include <arch/kbd.h>
 #include <kbd.h>
-#include <libadt/fifo.h>
 #include <key_buffer.h>
-#include <async.h>
 #include <keys.h>
 
@@ -59,5 +61,5 @@
 static void irq_handler(ipc_callid_t iid, ipc_call_t *call)
 {
-	int chr;
+	kbd_event_t ev;
 
 #ifdef MOUSE_ENABLED
@@ -70,12 +72,13 @@
 	if (cons_connected && phone2cons != -1) {
 		/*
-		 * recode to ASCII - one interrupt can produce more than one
-		 * code so result is stored in fifo
+		 * One interrupt can produce more than one event so the result
+		 * is stored in a FIFO.
 		 */
 		while (!keybuffer_empty(&keybuffer)) {
-			if (!keybuffer_pop(&keybuffer, (int *)&chr))
+			if (!keybuffer_pop(&keybuffer, &ev))
 				break;
 
-			async_msg_1(phone2cons, KBD_PUSHCHAR, chr);
+			async_msg_4(phone2cons, KBD_EVENT, ev.type, ev.key,
+			    ev.mods, ev.c);
 		}
 	}
Index: uspace/srv/kbd/generic/key_buffer.c
===================================================================
--- uspace/srv/kbd/generic/key_buffer.c	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/generic/key_buffer.c	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -41,5 +41,5 @@
 /** Clear key buffer.
  */
-void keybuffer_free(keybuffer_t *keybuffer) 
+void keybuffer_free(keybuffer_t *keybuffer)
 {
 	futex_down(&keybuffer_futex);
@@ -76,13 +76,16 @@
 }
 
-/** Push key to key buffer.
- * If buffer is full, character is ignored.
- * @param key code of stored key
+/** Push key event to key buffer.
+ *
+ * If the buffer is full, the event is ignored.
+ *
+ * @param keybuffer	The keybuffer.
+ * @param ev		The event to push.
  */
-void keybuffer_push(keybuffer_t *keybuffer, int key)
+void keybuffer_push(keybuffer_t *keybuffer, const kbd_event_t *ev)
 {
 	futex_down(&keybuffer_futex);
 	if (keybuffer->items < KEYBUFFER_SIZE) {
-		keybuffer->fifo[keybuffer->tail] = key;
+		keybuffer->fifo[keybuffer->tail] = *ev;
 		keybuffer->tail = (keybuffer->tail + 1) % KEYBUFFER_SIZE;
 		keybuffer->items++;
@@ -91,14 +94,23 @@
 }
 
-/** Pop character from buffer.
- * @param c pointer to space where to store character from buffer.
- * @return zero on empty buffer, nonzero else
+void keybuffer_push0(keybuffer_t *keybuffer, int c)
+{
+	kbd_event_t ev;
+
+	ev.key = c; ev.mods = 0; ev.c = c;
+	keybuffer_push(keybuffer, &ev);
+}
+
+/** Pop event from buffer.
+ *
+ * @param edst	Pointer to where the event should be saved.
+ * @return	Zero on empty buffer, nonzero otherwise.
  */
-int keybuffer_pop(keybuffer_t *keybuffer, int *c)
+int keybuffer_pop(keybuffer_t *keybuffer, kbd_event_t *edst)
 {
 	futex_down(&keybuffer_futex);
 	if (keybuffer->items > 0) {
 		keybuffer->items--;
-		*c = (keybuffer->fifo[keybuffer->head]) ;
+		*edst = (keybuffer->fifo[keybuffer->head]) ;
 		keybuffer->head = (keybuffer->head + 1) % KEYBUFFER_SIZE;
 		futex_up(&keybuffer_futex);
Index: uspace/srv/kbd/include/key_buffer.h
===================================================================
--- uspace/srv/kbd/include/key_buffer.h	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/include/key_buffer.h	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -39,4 +39,5 @@
 
 #include <sys/types.h>
+#include <kbd/kbd.h>
 
 /** Size of buffer for pressed keys */
@@ -44,5 +45,5 @@
 
 typedef struct {
-	int fifo[KEYBUFFER_SIZE];
+	kbd_event_t fifo[KEYBUFFER_SIZE];
 	unsigned long head;
 	unsigned long tail;
@@ -50,10 +51,11 @@
 } keybuffer_t;
 
-void keybuffer_free(keybuffer_t *keybuffer);
-void keybuffer_init(keybuffer_t *keybuffer);
-int keybuffer_available(keybuffer_t *keybuffer);
-int keybuffer_empty(keybuffer_t *keybuffer);
-void keybuffer_push(keybuffer_t *keybuffer, int key);
-int keybuffer_pop(keybuffer_t *keybuffer, int *c);
+extern void keybuffer_free(keybuffer_t *);
+extern void keybuffer_init(keybuffer_t *);
+extern int keybuffer_available(keybuffer_t *);
+extern int keybuffer_empty(keybuffer_t *);
+extern void keybuffer_push(keybuffer_t *, const kbd_event_t *);
+extern void keybuffer_push0(keybuffer_t *, int c);
+extern int keybuffer_pop(keybuffer_t *, kbd_event_t *);
 
 #endif
Index: uspace/srv/kbd/include/keys.h
===================================================================
--- uspace/srv/kbd/include/keys.h	(revision 76dd25b7f1290f21230e4d3c41919e84f05bb9d8)
+++ uspace/srv/kbd/include/keys.h	(revision fa094491c49be2130cd1f5bbad081181cbad82b1)
@@ -38,9 +38,9 @@
 #define _KBD_KEYS_H_
 
-#define KBD_PUSHCHAR    1024
-#define KBD_MS_LEFT     1025
-#define KBD_MS_RIGHT    1026
-#define KBD_MS_MIDDLE   1027
-#define KBD_MS_MOVE     1028
+#define KBD_EVENT	1024
+#define KBD_MS_LEFT	1025
+#define KBD_MS_RIGHT	1026
+#define KBD_MS_MIDDLE	1027
+#define KBD_MS_MOVE	1028
 
 #define KBD_KEY_F1	0x3b
