Index: kernel/generic/include/string.h
===================================================================
--- kernel/generic/include/string.h	(revision b60c582d0cf4f0476a720c8e05bd742fbffc87ce)
+++ kernel/generic/include/string.h	(revision c8bf88d737f715dd3bf256ec6f8bf31e0d3be7e1)
@@ -38,10 +38,29 @@
 #include <typedefs.h>
 
+/**< Common Unicode characters */
+#define U_SPECIAL      '?'
+
+#define U_LEFT_ARROW   0x2190
+#define U_UP_ARROW     0x2191
+#define U_RIGHT_ARROW  0x2192
+#define U_DOWN_ARROW   0x2193
+
+#define U_PAGE_UP      0x21de
+#define U_PAGE_DOWN    0x21df
+
+#define U_HOME_ARROW   0x21f1
+#define U_END_ARROW    0x21f2
+
+#define U_NULL         0x2400
+#define U_ESCAPE       0x241b
+#define U_DELETE       0x2421
+
+#define U_CURSOR       0x2588
+
+/**< No size limit constant */
 #define STR_NO_LIMIT  ((size_t) -1)
 
 /**< Maximum size of a string containing cnt characters */
 #define STR_BOUNDS(cnt)  (cnt << 2)
-
-extern char invalch;
 
 extern wchar_t str_decode(const char *str, size_t *offset, size_t sz);
Index: kernel/generic/include/sysinfo/sysinfo.h
===================================================================
--- kernel/generic/include/sysinfo/sysinfo.h	(revision b60c582d0cf4f0476a720c8e05bd742fbffc87ce)
+++ kernel/generic/include/sysinfo/sysinfo.h	(revision c8bf88d737f715dd3bf256ec6f8bf31e0d3be7e1)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup generic	
+/** @addtogroup generic
  * @{
  */
@@ -37,4 +37,5 @@
 
 #include <arch/types.h>
+#include <string.h>
 
 typedef union sysinfo_item_val {
@@ -60,11 +61,11 @@
 } sysinfo_item_t;
 
-#define SYSINFO_VAL_VAL 0
-#define SYSINFO_VAL_FUNCTION 1
-#define SYSINFO_VAL_UNDEFINED '?'
+#define SYSINFO_VAL_VAL        0
+#define SYSINFO_VAL_FUNCTION   1
+#define SYSINFO_VAL_UNDEFINED  U_SPECIAL
 
-#define SYSINFO_SUBINFO_NONE 0
-#define SYSINFO_SUBINFO_TABLE 1
-#define SYSINFO_SUBINFO_FUNCTION 2
+#define SYSINFO_SUBINFO_NONE      0
+#define SYSINFO_SUBINFO_TABLE     1
+#define SYSINFO_SUBINFO_FUNCTION  2
 
 typedef unative_t (*sysinfo_val_fn_t)(sysinfo_item_t *root);
Index: kernel/generic/src/console/kconsole.c
===================================================================
--- kernel/generic/src/console/kconsole.c	(revision b60c582d0cf4f0476a720c8e05bd742fbffc87ce)
+++ kernel/generic/src/console/kconsole.c	(revision c8bf88d737f715dd3bf256ec6f8bf31e0d3be7e1)
@@ -260,8 +260,8 @@
 			
 			if (wstr_remove(current, position - 1)) {
+				position--;
 				putchar('\b');
-				printf("%ls", current + position);
-				position--;
-				print_cc('\b', wstr_length(current) - position);
+				printf("%ls ", current + position);
+				print_cc('\b', wstr_length(current) - position + 1);
 				continue;
 			}
@@ -334,63 +334,67 @@
 		}
 		
-		if (ch == 0x1b) {
-			/* Special command */
-			wchar_t mod = _getc(indev);
-			wchar_t ch = _getc(indev);
-			
-			if ((mod != 0x5b) && (mod != 0x4f))
+		if (ch == U_LEFT_ARROW) {
+			/* Left */
+			if (position > 0) {
+				putchar('\b');
+				position--;
+			}
+			continue;
+		}
+		
+		if (ch == U_RIGHT_ARROW) {
+			/* Right */
+			if (position < wstr_length(current)) {
+				putchar(current[position]);
+				position++;
+			}
+			continue;
+		}
+		
+		if ((ch == U_UP_ARROW) || (ch == U_DOWN_ARROW)) {
+			/* Up, down */
+			print_cc('\b', position);
+			print_cc(' ', wstr_length(current));
+			print_cc('\b', wstr_length(current));
+			
+			if (ch == U_UP_ARROW) {
+				/* Up */
+				if (history_pos == 0)
+					history_pos = KCONSOLE_HISTORY - 1;
+				else
+					history_pos--;
+			} else {
+				/* Down */
+				history_pos++;
+				history_pos = history_pos % KCONSOLE_HISTORY;
+			}
+			current = history[history_pos];
+			printf("%ls", current);
+			position = wstr_length(current);
+			continue;
+		}
+		
+		if (ch == U_HOME_ARROW) {
+			/* Home */
+			print_cc('\b', position);
+			position = 0;
+			continue;
+		}
+		
+		if (ch == U_END_ARROW) {
+			/* End */
+			printf("%ls", current + position);
+			position = wstr_length(current);
+			continue;
+		}
+		
+		if (ch == U_DELETE) {
+			/* Delete */
+			if (position == wstr_length(current))
 				continue;
 			
-			if ((ch == 0x33) && (_getc(indev) == 0x7e)) {
-				/* Delete */
-				if (position == wstr_length(current))
-					continue;
-				
-				if (wstr_remove(current, position)) {
-					putchar('\b');
-					printf("%ls", current + position);
-					position--;
-					print_cc('\b', wstr_length(current) - position);
-				}
-			} else if (ch == 0x48) {
-				/* Home */
-				print_cc('\b', position);
-				position = 0;
-			} else if (ch == 0x46) {
-				/* End */
-				printf("%ls", current + position);
-				position = wstr_length(current);
-			} else if (ch == 0x44) {
-				/* Left */
-				if (position > 0) {
-					putchar('\b');
-					position--;
-				}
-			} else if (ch == 0x43) {
-				/* Right */
-				if (position < wstr_length(current)) {
-					putchar(current[position]);
-					position++;
-				}
-			} else if ((ch == 0x41) || (ch == 0x42)) {
-				/* Up, down */
-				print_cc('\b', position);
-				print_cc(' ', wstr_length(current));
-				print_cc('\b', wstr_length(current));
-				
-				if (ch == 0x41) {
-					/* Up */
-					if (history_pos == 0)
-						history_pos = KCONSOLE_HISTORY - 1;
-					else
-						history_pos--;
-				} else {
-					/* Down */
-					history_pos++;
-					history_pos = history_pos % KCONSOLE_HISTORY;
-				}
-				current = history[history_pos];
-				printf("%ls", current);
-				position = wstr_length(current);
+			if (wstr_remove(current, position)) {
+				printf("%ls ", current + position);
+				print_cc('\b', wstr_length(current) - position + 1);
 			}
 			continue;
Index: kernel/generic/src/lib/string.c
===================================================================
--- kernel/generic/src/lib/string.c	(revision b60c582d0cf4f0476a720c8e05bd742fbffc87ce)
+++ kernel/generic/src/lib/string.c	(revision c8bf88d737f715dd3bf256ec6f8bf31e0d3be7e1)
@@ -110,6 +110,4 @@
 #include <align.h>
 
-char invalch = '?';
-
 /** Byte mask consisting of lowest @n bits (out of 8) */
 #define LO_MASK_8(n)  ((uint8_t) ((1 << (n)) - 1))
@@ -135,5 +133,5 @@
  * @param size   Size of the string (in bytes).
  *
- * @return Value of decoded character, invalch on decoding error or
+ * @return Value of decoded character, U_SPECIAL on decoding error or
  *         NULL if attempt to decode beyond @a size.
  *
@@ -170,9 +168,9 @@
 	} else {
 		/* 10xxxxxx -- unexpected continuation byte */
-		return invalch;
+		return U_SPECIAL;
 	}
 	
 	if (*offset + cbytes > size)
-		return invalch;
+		return U_SPECIAL;
 	
 	wchar_t ch = b0 & LO_MASK_8(b0_bits);
@@ -184,5 +182,5 @@
 		/* Must be 10xxxxxx */
 		if ((b & 0xc0) != 0x80)
-			return invalch;
+			return U_SPECIAL;
 		
 		/* Shift data bits to ch */
Index: kernel/generic/src/printf/printf_core.c
===================================================================
--- kernel/generic/src/printf/printf_core.c	(revision b60c582d0cf4f0476a720c8e05bd742fbffc87ce)
+++ kernel/generic/src/printf/printf_core.c	(revision c8bf88d737f715dd3bf256ec6f8bf31e0d3be7e1)
@@ -82,4 +82,5 @@
 static char digits_small[] = "0123456789abcdef";
 static char digits_big[] = "0123456789ABCDEF";
+static char invalch = U_SPECIAL;
 
 /** Print one or more characters without adding newline.
