Index: uspace/app/bdsh/cmds/modules/cat/cat.c
===================================================================
--- uspace/app/bdsh/cmds/modules/cat/cat.c	(revision 33fc3aeab329e1c9379060b6ba8f5568ad21d9fa)
+++ uspace/app/bdsh/cmds/modules/cat/cat.c	(revision f4a8734aba1f1f8923661a4d49e442f2eeb00e06)
@@ -62,4 +62,5 @@
 static sysarg_t console_rows = 0;
 static bool should_quit = false;
+static bool dash_represents_stdin = false;
 
 static console_ctrl_t *console = NULL;
@@ -73,4 +74,5 @@
 	{ "more", no_argument, 0, 'm' },
 	{ "hex", no_argument, 0, 'x' },
+	{ "stdin", no_argument, 0, 's' },
 	{ 0, 0, 0, 0 }
 };
@@ -93,4 +95,5 @@
 		"  -m, --more       Pause after each screen full\n"
 		"  -x, --hex        Print bytes as hex values\n"
+		"  -s  --stdin      Treat `-' in file list as standard input\n"
 		"Currently, %s is under development, some options don't work.\n",
 		cmdname, cmdname);
@@ -172,5 +175,13 @@
 	off64_t file_size = 0, length = 0;
 
-	fd = open(fname, O_RDONLY);
+	bool reading_stdin = dash_represents_stdin && (str_cmp(fname, "-") == 0);
+
+	if (reading_stdin) {
+		fd = fileno(stdin);
+		/* Allow storing the whole UTF-8 character. */
+		blen = STR_BOUNDS(1);
+	} else {
+		fd = open(fname, O_RDONLY);
+	}
 	if (fd < 0) {
 		printf("Unable to open %s\n", fname);
@@ -207,8 +218,16 @@
 
 	do {
-		bytes = read(fd, buff + copied_bytes, (
-			(length != CAT_FULL_FILE && length - (off64_t)count <= (off64_t)(blen - copied_bytes)) ?
-			(size_t)(length - count) :
-			(blen - copied_bytes) ) );
+		size_t bytes_to_read;
+		if (reading_stdin) {
+			bytes_to_read = 1;
+		} else {
+			if ((length != CAT_FULL_FILE)
+			    && (length - (off64_t)count <= (off64_t)(blen - copied_bytes))) {
+				bytes_to_read = (size_t) (length - count);
+			} else {
+				bytes_to_read = blen - copied_bytes;
+			}
+		}
+		bytes = read(fd, buff + copied_bytes, bytes_to_read);
 		bytes += copied_bytes;
 		copied_bytes = 0;
@@ -242,4 +261,8 @@
 			reads++;
 		}
+
+		if (reading_stdin) {
+			fflush(stdout);
+		}
 	} while (bytes > 0 && !should_quit && (count < length || length == CAT_FULL_FILE));
 
@@ -284,5 +307,5 @@
 
 	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
-		c = getopt_long(argc, argv, "xhvmH:t:b:", long_options, &opt_ind);
+		c = getopt_long(argc, argv, "xhvmH:t:b:s", long_options, &opt_ind);
 		switch (c) {
 		case 'h':
@@ -318,4 +341,7 @@
 			hex = true;
 			break;
+		case 's':
+			dash_represents_stdin = true;
+			break;
 		}
 	}
Index: uspace/srv/hid/console/console.c
===================================================================
--- uspace/srv/hid/console/console.c	(revision 33fc3aeab329e1c9379060b6ba8f5568ad21d9fa)
+++ uspace/srv/hid/console/console.c	(revision f4a8734aba1f1f8923661a4d49e442f2eeb00e06)
@@ -76,7 +76,11 @@
 } console_state_t;
 
+#define UTF8_CHAR_BUFFER_SIZE (STR_BOUNDS(1) + 1)
+
 typedef struct {
 	atomic_t refcnt;           /**< Connection reference count */
 	prodcons_t input_pc;       /**< Incoming keyboard events */
+	char char_remains[UTF8_CHAR_BUFFER_SIZE]; /**< Not yet sent bytes of last char event. */
+	size_t char_remains_len;   /**< Number of not yet sent bytes. */
 	
 	fibril_mutex_t mtx;        /**< Lock protecting mutable fields */
@@ -613,14 +617,35 @@
 	
 	size_t pos = 0;
+
+	/*
+	 * Read input from keyboard and copy it to the buffer.
+	 * We need to handle situation when wchar is split by 2 following
+	 * reads.
+	 */
 	while (pos < size) {
-		link_t *link = prodcons_consume(&cons->input_pc);
-		kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
-		
-		if (event->type == KEY_PRESS) {
-			buf[pos] = event->c;
+		/* Copy to the buffer remaining characters. */
+		while ((pos < size) && (cons->char_remains_len > 0)) {
+			buf[pos] = cons->char_remains[0];
 			pos++;
-		}
-		
-		free(event);
+			/* Unshift the array. */
+			for (size_t i = 1; i < cons->char_remains_len; i++) {
+				cons->char_remains[i - 1] = cons->char_remains[i];
+			}
+			cons->char_remains_len--;
+		}
+		/* Still not enough? Then get another key from the queue. */
+		if (pos < size) {
+			link_t *link = prodcons_consume(&cons->input_pc);
+			kbd_event_t *event = list_get_instance(link, kbd_event_t, link);
+
+			/* Accept key presses of printable chars only. */
+			if ((event->type == KEY_PRESS) && (event->c != 0)) {
+				wchar_t tmp[2] = { event->c, 0 };
+				wstr_to_str(cons->char_remains, UTF8_CHAR_BUFFER_SIZE, tmp);
+				cons->char_remains_len = str_size(cons->char_remains);
+			}
+
+			free(event);
+		}
 	}
 	
@@ -930,4 +955,5 @@
 		fibril_mutex_initialize(&consoles[i].mtx);
 		prodcons_initialize(&consoles[i].input_pc);
+		consoles[i].char_remains_len = 0;
 		
 		if (graphics_state == GRAPHICS_FULL) {
