Index: uspace/srv/hid/input/Makefile
===================================================================
--- uspace/srv/hid/input/Makefile	(revision 9934f7d3082d2ffdd107cc0c78d61d504b0f401e)
+++ uspace/srv/hid/input/Makefile	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
@@ -45,4 +45,5 @@
 SOURCES = \
 	generic/input.c \
+	generic/layout.c \
 	genarch/gsp.c \
 	genarch/stroke.c \
Index: uspace/srv/hid/input/generic/input.c
===================================================================
--- uspace/srv/hid/input/generic/input.c	(revision 9934f7d3082d2ffdd107cc0c78d61d504b0f401e)
+++ uspace/srv/hid/input/generic/input.c	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
@@ -70,10 +70,4 @@
 int client_phone = -1;
 
-/** Currently active modifiers. */
-static unsigned mods = KM_NUM_LOCK;
-
-/** Currently pressed lock keys. We track these to tackle autorepeat. */
-static unsigned lock_keys;
-
 /** List of keyboard devices */
 static link_t kbd_devs;
@@ -84,11 +78,9 @@
 #define NUM_LAYOUTS 3
 
-static layout_op_t *layout[NUM_LAYOUTS] = {
-	&us_qwerty_op,
-	&us_dvorak_op,
-	&cz_op
+static layout_ops_t *layout[NUM_LAYOUTS] = {
+	&us_qwerty_ops,
+	&us_dvorak_ops,
+	&cz_ops
 };
-
-static int active_layout = 0;
 
 void kbd_push_scancode(kbd_dev_t *kdev, int scancode)
@@ -115,7 +107,7 @@
 	if (mod_mask != 0) {
 		if (type == KEY_PRESS)
-			mods = mods | mod_mask;
+			kdev->mods = kdev->mods | mod_mask;
 		else
-			mods = mods & ~mod_mask;
+			kdev->mods = kdev->mods & ~mod_mask;
 	}
 
@@ -134,11 +126,11 @@
 			 * up the lock state.
 			 */
-			mods = mods ^ (mod_mask & ~lock_keys);
-			lock_keys = lock_keys | mod_mask;
+			kdev->mods = kdev->mods ^ (mod_mask & ~kdev->lock_keys);
+			kdev->lock_keys = kdev->lock_keys | mod_mask;
 
 			/* Update keyboard lock indicator lights. */
-			(*kdev->ctl_ops->set_ind)(kdev, mods);
+			(*kdev->ctl_ops->set_ind)(kdev, kdev->mods);
 		} else {
-			lock_keys = lock_keys & ~mod_mask;
+			kdev->lock_keys = kdev->lock_keys & ~mod_mask;
 		}
 	}
@@ -148,22 +140,22 @@
 	printf("keycode: %u\n", key);
 */
-	if (type == KEY_PRESS && (mods & KM_LCTRL) &&
+	if (type == KEY_PRESS && (kdev->mods & KM_LCTRL) &&
 		key == KC_F1) {
-		active_layout = 0;
-		layout[active_layout]->reset();
+		layout_destroy(kdev->active_layout);
+		kdev->active_layout = layout_create(layout[0]);
 		return;
 	}
 
-	if (type == KEY_PRESS && (mods & KM_LCTRL) &&
+	if (type == KEY_PRESS && (kdev->mods & KM_LCTRL) &&
 		key == KC_F2) {
-		active_layout = 1;
-		layout[active_layout]->reset();
+		layout_destroy(kdev->active_layout);
+		kdev->active_layout = layout_create(layout[1]);
 		return;
 	}
 
-	if (type == KEY_PRESS && (mods & KM_LCTRL) &&
+	if (type == KEY_PRESS && (kdev->mods & KM_LCTRL) &&
 		key == KC_F3) {
-		active_layout = 2;
-		layout[active_layout]->reset();
+		layout_destroy(kdev->active_layout);
+		kdev->active_layout = layout_create(layout[2]);
 		return;
 	}
@@ -171,7 +163,7 @@
 	ev.type = type;
 	ev.key = key;
-	ev.mods = mods;
-
-	ev.c = layout[active_layout]->parse_ev(&ev);
+	ev.mods = kdev->mods;
+
+	ev.c = layout_parse_ev(kdev->active_layout, &ev);
 
 	async_obsolete_msg_4(client_phone, INPUT_EVENT, ev.type, ev.key, ev.mods, ev.c);
@@ -223,4 +215,23 @@
 }
 
+static kbd_dev_t *kbd_dev_new(void)
+{
+	kbd_dev_t *kdev;
+
+	kdev = calloc(1, sizeof(kbd_dev_t));
+	if (kdev == NULL) {
+		printf(NAME ": Allocating keyboard device. Out of memory.\n");
+		return NULL;
+	}
+
+	link_initialize(&kdev->kbd_devs);
+
+	kdev->mods = KM_NUM_LOCK;
+	kdev->lock_keys = 0;
+	kdev->active_layout = layout_create(layout[0]);
+
+	return kdev;
+}
+
 /** Add new legacy keyboard device. */
 static void kbd_add_dev(kbd_port_ops_t *port, kbd_ctl_ops_t *ctl)
@@ -228,14 +239,11 @@
 	kbd_dev_t *kdev;
 
-	kdev = malloc(sizeof(kbd_dev_t));
-	if (kdev == NULL) {
-		printf(NAME ": Failed adding keyboard device. Out of memory.\n");
+	kdev = kbd_dev_new();
+	if (kdev == NULL)
 		return;
-	}
-
-	link_initialize(&kdev->kbd_devs);
-	kdev->dev_path = NULL;
+
 	kdev->port_ops = port;
 	kdev->ctl_ops = ctl;
+	kdev->dev_path = NULL;
 
 	/* Initialize port driver. */
@@ -263,11 +271,8 @@
 	kbd_dev_t *kdev;
 
-	kdev = malloc(sizeof(kbd_dev_t));
-	if (kdev == NULL) {
-		printf(NAME ": Failed adding keyboard device. Out of memory.\n");
+	kdev = kbd_dev_new();
+	if (kdev == NULL)
 		return -1;
-	}
-
-	link_initialize(&kdev->kbd_devs);
+
 	kdev->dev_path = dev_path;
 	kdev->port_ops = NULL;
@@ -435,6 +440,4 @@
 	kbd_add_legacy_devs();
 
-	/* Initialize (reset) layout. */
-	layout[active_layout]->reset();
 	
 	/* Register driver */
Index: uspace/srv/hid/input/generic/layout.c
===================================================================
--- uspace/srv/hid/input/generic/layout.c	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
+++ uspace/srv/hid/input/generic/layout.c	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011 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 inputgen generic
+ * @brief Keyboard layouts
+ * @ingroup input
+ * @{
+ */
+/** @file
+ */
+
+#include <errno.h>
+#include <kbd.h>
+#include <layout.h>
+#include <stdlib.h>
+
+/** Create a new layout instance. */
+layout_t *layout_create(layout_ops_t *ops)
+{
+	layout_t *layout;
+
+	layout = calloc(1, sizeof(layout_t));
+	if (layout == NULL) {
+		printf(NAME ": Out of memory.\n");
+		return NULL;
+	}
+
+	layout->ops = ops;
+	if ((*ops->create)(layout) != EOK) {
+		free(layout);
+		return NULL;
+	}
+
+	return layout;
+}
+
+/** Destroy layout instance. */
+void layout_destroy(layout_t *layout)
+{
+	(*layout->ops->destroy)(layout);
+	free(layout);
+}
+
+/** Parse keyboard event. */
+wchar_t layout_parse_ev(layout_t *layout, kbd_event_t *ev)
+{
+	return (*layout->ops->parse_ev)(layout, ev);
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/input/include/kbd.h
===================================================================
--- uspace/srv/hid/input/include/kbd.h	(revision 9934f7d3082d2ffdd107cc0c78d61d504b0f401e)
+++ uspace/srv/hid/input/include/kbd.h	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
@@ -47,4 +47,5 @@
 struct kbd_port_ops;
 struct kbd_ctl_ops;
+struct layout;
 
 typedef struct kbd_dev {
@@ -63,4 +64,13 @@
 	/** Controller-private data */
 	void *ctl_private;
+
+	/** Currently active modifiers. */
+	unsigned mods;
+
+	/** Currently pressed lock keys. We track these to tackle autorepeat. */
+	unsigned lock_keys;
+
+	/** Active keyboard layout */
+	struct layout *active_layout;
 } kbd_dev_t;
 
Index: uspace/srv/hid/input/include/layout.h
===================================================================
--- uspace/srv/hid/input/include/layout.h	(revision 9934f7d3082d2ffdd107cc0c78d61d504b0f401e)
+++ uspace/srv/hid/input/include/layout.h	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
@@ -41,12 +41,27 @@
 #include <io/console.h>
 
-typedef struct {
-	void (*reset)(void);
-	wchar_t (*parse_ev)(kbd_event_t *);
-} layout_op_t;
+/** Layout instance state */
+typedef struct layout {
+	/** Ops structure */
+	struct layout_ops *ops;
 
-extern layout_op_t us_qwerty_op;
-extern layout_op_t us_dvorak_op;
-extern layout_op_t cz_op;
+	/* Layout-private data */
+	void *layout_priv;
+} layout_t;
+
+/** Layout ops */
+typedef struct layout_ops {
+	int (*create)(layout_t *);
+	void (*destroy)(layout_t *);
+	wchar_t (*parse_ev)(layout_t *, kbd_event_t *);
+} layout_ops_t;
+
+extern layout_ops_t us_qwerty_ops;
+extern layout_ops_t us_dvorak_ops;
+extern layout_ops_t cz_ops;
+
+extern layout_t *layout_create(layout_ops_t *);
+extern void layout_destroy(layout_t *);
+extern wchar_t layout_parse_ev(layout_t *, kbd_event_t *);
 
 #endif
Index: uspace/srv/hid/input/layout/cz.c
===================================================================
--- uspace/srv/hid/input/layout/cz.c	(revision 9934f7d3082d2ffdd107cc0c78d61d504b0f401e)
+++ uspace/srv/hid/input/layout/cz.c	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -32,4 +32,5 @@
  */
 
+#include <errno.h>
 #include <kbd.h>
 #include <io/console.h>
@@ -37,7 +38,9 @@
 #include <bool.h>
 #include <layout.h>
-
-static void layout_reset(void);
-static wchar_t layout_parse_ev(kbd_event_t *ev);
+#include <stdlib.h>
+
+static int cz_create(layout_t *);
+static void cz_destroy(layout_t *);
+static wchar_t cz_parse_ev(layout_t *, kbd_event_t *ev);
 
 enum m_state {
@@ -47,9 +50,12 @@
 };
 
-static enum m_state mstate;
-
-layout_op_t cz_op = {
-	layout_reset,
-	layout_parse_ev
+typedef struct {
+	enum m_state mstate;
+} layout_cz_t;
+
+layout_ops_t cz_ops = {
+	.create = cz_create,
+	.destroy = cz_destroy,
+	.parse_ev = cz_parse_ev
 };
 
@@ -273,9 +279,9 @@
 }
 
-static wchar_t parse_ms_hacek(kbd_event_t *ev)
+static wchar_t parse_ms_hacek(layout_cz_t *cz_state, kbd_event_t *ev)
 {
 	wchar_t c;
 
-	mstate = ms_start;
+	cz_state->mstate = ms_start;
 
 	/* Produce no characters when Ctrl or Alt is pressed. */
@@ -291,9 +297,9 @@
 }
 
-static wchar_t parse_ms_carka(kbd_event_t *ev)
+static wchar_t parse_ms_carka(layout_cz_t *cz_state, kbd_event_t *ev)
 {
 	wchar_t c;
 
-	mstate = ms_start;
+	cz_state->mstate = ms_start;
 
 	/* Produce no characters when Ctrl or Alt is pressed. */
@@ -309,5 +315,5 @@
 }
 
-static wchar_t parse_ms_start(kbd_event_t *ev)
+static wchar_t parse_ms_start(layout_cz_t *cz_state, kbd_event_t *ev)
 {
 	wchar_t c;
@@ -319,7 +325,7 @@
 	if (ev->key == KC_EQUALS) {
 		if ((ev->mods & KM_SHIFT) != 0)
-			mstate = ms_hacek;
+			cz_state->mstate = ms_hacek;
 		else
-			mstate = ms_carka;
+			cz_state->mstate = ms_carka;
 
 		return 0;
@@ -379,11 +385,29 @@
 }
 
-static void layout_reset(void)
-{
-	mstate = ms_start;
-}
-
-static wchar_t layout_parse_ev(kbd_event_t *ev)
-{
+static int cz_create(layout_t *state)
+{
+	layout_cz_t *cz_state;
+
+	cz_state = malloc(sizeof(layout_cz_t));
+	if (cz_state == NULL) {
+		printf(NAME ": Out of memory.\n");
+		return ENOMEM;
+	}
+
+	cz_state->mstate = ms_start;
+	state->layout_priv = (void *) cz_state;
+
+	return EOK;
+}
+
+static void cz_destroy(layout_t *state)
+{
+	free(state->layout_priv);
+}
+
+static wchar_t cz_parse_ev(layout_t *state, kbd_event_t *ev)
+{
+	layout_cz_t *cz_state = (layout_cz_t *) state->layout_priv;
+
 	if (ev->type != KEY_PRESS)
 		return 0;
@@ -392,11 +416,11 @@
 		return 0;
 	
-	switch (mstate) {
+	switch (cz_state->mstate) {
 	case ms_start:
-		return parse_ms_start(ev);
+		return parse_ms_start(cz_state, ev);
 	case ms_hacek:
-		return parse_ms_hacek(ev);
+		return parse_ms_hacek(cz_state, ev);
 	case ms_carka:
-		return parse_ms_carka(ev);
+		return parse_ms_carka(cz_state, ev);
 	}
 	
Index: uspace/srv/hid/input/layout/us_dvorak.c
===================================================================
--- uspace/srv/hid/input/layout/us_dvorak.c	(revision 9934f7d3082d2ffdd107cc0c78d61d504b0f401e)
+++ uspace/srv/hid/input/layout/us_dvorak.c	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -32,4 +32,5 @@
  */
 
+#include <errno.h>
 #include <kbd.h>
 #include <io/console.h>
@@ -37,10 +38,12 @@
 #include <layout.h>
 
-static void layout_reset(void);
-static wchar_t layout_parse_ev(kbd_event_t *ev);
-
-layout_op_t us_dvorak_op = {
-	layout_reset,
-	layout_parse_ev
+static int us_dvorak_create(layout_t *);
+static void us_dvorak_destroy(layout_t *);
+static wchar_t us_dvorak_parse_ev(layout_t *, kbd_event_t *ev);
+
+layout_ops_t us_dvorak_ops = {
+	.create = us_dvorak_create,
+	.destroy = us_dvorak_destroy,
+	.parse_ev = us_dvorak_parse_ev
 };
 
@@ -206,9 +209,14 @@
 }
 
-static void layout_reset(void)
-{
-}
-
-static wchar_t layout_parse_ev(kbd_event_t *ev)
+static int us_dvorak_create(layout_t *state)
+{
+	return EOK;
+}
+
+static void us_dvorak_destroy(layout_t *state)
+{
+}
+
+static wchar_t us_dvorak_parse_ev(layout_t *state, kbd_event_t *ev)
 {
 	wchar_t c;
Index: uspace/srv/hid/input/layout/us_qwerty.c
===================================================================
--- uspace/srv/hid/input/layout/us_qwerty.c	(revision 9934f7d3082d2ffdd107cc0c78d61d504b0f401e)
+++ uspace/srv/hid/input/layout/us_qwerty.c	(revision 2f7a5647f7a9315b07b64e4cab256d608a391065)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011 Jiri Svoboda
  * All rights reserved.
  *
@@ -32,4 +32,5 @@
  */
 
+#include <errno.h>
 #include <kbd.h>
 #include <io/console.h>
@@ -37,10 +38,12 @@
 #include <layout.h>
 
-static void layout_reset(void);
-static wchar_t layout_parse_ev(kbd_event_t *ev);
-
-layout_op_t us_qwerty_op = {
-	layout_reset,
-	layout_parse_ev
+static int us_qwerty_create(layout_t *);
+static void us_qwerty_destroy(layout_t *);
+static wchar_t us_qwerty_parse_ev(layout_t *, kbd_event_t *ev);
+
+layout_ops_t us_qwerty_ops = {
+	.create = us_qwerty_create,
+	.destroy = us_qwerty_destroy,
+	.parse_ev = us_qwerty_parse_ev
 };
 
@@ -200,9 +203,14 @@
 }
 
-static void layout_reset(void)
-{
-}
-
-static wchar_t layout_parse_ev(kbd_event_t *ev)
+static int us_qwerty_create(layout_t *state)
+{
+	return EOK;
+}
+
+static void us_qwerty_destroy(layout_t *state)
+{
+}
+
+static wchar_t us_qwerty_parse_ev(layout_t *state, kbd_event_t *ev)
 {
 	wchar_t c;
