New console code based on Win32 windows.

diff --git a/Makefile.in b/Makefile.in
index 1ea3e04..40f2aa8 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -28,7 +28,8 @@
 
 # Programs that link with libwine
 LIBPROGRAMS = \
-	debugger/winedbg
+	debugger/winedbg \
+	programs/wineconsole/wineconsole
 
 # Libraries (not dlls) to build
 LIBRARIES = \
@@ -59,6 +60,7 @@
 	include \
 	library \
 	ole \
+	programs/wineconsole \
 	server \
 	tools \
 	tsx11 \
diff --git a/configure b/configure
index 3fffe36..52f9d82 100755
--- a/configure
+++ b/configure
@@ -7166,6 +7166,7 @@
 programs/uninstaller/Makefile
 programs/view/Makefile
 programs/wcmd/Makefile
+programs/wineconsole/Makefile
 programs/winemine/Makefile
 programs/winetest/Makefile
 programs/winhelp/Makefile
@@ -7426,6 +7427,7 @@
 programs/uninstaller/Makefile
 programs/view/Makefile
 programs/wcmd/Makefile
+programs/wineconsole/Makefile
 programs/winemine/Makefile
 programs/winetest/Makefile
 programs/winhelp/Makefile
diff --git a/configure.in b/configure.in
index 333b38a..aaee280 100644
--- a/configure.in
+++ b/configure.in
@@ -1336,6 +1336,7 @@
 programs/uninstaller/Makefile
 programs/view/Makefile
 programs/wcmd/Makefile
+programs/wineconsole/Makefile
 programs/winemine/Makefile
 programs/winetest/Makefile
 programs/winhelp/Makefile
diff --git a/dlls/x11drv/x11drv_main.c b/dlls/x11drv/x11drv_main.c
index 476eba6..202e921 100644
--- a/dlls/x11drv/x11drv_main.c
+++ b/dlls/x11drv/x11drv_main.c
@@ -444,7 +444,7 @@
     if (synchronous) XSynchronize( data->display, True );
     wine_tsx11_unlock();
     data->display_fd = FILE_DupUnixHandle( ConnectionNumber(data->display),
-                                           GENERIC_READ | SYNCHRONIZE );
+                                           GENERIC_READ | SYNCHRONIZE, FALSE );
     data->process_event_count = 0;
     NtCurrentTeb()->driver_data = data;
     return data;
diff --git a/documentation/running.sgml b/documentation/running.sgml
index 4dd950e..e1277c6 100644
--- a/documentation/running.sgml
+++ b/documentation/running.sgml
@@ -93,6 +93,17 @@
         options that affect the Windows program should come
         <emphasis>after</emphasis> it.
       </para>
+
+      <para>
+        If you want to run a console program (aka a CUI executable), use
+	<command>wineconsole</command> instead of <command>wine</command>
+	to start it. It will display the program in a separate Window
+	(this requires X11 to be run). If you don't, you'll still be able
+	to run able your program, in the Unix console were you're started
+	your program, but with very limited capacities (so, your program
+	might work, but your mileage may vary). This shall be improved
+	in the future.
+      </para>
     </sect1>
 
     <sect1 id="command-line-options">
diff --git a/documentation/wine.man.in b/documentation/wine.man.in
index e87c156..88da2db 100644
--- a/documentation/wine.man.in
+++ b/documentation/wine.man.in
@@ -1,5 +1,5 @@
 .\" -*- nroff -*-
-.TH WINE 1 "Aug 5, 2001" "Version 20010731" "Windows On Unix"
+.TH WINE 1 "Oct 13, 2001" "Version 20011004" "Windows On Unix"
 .SH NAME
 wine \- run Windows programs on Unix
 .SH SYNOPSIS
@@ -20,6 +20,16 @@
 .I program
 instead.
 .PP
+For running CUI executables (Windows console programs), use
+.B wineconsole
+instead of
+.B wine
+. This will display all the output in a separate windows (this requires X11 to
+run). Not using
+.B wineconsole
+for CUI programs will only provide very limited console support, and your
+program might not function properly.
+.PP
 .B wine 
 currently runs a growing list of applications written for all kinds of
 Windows versions >= Win2.0, e.g. Win3.1, Win95/98, NT.
@@ -350,6 +360,11 @@
 .B wine 
 program loader.
 .TP
+.I @prefix@/bin/wineconsole
+The 
+.B wine 
+program loader for CUI (console) applications.
+.TP
 .I @prefix@/bin/dosmod
 The DOS program loader.
 .TP
diff --git a/files/file.c b/files/file.c
index b9e3fb0..42f69e7 100644
--- a/files/file.c
+++ b/files/file.c
@@ -182,7 +182,7 @@
  * Duplicate a Unix handle into a task handle.
  * Returns 0 on failure.
  */
-HANDLE FILE_DupUnixHandle( int fd, DWORD access )
+HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit )
 {
     HANDLE ret;
 
@@ -191,6 +191,7 @@
     SERVER_START_REQ( alloc_file_handle )
     {
         req->access  = access;
+        req->inherit = inherit;
         req->fd      = fd;
         SERVER_CALL();
         ret = req->handle;
@@ -255,14 +256,15 @@
  * Open a handle to the current process console.
  * Returns 0 on failure.
  */
-static HANDLE FILE_OpenConsole( BOOL output, DWORD access, LPSECURITY_ATTRIBUTES sa )
+static HANDLE FILE_OpenConsole( BOOL output, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa )
 {
     HANDLE ret;
 
     SERVER_START_REQ( open_console )
     {
-        req->output  = output;
+        req->from    = output;
         req->access  = access;
+	req->share   = sharing;
         req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
         SetLastError(0);
         SERVER_CALL_ERR();
@@ -477,12 +479,12 @@
     /* Open a console for CONIN$ or CONOUT$ */
     if (!strcasecmp(filename, "CONIN$"))
     {
-        ret = FILE_OpenConsole( FALSE, access, sa );
+        ret = FILE_OpenConsole( FALSE, access, sharing, sa );
         goto done;
     }
     if (!strcasecmp(filename, "CONOUT$"))
     {
-        ret = FILE_OpenConsole( TRUE, access, sa );
+        ret = FILE_OpenConsole( TRUE, access, sharing, sa );
         goto done;
     }
 
@@ -1452,15 +1454,14 @@
     if (!bytesToRead) return TRUE;
 
     unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type );
-    if (unix_handle == -1)
-        return FALSE;
 
-    switch(type)
+    switch (type)
     {
     case FD_TYPE_OVERLAPPED:
-        if(!overlapped)
+	if (unix_handle == -1) return FALSE;
+        if (!overlapped)
         {
-            close(unix_handle);
+	    close(unix_handle);
             SetLastError(ERROR_INVALID_PARAMETER);
             return FALSE;
         }
@@ -1493,23 +1494,28 @@
         SetLastError(ERROR_IO_PENDING);
         return FALSE;
 
+    case FD_TYPE_CONSOLE:
+	return ReadConsoleA(hFile, buffer, bytesToRead, bytesRead, NULL);
     default:
-        if(overlapped)
-        {
-            close(unix_handle);
-            SetLastError(ERROR_INVALID_PARAMETER);
-            return FALSE;
-        }
-        break;
+	/* normal unix files */
+	if (unix_handle == -1)
+	    return FALSE;    
+	if (overlapped)
+	{
+	    close(unix_handle);
+	    SetLastError(ERROR_INVALID_PARAMETER);
+	    return FALSE;
+	}
+	break;
     }
 
     /* code for synchronous reads */
     while ((result = read( unix_handle, buffer, bytesToRead )) == -1)
     {
-        if ((errno == EAGAIN) || (errno == EINTR)) continue;
-        if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
-        FILE_SetDosError();
-        break;
+	if ((errno == EAGAIN) || (errno == EINTR)) continue;
+	if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue;
+	FILE_SetDosError();
+	break;
     }
     close( unix_handle );
     if (result == -1) return FALSE;
@@ -1648,6 +1654,7 @@
                          LPDWORD bytesWritten, LPOVERLAPPED overlapped )
 {
     int unix_handle, result;
+    DWORD type;
 
     TRACE("%d %p %ld %p %p\n", hFile, buffer, bytesToWrite, 
           bytesWritten, overlapped );
@@ -1659,8 +1666,18 @@
     if ( overlapped )
         return WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL);
 
-    unix_handle = FILE_GetUnixHandle( hFile, GENERIC_WRITE );
-    if (unix_handle == -1) return FALSE;
+    unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type );
+
+    switch (type)
+    {
+    case FD_TYPE_CONSOLE:
+	TRACE("%d %s %ld %p %p\n", hFile, debugstr_an(buffer, bytesToWrite), bytesToWrite, 
+	      bytesWritten, overlapped );
+	return WriteConsoleA(hFile, buffer, bytesToWrite, bytesWritten, NULL);
+    default:
+	if (unix_handle == -1)
+	    return FALSE;
+    }
 
     /* synchronous file write */
     while ((result = write( unix_handle, buffer, bytesToWrite )) == -1)
diff --git a/include/file.h b/include/file.h
index 260f8dd..5efc9a5 100644
--- a/include/file.h
+++ b/include/file.h
@@ -71,7 +71,7 @@
 extern int FILE_strcasecmp( const char *str1, const char *str2 );
 extern int FILE_strncasecmp( const char *str1, const char *str2, int len );
 extern void FILE_SetDosError(void);
-extern HANDLE FILE_DupUnixHandle( int fd, DWORD access );
+extern HANDLE FILE_DupUnixHandle( int fd, DWORD access, BOOL inherit );
 extern int FILE_GetUnixHandle( HANDLE handle, DWORD access );
 extern BOOL FILE_Stat( LPCSTR unixName, BY_HANDLE_FILE_INFORMATION *info );
 extern HFILE16 FILE_Dup2( HFILE16 hFile1, HFILE16 hFile2 );
diff --git a/include/wincon.h b/include/wincon.h
index 016e0d1..233acda 100644
--- a/include/wincon.h
+++ b/include/wincon.h
@@ -17,6 +17,8 @@
 #define ENABLE_ECHO_INPUT      0x04
 #define ENABLE_WINDOW_INPUT    0x08
 #define ENABLE_MOUSE_INPUT     0x10
+/* Wine only code (extension) */
+#define WINE_ENABLE_LINE_INPUT_EMACS 0x80
 
 #define ENABLE_PROCESSED_OUTPUT   0x01
 #define ENABLE_WRAP_AT_EOL_OUTPUT 0x02
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index b83ca78..94f40d6 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -577,6 +577,7 @@
 {
     struct request_header __header;
     unsigned int access;
+    int          inherit;
     int          fd;
     handle_t     handle;
 };
@@ -755,8 +756,9 @@
     struct request_header __header;
     unsigned int access;
     int          inherit;
+    void*        pid;
     handle_t     handle_in;
-    handle_t     handle_out;
+    handle_t     event;
 };
 
 
@@ -767,25 +769,69 @@
 };
 
 
+#define CONSOLE_RENDERER_NONE_EVENT        0x00
+#define CONSOLE_RENDERER_TITLE_EVENT       0x01
+#define CONSOLE_RENDERER_ACTIVE_SB_EVENT   0x02
+#define CONSOLE_RENDERER_SB_RESIZE_EVENT   0x03
+#define CONSOLE_RENDERER_UPDATE_EVENT      0x04
+#define CONSOLE_RENDERER_CURSOR_POS_EVENT  0x05
+#define CONSOLE_RENDERER_CURSOR_GEOM_EVENT 0x06
+#define CONSOLE_RENDERER_DISPLAY_EVENT     0x07
+#define CONSOLE_RENDERER_EXIT_EVENT        0x08
+struct console_renderer_event
+{
+    short event;
+    union
+    {
+        struct update
+        {
+            short top;
+            short bottom;
+        } update;
+        struct resize
+        {
+            short width;
+            short height;
+        } resize;
+        struct cursor_pos
+        {
+            short x;
+            short y;
+        } cursor_pos;
+        struct cursor_geom
+        {
+            short visible;
+            short size;
+        } cursor_geom;
+        struct display
+        {
+            short left;
+            short top;
+            short width;
+            short height;
+        } display;
+    } u;
+};
 
-struct open_console_request
+
+struct get_console_renderer_events_request
 {
     struct request_header __header;
-    int          output;
-    unsigned int access;
-    int          inherit;
     handle_t     handle;
+    /* VARARG(data,bytes); */
 };
 
 
 
-struct set_console_fd_request
+struct open_console_request
 {
     struct request_header __header;
+    int          from;
+
+    unsigned int access;
+    int          inherit;
+    int          share;
     handle_t     handle;
-    int          fd_in;
-    int          fd_out;
-    int          pid;
 };
 
 
@@ -808,31 +854,114 @@
 
 
 
-struct set_console_info_request
+struct set_console_input_info_request
 {
     struct request_header __header;
     handle_t     handle;
     int          mask;
-    int          cursor_size;
-    int          cursor_visible;
-    /* VARARG(title,string); */
+    handle_t     active_sb;
+    int          history_mode;
+    int          history_size;
+    /* VARARG(title,unicode_str); */
 };
-#define SET_CONSOLE_INFO_CURSOR 0x01
-#define SET_CONSOLE_INFO_TITLE  0x02
+#define SET_CONSOLE_INPUT_INFO_ACTIVE_SB        0x01
+#define SET_CONSOLE_INPUT_INFO_TITLE            0x02
+#define SET_CONSOLE_INPUT_INFO_HISTORY_MODE     0x04
+#define SET_CONSOLE_INPUT_INFO_HISTORY_SIZE     0x08
 
 
-struct get_console_info_request
+
+struct get_console_input_info_request
 {
     struct request_header __header;
     handle_t     handle;
-    int          cursor_size;
-    int          cursor_visible;
-    int          pid;
-    /* VARARG(title,string); */
+    int          history_mode;
+    int          history_size;
+    int          history_index;
+    /* VARARG(title,unicode_str); */
 };
 
 
 
+struct append_console_input_history_request
+{
+    struct request_header __header;
+    handle_t     handle;
+    /* VARARG(line,unicode_str); */
+};
+
+
+
+struct get_console_input_history_request
+{
+    struct request_header __header;
+    handle_t     handle;
+    int          index;
+    /* VARARG(line,unicode_str); */
+};
+
+
+
+struct create_console_output_request
+{
+    struct request_header __header;
+    handle_t     handle_in;
+    int          access;
+    int          share;
+    int          inherit;
+    handle_t     handle_out;
+};
+
+
+
+struct set_console_output_info_request
+{
+    struct request_header __header;
+    handle_t     handle;
+    int          mask;
+    short int    cursor_size;
+    short int    cursor_visible;
+    short int    cursor_x;
+    short int    cursor_y;
+    short int    width;
+    short int    height;
+    short int    attr;
+    short int    win_left;
+    short int    win_top;
+    short int    win_right;
+    short int    win_bottom;
+    short int    max_width;
+    short int    max_height;
+};
+#define SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM     0x01
+#define SET_CONSOLE_OUTPUT_INFO_CURSOR_POS      0x02
+#define SET_CONSOLE_OUTPUT_INFO_SIZE            0x04
+#define SET_CONSOLE_OUTPUT_INFO_ATTR            0x08
+#define SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW  0x10
+#define SET_CONSOLE_OUTPUT_INFO_MAX_SIZE        0x20
+
+
+
+struct get_console_output_info_request
+{
+    struct request_header __header;
+    handle_t     handle;
+    short int    cursor_size;
+    short int    cursor_visible;
+    short int    cursor_x;
+    short int    cursor_y;
+    short int    width;
+    short int    height;
+    short int    attr;
+    short int    win_left;
+    short int    win_top;
+    short int    win_right;
+    short int    win_bottom;
+    short int    max_width;
+    short int    max_height;
+};
+
+
 struct write_console_input_request
 {
     struct request_header __header;
@@ -842,6 +971,7 @@
 };
 
 
+
 struct read_console_input_request
 {
     struct request_header __header;
@@ -853,6 +983,53 @@
 
 
 
+struct write_console_output_request
+{
+    struct request_header __header;
+    handle_t     handle;
+    int          mode;
+
+    short int    x;
+    short int    y;
+    /* VARARG(data,bytes); */
+    int          written;
+};
+#define WRITE_CONSOLE_MODE_TEXT         0x00
+#define WRITE_CONSOLE_MODE_ATTR         0x01
+#define WRITE_CONSOLE_MODE_TEXTATTR     0x02
+#define WRITE_CONSOLE_MODE_TEXTSTDATTR  0x03
+#define WRITE_CONSOLE_MODE_UNIFORM      0x04
+
+
+
+struct read_console_output_request
+{
+    struct request_header __header;
+    handle_t     handle;
+    short int    x;
+    short int    y;
+    short int    w;
+    short int    h;
+    short int    eff_w;
+    short int    eff_h;
+    /* VARARG(data,bytes); */
+};
+
+
+struct move_console_output_request
+{
+    struct request_header __header;
+    handle_t     handle;
+    short int    x_src;
+    short int    y_src;
+    short int    x_dst;
+    short int    y_dst;
+    short int    w;
+    short int    h;
+};
+
+
+
 struct create_change_notification_request
 {
     struct request_header __header;
@@ -1843,14 +2020,22 @@
     REQ_enable_socket_event,
     REQ_alloc_console,
     REQ_free_console,
+    REQ_get_console_renderer_events,
     REQ_open_console,
-    REQ_set_console_fd,
     REQ_get_console_mode,
     REQ_set_console_mode,
-    REQ_set_console_info,
-    REQ_get_console_info,
+    REQ_set_console_input_info,
+    REQ_get_console_input_info,
+    REQ_append_console_input_history,
+    REQ_get_console_input_history,
+    REQ_create_console_output,
+    REQ_set_console_output_info,
+    REQ_get_console_output_info,
     REQ_write_console_input,
     REQ_read_console_input,
+    REQ_write_console_output,
+    REQ_read_console_output,
+    REQ_move_console_output,
     REQ_create_change_notification,
     REQ_create_mapping,
     REQ_open_mapping,
@@ -1990,14 +2175,22 @@
     struct enable_socket_event_request enable_socket_event;
     struct alloc_console_request alloc_console;
     struct free_console_request free_console;
+    struct get_console_renderer_events_request get_console_renderer_events;
     struct open_console_request open_console;
-    struct set_console_fd_request set_console_fd;
     struct get_console_mode_request get_console_mode;
     struct set_console_mode_request set_console_mode;
-    struct set_console_info_request set_console_info;
-    struct get_console_info_request get_console_info;
+    struct set_console_input_info_request set_console_input_info;
+    struct get_console_input_info_request get_console_input_info;
+    struct append_console_input_history_request append_console_input_history;
+    struct get_console_input_history_request get_console_input_history;
+    struct create_console_output_request create_console_output;
+    struct set_console_output_info_request set_console_output_info;
+    struct get_console_output_info_request get_console_output_info;
     struct write_console_input_request write_console_input;
     struct read_console_input_request read_console_input;
+    struct write_console_output_request write_console_output;
+    struct read_console_output_request read_console_output;
+    struct move_console_output_request move_console_output;
     struct create_change_notification_request create_change_notification;
     struct create_mapping_request create_mapping;
     struct open_mapping_request open_mapping;
@@ -2080,6 +2273,6 @@
     struct get_window_properties_request get_window_properties;
 };
 
-#define SERVER_PROTOCOL_VERSION 64
+#define SERVER_PROTOCOL_VERSION 65
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/loader/module.c b/loader/module.c
index 2e9d887..fa6fc0f 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -1052,10 +1052,6 @@
 
     /* Warn if unsupported features are used */
 
-    if (dwCreationFlags & DETACHED_PROCESS)
-        FIXME("(%s,...): DETACHED_PROCESS ignored\n", name);
-    if (dwCreationFlags & CREATE_NEW_CONSOLE)
-        FIXME("(%s,...): CREATE_NEW_CONSOLE ignored\n", name);
     if (dwCreationFlags & NORMAL_PRIORITY_CLASS)
         FIXME("(%s,...): NORMAL_PRIORITY_CLASS ignored\n", name);
     if (dwCreationFlags & IDLE_PRIORITY_CLASS)
diff --git a/programs/Makefile.in b/programs/Makefile.in
index a0c47c7..5a73a09 100644
--- a/programs/Makefile.in
+++ b/programs/Makefile.in
@@ -17,6 +17,7 @@
 	uninstaller \
 	view \
 	wcmd \
+	wineconsole \
 	winemine \
 	winetest \
 	winhelp \
diff --git a/programs/wineconsole/.cvsignore b/programs/wineconsole/.cvsignore
new file mode 100644
index 0000000..ad904a9
--- /dev/null
+++ b/programs/wineconsole/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+wineconsole.spec.c
+wineconsole_res.res
diff --git a/programs/wineconsole/Makefile.in b/programs/wineconsole/Makefile.in
new file mode 100644
index 0000000..672de8f
--- /dev/null
+++ b/programs/wineconsole/Makefile.in
@@ -0,0 +1,19 @@
+EXTRADEFS = -DSTRICT -DUNICODE
+TOPSRCDIR = @top_srcdir@
+TOPOBJDIR = ../..
+SRCDIR    = @srcdir@
+VPATH     = @srcdir@
+MODULE    = wineconsole
+
+C_SRCS = \
+	dialog.c \
+	user.c \
+        wineconsole.c
+
+RC_SRCS = \
+        wineconsole_res.rc
+
+@MAKE_PROG_RULES@
+
+
+### Dependencies:
diff --git a/programs/wineconsole/dialog.c b/programs/wineconsole/dialog.c
new file mode 100644
index 0000000..04220ac
--- /dev/null
+++ b/programs/wineconsole/dialog.c
@@ -0,0 +1,515 @@
+/* dialog management for wineconsole
+ * (c) 2001 Eric Pouech
+ */
+
+#include <stdio.h>
+#include "winecon_private.h"
+#include "commctrl.h"
+#include "prsht.h"
+
+/* FIXME: so far, part of the code is made in ASCII because the Uncode property sheet functions
+ * are not implemented yet
+ */
+struct dialog_info 
+{
+    struct inner_data*	data;		/* pointer to current winecon info */
+    HWND		hDlg;		/* handle to window dialog */
+    int			nFont;		/* number of font size in size LB */
+    struct font_info 
+    {
+	TEXTMETRIC		tm;
+	LOGFONT			lf;
+    } 			*font;		/* array of nFont. index sync'ed with SIZE LB */
+};
+
+/******************************************************************
+ *		WCUSER_OptionDlgProc
+ *
+ * Dialog prop for the option property sheet
+ */
+static BOOL WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    struct dialog_info*		di;
+    unsigned 			idc;
+    
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+	di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
+	di->hDlg = hDlg;
+	SetWindowLongA(hDlg, DWL_USER, (DWORD)di);
+	if (di->data->cursor_size < 33)		idc = IDC_OPT_CURSOR_SMALL;
+	else if (di->data->cursor_size < 66)	idc = IDC_OPT_CURSOR_MEDIUM;
+	else					idc = IDC_OPT_CURSOR_LARGE;
+	SendDlgItemMessage(hDlg, idc, BM_SETCHECK, BST_CHECKED, 0L);
+	SetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, WINECON_GetHistorySize(di->data->hConIn),  FALSE);
+	if (WINECON_GetHistoryMode(di->data->hConIn))
+	    SendDlgItemMessage(hDlg, IDC_OPT_HIST_DOUBLE, BM_SETCHECK, BST_CHECKED, 0L);
+	return FALSE; /* because we set the focus */
+    case WM_COMMAND:
+	break;
+    case WM_NOTIFY:
+    {
+	NMHDR*	nmhdr = (NMHDR*)lParam;
+
+	di = (struct dialog_info*)GetWindowLongA(hDlg, DWL_USER);
+	switch (nmhdr->code) 
+	{
+	case PSN_SETACTIVE:
+	    /* needed in propsheet to keep properly the selected radio button
+	     * otherwise, the focus would be set to the first tab stop in the
+	     * propsheet, which would always activate the first radio button
+	     */
+	    if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED) 
+		idc = IDC_OPT_CURSOR_SMALL;
+	    else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED)
+		idc = IDC_OPT_CURSOR_MEDIUM;
+	    else
+		idc = IDC_OPT_CURSOR_LARGE;
+	    PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, idc), TRUE);
+	    break;
+	case PSN_APPLY:
+	{
+	    int		curs_size;
+	    int		hist_size;
+	    BOOL	done;
+
+	    if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED)	curs_size = 33;
+	    else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED) curs_size = 66;
+	    else curs_size = 99;
+	    if (curs_size != di->data->cursor_size)
+	    {
+		CONSOLE_CURSOR_INFO cinfo;
+		cinfo.dwSize = curs_size;
+		cinfo.bVisible = di->data->cursor_visible;
+		SetConsoleCursorInfo(di->data->hConOut, &cinfo);
+	    }
+	    hist_size = GetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, &done, FALSE);
+	    if (done) WINECON_SetHistorySize(di->data->hConIn, hist_size);
+	    SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
+	    WINECON_SetHistoryMode(di->data->hConIn, 
+				   IsDlgButtonChecked(hDlg, IDC_OPT_HIST_DOUBLE) & BST_CHECKED);
+	    return TRUE;
+	}
+	default:
+	    return FALSE;
+	}
+	break;
+    }
+    default:
+	return FALSE;
+    }
+    return TRUE;
+}
+
+/******************************************************************
+ *		WCUSER_FontPreviewProc
+ *
+ * Window proc for font previewer in font property sheet
+ */
+static LRESULT WINAPI WCUSER_FontPreviewProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch (msg)
+    {
+    case WM_PAINT:
+    {
+	PAINTSTRUCT	ps;
+	int		font_idx;
+	int		size_idx;
+	struct dialog_info*	di;
+
+	di = (struct dialog_info*)GetWindowLong(GetParent(hWnd), DWL_USER);
+	BeginPaint(hWnd, &ps);
+	
+	font_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
+	size_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
+
+	if (font_idx >= 0 && size_idx >= 0 && size_idx < di->nFont)
+	{
+	    HFONT	hFont, hOldFont;
+	    WCHAR	buf1[256];
+	    WCHAR	buf2[256];
+	    int		len1, len2;
+
+	    hFont = CreateFontIndirect(&di->font[size_idx].lf);
+	    len1 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_1, 
+			      buf1, sizeof(buf1) / sizeof(WCHAR));
+	    len2 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_2,
+			      buf2, sizeof(buf2) / sizeof(WCHAR));
+	    if (hFont && len1)
+	    {
+		hOldFont = SelectObject(ps.hdc, hFont);
+		SetBkColor(ps.hdc, RGB(0x00, 0x00, 0x00));
+		SetTextColor(ps.hdc, RGB(0xFF, 0xFF, 0xFF));
+		TextOut(ps.hdc, 0, 0, buf1, len1);
+		if (len2)
+		    TextOut(ps.hdc, 0, di->font[size_idx].tm.tmHeight, buf2, len2);
+		SelectObject(ps.hdc, hOldFont);
+		DeleteObject(hFont);
+	    }
+	}
+	EndPaint(hWnd, &ps);
+	break;
+    }
+    default:
+	return DefWindowProc(hWnd, msg, wParam, lParam);
+    }
+    return 0L;
+}
+
+/******************************************************************
+ *		font_enum
+ *
+ *
+ */
+static int CALLBACK font_enum_size2(const LOGFONT* lf, const TEXTMETRIC* tm, 
+				    DWORD FontType, LPARAM lParam)
+{
+    struct dialog_info*	di = (struct dialog_info*)lParam;
+
+    if (WCUSER_ValidateFontMetric(di->data, tm))
+    {
+	di->nFont++;
+    }
+    return 1;
+}
+
+static int CALLBACK font_enum(const LOGFONT* lf, const TEXTMETRIC* tm, 
+			      DWORD FontType, LPARAM lParam)
+{
+    struct dialog_info*	di = (struct dialog_info*)lParam;
+    HDC	hdc;
+
+    if (WCUSER_ValidateFont(di->data, lf) && (hdc = GetDC(di->hDlg)))
+    {
+	di->nFont = 0;
+	EnumFontFamilies(hdc, lf->lfFaceName, font_enum_size2, (LPARAM)di);
+	if (di->nFont)
+	{
+	    int idx;
+	    idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_ADDSTRING, 
+				     0, (LPARAM)lf->lfFaceName);
+	}
+	ReleaseDC(di->hDlg, hdc);
+    }
+    return 1;
+}
+
+/******************************************************************
+ *		font_enum_size
+ *
+ *
+ */
+static int CALLBACK font_enum_size(const LOGFONT* lf, const TEXTMETRIC* tm, 
+				   DWORD FontType, LPARAM lParam)
+{
+    struct dialog_info*	di = (struct dialog_info*)lParam;
+
+    if (WCUSER_ValidateFontMetric(di->data, tm))
+    {
+	WCHAR	buf[32];
+	WCHAR	fmt[] = {'%','l','d',0};
+	int	idx;
+
+	/* we want the string to be sorted with a numeric order, not a lexicographic...
+	 * do the job by hand... get where to insert the new string
+	 */
+	for (idx = 0; idx < di->nFont && tm->tmHeight > di->font[idx].tm.tmHeight; idx++);
+	wsprintfW(buf, fmt, tm->tmHeight);
+	SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, idx, (LPARAM)buf);
+
+	/* now grow our arrays and insert to values at the same index than in the list box */
+	di->font = HeapReAlloc(GetProcessHeap(), 0, di->font, sizeof(*di->font) * (di->nFont + 1));
+	if (idx != di->nFont)
+	    memmove(&di->font[idx + 1], &di->font[idx], (di->nFont - idx) * sizeof(*di->font));
+	di->font[idx].tm = *tm;
+	di->font[idx].lf = *lf;
+	di->nFont++;
+
+    }
+    return 1;
+}
+
+/******************************************************************
+ *		select_font
+ *
+ *
+ */
+static BOOL  select_font(struct dialog_info* di)
+{
+    int		idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
+    WCHAR	buf[256];
+    WCHAR	fmt[128];
+
+    if (idx < 0 || idx >= di->nFont)
+	return FALSE;
+
+    LoadString(GetModuleHandle(NULL), IDS_FNT_DISPLAY, fmt, sizeof(fmt) / sizeof(WCHAR));
+    wsprintfW(buf, fmt, di->font[idx].tm.tmMaxCharWidth, di->font[idx].tm.tmHeight);
+
+    SendDlgItemMessage(di->hDlg, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf);
+    InvalidateRect(GetDlgItem(di->hDlg, IDC_FNT_PREVIEW), NULL, TRUE);
+    UpdateWindow(GetDlgItem(di->hDlg, IDC_FNT_PREVIEW));
+    return TRUE;
+}
+
+/******************************************************************
+ *		fill_list_size
+ *
+ * fills the size list box according to selected family in font LB
+ */
+static BOOL  fill_list_size(struct dialog_info* di, BOOL doInit)
+{
+    HDC 	hdc;
+    int		idx;
+    WCHAR	lfFaceName[LF_FACESIZE];
+
+    idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
+    if (idx < 0) return FALSE;
+    
+    hdc = GetDC(di->hDlg);
+    if (!hdc) return FALSE;
+
+    SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETTEXT, idx, (LPARAM)lfFaceName);
+    SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_RESETCONTENT, 0L, 0L);
+    if (di->font) HeapFree(GetProcessHeap(), 0, di->font);
+    di->nFont = 0;
+    di->font = NULL;
+
+    EnumFontFamilies(hdc, lfFaceName, font_enum_size, (LPARAM)di);
+    ReleaseDC(di->hDlg, hdc);
+
+    if (doInit)
+    {
+	for (idx = 0; idx < di->nFont; idx++)
+	{
+	    if (memcmp(&di->data->logFont, &di->font[idx].lf, sizeof(LOGFONT)) == 0)
+		break;
+	}
+	if (idx == di->nFont) idx = 0;
+    }
+    else
+	idx = 0;
+    SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0L);
+    select_font(di);
+    return TRUE;
+}
+
+/******************************************************************
+ *		fill_list_font
+ *
+ * Fills the font LB
+ */
+static BOOL fill_list_font(struct dialog_info* di)
+{
+    HDC hdc;
+
+    hdc = GetDC(di->hDlg);
+    if (!hdc) return FALSE;
+
+    SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_RESETCONTENT, 0L, 0L);
+    EnumFontFamilies(hdc, NULL, font_enum, (LPARAM)di);
+    ReleaseDC(di->hDlg, hdc);
+    if (SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SELECTSTRING, 
+			   (WPARAM)-1, (LPARAM)di->data->logFont.lfFaceName) == LB_ERR)
+	SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0L, 0L);
+    fill_list_size(di, TRUE);
+    return TRUE;
+}
+
+/******************************************************************
+ *		WCUSER_FontDlgProc
+ *
+ * Dialog proc for the Font property sheet
+ */
+static BOOL WINAPI WCUSER_FontDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    struct dialog_info*		di;
+
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+	di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
+	di->hDlg = hDlg;
+	SetWindowLong(hDlg, DWL_USER, (DWORD)di);
+	fill_list_font(di);
+	break;
+    case WM_COMMAND:
+	di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
+	switch (LOWORD(wParam)) 
+	{
+	case IDC_FNT_LIST_FONT:	
+	    if (HIWORD(wParam) == LBN_SELCHANGE)
+	    {
+		fill_list_size(di, FALSE);
+	    }
+	    break;
+	case IDC_FNT_LIST_SIZE:	
+	    if (HIWORD(wParam) == LBN_SELCHANGE)
+	    {
+		select_font(di);
+	    }
+	    break;
+	}
+	break;
+    case WM_NOTIFY:
+    {
+	NMHDR*	nmhdr = (NMHDR*)lParam;
+
+	di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
+	switch (nmhdr->code) 
+	{
+	case PSN_APPLY:
+	{
+	    int idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
+
+	    if (idx >= 0 && idx < di->nFont)
+	    {
+		WCUSER_SetFont(di->data, &di->font[idx].lf, &di->font[idx].tm);
+	    }
+	    SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
+	    return TRUE;
+	}
+	default:
+	    return FALSE;
+	}
+	break;
+    }
+    default:
+	return FALSE;
+    }
+    return TRUE;
+}
+
+/******************************************************************
+ *		WCUSER_ConfigDlgProc
+ *
+ * Dialog proc for the config property sheet
+ */
+static BOOL WINAPI WCUSER_ConfigDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    struct dialog_info*		di;
+
+    switch (msg) 
+    {
+    case WM_INITDIALOG:
+	di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
+	di->hDlg = hDlg;
+	SetWindowLong(hDlg, DWL_USER, (DWORD)di);
+	SetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH,   di->data->sb_width,   FALSE);
+	SetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT,  di->data->sb_height,  FALSE);
+	SetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH,  di->data->win_width,  FALSE);
+	SetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, di->data->win_height, FALSE);
+	break;
+    case WM_COMMAND:
+	di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
+	switch (LOWORD(wParam)) 
+	{
+	}
+	break;
+    case WM_NOTIFY:
+    {
+	NMHDR*	nmhdr = (NMHDR*)lParam;
+
+	di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
+	switch (nmhdr->code) 
+	{
+	case PSN_APPLY:
+	{
+	    COORD	sb;
+	    SMALL_RECT	pos;
+	    BOOL	st_w, st_h;
+
+	    sb.X = GetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH,  &st_w, FALSE);
+	    sb.Y = GetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT, &st_h, FALSE);
+	    if (st_w && st_h && (sb.X != di->data->sb_width || sb.Y != di->data->sb_height))
+	    {
+		SetConsoleScreenBufferSize(di->data->hConOut, sb);
+	    }
+
+	    pos.Right  = GetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH,  &st_w, FALSE);
+	    pos.Bottom = GetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, &st_h, FALSE);
+	    if (st_w && st_h && 
+		(pos.Right != di->data->win_width || pos.Bottom != di->data->win_height))
+	    {
+		pos.Left = pos.Top = 0;
+		pos.Right--; pos.Bottom--;
+		SetConsoleWindowInfo(di->data->hConOut, FALSE, &pos);
+	    }
+
+	    SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
+	    return TRUE;
+	}
+	default:
+	    return FALSE;
+	}
+	break;
+    }
+    default:
+	return FALSE;
+    }
+    return TRUE;
+}
+
+/******************************************************************
+ *		WCUSER_GetProperties
+ *
+ * Runs the dialog box to set up the winconsole options
+ */
+BOOL WCUSER_GetProperties(struct inner_data* data)
+{
+    HPROPSHEETPAGE	psPage[3];
+    PROPSHEETPAGEA	psp;
+    PROPSHEETHEADERA	psHead;
+    WNDCLASS		wndclass;
+    static WCHAR	szFntPreview[] = {'W','i','n','e','C','o','n','F','o','n','t','P','r','e','v','i','e','w',0};
+    struct dialog_info	di;
+
+    InitCommonControls();
+
+    di.data = data;
+    di.nFont = 0;
+    di.font = NULL;
+
+    wndclass.style         = 0;
+    wndclass.lpfnWndProc   = WCUSER_FontPreviewProc;
+    wndclass.cbClsExtra    = 0;
+    wndclass.cbWndExtra    = 0;
+    wndclass.hInstance     = GetModuleHandle(NULL);
+    wndclass.hIcon         = 0;
+    wndclass.hCursor       = LoadCursor(0, IDC_ARROW);
+    wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
+    wndclass.lpszMenuName  = NULL;
+    wndclass.lpszClassName = szFntPreview;
+    RegisterClass(&wndclass);
+
+    memset(&psp, 0, sizeof(psp));
+    psp.dwSize = sizeof(psp);
+    psp.dwFlags = 0;
+    psp.hInstance = wndclass.hInstance;
+    psp.lParam = (LPARAM)&di;
+
+    psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_OPTION);
+    psp.pfnDlgProc = WCUSER_OptionDlgProc;
+    psPage[0] = CreatePropertySheetPageA(&psp);
+
+    psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_FONT);
+    psp.pfnDlgProc = WCUSER_FontDlgProc;
+    psPage[1] = CreatePropertySheetPageA(&psp);
+
+    psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_CONFIG);
+    psp.pfnDlgProc = WCUSER_ConfigDlgProc;
+    psPage[2] = CreatePropertySheetPageA(&psp);
+
+    memset(&psHead, 0, sizeof(psHead));
+    psHead.dwSize = sizeof(psHead);
+    psHead.pszCaption = "Setup";
+    psHead.nPages = 3;
+    psHead.hwndParent = data->hWnd;
+    psHead.u3.phpage = psPage;
+ 
+    PropertySheetA(&psHead);
+
+    return TRUE;
+}
+
diff --git a/programs/wineconsole/user.c b/programs/wineconsole/user.c
new file mode 100644
index 0000000..2d25c66
--- /dev/null
+++ b/programs/wineconsole/user.c
@@ -0,0 +1,957 @@
+/*
+ * a GUI application for displaying a console
+ *	USER32 back end
+ * Copyright 2001 Eric Pouech
+ */
+
+#include <stdio.h>
+#include "winecon_private.h"
+
+/* mapping console colors to RGB values */
+static	COLORREF	color_map[16] = 
+{
+    RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
+    RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0x80, 0x80, 0x80),
+    RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
+    RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF),
+};
+
+/******************************************************************
+ *		WCUSER_FillMemDC
+ *
+ * Fills the Mem DC with current cells values
+ */
+static void WCUSER_FillMemDC(const struct inner_data* data, int upd_tp, int upd_bm)
+{
+    unsigned		i, j, k;
+    CHAR_INFO*		cell;
+    HFONT		hOldFont;
+    WORD		attr;
+    WCHAR*		line;
+
+    if (!(line = HeapAlloc(GetProcessHeap(), 0, data->sb_width * sizeof(WCHAR))))
+    {Trace(0, "OOM\n"); return;}
+
+    hOldFont = SelectObject(data->hMemDC, data->hFont);
+    for (j = upd_tp; j <= upd_bm; j++)
+    {
+	cell = &data->cells[j * data->sb_width];
+	for (i = 0; i < data->win_width; i++)
+	{
+	    attr = cell[i].Attributes;
+	    SetBkColor(data->hMemDC, color_map[attr & 0x0F]);
+	    SetTextColor(data->hMemDC, color_map[(attr >> 4) & 0x0F]);
+	    for (k = i; k < data->win_width && cell[k].Attributes == attr; k++)
+	    {
+		line[k - i] = cell[k].Char.UnicodeChar;
+	    }
+	    TextOut(data->hMemDC, i * data->cell_width, j * data->cell_height, 
+		    line, k - i);
+	    i = k - 1;
+	}
+    }
+    SelectObject(data->hMemDC, hOldFont);
+    HeapFree(GetProcessHeap(), 0, line);
+}
+
+/******************************************************************
+ *		WCUSER_NewBitmap
+ *
+ * Either the font geometry or the sb geometry has changed. we need to recreate the
+ * bitmap geometry
+ */
+static void WCUSER_NewBitmap(struct inner_data* data, BOOL fill)
+{
+    HBITMAP	hnew, hold;
+
+    if (!data->sb_width || !data->sb_height)
+	return;
+    hnew = CreateCompatibleBitmap(data->hMemDC, 
+				  data->sb_width  * data->cell_width, 
+				  data->sb_height * data->cell_height);
+    hold = SelectObject(data->hMemDC, hnew);
+
+    if (data->hBitmap)
+    {
+	if (hold == data->hBitmap)
+	    DeleteObject(data->hBitmap);
+	else
+	    Trace(0, "leak\n");
+    }
+    data->hBitmap = hnew;
+    if (fill)
+	WCUSER_FillMemDC(data, 0, data->sb_height - 1);
+}
+
+/******************************************************************
+ *		WCUSER_ResizeScreenBuffer
+ *
+ *
+ */
+static void WCUSER_ResizeScreenBuffer(struct inner_data* data)
+{
+    WCUSER_NewBitmap(data, FALSE);
+}
+
+/******************************************************************
+ *		WCUSER_PosCursor
+ *
+ * Set a new position for the cursor
+ */
+static void	WCUSER_PosCursor(const struct inner_data* data)
+{
+    if (data->hWnd != GetFocus() || !data->cursor_visible) return;
+
+    SetCaretPos((data->cursor.X - data->win_pos.X) * data->cell_width, 
+		(data->cursor.Y - data->win_pos.Y) * data->cell_height);
+    ShowCaret(data->hWnd); 
+}
+
+/******************************************************************
+ *		WCUSER_ShapeCursor
+ *
+ * Sets a new shape for the cursor
+ */
+void	WCUSER_ShapeCursor(struct inner_data* data, int size, int vis, BOOL force)
+{
+    if (force || size != data->cursor_size)
+    {
+	if (data->cursor_visible && data->hWnd == GetFocus()) DestroyCaret();
+	if (data->cursor_bitmap) DeleteObject(data->cursor_bitmap);
+	data->cursor_bitmap = (HBITMAP)0;
+	if (size != 100)
+	{
+	    int		w16b; /* number of byets per row, aligned on word size */
+	    BYTE*	ptr;
+	    int		i, j, nbl;
+
+	    w16b = ((data->cell_width + 15) & ~15) / 8;
+	    ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, w16b * data->cell_height);
+	    if (!ptr) {Trace(0, "OOM\n"); return;}
+	    nbl = max((data->cell_height * size) / 100, 1);
+	    for (j = data->cell_height - nbl; j < data->cell_height; j++)
+	    {
+		for (i = 0; i < data->cell_width; i++)
+		{
+		    ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
+		}
+	    }
+	    data->cursor_bitmap = CreateBitmap(data->cell_width, data->cell_height, 1, 1, ptr);
+	    HeapFree(GetProcessHeap(), 0, ptr);
+	}
+	data->cursor_size = size;
+	data->cursor_visible = -1;
+    }
+
+    vis = (vis) ? TRUE : FALSE;
+    if (force || vis != data->cursor_visible)
+    {
+	data->cursor_visible = vis;
+	if (data->hWnd == GetFocus())
+	{
+	    if (vis)
+	    {
+		CreateCaret(data->hWnd, data->cursor_bitmap, data->cell_width, data->cell_height);
+		WCUSER_PosCursor(data);
+	    }
+	    else
+	    {
+		DestroyCaret();
+	    }
+	}
+    }
+}
+
+/******************************************************************
+ *		INECON_ComputePositions
+ *
+ * Recomputes all the components (mainly scroll bars) positions
+ */
+void	WCUSER_ComputePositions(struct inner_data* data)
+{
+    RECT		r;
+    int			dx, dy;
+
+    /* compute window size from desired client size */
+    r.left = r.top = 0;
+    r.right = data->win_width * data->cell_width;
+    r.bottom = data->win_height * data->cell_height;
+
+    if (IsRectEmpty(&r))
+    {
+	ShowWindow(data->hWnd, SW_HIDE);
+	return;
+    }
+
+    AdjustWindowRect(&r, GetWindowLong(data->hWnd, GWL_STYLE), FALSE);
+
+    dx = dy = 0;
+    if (data->sb_width > data->win_width)
+    {
+	dy = GetSystemMetrics(SM_CYHSCROLL);
+	SetScrollRange(data->hWnd, SB_HORZ, 0, data->sb_width - data->win_width, FALSE);
+	SetScrollPos(data->hWnd, SB_HORZ, 0, FALSE); /* FIXME */
+	ShowScrollBar(data->hWnd, SB_HORZ, TRUE);
+    }
+    else
+    {
+	ShowScrollBar(data->hWnd, SB_HORZ, FALSE);
+    }
+
+    if (data->sb_height > data->win_height)
+    {
+	dx = GetSystemMetrics(SM_CXVSCROLL);
+	SetScrollRange(data->hWnd, SB_VERT, 0, data->sb_height - data->win_height, FALSE);
+	SetScrollPos(data->hWnd, SB_VERT, 0, FALSE); /* FIXME */
+	ShowScrollBar(data->hWnd, SB_VERT, TRUE);
+    }	
+    else
+    {
+	ShowScrollBar(data->hWnd, SB_VERT, FALSE);
+    }
+
+    SetWindowPos(data->hWnd, 0, 0, 0, r.right - r.left + dx, r.bottom - r.top + dy,
+		 SWP_NOMOVE|SWP_NOZORDER|SWP_SHOWWINDOW);
+    WCUSER_ShapeCursor(data, data->cursor_size, data->cursor_visible, TRUE);
+    WCUSER_PosCursor(data);
+}
+
+/******************************************************************
+ *		WCUSER_SetTitle
+ *
+ * Sets the title to the wine console
+ */
+static void	WCUSER_SetTitle(const struct inner_data* data)
+{
+    WCHAR	buffer[256];	
+
+    if (WINECON_GetConsoleTitle(data->hConIn, buffer, sizeof(buffer)))
+	SetWindowText(data->hWnd, buffer);
+}
+
+/******************************************************************
+ *		WCUSER_SetFont
+ *
+ *
+ */
+BOOL	WCUSER_SetFont(struct inner_data* data, const LOGFONT* logfont, const TEXTMETRIC* tm)
+{
+    if (!memcmp(logfont, &data->logFont, sizeof(LOGFONT))) return TRUE;
+    if (data->hFont) DeleteObject(data->hFont);
+    data->hFont = CreateFontIndirect(logfont);
+    if (!data->hFont) {Trace(0, "wrong font\n");return FALSE;}
+    data->cell_width = tm->tmMaxCharWidth; /* font is fixed Avg == Max */
+    data->cell_height = tm->tmHeight;
+    data->logFont = *logfont;
+    WCUSER_ComputePositions(data);
+    WCUSER_NewBitmap(data, TRUE);
+    InvalidateRect(data->hWnd, NULL, FALSE);
+    UpdateWindow(data->hWnd);
+    return TRUE;
+}
+
+/******************************************************************
+ *		WCUSER_GetCell
+ *
+ * Get a cell from the a relative coordinate in window (takes into
+ * account the scrolling)
+ */
+static COORD	WCUSER_GetCell(const struct inner_data* data, LPARAM lParam)
+{
+    COORD	c;
+
+    c.X = data->win_pos.X + (short)LOWORD(lParam) / data->cell_width;
+    c.Y = data->win_pos.Y + (short)HIWORD(lParam) / data->cell_height;
+
+    return c;
+}
+
+/******************************************************************
+ *		WCUSER_GetSelectionRect
+ *
+ * Get the selection rectangle
+ */
+static void	WCUSER_GetSelectionRect(const struct inner_data* data, LPRECT r)
+{
+    r->left   = (min(data->selectPt1.X, data->selectPt2.X)    ) * data->cell_width;
+    r->top    = (min(data->selectPt1.Y, data->selectPt2.Y)    ) * data->cell_height;
+    r->right  = (max(data->selectPt1.X, data->selectPt2.X) + 1) * data->cell_width;
+    r->bottom = (max(data->selectPt1.Y, data->selectPt2.Y) + 1) * data->cell_height;
+}
+
+/******************************************************************
+ *		WCUSER_SetSelection
+ *
+ *
+ */
+static void	WCUSER_SetSelection(const struct inner_data* data, HDC hRefDC)
+{
+    HDC		hDC;
+    RECT	r;
+
+    WCUSER_GetSelectionRect(data, &r);
+    hDC = hRefDC ? hRefDC : GetDC(data->hWnd);
+    if (hDC)
+    {
+	if (data->hWnd == GetFocus() && data->cursor_visible)
+	    HideCaret(data->hWnd);
+	InvertRect(hDC, &r);
+	if (hDC != hRefDC)
+	    ReleaseDC(data->hWnd, hDC);
+	if (data->hWnd == GetFocus() && data->cursor_visible)
+	    ShowCaret(data->hWnd);
+    }
+}
+
+/******************************************************************
+ *		WCUSER_MoveSelection
+ *
+ *
+ */
+static void	WCUSER_MoveSelection(struct inner_data* data, COORD dst, BOOL final)
+{
+    RECT	r;
+    HDC		hDC;
+
+    WCUSER_GetSelectionRect(data, &r);
+    hDC = GetDC(data->hWnd);
+    if (hDC)
+    {
+	if (data->hWnd == GetFocus() && data->cursor_visible)
+	    HideCaret(data->hWnd);
+	InvertRect(hDC, &r);
+    }
+    data->selectPt2 = dst;
+    if (hDC)
+    {
+	WCUSER_GetSelectionRect(data, &r);
+	InvertRect(hDC, &r);
+	ReleaseDC(data->hWnd, hDC);
+	if (data->hWnd == GetFocus() && data->cursor_visible)
+	    ShowCaret(data->hWnd);
+    }
+    if (final)
+    {
+	ReleaseCapture();
+	data->hasSelection = TRUE;
+    }
+}
+
+/******************************************************************
+ *		WCUSER_CopySelectionToClipboard
+ *
+ * Copies the current selection into the clipboard
+ */
+static void	WCUSER_CopySelectionToClipboard(const struct inner_data* data)
+{
+    HANDLE	hMem;
+    LPWSTR	p;
+    unsigned	w, h;
+
+    w = abs(data->selectPt1.X - data->selectPt2.X) + 2;
+    h = abs(data->selectPt1.Y - data->selectPt2.Y) + 1;
+
+    if (!OpenClipboard(data->hWnd)) return;
+    EmptyClipboard();
+
+    hMem = GlobalAlloc(GMEM_MOVEABLE, (w * h - 1) * sizeof(WCHAR));
+    if (hMem && (p = GlobalLock(hMem)))
+    {
+	COORD	c;
+	int	y;
+
+	c.X = data->win_pos.X + min(data->selectPt1.X, data->selectPt2.X);
+	c.Y = data->win_pos.Y + min(data->selectPt1.Y, data->selectPt2.Y);
+	
+	for (y = 0; y < h; y++, c.Y++)
+	{
+	    ReadConsoleOutputCharacter(data->hConOut, &p[y * w], w - 1, c, NULL);
+	    if (y < h - 1) p[y * w + w - 1] = '\n';
+	}
+	GlobalUnlock(hMem);
+	SetClipboardData(CF_UNICODETEXT, hMem);
+    }
+    CloseClipboard();
+}
+
+/******************************************************************
+ *		WCUSER_PasteFromClipboard
+ *
+ *
+ */
+static void	WCUSER_PasteFromClipboard(struct inner_data* data)
+{
+    HANDLE	h;
+    WCHAR*	ptr;
+
+    if (!OpenClipboard(data->hWnd)) return;
+    h = GetClipboardData(CF_UNICODETEXT);
+    if (h && (ptr = GlobalLock(h)))
+    {
+	int		i, len = GlobalSize(h) / sizeof(WCHAR);
+	INPUT_RECORD	ir[2];
+	DWORD		n;
+	SHORT		sh;
+
+	ir[0].EventType = KEY_EVENT;
+	ir[0].Event.KeyEvent.wRepeatCount = 0;
+	ir[0].Event.KeyEvent.dwControlKeyState = 0;
+	ir[0].Event.KeyEvent.bKeyDown = TRUE;
+
+	/* generate the corresponding input records */
+	for (i = 0; i < len; i++)
+	{
+	    /* FIXME: the modifying keys are not generated (shift, ctrl...) */
+	    sh = VkKeyScan(ptr[i]);
+	    ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
+	    ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(LOBYTE(sh), 0);
+	    ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
+	    
+	    ir[1] = ir[0];
+	    ir[1].Event.KeyEvent.bKeyDown = FALSE;
+	    
+	    WriteConsoleInput(data->hConIn, ir, 2, &n);
+	}
+	GlobalUnlock(h);
+    }
+    CloseClipboard();
+}
+
+static void WCUSER_Refresh(const struct inner_data* data, int tp, int bm)
+{
+    if (data->win_pos.Y <= bm && data->win_pos.Y + data->win_height >= tp)
+    {
+	RECT	r;
+
+	r.left   = 0;
+	r.right  = data->win_width * data->cell_width;
+	r.top    = (tp - data->win_pos.Y) * data->cell_height;
+	r.bottom = (bm - data->win_pos.Y + 1) * data->cell_height;
+	InvalidateRect(data->hWnd, &r, FALSE);
+	WCUSER_FillMemDC(data, tp, bm);
+	UpdateWindow(data->hWnd);
+    }
+}
+
+/******************************************************************
+ *		WCUSER_Paint
+ *
+ *
+ */
+static void	WCUSER_Paint(const struct inner_data* data)
+{
+    PAINTSTRUCT		ps;
+
+    BeginPaint(data->hWnd, &ps);
+    BitBlt(ps.hdc, 0, 0, data->win_width * data->cell_width, data->win_height * data->cell_height,
+	   data->hMemDC, data->win_pos.X * data->cell_width, data->win_pos.Y * data->cell_height,
+	   SRCCOPY);
+    if (data->hasSelection)
+	WCUSER_SetSelection(data, ps.hdc);
+    EndPaint(data->hWnd, &ps);
+}
+
+/******************************************************************
+ *		WCUSER_Scroll
+ *
+ *
+ */
+static void WCUSER_Scroll(struct inner_data* data, int pos, BOOL horz)
+{
+    if (horz)
+    {
+	SetScrollPos(data->hWnd, SB_HORZ, pos, TRUE);
+	data->win_pos.X = pos;
+	InvalidateRect(data->hWnd, NULL, FALSE);
+    }
+    else
+    {
+	SetScrollPos(data->hWnd, SB_VERT, pos, TRUE);
+	data->win_pos.Y = pos;
+    }
+    InvalidateRect(data->hWnd, NULL, FALSE);
+}
+
+struct font_chooser {
+    struct inner_data*	data;
+    int			done;
+};
+
+/******************************************************************
+ *		WCUSER_ValidateFontMetric
+ *
+ * Returns true if the font described in tm is usable as a font for the renderer
+ */
+BOOL	WCUSER_ValidateFontMetric(const struct inner_data* data, const TEXTMETRIC* tm)
+{
+    return tm->tmMaxCharWidth * data->win_width < GetSystemMetrics(SM_CXSCREEN) &&
+	tm->tmHeight * data->win_height < GetSystemMetrics(SM_CYSCREEN) &&
+	!tm->tmItalic && !tm->tmUnderlined && !tm->tmStruckOut;
+}
+
+/******************************************************************
+ *		WCUSER_ValidateFont
+ *
+ * Returns true if the font family described in lf is usable as a font for the renderer
+ */
+BOOL	WCUSER_ValidateFont(const struct inner_data* data, const LOGFONT* lf)
+{
+    return (lf->lfPitchAndFamily & 3) == FIXED_PITCH && (lf->lfPitchAndFamily & 0xF0) == FF_MODERN;
+}
+
+/******************************************************************
+ *		get_first_font_enum_2
+ *		get_first_font_enum
+ *
+ * Helper functions to get a decent font for the renderer
+ */
+static int CALLBACK get_first_font_enum_2(const LOGFONT* lf, const TEXTMETRIC* tm, 
+					  DWORD FontType, LPARAM lParam)
+{
+    struct font_chooser*	fc = (struct font_chooser*)lParam;
+
+    if (WCUSER_ValidateFontMetric(fc->data, tm))
+    {
+	WCUSER_SetFont(fc->data, lf, tm);
+	fc->done = 1;
+	return 0;
+    }
+    return 1;
+}
+
+static int CALLBACK get_first_font_enum(const LOGFONT* lf, const TEXTMETRIC* tm, 
+					DWORD FontType, LPARAM lParam)
+{
+    struct font_chooser*	fc = (struct font_chooser*)lParam;
+
+    if (WCUSER_ValidateFont(fc->data, lf))
+    {
+	EnumFontFamilies(fc->data->hMemDC, lf->lfFaceName, get_first_font_enum_2, lParam);
+	return !fc->done; /* we just need the first matching one... */
+    }
+    return 1;
+}
+
+/******************************************************************
+ *		WCUSER_Create
+ *
+ * Creates the window for the rendering
+ */
+static LRESULT WCUSER_Create(HWND hWnd, LPCREATESTRUCT lpcs)
+{
+    struct inner_data*	data;
+    HMENU		hMenu;
+    HMENU		hSubMenu;
+    WCHAR		buff[256];
+    HINSTANCE		hInstance = GetModuleHandle(NULL);
+
+    data = lpcs->lpCreateParams;
+    SetWindowLong(hWnd, 0L, (DWORD)data);
+    data->hWnd = hWnd;
+
+    data->cursor_size = 101; /* invalid value, will trigger a complete cleanup */
+    /* FIXME: error handling & memory cleanup */
+    hSubMenu = CreateMenu();
+    if (!hSubMenu) return 0;
+
+    hMenu = GetSystemMenu(hWnd, FALSE);
+    if (!hMenu) return 0;
+
+    LoadString(hInstance, IDS_MARK, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff);
+    LoadString(hInstance, IDS_COPY, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff);
+    LoadString(hInstance, IDS_PASTE, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff);
+    LoadString(hInstance, IDS_SELECTALL, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff);
+    LoadString(hInstance, IDS_SCROLL, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff);
+    LoadString(hInstance, IDS_SEARCH, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff);
+
+    InsertMenu(hMenu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
+    LoadString(hInstance, IDS_EDIT, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)hSubMenu, buff);
+    LoadString(hInstance, IDS_DEFAULT, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff);
+    LoadString(hInstance, IDS_PROPERTY, buff, sizeof(buff) / sizeof(WCHAR));
+    InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTY, buff);
+
+    data->hMemDC = CreateCompatibleDC(0);
+    if (!data->hMemDC) {Trace(0, "no mem dc\n");return 0;}
+
+    return 0;
+}
+
+/******************************************************************
+ *		WCUSER_SetMenuDetails
+ *
+ * Grays / ungrays the menu items according to their state
+ */
+static void	WCUSER_SetMenuDetails(const struct inner_data* data)
+{
+    HMENU		hMenu = GetSystemMenu(data->hWnd, FALSE);
+
+    if (!hMenu) {Trace(0, "Issue in getting menu bits\n");return;}
+
+    /* FIXME: set the various menu items to their state (if known) */
+    EnableMenuItem(hMenu, IDS_DEFAULT, MF_BYCOMMAND|MF_GRAYED);
+
+    EnableMenuItem(hMenu, IDS_MARK, MF_BYCOMMAND|MF_GRAYED);
+    EnableMenuItem(hMenu, IDS_COPY, MF_BYCOMMAND|(data->hasSelection ? MF_ENABLED : MF_GRAYED));
+    EnableMenuItem(hMenu, IDS_PASTE, 
+		   MF_BYCOMMAND|(IsClipboardFormatAvailable(CF_UNICODETEXT) 
+				 ? MF_ENABLED : MF_GRAYED));
+    /* Select all: always active */
+    EnableMenuItem(hMenu, IDS_SCROLL, MF_BYCOMMAND|MF_GRAYED);
+    EnableMenuItem(hMenu, IDS_SEARCH, MF_BYCOMMAND|MF_GRAYED);
+}
+
+/******************************************************************
+ *		WCUSER_GenerateInputRecord
+ *
+ * generates input_record from windows WM_KEYUP/WM_KEYDOWN messages
+ */
+static void    WCUSER_GenerateInputRecord(struct inner_data* data, BOOL down, 
+					   WPARAM wParam, LPARAM lParam, BOOL sys)
+{
+    INPUT_RECORD	ir;
+    DWORD		n;
+    WCHAR		buf[2];
+    BYTE		keyState[256];
+    static	WCHAR	last; /* keep last char seen as feed for key up message */
+
+    ir.EventType = KEY_EVENT;
+    ir.Event.KeyEvent.bKeyDown = down;
+    ir.Event.KeyEvent.wRepeatCount = LOWORD(lParam);
+    ir.Event.KeyEvent.wVirtualKeyCode = wParam;
+    
+    ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lParam) & 0xFF;
+    GetKeyboardState(keyState);
+    
+    ir.Event.KeyEvent.uChar.UnicodeChar = 0;
+    ir.Event.KeyEvent.dwControlKeyState = 0;
+    if (lParam & (1L << 24))		ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
+    if (keyState[VK_SHIFT]    & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
+    if (keyState[VK_CONTROL]  & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; /* FIXME: gotta choose one */
+    if (keyState[VK_LCONTROL] & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED;
+    if (keyState[VK_RCONTROL] & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
+    if (sys)				ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; /* FIXME: gotta choose one */
+    if (keyState[VK_LMENU]    & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED;
+    if (keyState[VK_RMENU]    & 0x80)	ir.Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
+    if (keyState[VK_CAPITAL]  & 0x01)	ir.Event.KeyEvent.dwControlKeyState |= CAPSLOCK_ON;	    
+    if (keyState[VK_NUMLOCK]  & 0x01)	ir.Event.KeyEvent.dwControlKeyState |= NUMLOCK_ON;
+    if (keyState[VK_SCROLL]   & 0x01)	ir.Event.KeyEvent.dwControlKeyState |= SCROLLLOCK_ON;
+
+    if (data->hasSelection && ir.Event.KeyEvent.dwControlKeyState == 0 && 
+	ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN)
+    {
+	data->hasSelection = FALSE;
+	WCUSER_SetSelection(data, 0);
+	WCUSER_CopySelectionToClipboard(data);
+	return;
+    }
+    
+    if (!(ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
+    {
+	if (down)
+	{
+	    switch (ToUnicode(wParam, HIWORD(lParam), keyState, buf, 2, 0))
+	    {
+	    case 2:
+		/* FIXME... should generate two events... */
+		/* fall thru */
+	    case 1:	
+		last = buf[0];
+		break;
+	    default:
+		last = 0;
+		break;
+	    }
+	}
+	ir.Event.KeyEvent.uChar.UnicodeChar = last; /* FIXME HACKY... and buggy 'coz it should be a stack, not a single value */
+	if (!down) last = 0;
+    }
+
+    WriteConsoleInput(data->hConIn, &ir, 1, &n);
+}
+
+/******************************************************************
+ *		WCUSER_Proc
+ *
+ *
+ */
+static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    struct inner_data*	data = (struct inner_data*)GetWindowLong(hWnd, 0);
+
+    switch (uMsg)
+    {
+    case WM_CREATE:
+        return WCUSER_Create(hWnd, (LPCREATESTRUCT)lParam);
+    case WM_DESTROY:
+	data->hWnd = 0;
+	PostQuitMessage(0);
+	break;
+    case WM_PAINT:
+	WCUSER_Paint(data);
+	break;
+    case WM_KEYDOWN:
+    case WM_KEYUP:
+	WCUSER_GenerateInputRecord(data, uMsg == WM_KEYDOWN, wParam, lParam, FALSE);
+	break;
+    case WM_SYSKEYDOWN:
+    case WM_SYSKEYUP:
+	WCUSER_GenerateInputRecord(data, uMsg == WM_SYSKEYDOWN, wParam, lParam, TRUE);
+	break;
+    case WM_LBUTTONDOWN:
+	/* EPP if (wParam != MK_LBUTTON) */
+	if (data->hasSelection)
+	{
+	    data->hasSelection = FALSE;
+	}
+	else
+	{
+	    data->selectPt1 = data->selectPt2 = WCUSER_GetCell(data, lParam);
+	    SetCapture(data->hWnd);
+	}
+	WCUSER_SetSelection(data, 0);
+	break;
+    case WM_MOUSEMOVE:
+	/* EPP if (wParam != MK_LBUTTON) */
+        if (GetCapture() == data->hWnd)
+	{
+	    WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), FALSE);
+	}
+	break;
+    case WM_LBUTTONUP:
+	/* EPP if (wParam != MK_LBUTTON) */
+        if (GetCapture() == data->hWnd)
+	{
+	    WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), TRUE);
+	}
+	break;
+    case WM_SETFOCUS:
+	if (data->cursor_visible)
+	{
+	    CreateCaret(data->hWnd, data->cursor_bitmap, data->cell_width, data->cell_height); 
+	    WCUSER_PosCursor(data);
+	}
+        break; 
+    case WM_KILLFOCUS: 
+	if (data->cursor_visible)
+	    DestroyCaret(); 
+	break;
+    case WM_HSCROLL: 
+        {
+	    int	pos = data->win_pos.X;
+
+	    switch (LOWORD(wParam)) 
+	    { 
+            case SB_PAGEUP: 	pos -= 8; 		break; 
+            case SB_PAGEDOWN: 	pos += 8; 		break; 
+            case SB_LINEUP: 	pos--;			break;
+	    case SB_LINEDOWN: 	pos++;	 		break;
+            case SB_THUMBTRACK: pos = HIWORD(wParam);	break;
+            default: 					break;
+	    } 
+	    if (pos < 0) pos = 0;
+	    if (pos > data->sb_width - data->win_width) pos = data->sb_width - data->win_width;
+	    if (pos != data->win_pos.X)
+	    {
+		ScrollWindow(hWnd, (data->win_pos.X - pos) * data->cell_width, 0, NULL, NULL);
+		data->win_pos.X = pos;
+		SetScrollPos(hWnd, SB_HORZ, pos, TRUE); 
+		UpdateWindow(hWnd); 
+		WCUSER_PosCursor(data);
+		WINECON_NotifyWindowChange(data);
+	    }
+        } 
+	break;
+    case WM_VSCROLL: 
+        {
+	    int	pos = data->win_pos.Y;
+
+	    switch (LOWORD(wParam)) 
+	    { 
+            case SB_PAGEUP: 	pos -= 8; 		break; 
+            case SB_PAGEDOWN: 	pos += 8; 		break; 
+            case SB_LINEUP: 	pos--;			break;
+	    case SB_LINEDOWN: 	pos++;	 		break;
+            case SB_THUMBTRACK: pos = HIWORD(wParam);	break;
+            default: 					break;
+	    } 
+	    if (pos < 0) pos = 0;
+	    if (pos > data->sb_height - data->win_height) pos = data->sb_height - data->win_height;
+	    if (pos != data->win_pos.Y)
+	    {
+		ScrollWindow(hWnd, 0, (data->win_pos.Y - pos) * data->cell_height, NULL, NULL);
+		data->win_pos.Y = pos;
+		SetScrollPos(hWnd, SB_VERT, pos, TRUE); 
+		UpdateWindow(hWnd); 
+		WCUSER_PosCursor(data);
+		WINECON_NotifyWindowChange(data);
+	    }
+        } 
+	break;
+    case WM_SYSCOMMAND:
+	switch (wParam)
+	{
+	case IDS_DEFAULT:
+	    Trace(0, "unhandled yet command: %x\n", wParam);
+	    break;
+	case IDS_PROPERTY:
+	    WCUSER_GetProperties(data);
+	    break;
+	default: 
+	    return DefWindowProc(hWnd, uMsg, wParam, lParam);
+	}
+	break;
+    case WM_RBUTTONDOWN:
+	WCUSER_GetProperties(data);
+	break;    
+    case WM_COMMAND:
+	switch (wParam)
+	{
+	case IDS_MARK:
+	    goto niy;
+	case IDS_COPY:
+	    data->hasSelection = FALSE;
+	    WCUSER_SetSelection(data, 0);
+	    WCUSER_CopySelectionToClipboard(data);
+	    break;
+	case IDS_PASTE:
+	    WCUSER_PasteFromClipboard(data);
+	    break;
+	case IDS_SELECTALL:
+	    data->selectPt1.X = data->selectPt1.Y = 0;
+	    data->selectPt2.X = (data->sb_width - 1) * data->cell_width;
+	    data->selectPt2.Y = (data->sb_height - 1) * data->cell_height;
+	    WCUSER_SetSelection(data, 0);
+	    data->hasSelection = TRUE;
+	    break;
+	case IDS_SCROLL:
+	case IDS_SEARCH:
+	niy:
+	    Trace(0, "unhandled yet command: %x\n", wParam);
+	    break;
+	default: 
+	    return DefWindowProc(hWnd, uMsg, wParam, lParam);
+	}
+	break;
+    case WM_INITMENUPOPUP:
+	if (!HIWORD(lParam))	return DefWindowProc(hWnd, uMsg, wParam, lParam);
+	WCUSER_SetMenuDetails(data);
+	break;
+    default:
+	return DefWindowProc(hWnd, uMsg, wParam, lParam);
+    }
+    return 0;
+}
+
+/******************************************************************
+ *		WCUSER_DeleteBackend
+ *
+ *
+ */
+void WCUSER_DeleteBackend(struct inner_data* data)
+{
+    if (data->hWnd)		DestroyWindow(data->hWnd);
+    if (data->hFont)		DeleteObject(data->hFont);
+    if (data->cursor_bitmap)	DeleteObject(data->cursor_bitmap);
+    if (data->hMemDC)		DeleteDC(data->hMemDC);
+    if (data->hBitmap)		DeleteObject(data->hBitmap);
+}
+
+/******************************************************************
+ *		WCUSER_MainLoop
+ *
+ *
+ */
+static int WCUSER_MainLoop(struct inner_data* data)
+{
+    MSG		msg;
+
+    for (;;) 
+    {
+	switch (MsgWaitForMultipleObjects(1, &data->hSynchro, FALSE, INFINITE, QS_ALLINPUT))
+	{
+	case WAIT_OBJECT_0:
+	    if (!WINECON_GrabChanges(data))
+		PostQuitMessage(0);
+	    break;
+	case WAIT_OBJECT_0+1:
+	    switch (GetMessage(&msg, 0, 0, 0))
+	    {
+	    case -1: /* the event handle became invalid, so exit */
+		return -1;
+	    case 0: /* WM_QUIT has been posted */
+		return 0;
+	    default:
+		DispatchMessage(&msg);
+		break;
+	    }
+	    break;
+	default:
+	    Trace(0, "got pb\n");
+	    /* err */
+	    break;
+	}
+    }	
+}
+
+/******************************************************************
+ *		WCUSER_InitBackend
+ *
+ * Initialisation part II: creation of window.
+ *
+ */
+BOOL WCUSER_InitBackend(struct inner_data* data)
+{
+    static WCHAR wClassName[] = {'W','i','n','e','C','o','n','s','o','l','e','C','l','a','s','s',0};
+
+    WNDCLASS		wndclass;
+    struct font_chooser fc;
+
+    data->fnMainLoop = WCUSER_MainLoop;
+    data->fnPosCursor = WCUSER_PosCursor;
+    data->fnShapeCursor = WCUSER_ShapeCursor;
+    data->fnComputePositions = WCUSER_ComputePositions;
+    data->fnRefresh = WCUSER_Refresh;
+    data->fnResizeScreenBuffer = WCUSER_ResizeScreenBuffer;
+    data->fnSetTitle = WCUSER_SetTitle;
+    data->fnScroll = WCUSER_Scroll;
+    data->fnDeleteBackend = WCUSER_DeleteBackend;
+
+    wndclass.style         = 0;
+    wndclass.lpfnWndProc   = WCUSER_Proc;
+    wndclass.cbClsExtra    = 0;
+    wndclass.cbWndExtra    = sizeof(DWORD);
+    wndclass.hInstance     = GetModuleHandle(NULL);
+    wndclass.hIcon         = LoadIcon(0, IDI_WINLOGO);
+    wndclass.hCursor       = LoadCursor(0, IDC_ARROW);
+    wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
+    wndclass.lpszMenuName  = NULL;
+    wndclass.lpszClassName = wClassName;
+  
+    RegisterClass(&wndclass);
+
+    CreateWindow(wndclass.lpszClassName, NULL,
+		 WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_HSCROLL|WS_VSCROLL, 
+		 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, 0, wndclass.hInstance, data);   
+    if (!data->hWnd) return FALSE;
+
+    /* force update of current data */
+    WINECON_GrabChanges(data);
+
+    /* try to find an acceptable font */
+    fc.data = data;
+    fc.done = 0;
+    EnumFontFamilies(data->hMemDC, NULL, get_first_font_enum, (LPARAM)&fc);
+
+    return fc.done;
+}
+
+
+
diff --git a/programs/wineconsole/winecon_private.h b/programs/wineconsole/winecon_private.h
new file mode 100644
index 0000000..b444164
--- /dev/null
+++ b/programs/wineconsole/winecon_private.h
@@ -0,0 +1,75 @@
+#include <winbase.h>
+#include <wingdi.h>
+#include <winuser.h>
+#include <wincon.h>
+
+#include "wineconsole_res.h"
+
+struct inner_data {
+    unsigned		sb_width;	/* active screen buffer width */
+    unsigned		sb_height;	/* active screen buffer height */
+    CHAR_INFO*		cells;		/* local copy of cells (sb_width * sb_height) */
+    COORD		win_pos;	/* position (in cells) of visible part of screen buffer in window */
+    unsigned		win_width;	/* size (in cells) of visible part of window (width & height) */
+    unsigned		win_height;
+
+    COORD		cursor;		/* position in cells of cursor */
+    int			cursor_visible;
+    int			cursor_size;	/* in % of cell height */
+
+    HANDLE		hConIn;		/* console input handle */
+    HANDLE		hConOut;	/* screen buffer handle: has to be changed when active sb changes */
+    HANDLE		hSynchro;	/* waitable handle signalled by server when something in server has been modified */
+
+    int			(*fnMainLoop)(struct inner_data* data);
+    void		(*fnPosCursor)(const struct inner_data* data);
+    void		(*fnShapeCursor)(struct inner_data* data, int size, int vis, BOOL force);
+    void		(*fnComputePositions)(struct inner_data* data);
+    void		(*fnRefresh)(const struct inner_data* data, int tp, int bm);
+    void		(*fnResizeScreenBuffer)(struct inner_data* data);
+    void		(*fnSetTitle)(const struct inner_data* data);
+    void		(*fnScroll)(struct inner_data* data, int pos, BOOL horz);
+    void		(*fnDeleteBackend)(struct inner_data* data);
+
+    /* the following fields are only user by the USER backend (should be hidden in user) */
+    HWND		hWnd;		/* handle to windows for rendering */
+    HFONT		hFont;		/* font used for rendering, usually fixed */
+    LOGFONT		logFont;	/* logFont dscription for used hFont */
+    unsigned		cell_width;	/* width in pixels of a character */	
+    unsigned		cell_height;	/* height in pixels of a character */
+    HDC			hMemDC;		/* memory DC holding the bitmap below */
+    HBITMAP		hBitmap;	/* bitmap of display window content */
+
+    HBITMAP		cursor_bitmap;  /* bitmap used for the caret */
+    BOOL		hasSelection;	/* a rectangular mouse selection has taken place */
+    COORD		selectPt1;	/* start (and end) point of a mouse selection */
+    COORD		selectPt2;
+};
+
+#  ifdef __GNUC__
+extern void  XTracer(int level, const char* format, ...) __attribute__((format (printf,2,3)));
+#  else
+extern void  XTracer(int level, const char* format, ...);
+#  endif
+#if 0
+/* Trace mode */
+#  define Trace XTracer
+#else
+/* non trace mode */
+#  define Trace (1) ? (void)0 : XTracer
+#endif
+
+extern void WINECON_NotifyWindowChange(struct inner_data* data);
+extern int  WINECON_GetHistorySize(HANDLE hConIn);
+extern BOOL WINECON_SetHistorySize(HANDLE hConIn, int size);
+extern int  WINECON_GetHistoryMode(HANDLE hConIn);
+extern BOOL WINECON_SetHistoryMode(HANDLE hConIn, int mode);
+extern BOOL WINECON_GetConsoleTitle(HANDLE hConIn, WCHAR* buffer, size_t len);
+extern void WINECON_FetchCells(struct inner_data* data, int upd_tp, int upd_bm);
+extern int  WINECON_GrabChanges(struct inner_data* data);
+
+extern BOOL WCUSER_GetProperties(struct inner_data*);
+extern BOOL WCUSER_SetFont(struct inner_data* data, const LOGFONT* font, const TEXTMETRIC* tm);
+extern BOOL WCUSER_ValidateFont(const struct inner_data* data, const LOGFONT* lf);
+extern BOOL WCUSER_ValidateFontMetric(const struct inner_data* data, const TEXTMETRIC* tm);
+extern BOOL WCUSER_InitBackend(struct inner_data* data);
diff --git a/programs/wineconsole/wineconsole.c b/programs/wineconsole/wineconsole.c
new file mode 100644
index 0000000..38ba58d
--- /dev/null
+++ b/programs/wineconsole/wineconsole.c
@@ -0,0 +1,479 @@
+/*
+ * an application for displaying Win32 console
+ *
+ * Copyright 2001 Eric Pouech
+ */
+
+#include <stdio.h>
+#include <wine/server.h>
+#include "winecon_private.h"
+
+static int trace_level = 1;
+void      XTracer(int level, const char* format, ...)
+{
+    char        buf[1024];
+    va_list     valist;
+    int         len;
+
+    if (level > trace_level) return;
+
+    va_start(valist, format);
+    len = wvsnprintfA(buf, sizeof(buf), format, valist);
+    va_end(valist);
+ 
+    if (len <= -1) 
+    {
+        len = sizeof(buf) - 1;
+        buf[len] = 0;
+        buf[len - 1] = buf[len - 2] = buf[len - 3] = '.';
+    }
+    fprintf(stderr, buf);
+}
+
+/******************************************************************
+ *		WINECON_FetchCells
+ *
+ * updates the local copy of cells (band to update)
+ */
+void	WINECON_FetchCells(struct inner_data* data, int upd_tp, int upd_bm)
+{
+    int		step;
+    int		j, nr;
+
+    step = REQUEST_MAX_VAR_SIZE / (data->sb_width * 4);
+
+    for (j = upd_tp; j <= upd_bm; j += step)
+    {
+	nr = min(step, upd_bm - j + 1);
+	SERVER_START_VAR_REQ( read_console_output, 4 * nr * data->sb_width )
+	{
+	    req->handle       = (handle_t)data->hConOut;
+	    req->x            = 0;
+	    req->y            = j;
+	    req->w            = data->sb_width;
+	    req->h            = nr;
+	    if (!SERVER_CALL_ERR())
+	    {
+		if (data->sb_width != req->eff_w || nr != req->eff_h) 
+		    Trace(0, "pb here... wrong eff_w %d/%d or eff_h %d/%d\n", 
+			  req->eff_w, data->sb_width, req->eff_h, nr);
+		memcpy(&data->cells[j * data->sb_width], server_data_ptr(req), 
+		       4 * nr * data->sb_width);
+	    }
+	}
+	SERVER_END_VAR_REQ;
+    }
+    data->fnRefresh(data, upd_tp, upd_bm);
+}
+
+/******************************************************************
+ *		WINECON_NotifyWindowChange
+ *
+ * Inform server that visible window on sb has changed
+ */
+void	WINECON_NotifyWindowChange(struct inner_data* data)
+{
+    SERVER_START_REQ( set_console_output_info )
+    {
+	req->handle       = (handle_t)data->hConOut;
+	req->win_left     = data->win_pos.X;
+	req->win_top      = data->win_pos.Y;
+	req->win_right    = data->win_pos.X + data->win_width - 1;
+	req->win_bottom   = data->win_pos.Y + data->win_height - 1;
+	req->mask         = SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW;
+	if (!SERVER_CALL_ERR())
+	{
+	}
+    }
+    SERVER_END_REQ;
+}
+
+/******************************************************************
+ *		WINECON_GetHistorySize
+ *
+ *
+ */
+int	WINECON_GetHistorySize(HANDLE hConIn)
+{
+    int	ret = 0;
+
+    SERVER_START_REQ(get_console_input_info)
+    {
+	req->handle = (handle_t)hConIn;
+	if (!SERVER_CALL_ERR()) ret = req->history_size;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+/******************************************************************
+ *		WINECON_SetHistorySize
+ *
+ *
+ */
+BOOL	WINECON_SetHistorySize(HANDLE hConIn, int size)
+{
+    BOOL	ret;
+
+    SERVER_START_REQ(set_console_input_info)
+    {
+	req->handle = (handle_t)hConIn;
+	req->mask = SET_CONSOLE_INPUT_INFO_HISTORY_SIZE;
+	req->history_size = size;
+	ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+
+/******************************************************************
+ *		WINECON_GetHistoryMode
+ *
+ *
+ */
+int	WINECON_GetHistoryMode(HANDLE hConIn)
+{
+    int	ret = 0;
+
+    SERVER_START_REQ(get_console_input_info)
+    {
+	req->handle = (handle_t)hConIn;
+	if (!SERVER_CALL_ERR()) ret = req->history_mode;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+/******************************************************************
+ *		WINECON_SetHistoryMode
+ *
+ *
+ */
+BOOL	WINECON_SetHistoryMode(HANDLE hConIn, int mode)
+{
+    BOOL	ret;
+
+    SERVER_START_REQ(set_console_input_info)
+    {
+	req->handle = (handle_t)hConIn;
+	req->mask = SET_CONSOLE_INPUT_INFO_HISTORY_MODE;
+	req->history_mode = mode;
+	ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
+/******************************************************************
+ *		WINECON_GetConsoleTitle
+ *
+ *
+ */
+BOOL	WINECON_GetConsoleTitle(HANDLE hConIn, WCHAR* buffer, size_t len)
+{
+    BOOL	ret;
+    DWORD 	size = 0;
+
+    SERVER_START_VAR_REQ(get_console_input_info, sizeof(buffer))
+    {
+	req->handle = (handle_t)hConIn;
+        if ((ret = !SERVER_CALL_ERR()))
+        {
+            size = min(len - sizeof(WCHAR), server_data_size(req));
+            memcpy(buffer, server_data_ptr(req), size);
+            buffer[size / sizeof(WCHAR)] = 0;
+        }
+    }
+    SERVER_END_VAR_REQ;
+    return ret;
+}
+
+/******************************************************************
+ *		WINECON_GrabChanges
+ *
+ * A change occurs, try to figure out which
+ */
+int	WINECON_GrabChanges(struct inner_data* data)
+{
+    struct console_renderer_event	evts[16];
+    int	i, num;
+    HANDLE h;
+
+    SERVER_START_VAR_REQ( get_console_renderer_events, sizeof(evts) )
+    {
+	req->handle       = (handle_t)data->hSynchro;
+	if (!SERVER_CALL_ERR())
+	{
+	    num = server_data_size(req);
+	    memcpy(evts, server_data_ptr(req), num);
+	    num /= sizeof(evts[0]);
+	}
+	else num = 0;
+    }
+    SERVER_END_VAR_REQ;
+    if (!num) {Trace(0, "hmm renderer signaled but no events available\n"); return 1;}
+    
+    /* FIXME: should do some event compression here (cursor pos, update) */
+    Trace(1, "Change notification:");
+    for (i = 0; i < num; i++)
+    {
+	switch (evts[i].event)
+	{
+	case CONSOLE_RENDERER_TITLE_EVENT:
+	    data->fnSetTitle(data);
+	    break;
+	case CONSOLE_RENDERER_ACTIVE_SB_EVENT:
+	    SERVER_START_REQ( open_console )
+	    {
+		req->from    = (int)data->hConIn;
+		req->access  = GENERIC_READ | GENERIC_WRITE;
+		req->share   = FILE_SHARE_READ | FILE_SHARE_WRITE;
+		req->inherit = FALSE;
+		h = SERVER_CALL_ERR() ? 0 : (HANDLE)req->handle;
+	    }
+	    SERVER_END_REQ;
+	    Trace(1, " active(%d)", (int)h);
+	    if (h)
+	    {
+		CloseHandle(data->hConOut);
+		data->hConOut = h;
+	    }
+	    break;
+	case CONSOLE_RENDERER_SB_RESIZE_EVENT:
+	    if (data->sb_width != evts[i].u.resize.width || 
+		data->sb_height != evts[i].u.resize.height)
+	    {
+		Trace(1, " resize(%d,%d)", evts[i].u.resize.width, evts[i].u.resize.height);
+		data->sb_width  = evts[i].u.resize.width;
+		data->sb_height = evts[i].u.resize.height;
+		
+		data->cells = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data->cells,
+					  data->sb_width * data->sb_height * sizeof(CHAR_INFO));
+		if (!data->cells) {Trace(0, "OOM\n"); exit(0);}
+		data->fnResizeScreenBuffer(data);
+		data->fnComputePositions(data);
+	    }
+	    break;
+	case CONSOLE_RENDERER_UPDATE_EVENT:
+	    Trace(1, " update(%d,%d)", evts[i].u.update.top, evts[i].u.update.bottom);
+	    WINECON_FetchCells(data, evts[i].u.update.top, evts[i].u.update.bottom);
+	    break;
+	case CONSOLE_RENDERER_CURSOR_POS_EVENT:
+	    if (evts[i].u.cursor_pos.x != data->cursor.X || evts[i].u.cursor_pos.y != data->cursor.Y)
+	    {	
+		data->cursor.X = evts[i].u.cursor_pos.x;
+		data->cursor.Y = evts[i].u.cursor_pos.y;
+		data->fnPosCursor(data);
+		Trace(1, " curs-pos(%d,%d)",evts[i].u.cursor_pos.x, evts[i].u.cursor_pos.y);
+	    }
+	    break;
+	case CONSOLE_RENDERER_CURSOR_GEOM_EVENT:
+	    if (evts[i].u.cursor_geom.size != data->cursor_size || 
+		evts[i].u.cursor_geom.visible != data->cursor_visible)
+	    {
+		data->fnShapeCursor(data, evts[i].u.cursor_geom.size, 
+				    evts[i].u.cursor_geom.visible, FALSE);
+		Trace(1, " curs-geom(%d,%d)", 
+		      evts[i].u.cursor_geom.size, evts[i].u.cursor_geom.visible);
+	    }
+	    break;
+	case CONSOLE_RENDERER_DISPLAY_EVENT:
+	    if (evts[i].u.display.left != data->win_pos.X)
+	    {
+		data->fnScroll(data, evts[i].u.display.left, TRUE);
+		data->fnPosCursor(data);
+		Trace(1, " h-scroll(%d)", evts[i].u.display.left);
+	    }
+	    if (evts[i].u.display.top != data->win_pos.Y)
+	    {
+		data->fnScroll(data, evts[i].u.display.top, FALSE);
+		data->fnPosCursor(data);
+		Trace(1, " v-scroll(%d)", evts[i].u.display.top);
+	    }
+	    if (evts[i].u.display.width != data->win_width || 
+		evts[i].u.display.height != data->win_height)
+	    {
+		Trace(1, " win-size(%d,%d)", evts[i].u.display.width, evts[i].u.display.height);
+		data->win_width = evts[i].u.display.width;
+		data->win_height = evts[i].u.display.height;
+		data->fnComputePositions(data);
+	    }
+	    break;
+	case CONSOLE_RENDERER_EXIT_EVENT:
+	    Trace(1, ". Exit!!\n");
+	    return 0;
+	default:
+	    Trace(0, "Unknown event type (%d)\n", evts[i].event);
+	}
+    }
+
+    Trace(1, ". Done\n");
+    return 1;
+}
+
+/******************************************************************
+ *		WINECON_Delete
+ *
+ * Destroy wineconsole internal data
+ */
+static void WINECON_Delete(struct inner_data* data)
+{
+    if (!data) return;
+
+    if (data->hConIn)		CloseHandle(data->hConIn);
+    if (data->hConOut)		CloseHandle(data->hConOut);
+    if (data->hSynchro)		CloseHandle(data->hSynchro);
+    if (data->cells)		HeapFree(GetProcessHeap(), 0, data->cells);
+    data->fnDeleteBackend(data);
+    HeapFree(GetProcessHeap(), 0, data);
+}
+
+/******************************************************************
+ *		WINECON_Init
+ *
+ * Initialisation part I. Creation of server object (console input and
+ * active screen buffer)
+ */
+static struct inner_data* WINECON_Init(HINSTANCE hInst, void* pid)
+{
+    struct inner_data*	data = NULL;
+    DWORD		ret;
+    WCHAR		szTitle[] = {'W','i','n','e',' ','c','o','n','s','o','l','e',0};
+    size_t		len;
+
+    data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
+    if (!data) return 0;
+
+    /* the handles here are created without the whistles and bells required by console
+     * (mainly because wineconsole doesn't need it)
+     * - there are not inheritable
+     * - hConIn is not synchronizable
+     */
+    SERVER_START_REQ(alloc_console)
+    {
+        req->access  = GENERIC_READ | GENERIC_WRITE;
+        req->inherit = FALSE;
+	req->pid     = pid;
+        ret = !SERVER_CALL_ERR();
+        data->hConIn = (HANDLE)req->handle_in;
+	data->hSynchro = (HANDLE)req->event;
+    }
+    SERVER_END_REQ;
+    if (!ret) goto error;
+
+    len = lstrlenW(szTitle) * sizeof(WCHAR);
+    len = min(len, REQUEST_MAX_VAR_SIZE);
+
+    SERVER_START_VAR_REQ(set_console_input_info, len)
+    {
+	req->handle = (handle_t)data->hConIn;
+        req->mask = SET_CONSOLE_INPUT_INFO_TITLE;
+        memcpy(server_data_ptr(req), szTitle, len);
+        ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_VAR_REQ;
+
+    if (ret) 
+    {    
+	SERVER_START_REQ(create_console_output)
+	{
+	    req->handle_in = (handle_t)data->hConIn;
+	    req->access    = GENERIC_WRITE|GENERIC_READ;
+	    req->share     = FILE_SHARE_READ|FILE_SHARE_WRITE;
+	    req->inherit   = FALSE;
+	    data->hConOut  = (HANDLE)(SERVER_CALL_ERR() ? 0 : req->handle_out);
+	}
+	SERVER_END_REQ;
+	if (data->hConOut) return data;
+    }
+
+ error:
+    WINECON_Delete(data);
+    return NULL;
+}
+
+/******************************************************************
+ *		WINECON_Spawn
+ *
+ * Spawn the child processus when invoked with wineconsole foo bar
+ */
+static BOOL WINECON_Spawn(struct inner_data* data, LPCSTR lpCmdLine)
+{
+    PROCESS_INFORMATION	info;
+    STARTUPINFO		startup;
+    LPWSTR		ptr = GetCommandLine(); /* we're unicode... */
+    BOOL		done;
+
+    /* we're in the case wineconsole <exe> <options>... spawn the new process */
+    memset(&startup, 0, sizeof(startup));
+    startup.cb          = sizeof(startup);
+    startup.dwFlags     = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
+    startup.wShowWindow = SW_SHOWNORMAL;
+
+    /* the attributes of wineconsole's handles are not adequate for inheritance, so
+     * get them with the correct attributes before process creation
+     */
+    if (!DuplicateHandle(GetCurrentProcess(), data->hConIn,  GetCurrentProcess(),
+			 &startup.hStdInput, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, TRUE, 0) ||
+	!DuplicateHandle(GetCurrentProcess(), data->hConOut, GetCurrentProcess(), 
+			 &startup.hStdOutput, GENERIC_READ|GENERIC_WRITE, TRUE, 0) ||
+	!DuplicateHandle(GetCurrentProcess(), data->hConOut, GetCurrentProcess(), 
+			     &startup.hStdError, GENERIC_READ|GENERIC_WRITE, TRUE, 0))
+    {
+	Trace(0, "can't dup handles\n");
+	/* no need to delete handles, we're exiting the programm anyway */
+	return FALSE;
+    }
+
+    /* we could have several ' ' in process command line... so try first space...
+     * FIXME:
+     * the correct way would be to check the existence of the left part of ptr
+     * (to be a file)
+     */
+    while (*ptr && *ptr++ != ' ');
+
+    done = *ptr && CreateProcess(NULL, ptr, NULL, NULL, TRUE, 0L, NULL, NULL, &startup, &info);
+    
+    /* we no longer need the handles passed to the child for the console */
+    CloseHandle(startup.hStdInput);
+    CloseHandle(startup.hStdOutput);
+    CloseHandle(startup.hStdError);
+
+    return done;
+}
+
+/******************************************************************
+ *		WINECON_WinMain
+ *
+ * wineconsole can either be started as:
+ *	wineconsole <int>		used when a new console is created (AllocConsole)
+ *	wineconsole <pgm> <arguments>	used to start the program <pgm> from the command line in
+ *					a freshly created console
+ */
+int PASCAL WINECON_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPCSTR lpCmdLine, UINT nCmdShow)
+{
+    struct inner_data*	data;
+    int			ret = 1;
+    unsigned		evt;
+
+    /* case of wineconsole <evt>, signal process that created us that we're up and running */
+    if (sscanf(lpCmdLine, "%d", &evt) == 1)
+    {
+        if (!(data = WINECON_Init(hInst, 0))) return 0;
+	ret = SetEvent((HANDLE)evt);
+    }
+    else
+    {
+        if (!(data = WINECON_Init(hInst, (void*)GetCurrentProcessId()))) return 0;
+	ret = WINECON_Spawn(data, lpCmdLine);
+    }
+
+    if (ret && WCUSER_InitBackend(data))
+    {
+	ret = data->fnMainLoop(data);
+    }
+    WINECON_Delete(data);
+
+    return ret;
+}
diff --git a/programs/wineconsole/wineconsole.spec b/programs/wineconsole/wineconsole.spec
new file mode 100644
index 0000000..a5c6544
--- /dev/null
+++ b/programs/wineconsole/wineconsole.spec
@@ -0,0 +1,12 @@
+name	wineconsole
+mode	guiexe
+type	win32
+init	WINECON_WinMain
+rsrc    wineconsole_res.res                                                                                                                                                                  
+
+import -delay comctl32
+import  gdi32.dll
+import  user32.dll
+#import	advapi32.dll
+import	kernel32.dll
+import	ntdll.dll
diff --git a/programs/wineconsole/wineconsole_En.rc b/programs/wineconsole/wineconsole_En.rc
new file mode 100644
index 0000000..50b6f6d
--- /dev/null
+++ b/programs/wineconsole/wineconsole_En.rc
@@ -0,0 +1,70 @@
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+BEGIN
+IDS_EDIT,		"&Edit"
+IDS_DEFAULT,		"&Default"
+IDS_PROPERTY,		"&Property"
+IDS_MARK,		"&Mark"
+IDS_COPY,		"&Copy"
+IDS_PASTE,		"&Paste"
+IDS_SELECTALL,		"&Select all"
+IDS_SCROLL,		"Sc&roll"
+IDS_SEARCH,		"S&earch"
+IDS_FNT_DISPLAY,	"Each character is %ld pixels wide on %ld pixels high"
+IDS_FNT_PREVIEW_1,	"This is a test"
+IDS_FNT_PREVIEW_2,	""
+END
+
+IDD_OPTION DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION " Options "
+FONT 8, "Helv"
+{
+	GROUPBOX "Cursor size", -1, 10, 11, 120, 44, BS_GROUPBOX
+	AUTORADIOBUTTON "&Small", IDC_OPT_CURSOR_SMALL, 14, 23, 84, 10, WS_TABSTOP
+	AUTORADIOBUTTON "&Medium", IDC_OPT_CURSOR_MEDIUM, 14, 33, 84, 10, WS_TABSTOP
+	AUTORADIOBUTTON "&Large", IDC_OPT_CURSOR_LARGE, 14, 43, 84, 10, WS_TABSTOP
+
+	GROUPBOX "Command history", -1, 10, 57, 180, 35, BS_GROUPBOX
+	LTEXT "&Numbers of recalled commands :", -1, 14, 67, 78, 18
+	EDITTEXT IDC_OPT_HIST_SIZE, 92, 69, 31, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_OPT_HIST_SIZE_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+	AUTOCHECKBOX "&Remove doubles", IDC_OPT_HIST_DOUBLE, 130, 67, 50, 18, WS_TABSTOP|BS_MULTILINE
+}
+
+IDD_FONT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION " Font "
+FONT 8, "Helv"
+{
+	LTEXT "&Font", -1, 5, 5, 24, 8
+	LISTBOX IDC_FNT_LIST_FONT, 5,18,109,42, LBS_SORT|WS_VSCROLL
+	LTEXT "&Size", -1, 128, 5, 60, 8
+	LISTBOX IDC_FNT_LIST_SIZE, 128, 18, 50, 60, WS_VSCROLL
+	CONTROL "", IDC_FNT_PREVIEW, "WineConFontPreview", 0L, 5,60,109,40
+	LTEXT "", IDC_FNT_FONT_INFO, 128, 76, 80, 18
+}
+
+IDD_CONFIG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION " Configuration "
+FONT 8, "Helv"
+{
+	GROUPBOX "Buffer zone", -1, 10, 11, 110, 42, BS_GROUPBOX
+	LTEXT "&Width :", -1, 14, 25, 54, 9
+	EDITTEXT IDC_CNF_SB_WIDTH, 78, 23, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_CNF_SB_WIDTH_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+	LTEXT "&Height :", -1, 14, 39, 54, 9
+	EDITTEXT IDC_CNF_SB_HEIGHT, 78, 37, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_CNF_SB_HEIGHT_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+
+	GROUPBOX "Window size", -1, 10, 55, 110, 42
+	LTEXT "W&idth :", -1, 14, 69, 54, 9
+	EDITTEXT IDC_CNF_WIN_WIDTH, 78, 67, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_CNF_WIN_WIDTH_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+	LTEXT "H&eight :", -1, 14, 83, 54, 9
+	EDITTEXT IDC_CNF_WIN_HEIGHT, 78, 81, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_CNF_WIN_HEIGHT_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+}
+
diff --git a/programs/wineconsole/wineconsole_Fr.rc b/programs/wineconsole/wineconsole_Fr.rc
new file mode 100644
index 0000000..d5a7841
--- /dev/null
+++ b/programs/wineconsole/wineconsole_Fr.rc
@@ -0,0 +1,72 @@
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+STRINGTABLE LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+BEGIN
+IDS_EDIT,		"&Editer"
+IDS_DEFAULT,		"Par &défaut"
+IDS_PROPERTY,		"&Propriétés"
+IDS_MARK,		"&Marquer"
+IDS_COPY,		"&Copier"
+IDS_PASTE,		"C&oller"
+IDS_SELECTALL,		"&Sélectionner tout"
+IDS_SCROLL,		"&Défiler"
+IDS_SEARCH,		"C&hercher"
+IDS_FNT_DISPLAY,	"Chaque caractère a %ld points en largeur et %ld points en hauteur"
+IDS_FNT_PREVIEW_1,	"Ceci est un test"
+IDS_FNT_PREVIEW_2,	"éèàôë"
+END
+
+IDD_OPTION DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION " Options "
+FONT 8, "Helv"
+{
+	GROUPBOX "Taille du curseur", -1, 10, 11, 120, 44, BS_GROUPBOX
+	AUTORADIOBUTTON "&Petit", IDC_OPT_CURSOR_SMALL, 14, 23, 84, 10, WS_TABSTOP
+	AUTORADIOBUTTON "&Moyen", IDC_OPT_CURSOR_MEDIUM, 14, 33, 84, 10, WS_TABSTOP
+	AUTORADIOBUTTON "&Grand", IDC_OPT_CURSOR_LARGE, 14, 43, 84, 10, WS_TABSTOP
+
+	GROUPBOX "Historique des commandes", -1, 10, 57, 180, 35, BS_GROUPBOX
+	LTEXT "&Taille de la mémoire tampon :", -1, 14, 67, 78, 18
+	EDITTEXT IDC_OPT_HIST_SIZE, 92, 69, 31, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_OPT_HIST_SIZE_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+	AUTOCHECKBOX "&Supprimer les doublons", IDC_OPT_HIST_DOUBLE, 130, 67, 50, 18, WS_TABSTOP|BS_MULTILINE
+}
+
+IDD_FONT DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION " Police "
+FONT 8, "Helv"
+{
+	LTEXT "&Police", -1, 5, 5, 24, 8
+	LISTBOX IDC_FNT_LIST_FONT, 5, 18, 109, 42, LBS_SORT|WS_VSCROLL
+	LTEXT "&Taille", -1, 128, 5, 60, 8
+	LISTBOX IDC_FNT_LIST_SIZE, 128, 18, 50, 60, WS_VSCROLL
+	CONTROL "", IDC_FNT_PREVIEW, "WineConFontPreview", 0L, 5, 60, 109, 40
+	LTEXT "", IDC_FNT_FONT_INFO, 128, 76, 80, 18
+}
+
+IDD_CONFIG DIALOG LOADONCALL MOVEABLE DISCARDABLE 36, 24, 140, 105 LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION " Configuration "
+FONT 8, "Helv"
+{
+	GROUPBOX "Taille mémoire tampon écran", -1, 10, 11, 110, 42, BS_GROUPBOX
+	LTEXT "&Largeur :", -1, 14, 25, 54, 9
+	EDITTEXT IDC_CNF_SB_WIDTH, 78, 23, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_CNF_SB_WIDTH_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+	LTEXT "Ha&uteur :", -1, 14, 39, 54, 9
+	EDITTEXT IDC_CNF_SB_HEIGHT, 78, 37, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_CNF_SB_HEIGHT_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+
+	GROUPBOX "Taille de la fenêtre", -1, 10, 55, 110, 42
+	LTEXT "La&rgeur :", -1, 14, 69, 54, 9
+	EDITTEXT IDC_CNF_WIN_WIDTH, 78, 67, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_CNF_WIN_WIDTH_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+	LTEXT "Hau&teur :", -1, 14, 83, 54, 9
+	EDITTEXT IDC_CNF_WIN_HEIGHT, 78, 81, 36, 12, WS_TABSTOP|WS_BORDER|ES_NUMBER
+	CONTROL "", IDC_CNF_WIN_HEIGHT_UD, "msctls_updown32", UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_AUTOBUDDY|UDS_ARROWKEYS|UDS_NOTHOUSANDS, 0, 0, 0, 0
+}
+
+
+
diff --git a/programs/wineconsole/wineconsole_res.h b/programs/wineconsole/wineconsole_res.h
new file mode 100644
index 0000000..17c8cba
--- /dev/null
+++ b/programs/wineconsole/wineconsole_res.h
@@ -0,0 +1,44 @@
+/* wineconsole resource definitions */
+
+/* strings */
+#define IDS_EDIT		0x100
+#define IDS_DEFAULT		0x101
+#define IDS_PROPERTY		0x102
+
+#define IDS_MARK		0x110
+#define IDS_COPY		0x111
+#define IDS_PASTE		0x112
+#define IDS_SELECTALL		0x113
+#define IDS_SCROLL		0x114
+#define IDS_SEARCH		0x115
+
+#define IDS_FNT_DISPLAY		0x200
+#define IDS_FNT_PREVIEW_1	0x201
+#define IDS_FNT_PREVIEW_2	0x202
+
+#define IDD_OPTION		0x0100
+#define IDD_FONT		0x0200
+#define IDD_CONFIG		0x0300
+
+/* dialog boxes */
+#define IDC_OPT_CURSOR_SMALL	0x0101
+#define IDC_OPT_CURSOR_MEDIUM	0x0102
+#define IDC_OPT_CURSOR_LARGE	0x0103
+#define IDC_OPT_HIST_SIZE	0x0104
+#define IDC_OPT_HIST_SIZE_UD	0x0105
+#define IDC_OPT_HIST_DOUBLE	0x0106
+
+#define IDC_FNT_LIST_FONT	0x0201
+#define IDC_FNT_LIST_SIZE	0x0202
+#define IDC_FNT_FONT_INFO	0x0203
+#define IDC_FNT_PREVIEW		0x0204
+
+#define IDC_CNF_SB_WIDTH	0x0301
+#define IDC_CNF_SB_WIDTH_UD	0x0302
+#define IDC_CNF_SB_HEIGHT	0x0303
+#define IDC_CNF_SB_HEIGHT_UD	0x0304
+#define IDC_CNF_WIN_WIDTH	0x0305
+#define IDC_CNF_WIN_WIDTH_UD	0x0306
+#define IDC_CNF_WIN_HEIGHT	0x0307
+#define IDC_CNF_WIN_HEIGHT_UD	0x0308
+
diff --git a/programs/wineconsole/wineconsole_res.rc b/programs/wineconsole/wineconsole_res.rc
new file mode 100644
index 0000000..6ebc40c
--- /dev/null
+++ b/programs/wineconsole/wineconsole_res.rc
@@ -0,0 +1,8 @@
+#include "windef.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "commctrl.h"
+#include "wineconsole_res.h"
+
+#include "wineconsole_En.rc"
+#include "wineconsole_Fr.rc"
diff --git a/scheduler/process.c b/scheduler/process.c
index ab5db91..755dd39 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -20,6 +20,7 @@
 #include "file.h"
 #include "thread.h"
 #include "winerror.h"
+#include "wincon.h"
 #include "wine/server.h"
 #include "options.h"
 #include "callback.h"
@@ -216,29 +217,6 @@
         Callout.UserSignalProc( uCode, GetCurrentProcessId(), dwFlags, hModule );
 }
 
-
-/***********************************************************************
- *           set_console_handles
- *
- * Set the console handles to use stdin/stdout.
- */
-static void set_console_handles( HANDLE console )
-{
-    wine_server_send_fd( 0 );
-    wine_server_send_fd( 1 );
-
-    SERVER_START_REQ( set_console_fd )
-    {
-        req->handle = console;
-        req->fd_in  = 0;
-        req->fd_out = 1;
-        req->pid    = 0;
-        SERVER_CALL();
-    }
-    SERVER_END_REQ;
-}
-
-
 /***********************************************************************
  *           process_init
  *
@@ -287,15 +265,28 @@
     SERVER_END_VAR_REQ;
     if (!ret) return FALSE;
 
-    SetStdHandle( STD_INPUT_HANDLE,  current_startupinfo.hStdInput );
-    SetStdHandle( STD_OUTPUT_HANDLE, current_startupinfo.hStdOutput );
-    SetStdHandle( STD_ERROR_HANDLE,  current_startupinfo.hStdError );
-    if (create_flags & CREATE_NEW_CONSOLE)
-        set_console_handles( current_startupinfo.hStdOutput );
-
     /* Create the process heap */
     current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
 
+    if (create_flags == 0 &&
+	current_startupinfo.hStdInput  == 0 &&
+	current_startupinfo.hStdOutput == 0 && 
+	current_startupinfo.hStdError  == 0)
+    {
+	/* no parent, and no new console requested, create a simple console with bare handles to
+	 * unix stdio input & output streams (aka simple console)
+	 */
+	SetStdHandle( STD_INPUT_HANDLE,  FILE_DupUnixHandle( 0, GENERIC_READ, TRUE ));
+	SetStdHandle( STD_OUTPUT_HANDLE, FILE_DupUnixHandle( 1, GENERIC_WRITE, TRUE ));
+	SetStdHandle( STD_ERROR_HANDLE,  FILE_DupUnixHandle( 1, GENERIC_WRITE, TRUE ));
+    }
+    else if (!(create_flags & (DETACHED_PROCESS|CREATE_NEW_CONSOLE)))
+    {
+	SetStdHandle( STD_INPUT_HANDLE,  current_startupinfo.hStdInput  );
+	SetStdHandle( STD_OUTPUT_HANDLE, current_startupinfo.hStdOutput );
+	SetStdHandle( STD_ERROR_HANDLE,  current_startupinfo.hStdError  );
+    }
+
     /* Now we can use the pthreads routines */
     PTHREAD_init_done();
 
@@ -305,7 +296,11 @@
     /* Parse command line arguments */
     OPTIONS_ParseOptions( argv );
 
-    return MAIN_MainInit();
+    ret = MAIN_MainInit();
+
+    if (create_flags & CREATE_NEW_CONSOLE)
+	AllocConsole();
+    return ret;
 }
 
 
diff --git a/server/console.c b/server/console.c
index 6aab563..bd6dd39 100644
--- a/server/console.c
+++ b/server/console.c
@@ -2,22 +2,15 @@
  * Server-side console management
  *
  * Copyright (C) 1998 Alexandre Julliard
+ *               2001 Eric Pouech
  *
- * FIXME: all this stuff is a hack to avoid breaking
- *        the client-side console support.
  */
 
 #include "config.h"
 
 #include <assert.h>
-#include <fcntl.h>
-#include <signal.h>
 #include <string.h>
 #include <stdio.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <time.h>
 #include <unistd.h>
 
 #include "winnt.h"
@@ -26,18 +19,60 @@
 
 #include "handle.h"
 #include "process.h"
-#include "thread.h"
 #include "request.h"
+#include "unicode.h"
+#include "console.h"
 
-struct screen_buffer;
 
-struct console_input
+static void console_input_dump( struct object *obj, int verbose );
+static void console_input_destroy( struct object *obj );
+static int console_input_signaled( struct object *obj, struct thread *thread );
+
+/* common routine */
+static int console_get_file_info( struct object *obj, struct get_file_info_request *req );
+
+static const struct object_ops console_input_ops =
 {
-    struct object         obj;           /* object header */
-    int                   mode;          /* input mode */
-    struct screen_buffer *output;        /* associated screen buffer */
-    int                   recnum;        /* number of input records */
-    INPUT_RECORD         *records;       /* input records */
+    sizeof(struct console_input),     /* size */
+    console_input_dump,               /* dump */
+    add_queue,                        /* add_queue */
+    remove_queue,                     /* remove_queue */
+    console_input_signaled,           /* signaled */
+    no_satisfied,                     /* satisfied */
+    NULL,                             /* get_poll_events */
+    NULL,                             /* poll_event */
+    no_get_fd,                        /* get_fd */
+    no_flush,                         /* flush */
+    console_get_file_info,            /* get_file_info */
+    console_input_destroy             /* destroy */
+};
+
+static void console_input_events_dump( struct object *obj, int verbose );
+static void console_input_events_destroy( struct object *obj );
+static int  console_input_events_signaled( struct object *obj, struct thread *thread );
+
+struct console_input_events 
+{
+    struct object         obj;         /* object header */
+    int			  num_alloc;   /* number of allocated events */
+    int 		  num_used;    /* number of actually used events */
+    struct console_renderer_event*	events;
+};
+
+static const struct object_ops console_input_events_ops =
+{
+    sizeof(struct console_input_events), /* size */
+    console_input_events_dump,        /* dump */
+    add_queue,                        /* add_queue */
+    remove_queue,                     /* remove_queue */
+    console_input_events_signaled,    /* signaled */
+    no_satisfied,                     /* satisfied */
+    NULL,                             /* get_poll_events */
+    NULL,                             /* poll_event */
+    no_get_fd,                        /* get_fd */
+    no_flush,                         /* flush */
+    no_get_file_info,                 /* get_file_info */
+    console_input_events_destroy      /* destroy */
 };
 
 struct screen_buffer
@@ -45,161 +80,292 @@
     struct object         obj;           /* object header */
     int                   mode;          /* output mode */
     struct console_input *input;         /* associated console input */
-    int                   cursor_size;   /* size of cursor (percentage filled) */
-    int                   cursor_visible;/* cursor visibility flag */
-    int                   pid;           /* xterm pid (hack) */
-    char                 *title;         /* console title */
+    struct screen_buffer *next;          /* linked list of all screen buffers */
+    short int             cursor_size;   /* size of cursor (percentage filled) */
+    short int             cursor_visible;/* cursor visibility flag */
+    COORD                 cursor;        /* position of cursor */
+    short int             width;         /* size (w-h) of the screen buffer */
+    short int             height;
+    short int             max_width;     /* size (w-h) of the window given font size */
+    short int             max_height;
+    unsigned             *data;          /* the data for each cell - a width x height matrix */
+    unsigned short        attr;          /* default attribute for screen buffer */
+    SMALL_RECT            win;           /* current visible window on the screen buffer *
+					  * as seen in wineconsole */
 };
 
-
-static void console_input_dump( struct object *obj, int verbose );
-static int console_input_get_poll_events( struct object *obj );
-static int console_input_get_fd( struct object *obj );
-static void console_input_destroy( struct object *obj );
-
 static void screen_buffer_dump( struct object *obj, int verbose );
-static int screen_buffer_get_poll_events( struct object *obj );
-static int screen_buffer_get_fd( struct object *obj );
 static void screen_buffer_destroy( struct object *obj );
 
-/* common routine */
-static int console_get_info( struct object *obj, struct get_file_info_request *req );
-
-static const struct object_ops console_input_ops =
-{
-    sizeof(struct console_input),     /* size */
-    console_input_dump,               /* dump */
-    default_poll_add_queue,           /* add_queue */
-    default_poll_remove_queue,        /* remove_queue */
-    default_poll_signaled,            /* signaled */
-    no_satisfied,                     /* satisfied */
-    console_input_get_poll_events,    /* get_poll_events */
-    default_poll_event,               /* poll_event */
-    console_input_get_fd,             /* get_fd */
-    no_flush,                         /* flush */
-    console_get_info,                 /* get_file_info */
-    console_input_destroy             /* destroy */
-};
-
 static const struct object_ops screen_buffer_ops =
 {
     sizeof(struct screen_buffer),     /* size */
     screen_buffer_dump,               /* dump */
-    default_poll_add_queue,           /* add_queue */
-    default_poll_remove_queue,        /* remove_queue */
-    default_poll_signaled,            /* signaled */
-    no_satisfied,                     /* satisfied */
-    screen_buffer_get_poll_events,    /* get_poll_events */
-    default_poll_event,               /* poll_event */
-    screen_buffer_get_fd,             /* get_fd */
+    no_add_queue,                     /* add_queue */
+    NULL,                             /* remove_queue */
+    NULL,                             /* signaled */
+    NULL,                             /* satisfied */
+    NULL,                             /* get_poll_events */
+    NULL,                             /* poll_event */
+    no_get_fd,                        /* get_fd */
     no_flush,                         /* flush */
-    console_get_info,                 /* get_file_info */
+    console_get_file_info,            /* get_file_info */
     screen_buffer_destroy             /* destroy */
 };
 
+static struct screen_buffer *screen_buffer_list;
 
-static struct object *create_console_input( int fd )
+/* dumps the renderer events of a console */
+static void console_input_events_dump( struct object *obj, int verbose )
+{
+    struct console_input_events *evts = (struct console_input_events *)obj;
+    assert( obj->ops == &console_input_events_ops );
+    fprintf( stderr, "Console input events: %d/%d events\n", 
+	     evts->num_used, evts->num_alloc );
+}
+
+/* destroys the renderer events of a console */
+static void console_input_events_destroy( struct object *obj )
+{
+    struct console_input_events *evts = (struct console_input_events *)obj;
+    assert( obj->ops == &console_input_events_ops );
+    free( evts->events );
+}
+
+/* the rendere events list is signaled when it's not empty */
+static int  console_input_events_signaled( struct object *obj, struct thread *thread )
+{
+    struct console_input_events *evts = (struct console_input_events *)obj;
+    assert( obj->ops == &console_input_events_ops );
+    return evts->num_used ? 1 : 0;
+}
+
+/* add an event to the console's renderer events list */
+static void console_input_events_append( struct console_input_events* evts, 
+					 struct console_renderer_event* evt)
+{
+    if (!evt) return;
+
+    /* to be done even when the renderer generates the events ? */
+    if (evts->num_used == evts->num_alloc)
+    {
+	evts->num_alloc += 16;
+	evts->events = realloc( evts->events, evts->num_alloc * sizeof(*evt) );
+	assert(evts->events);
+    }
+    evts->events[evts->num_used++] = *evt;
+    wake_up( &evts->obj, 0 );
+}
+
+/* retrieves events from the console's renderer events list */
+static size_t  console_input_events_get( struct console_input_events* evts, 
+					 struct console_renderer_event* evt, size_t num )
+{
+    if (num % sizeof(*evt) != 0)
+    {
+	set_error( STATUS_INVALID_PARAMETER );
+	return 0;
+    }
+    num /= sizeof(*evt);
+    if (num > evts->num_used)
+	num = evts->num_used;
+    memcpy( evt, evts->events, num * sizeof(*evt) );
+    if (num < evts->num_used)
+    {
+	memmove( &evts->events[0], &evts->events[num], 
+		 (evts->num_used - num) * sizeof(*evt) );
+    }
+    evts->num_used -= num;
+    return num * sizeof(struct console_renderer_event);
+}
+
+static struct console_input_events *create_console_input_events(void)
+{
+    struct console_input_events*	evt;
+
+    if (!(evt = alloc_object( &console_input_events_ops, -1 ))) return NULL;
+    evt->num_alloc = evt->num_used = 0;
+    evt->events = NULL;
+    return evt;
+}
+
+static struct object *create_console_input( struct process* renderer )
 {
     struct console_input *console_input;
 
-    if ((fd = (fd != -1) ? dup(fd) : dup(0)) == -1)
+    if (!(console_input = alloc_object( &console_input_ops, -1 ))) return NULL;
+    console_input->renderer      = renderer;
+    console_input->mode          = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
+	                           ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
+    console_input->num_proc      = 0;
+    console_input->active        = NULL;
+    console_input->recnum        = 0;
+    console_input->records       = NULL;
+    console_input->evt           = create_console_input_events();
+    console_input->title         = NULL;
+    console_input->history_size  = 50;
+    console_input->history       = calloc( console_input->history_size, sizeof(WCHAR*) );
+    console_input->history_index = 0;
+    console_input->history_mode  = 0;
+
+    if (!console_input->history || !console_input->evt)
     {
-        file_set_error();
-        return NULL;
+	release_object( console_input );
+	return NULL;
     }
-    if (!(console_input = alloc_object( &console_input_ops, fd ))) return NULL;
-    console_input->mode    = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT |
-                             ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT;
-    console_input->output  = NULL;
-    console_input->recnum  = 0;
-    console_input->records = NULL;
     return &console_input->obj;
 }
 
-static struct object *create_console_output( int fd, struct object *input )
+static struct object *create_console_output( struct console_input *console_input )
 {
-    struct console_input *console_input = (struct console_input *)input;
     struct screen_buffer *screen_buffer;
+    struct console_renderer_event evt;
+    int	i;
 
-    if ((fd = (fd != -1) ? dup(fd) : dup(1)) == -1)
-    {
-        file_set_error();
-        return NULL;
-    }
-    if (!(screen_buffer = alloc_object( &screen_buffer_ops, fd ))) return NULL;
+    if (!(screen_buffer = alloc_object( &screen_buffer_ops, -1 ))) return NULL;
     screen_buffer->mode           = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
     screen_buffer->input          = console_input;
     screen_buffer->cursor_size    = 100;
     screen_buffer->cursor_visible = 1;
-    screen_buffer->pid            = 0;
-    screen_buffer->title          = strdup( "Wine console" );
-    console_input->output = screen_buffer;
-    return &screen_buffer->obj;
-}
+    screen_buffer->width          = 80;
+    screen_buffer->height         = 150;
+    screen_buffer->max_width      = 80;
+    screen_buffer->max_height     = 25;
+    screen_buffer->data           = malloc( 4 * screen_buffer->width * screen_buffer->height );
+    /* fill the buffer with white on black spaces */
+    for (i = 0; i < screen_buffer->width * screen_buffer->height; i++)
+    {
+	screen_buffer->data[i] = 0x00F00020;
+    }
+    screen_buffer->cursor.X	  = 0;
+    screen_buffer->cursor.Y	  = 0;
+    screen_buffer->attr           = 0xF0;
+    screen_buffer->win.Left       = 0;
+    screen_buffer->win.Right      = screen_buffer->max_width - 1;
+    screen_buffer->win.Top        = 0;
+    screen_buffer->win.Bottom     = screen_buffer->max_height - 1;
 
-/* allocate a console for this process */
-int alloc_console( struct process *process )
-{
-    if (process->console_in || process->console_out)
+    screen_buffer->next = screen_buffer_list;
+    screen_buffer_list = screen_buffer;
+
+    if (!console_input->active)
     {
-        set_error( STATUS_ACCESS_DENIED );
-        return 0;
+	console_input->active = (struct screen_buffer*)grab_object( screen_buffer );
+
+	/* generate the fist events */
+	evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT;
+	console_input_events_append( console_input->evt, &evt );
+
+	evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT;
+	evt.u.resize.width  = screen_buffer->width;
+	evt.u.resize.height = screen_buffer->height;
+	console_input_events_append( console_input->evt, &evt );
+
+	evt.event = CONSOLE_RENDERER_DISPLAY_EVENT;
+	evt.u.display.left   = screen_buffer->win.Left;
+	evt.u.display.top    = screen_buffer->win.Top;
+	evt.u.display.width  = screen_buffer->win.Right - screen_buffer->win.Left + 1;
+	evt.u.display.height = screen_buffer->win.Bottom - screen_buffer->win.Top + 1;
+	console_input_events_append( console_input->evt, &evt );
+
+	evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
+	evt.u.update.top    = 0;
+	evt.u.update.bottom = screen_buffer->height - 1;
+	console_input_events_append( console_input->evt, &evt );
+
+	evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT;
+	evt.u.cursor_geom.size    = screen_buffer->cursor_size;
+	evt.u.cursor_geom.visible = screen_buffer->cursor_visible;
+	console_input_events_append( console_input->evt, &evt );
+
+	evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
+	evt.u.cursor_pos.x = screen_buffer->cursor.X;
+	evt.u.cursor_pos.y = screen_buffer->cursor.Y;
+	console_input_events_append( console_input->evt, &evt );
     }
-    if ((process->console_in = create_console_input( -1 )))
-    {
-        if ((process->console_out = create_console_output( -1, process->console_in )))
-            return 1;
-        release_object( process->console_in );
-    }
-    return 0;
+
+    return &screen_buffer->obj;
 }
 
 /* free the console for this process */
 int free_console( struct process *process )
 {
-    if (process->console_in) release_object( process->console_in );
-    if (process->console_out) release_object( process->console_out );
-    process->console_in = process->console_out = NULL;
+    struct console_input* console = process->console;
+
+    if (!console || !console->renderer) return 0;
+
+    process->console = NULL;
+    if (--console->num_proc == 0)
+    {
+	/* all processes have terminated... tell the renderer to terminate too */
+	struct console_renderer_event evt;
+	evt.event = CONSOLE_RENDERER_EXIT_EVENT;
+	console_input_events_append( console->evt, &evt );
+    }
+    release_object( console );
+
     return 1;
 }
 
-static int set_console_fd( handle_t handle, int fd_in, int fd_out, int pid )
+/* let process inherit the console from parent... this handle two cases :
+ *	1/ generic console inheritance
+ *	2/ parent is a renderer which launches process, and process should attach to the console
+ *	   renderered by parent
+ */
+void inherit_console(struct process *parent, struct process *process, handle_t hconin)
 {
-    struct console_input *input;
-    struct screen_buffer *output;
-    struct object *obj;
+    int done = 0;
 
-    if (!(obj = get_handle_obj( current->process, handle, 0, NULL )))
-        return 0;
-    if (obj->ops == &console_input_ops)
+    /* if parent is a renderer, then attach current process to its console
+     * a bit hacky....
+     */
+    if (hconin)
     {
-        input = (struct console_input *)obj;
-        output = input->output;
-        grab_object( output );
+	struct console_input* console;
+
+        if ((console = (struct console_input*)get_handle_obj( parent, hconin, 0, NULL )))
+	{
+	    if (console->renderer == parent)
+	    {
+		process->console = (struct console_input*)grab_object( console );
+		process->console->num_proc++;
+		done = 1;
+	    }
+	    release_object( console );
+	}
     }
-    else if (obj->ops == &screen_buffer_ops)
+    /* otherwise, if parent has a console, attach child to this console */
+    if (!done && parent->console)
     {
-        output = (struct screen_buffer *)obj;
-        input = output->input;
-        grab_object( input );
+	assert(parent->console->renderer);
+	process->console = (struct console_input*)grab_object( parent->console );
+	process->console->num_proc++;
     }
-    else
+}
+
+static struct console_input* console_input_get( handle_t handle, unsigned access )
+{
+    struct console_input*	console = 0;
+
+    if (handle)
+	console = (struct console_input *)get_handle_obj( current->process, handle,
+							  access, &console_input_ops );
+    else if (current->process->console)
     {
-        set_error( STATUS_OBJECT_TYPE_MISMATCH );
-        release_object( obj );
-        return 0;
+	assert( current->process->console->renderer );
+	console = (struct console_input *)grab_object( current->process->console );
     }
 
-    /* can't change the fd if someone is waiting on it */
-    assert( !input->obj.head );
-    assert( !output->obj.head );
+    if (!console && !get_error()) set_error(STATUS_INVALID_PARAMETER);
+    return console;
+}
 
-    change_select_fd( &input->obj, fd_in );
-    change_select_fd( &output->obj, fd_out );
-    output->pid = pid;
-    release_object( input );
-    release_object( output );
-    return 1;
+/* check if a console input is signaled: yes if non read input records */
+static int console_input_signaled( struct object *obj, struct thread *thread )
+{
+    struct console_input *console = (struct console_input *)obj;
+    assert( obj->ops == &console_input_ops );
+    return console->recnum ? 1 : 0;
 }
 
 static int get_console_mode( handle_t handle )
@@ -220,15 +386,17 @@
     return ret;
 }
 
+/* changes the mode of either a console input or a screen buffer */
 static int set_console_mode( handle_t handle, int mode )
 {
     struct object *obj;
     int ret = 0;
 
-    if (!(obj = get_handle_obj( current->process, handle, GENERIC_READ, NULL )))
+    if (!(obj = get_handle_obj( current->process, handle, GENERIC_WRITE, NULL )))
         return 0;
     if (obj->ops == &console_input_ops)
     {
+	/* FIXME: if we remove the edit mode bits, we need (???) to clean up the history */
         ((struct console_input *)obj)->mode = mode;
         ret = 1;
     }
@@ -242,43 +410,12 @@
     return ret;
 }
 
-/* set misc console information (output handle only) */
-static int set_console_info( handle_t handle, struct set_console_info_request *req,
-                             const char *title, size_t len )
-{
-    struct screen_buffer *console;
-    if (!(console = (struct screen_buffer *)get_handle_obj( current->process, handle,
-                                                            GENERIC_WRITE, &screen_buffer_ops )))
-        return 0;
-    if (req->mask & SET_CONSOLE_INFO_CURSOR)
-    {
-        console->cursor_size    = req->cursor_size;
-        console->cursor_visible = req->cursor_visible;
-    }
-    if (req->mask & SET_CONSOLE_INFO_TITLE)
-    {
-        char *new_title = mem_alloc( len + 1 );
-        if (new_title)
-        {
-            memcpy( new_title, title, len );
-            new_title[len] = 0;
-            if (console->title) free( console->title );
-            console->title = new_title;
-        }
-    }
-    release_object( console );
-    return 1;
-}
-
 /* add input events to a console input queue */
-static int write_console_input( handle_t handle, int count, INPUT_RECORD *records )
+static int write_console_input( struct console_input* console, int count, INPUT_RECORD *records )
 {
     INPUT_RECORD *new_rec;
-    struct console_input *console;
 
-    if (!(console = (struct console_input *)get_handle_obj( current->process, handle,
-                                                            GENERIC_WRITE, &console_input_ops )))
-        return -1;
+    assert(count);
     if (!(new_rec = realloc( console->records,
                              (console->recnum + count) * sizeof(INPUT_RECORD) )))
     {
@@ -289,7 +426,9 @@
     console->records = new_rec;
     memcpy( new_rec + console->recnum, records, count * sizeof(INPUT_RECORD) );
     console->recnum += count;
-    release_object( console );
+
+    /* wake up all waiters */
+    wake_up( &console->obj, 0 );
     return count;
 }
 
@@ -317,7 +456,7 @@
     {
         int i;
         for (i = count; i < console->recnum; i++)
-            console->records[i-count] = console->records[i];
+            ((INPUT_RECORD*)console->records)[i-count] = ((INPUT_RECORD*)console->records)[i];
         if ((console->recnum -= count) > 0)
         {
             INPUT_RECORD *new_rec = realloc( console->records,
@@ -334,26 +473,283 @@
     return count;
 }
 
+/* set misc console input information */
+static int set_console_input_info( struct set_console_input_info_request *req, 
+				   const WCHAR *title, size_t len )
+{
+    struct console_input *console;
+    struct console_renderer_event evt;
+
+    if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) goto error;
+
+    if (req->mask & SET_CONSOLE_INPUT_INFO_ACTIVE_SB)
+    {
+	struct screen_buffer *screen_buffer;
+
+	screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, req->active_sb, 
+								GENERIC_READ, &screen_buffer_ops );
+	if (!screen_buffer || screen_buffer->input != console)
+	{
+	    set_error( STATUS_INVALID_PARAMETER );
+	    if (screen_buffer) release_object( screen_buffer );
+	    goto error;
+	}
+
+	if (screen_buffer != console->active)
+	{
+	    if (console->active) release_object( console->active );
+	    console->active = screen_buffer;
+	    evt.event = CONSOLE_RENDERER_ACTIVE_SB_EVENT;
+	    console_input_events_append( console->evt, &evt );
+	}
+	else
+	    release_object( screen_buffer );
+    }
+    if (req->mask & SET_CONSOLE_INPUT_INFO_TITLE)
+    {
+        WCHAR *new_title = mem_alloc( len + sizeof(WCHAR) );
+        if (new_title)
+        {
+            memcpy( new_title, title, len + sizeof(WCHAR) );
+            new_title[len / sizeof(WCHAR)] = 0;
+            if (console->title) free( console->title );
+            console->title = new_title;
+        }
+    }
+    if (req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_MODE)
+    {
+	console->history_mode = req->history_mode;
+    }
+    if ((req->mask & SET_CONSOLE_INPUT_INFO_HISTORY_SIZE) && 
+	console->history_size != req->history_size)
+    {
+	WCHAR**	mem = NULL;
+	int	i;
+	int	delta;
+
+	if (req->history_size)
+	{
+	    mem = mem_alloc( req->history_size * sizeof(WCHAR*) );
+	    if (!mem) goto error;
+	    memset( mem, 0, req->history_size * sizeof(WCHAR*) );
+	}
+
+	delta = (console->history_index > req->history_size) ? 
+	    (console->history_index - req->history_size) : 0;
+
+	for (i = delta; i < console->history_index; i++)
+	{
+	    mem[i - delta] = console->history[i];
+	    console->history[i] = NULL;
+	}
+	console->history_index -= delta;
+
+	for (i = 0; i < console->history_size; i++)
+	    if (console->history[i]) free( console->history[i] );
+	free( console->history );
+	console->history = mem;
+	console->history_size = req->history_size;
+    }
+    release_object( console );
+    return 1;
+ error:
+    if (console) release_object( console );
+    return 0;
+}
+
+/* set misc screen buffer information */
+static int set_console_output_info( struct screen_buffer *screen_buffer, 
+				    struct set_console_output_info_request *req )
+{
+    struct console_renderer_event evt;
+
+    if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM)
+    {
+	if (req->cursor_size < 1 || req->cursor_size > 100)
+	{
+	    set_error( STATUS_INVALID_PARAMETER );
+	    return 0;
+	}
+        if (screen_buffer->cursor_size != req->cursor_size || 
+	    screen_buffer->cursor_visible != req->cursor_visible)
+	{
+	    screen_buffer->cursor_size    = req->cursor_size;
+	    screen_buffer->cursor_visible = req->cursor_visible;
+	    evt.event = CONSOLE_RENDERER_CURSOR_GEOM_EVENT;
+	    evt.u.cursor_geom.size    = req->cursor_size;
+	    evt.u.cursor_geom.visible = req->cursor_visible;
+	    console_input_events_append( screen_buffer->input->evt, &evt );
+	}
+    }
+    if (req->mask & SET_CONSOLE_OUTPUT_INFO_CURSOR_POS)
+    {
+	if (req->cursor_x < 0 || req->cursor_x >= screen_buffer->width || 
+	    req->cursor_y < 0 || req->cursor_y >= screen_buffer->height)
+	{
+	    set_error( STATUS_INVALID_PARAMETER );
+	    return 0;
+	}
+	if (screen_buffer->cursor.X != req->cursor_x || screen_buffer->cursor.Y != req->cursor_y)
+	{
+	    screen_buffer->cursor.X       = req->cursor_x;
+	    screen_buffer->cursor.Y       = req->cursor_y;
+	    evt.event = CONSOLE_RENDERER_CURSOR_POS_EVENT;
+	    evt.u.cursor_pos.x = req->cursor_x;
+	    evt.u.cursor_pos.y = req->cursor_y;
+	    console_input_events_append( screen_buffer->input->evt, &evt );
+	}
+    }
+    if (req->mask & SET_CONSOLE_OUTPUT_INFO_SIZE)
+    {
+	int		i, j;
+	/* FIXME: there are also some basic minimum and max size to deal with */
+	unsigned*	new_data = mem_alloc( 4 * req->width * req->height );
+
+	if (!new_data) return 0;
+
+	/* fill the buffer with either the old buffer content or white on black spaces */
+	for (j = 0; j < req->height; j++)
+	{
+	    for (i = 0; i < req->width; i++)
+	    {
+		new_data[j * req->width + i] = 
+		    (i < screen_buffer->width && j < screen_buffer->height) ?
+		    screen_buffer->data[j * screen_buffer->width + i] : 0x00F00020;
+	    }	
+	}
+	free( screen_buffer->data );
+	screen_buffer->data = new_data;
+	screen_buffer->width = req->width;
+	screen_buffer->height = req->height;
+	evt.event = CONSOLE_RENDERER_SB_RESIZE_EVENT;
+	evt.u.resize.width  = req->width;
+	evt.u.resize.height = req->height;
+	console_input_events_append( screen_buffer->input->evt, &evt );
+
+	if (screen_buffer == screen_buffer->input->active && 
+	    screen_buffer->input->mode & ENABLE_WINDOW_INPUT)
+	{
+	    INPUT_RECORD	ir;
+	    ir.EventType = WINDOW_BUFFER_SIZE_EVENT;
+	    ir.Event.WindowBufferSizeEvent.dwSize.X = req->width;
+	    ir.Event.WindowBufferSizeEvent.dwSize.Y = req->height;
+	    write_console_input( screen_buffer->input, 1, &ir );
+	}
+    }
+    if (req->mask & SET_CONSOLE_OUTPUT_INFO_ATTR)
+    {
+	screen_buffer->attr = req->attr;
+    }
+    if (req->mask & SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW)
+    {
+	if (req->win_left < 0 || req->win_left > req->win_right || 
+	    req->win_right >= screen_buffer->width ||
+	    req->win_top < 0  || req->win_top > req->win_bottom || 
+	    req->win_bottom >= screen_buffer->height)
+	{
+	    set_error( STATUS_INVALID_PARAMETER );
+	    return 0;
+	}
+	if (screen_buffer->win.Left != req->win_left || screen_buffer->win.Top != req->win_top ||
+	    screen_buffer->win.Right != req->win_right || screen_buffer->win.Bottom != req->win_bottom)
+	{
+	    screen_buffer->win.Left   = req->win_left;
+	    screen_buffer->win.Top    = req->win_top;
+	    screen_buffer->win.Right  = req->win_right;
+	    screen_buffer->win.Bottom = req->win_bottom;
+	    evt.event = CONSOLE_RENDERER_DISPLAY_EVENT;
+	    evt.u.display.left   = req->win_left;
+	    evt.u.display.top    = req->win_top;
+	    evt.u.display.width  = req->win_right - req->win_left + 1;
+	    evt.u.display.height = req->win_bottom - req->win_top + 1;
+	    console_input_events_append( screen_buffer->input->evt, &evt );
+	}
+    }
+    if (req->mask & SET_CONSOLE_OUTPUT_INFO_MAX_SIZE)
+    {
+	/* can only be done by renderer */
+	if (current->process->console != screen_buffer->input)
+	{
+	    set_error( STATUS_INVALID_PARAMETER );
+	    return 0;
+	}
+
+	screen_buffer->max_width  = req->max_width;
+	screen_buffer->max_height = req->max_height;
+    }
+
+    return 1;
+}
+
+/* appends a new line to history (history is a fixed size array) */
+static void console_input_append_hist( struct console_input* console, const WCHAR* buf, size_t len )
+{
+    WCHAR*	ptr = mem_alloc( (len + 1) * sizeof(WCHAR) );
+
+    if (!ptr)
+    {
+	set_error( STATUS_NO_MEMORY );
+	return;
+    }
+    if (!console || !console->history_size)
+    {
+	set_error( STATUS_INVALID_PARAMETER ); /* FIXME */
+	return;
+    }
+
+    memcpy( ptr, buf, len * sizeof(WCHAR) );
+    ptr[len] = 0;
+
+    if (console->history_mode && console->history_index &&
+	strncmpW( console->history[console->history_index - 1], ptr, len * sizeof(WCHAR) ) == 0)
+    {
+	/* ok, mode ask us to not use twice the same string...
+	 * so just free mem and returns
+	 */
+	set_error( STATUS_ALIAS_EXISTS );
+	free(ptr);
+	return;
+    }
+
+    if (console->history_index < console->history_size)
+    {
+	console->history[console->history_index++] = ptr;
+    }
+    else
+    {
+	free( console->history[0]) ;
+	memmove( &console->history[0], &console->history[1], 
+		 (console->history_size - 1) * sizeof(WCHAR*) );
+	console->history[console->history_size - 1] = ptr;
+    }
+}
+
+/* returns a line from the cachde */
+static int console_input_get_hist( struct console_input* console, WCHAR* buf, size_t len, int index )
+{
+    int	ret;
+
+    /* FIXME: don't use len yet */
+    if (!console || index >= console->history_index)
+    {
+	set_error( STATUS_INVALID_PARAMETER );
+	return 0;
+    }
+    ret = strlenW(console->history[index]);
+    memcpy( buf, console->history[index], ret * sizeof(WCHAR) ); /* FIXME should use len */
+    return ret;
+}
+
+/* dumb dump */
 static void console_input_dump( struct object *obj, int verbose )
 {
     struct console_input *console = (struct console_input *)obj;
     assert( obj->ops == &console_input_ops );
-    fprintf( stderr, "Console input fd=%d\n", console->obj.fd );
+    fprintf( stderr, "Console input active=%p evt=%p\n", 
+	     console->active, console->evt );
 }
 
-static int console_input_get_poll_events( struct object *obj )
-{
-    return POLLIN;
-}
-
-static int console_input_get_fd( struct object *obj )
-{
-    struct console_input *console = (struct console_input *)obj;
-    assert( obj->ops == &console_input_ops );
-    return console->obj.fd;
-}
-
-static int console_get_info( struct object *obj, struct get_file_info_request *req )
+static int console_get_file_info( struct object *obj, struct get_file_info_request *req )
 {
     if (req)
     {
@@ -373,59 +769,245 @@
 
 static void console_input_destroy( struct object *obj )
 {
-    struct console_input *console = (struct console_input *)obj;
+    struct console_input*	console_in = (struct console_input *)obj;
+    struct screen_buffer*	curr;
+    int				i;
+
     assert( obj->ops == &console_input_ops );
-    if (console->output) console->output->input = NULL;
+    if (console_in->title) free( console_in->title );
+    if (console_in->records) free( console_in->records );
+
+    if (console_in->active)	release_object( console_in->active );
+    console_in->active = NULL;
+
+    for (curr = screen_buffer_list; curr; curr = curr->next)
+    {
+	if (curr->input == console_in) curr->input = NULL;
+    }
+
+    release_object( console_in->evt );
+    console_in->evt = NULL;
+
+    for (i = 0; i < console_in->history_size; i++)
+	if (console_in->history[i]) free( console_in->history[i] );
+    if (console_in->history) free( console_in->history );
 }
 
 static void screen_buffer_dump( struct object *obj, int verbose )
 {
-    struct screen_buffer *console = (struct screen_buffer *)obj;
+    struct screen_buffer *screen_buffer = (struct screen_buffer *)obj;
     assert( obj->ops == &screen_buffer_ops );
-    fprintf( stderr, "Console screen buffer fd=%d\n", console->obj.fd );
-}
 
-static int screen_buffer_get_poll_events( struct object *obj )
-{
-    return POLLOUT;
-}
-
-static int screen_buffer_get_fd( struct object *obj )
-{
-    struct screen_buffer *console = (struct screen_buffer *)obj;
-    assert( obj->ops == &screen_buffer_ops );
-    return console->obj.fd;
+    fprintf(stderr, "Console screen buffer input=%p\n", screen_buffer->input );
 }
 
 static void screen_buffer_destroy( struct object *obj )
 {
-    struct screen_buffer *console = (struct screen_buffer *)obj;
+    struct screen_buffer*	screen_buffer = (struct screen_buffer *)obj;
+    struct screen_buffer**	psb;
+
     assert( obj->ops == &screen_buffer_ops );
-    if (console->input) console->input->output = NULL;
-    if (console->title) free( console->title );
+
+    for (psb = &screen_buffer_list; *psb; *psb = (*psb)->next)
+    {
+	if (*psb == screen_buffer)
+	{
+	    *psb = screen_buffer->next;
+	    break;
+	}
+    }	
+    if (screen_buffer->input && screen_buffer->input->active == screen_buffer)
+    {
+	struct screen_buffer*	sb;
+	for (sb = screen_buffer_list; sb && sb->input != screen_buffer->input; sb = sb->next);
+	screen_buffer->input->active = sb;
+    }
 }
 
-/* allocate a console for the current process */
+/* write data into a screen buffer */
+static int write_console_output( struct screen_buffer *screen_buffer, size_t size, 
+				 const unsigned char* data, int mode, short int x, short int y )
+{
+    int 			uniform = mode & WRITE_CONSOLE_MODE_UNIFORM;
+    unsigned		       *ptr;
+    unsigned			i, inc;
+    int				len;
+
+    mode &= ~WRITE_CONSOLE_MODE_UNIFORM;
+
+    if (mode < 0 || mode > 3)
+    {
+	set_error(STATUS_INVALID_PARAMETER);
+	return 0;
+    }
+
+    /* set destination pointer and increment */
+    ptr = screen_buffer->data + (y * screen_buffer->width + x);
+    if (mode == WRITE_CONSOLE_MODE_ATTR) ptr = (unsigned*)((char*)ptr + 2);
+    inc = (mode == WRITE_CONSOLE_MODE_TEXTATTR) ? 4 : 2;
+    len = size / inc;
+
+    /* crop if needed */
+    if (x + len > screen_buffer->width) len = screen_buffer->width - x;
+
+    for (i = 0; i < len; i++)
+    {
+	if (mode == WRITE_CONSOLE_MODE_TEXTSTDATTR)
+	{
+	    memcpy( (char*)ptr + 2, &screen_buffer->attr, 2 );
+	}	
+	memcpy( ptr++, data, inc );
+	if (!uniform) data += inc;
+    }
+
+    if (len && screen_buffer == screen_buffer->input->active)
+    {
+	int	y2;
+	struct console_renderer_event evt;
+
+	y2 = (y * screen_buffer->width + x + len - 1) / screen_buffer->width;
+
+	evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
+	evt.u.update.top    = y;
+	evt.u.update.bottom = y2;
+	console_input_events_append( screen_buffer->input->evt, &evt );
+    }
+    return len;
+}
+
+/* read data from a screen buffer */
+static int read_console_output( struct screen_buffer *screen_buffer, size_t size, void* data, 
+				short int x, short int y, short int w, short int h, 
+				short int* eff_w, short int* eff_h )
+{
+    int	j;
+
+    if (size < w * h * 4 || x >= screen_buffer->width || y >= screen_buffer->height)
+    {	
+	set_error(STATUS_INVALID_PARAMETER);
+	return 0;
+    }
+
+    *eff_w = w;
+    *eff_h = h;
+    if (x + w > screen_buffer->width)  *eff_w = screen_buffer->width  - x;
+    if (y + h > screen_buffer->height) *eff_h = screen_buffer->height - y;
+
+    for (j = 0; j < *eff_h; j++)
+    {
+	memcpy( (char*)data + 4 * j * w, &screen_buffer->data[(y + j) * screen_buffer->width + x],
+	        *eff_w * 4 );
+    }
+
+    return *eff_w * *eff_h;
+}
+
+/* scroll parts of a screen buffer */
+static void scroll_console_output( handle_t handle, short int xsrc, short int ysrc, 
+				   short int xdst, short int ydst, short int w, short int h )
+{
+    struct screen_buffer *screen_buffer;
+    int				j;
+    unsigned*			psrc;
+    unsigned*			pdst;
+    struct console_renderer_event evt;
+
+    if (!(screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, handle,
+								  GENERIC_READ, &screen_buffer_ops )))
+	return;
+    if (xsrc < 0 || ysrc < 0 || xdst < 0 || ydst < 0 ||
+	xsrc + w > screen_buffer->width  ||
+	xdst + w > screen_buffer->width  ||
+	ysrc + h > screen_buffer->height ||
+	ydst + h > screen_buffer->height ||
+	w == 0 || h == 0)
+    {
+	set_error( STATUS_INVALID_PARAMETER );
+	release_object( screen_buffer );
+	return;
+    }
+
+    if (ysrc < ydst)
+    {
+	psrc = &screen_buffer->data[(ysrc + h - 1) * screen_buffer->width + xsrc];
+	pdst = &screen_buffer->data[(ydst + h - 1) * screen_buffer->width + xdst];
+
+	for (j = h; j > 0; j--)
+	{
+	    memcpy(pdst, psrc, w * 4);
+	    pdst -= screen_buffer->width;
+	    psrc -= screen_buffer->width;
+	}
+    }
+    else
+    {
+	psrc = &screen_buffer->data[ysrc * screen_buffer->width + xsrc];
+	pdst = &screen_buffer->data[ydst * screen_buffer->width + xdst];
+
+	for (j = 0; j < h; j++)
+	{
+	    /* we use memmove here because when psrc and pdst are the same, 
+	     * copies are done on the same row, so the dst and src blocks
+	     * can overlap */
+	    memmove( pdst, psrc, w * 4 );
+	    pdst += screen_buffer->width;
+	    psrc += screen_buffer->width;
+	}
+    }
+
+    /* FIXME: this could be enhanced, by signalling scroll */
+    evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
+    evt.u.update.top    = min(ysrc, ydst);
+    evt.u.update.bottom = max(ysrc, ydst) + h - 1;
+    console_input_events_append( screen_buffer->input->evt, &evt );
+
+    release_object( screen_buffer );
+}
+
+/* allocate a console for the renderer */
 DECL_HANDLER(alloc_console)
 {
-    handle_t in = 0, out = 0;
+    handle_t in = 0;
+    handle_t evt = 0;
+    struct process *process;
+    struct process *renderer = current->process;
+    struct console_input *console;
 
-    if (!alloc_console( current->process )) goto done;
+    process = (req->pid) ? get_process_from_id( req->pid ) :
+              (struct process *)grab_object( renderer->parent );
 
-    if ((in = alloc_handle( current->process, current->process->console_in,
-                            req->access, req->inherit )))
-    {
-        if ((out = alloc_handle( current->process, current->process->console_out,
-                                 req->access, req->inherit )))
-            goto done;  /* everything is fine */
-        close_handle( current->process, in, NULL );
-        in = 0;
+    req->handle_in = 0;
+    req->event = 0;
+    if (!process) return;
+    if (process != renderer && process->console)
+    {	
+	set_error( STATUS_ACCESS_DENIED );
+	goto the_end;
     }
-    free_console( current->process );
 
- done:
-    req->handle_in  = in;
-    req->handle_out = out;
+    if ((console = (struct console_input*)create_console_input( renderer )))
+    {
+	if ((in = alloc_handle( renderer, console, req->access, req->inherit )))
+	{
+	    if ((evt = alloc_handle( renderer, console->evt, 
+				     SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE, FALSE )))
+	    {
+		if (process != renderer)
+		{
+		    process->console = (struct console_input*)grab_object( console );
+		    console->num_proc++;
+		}
+		req->handle_in = in;
+		req->event = evt;
+		release_object( console );
+		goto the_end;
+	    }
+	    close_handle( renderer, in, NULL );
+	}
+	free_console( process );
+    }
+ the_end:
+    release_object( process );
 }
 
 /* free the console of the current process */
@@ -434,58 +1016,83 @@
     free_console( current->process );
 }
 
+/* let the renderer peek the events it's waiting on */
+DECL_HANDLER(get_console_renderer_events)
+{
+    struct console_input_events*	evt;
+    size_t len = 0;
+
+    evt = (struct console_input_events *)get_handle_obj( current->process, req->handle,
+							 GENERIC_WRITE, &console_input_events_ops );
+    if (!evt) return;
+    len = console_input_events_get( evt, get_req_data(req), get_req_data_size(req) );
+    set_req_data_size( req, len );
+    release_object( evt );
+}
+
 /* open a handle to the process console */
 DECL_HANDLER(open_console)
 {
-    struct object *obj= req->output ? current->process->console_out : current->process->console_in;
+    struct object      *obj = NULL;
 
     req->handle = 0;
-    if (obj) req->handle = alloc_handle( current->process, obj, req->access, req->inherit );
-    else set_error( STATUS_ACCESS_DENIED );
+    switch (req->from)
+    {
+    case 0: 
+	if (current->process->console && current->process->console->renderer)
+	    obj = grab_object( (struct object*)current->process->console );
+	break;
+    case 1: 
+	 if (current->process->console && current->process->console->renderer && 
+	     current->process->console->active)
+	     obj = grab_object( (struct object*)current->process->console->active );
+	break;
+    default:
+	if ((obj = get_handle_obj( current->process, (handle_t)req->from,
+				   GENERIC_READ|GENERIC_WRITE, &console_input_ops )))
+	{
+	    struct console_input* console = (struct console_input*)obj;
+	    obj = (console->active) ? grab_object( console->active ) : NULL;
+	    release_object( console );
+	}
+	break;
+    }
+
+    /* FIXME: req->share is not used (as in screen buffer creation)  */
+    if (obj)
+    {
+	req->handle = alloc_handle( current->process, obj, req->access, req->inherit );
+	release_object( obj );
+    }
+    if (!req->handle && !get_error()) set_error( STATUS_ACCESS_DENIED );
 }
 
-/* set info about a console (output only) */
-DECL_HANDLER(set_console_info)
+/* set info about a console input */
+DECL_HANDLER(set_console_input_info)
 {
-    set_console_info( req->handle, req, get_req_data(req), get_req_data_size(req) );
+    set_console_input_info( req, get_req_data(req), get_req_data_size(req) );
 }
 
 /* get info about a console (output only) */
-DECL_HANDLER(get_console_info)
+DECL_HANDLER(get_console_input_info)
 {
-    struct screen_buffer *console;
-    size_t len = 0;
+    struct console_input *console = 0;
 
-    if ((console = (struct screen_buffer *)get_handle_obj( current->process, req->handle,
-                                                           GENERIC_READ, &screen_buffer_ops )))
+    set_req_data_size( req, 0 );
+    if (!(console = console_input_get( req->handle, GENERIC_READ ))) return;
+
+    if (console->title)
     {
-        req->cursor_size    = console->cursor_size;
-        req->cursor_visible = console->cursor_visible;
-        req->pid            = console->pid;
-        if (console->title)
-        {
-            len = strlen( console->title );
-            if (len > get_req_data_size(req)) len = get_req_data_size(req);
-            memcpy( get_req_data(req), console->title, len );
-        }
-        release_object( console );
+	size_t len = strlenW( console->title ) * sizeof(WCHAR);
+	if (len > get_req_data_size(req)) len = get_req_data_size(req);
+	memcpy( get_req_data(req), console->title, len );
+	set_req_data_size( req, len );
     }
-    set_req_data_size( req, len );
-}
+    req->history_mode  = console->history_mode;
+    req->history_size  = console->history_size;
+    req->history_index = console->history_index;
 
-/* set a console fd */
-DECL_HANDLER(set_console_fd)
-{
-    int fd_out, fd_in  = thread_get_inflight_fd( current, req->fd_in );
-
-    if (req->fd_out == req->fd_in) fd_out = dup( fd_in );
-    else fd_out = thread_get_inflight_fd( current, req->fd_out );
-
-    if (fd_in == -1 || fd_out == -1) set_error( STATUS_INVALID_HANDLE );
-    else if (set_console_fd( req->handle, fd_in, fd_out, req->pid )) return;
-
-    if (fd_in != -1) close( fd_in );
-    if (fd_out != -1) close( fd_out );
+    release_object( console );
 }
 
 /* get a console mode (input or output) */
@@ -503,8 +1110,16 @@
 /* add input records to a console input queue */
 DECL_HANDLER(write_console_input)
 {
-    req->written = write_console_input( req->handle, get_req_data_size(req) / sizeof(INPUT_RECORD),
+    struct console_input *console;
+
+    req->written = 0;
+    if (!(console = (struct console_input *)get_handle_obj( current->process, req->handle,
+                                                            GENERIC_WRITE, &console_input_ops )))
+        return;
+
+    req->written = write_console_input( console, get_req_data_size(req) / sizeof(INPUT_RECORD),
                                         get_req_data(req) );
+    release_object( console );
 }
 
 /* fetch input records from a console input queue */
@@ -516,3 +1131,132 @@
     if (size) set_req_data_size( req, res * sizeof(INPUT_RECORD) );
     req->read = res;
 }
+
+/* appends a string to console's history */
+DECL_HANDLER(append_console_input_history)
+{
+    struct console_input*	console;
+
+    if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) return;
+    console_input_append_hist( console, get_req_data(req), 
+			       get_req_data_size(req) / sizeof(WCHAR) );
+    release_object( console );
+}
+
+/* appends a string to console's history */
+DECL_HANDLER(get_console_input_history)
+{
+    struct console_input*	console;
+    int len;
+
+    if (!(console = console_input_get( req->handle, GENERIC_WRITE ))) return;
+
+    len = console_input_get_hist( console, get_req_data(req), 0 /* FIXME */, req->index );
+    set_req_data_size( req, len * sizeof(WCHAR));
+    release_object( console );
+}
+
+/* creates a screen buffer */
+DECL_HANDLER(create_console_output)
+{
+    struct console_input*	console;
+    struct screen_buffer*	screen_buffer;
+
+    if (!(console = console_input_get( req->handle_in, GENERIC_WRITE))) return;
+
+    screen_buffer = (struct screen_buffer*)create_console_output( console );
+    if (screen_buffer)
+    {
+	/* FIXME: should store sharing and test it when opening the CONOUT$ device 
+	 * see file.c on how this could be done
+	 */
+	req->handle_out = alloc_handle( current->process, screen_buffer, req->access, req->inherit );
+	release_object( screen_buffer );
+    }
+    release_object( console );
+}
+
+/* set info about a console screen buffer */
+DECL_HANDLER(set_console_output_info)
+{
+    struct screen_buffer       *screen_buffer;
+
+    if (!(screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
+								 GENERIC_WRITE, &screen_buffer_ops )))
+	return;
+
+    set_console_output_info( screen_buffer, req );
+    release_object( screen_buffer );
+}
+
+/* get info about a console screen buffer */
+DECL_HANDLER(get_console_output_info)
+{
+    struct screen_buffer *screen_buffer;
+    size_t len = 0;
+
+    if ((screen_buffer = (struct screen_buffer *)get_handle_obj( current->process, req->handle,
+								 GENERIC_READ, &screen_buffer_ops )))
+    {
+        req->cursor_size    = screen_buffer->cursor_size;
+        req->cursor_visible = screen_buffer->cursor_visible;
+	req->cursor_x       = screen_buffer->cursor.X;
+	req->cursor_y       = screen_buffer->cursor.Y;
+	req->width          = screen_buffer->width;
+	req->height         = screen_buffer->height;
+	req->attr           = screen_buffer->attr;
+	req->win_left       = screen_buffer->win.Left;
+	req->win_top        = screen_buffer->win.Top;
+	req->win_right      = screen_buffer->win.Right;
+	req->win_bottom     = screen_buffer->win.Bottom;
+	req->max_width      = screen_buffer->max_width;
+	req->max_height     = screen_buffer->max_height;
+
+        release_object( screen_buffer );
+    }
+    set_req_data_size( req, len );
+}
+
+/* read data (chars & attrs) from a screen buffer */
+DECL_HANDLER(read_console_output)
+{
+    struct screen_buffer       *screen_buffer;
+    size_t 			size = get_req_data_size(req);
+    int				res;
+
+    if (!(screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
+								 GENERIC_READ, &screen_buffer_ops )))
+	return;
+
+    res = read_console_output( screen_buffer, size, get_req_data(req), 
+			       req->x, req->y, req->w, req->h, &req->eff_w, &req->eff_h);
+    /* if size was 0 we didn't fetch anything */
+    if (size) set_req_data_size( req, res * 4 );
+    release_object( screen_buffer );
+}
+
+/* write data (char and/or attrs) to a screen buffer */
+DECL_HANDLER(write_console_output)
+{
+    struct screen_buffer       *screen_buffer;
+    size_t 			size = get_req_data_size(req);
+    int				res;
+
+    if (!(screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
+								 GENERIC_WRITE, &screen_buffer_ops )))
+	return;
+
+    res = write_console_output( screen_buffer, size, get_req_data(req), req->mode, req->x, req->y );
+
+    /* if size was 0 we didn't fetch anything */
+    if (size) set_req_data_size( req, res );
+    req->written = res;
+    release_object( screen_buffer );
+}
+
+/* move a rect of data in a screen buffer */
+DECL_HANDLER(move_console_output)
+{
+    scroll_console_output( req->handle, req->x_src, req->y_src, req->x_dst, req->y_dst, 
+			   req->w, req->h );
+}
diff --git a/server/console.h b/server/console.h
new file mode 100644
index 0000000..88999a1
--- /dev/null
+++ b/server/console.h
@@ -0,0 +1,35 @@
+/*
+ * Wine server consoles
+ *
+ * Copyright (C) 2001 Eric Pouech
+ */
+
+#ifndef __WINE_SERVER_CONSOLE_H
+#define __WINE_SERVER_CONSOLE_H
+
+struct screen_buffer;
+struct console_input_events;
+
+struct console_input
+{
+    struct object                obj;           /* object header */
+    int                          num_proc;      /* number of processes attached to this console */
+    struct process              *renderer;      /* console renderer thread */
+    int                          mode;          /* input mode */
+    struct screen_buffer        *active;        /* active screen buffer */
+    int                          recnum;        /* number of input records */
+    void                        *records;       /* input records */
+    struct console_input_events *evt;           /* synchronization event with renderer */
+    WCHAR                       *title;         /* console title */
+    WCHAR                      **history;       /* lines history */
+    int                          history_size;  /* number of entries in history array */
+    int                          history_index; /* number of used entries in history array */
+    int                          history_mode;  /* mode of history (non zero means remove doubled strings */
+};
+
+/* console functions */
+
+extern void inherit_console(struct process *parent, struct process *process, handle_t hconin);
+extern int free_console( struct process *process );
+
+#endif  /* __WINE_SERVER_CONSOLE_H */
diff --git a/server/debugger.c b/server/debugger.c
index bde3444..09b4240 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -14,6 +14,7 @@
 #include "process.h"
 #include "thread.h"
 #include "request.h"
+#include "console.h"
 
 enum debug_event_state { EVENT_QUEUED, EVENT_SENT, EVENT_CONTINUED };
 
@@ -411,6 +412,11 @@
     for (thread = debugger; thread; thread = thread->process->debugger)
         if (thread->process == process) goto error;
 
+    /* don't let a debugger debug its console... won't work */
+    if (debugger->process->console &&
+        debugger->process->console->renderer == process &&
+        process->console) goto error;
+
     suspend_process( process );
 
     /* we must have been able to attach all threads */
diff --git a/server/file.c b/server/file.c
index 4ed9eac..6dde94c 100644
--- a/server/file.c
+++ b/server/file.c
@@ -494,7 +494,7 @@
     if ((file = create_file_for_fd( fd, req->access, FILE_SHARE_READ | FILE_SHARE_WRITE,
                                     0, DRIVE_UNKNOWN )))
     {
-        req->handle = alloc_handle( current->process, file, req->access, 0 );
+        req->handle = alloc_handle( current->process, file, req->access, req->inherit );
         release_object( file );
     }
 }
diff --git a/server/handle.c b/server/handle.c
index 50fef3e..ac4235f 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -355,6 +355,7 @@
         if (!(entry = get_handle( process, handle ))) return NULL;
         if ((entry->access & access) != access)
         {
+            fprintf( stderr, "handle %d access %08x denied (%08x)\n", handle, access, entry->access );
             set_error( STATUS_ACCESS_DENIED );
             return NULL;
         }
@@ -376,6 +377,7 @@
     if (!(entry = get_handle( process, handle ))) return -1;
     if ((entry->access & access) != access)
     {
+        fprintf( stderr, "handle %d access %08x denied (%08x)\n", handle, access, entry->access );
         set_error( STATUS_ACCESS_DENIED );
         return -1;
     }
diff --git a/server/object.h b/server/object.h
index 32fa346..09641d3 100644
--- a/server/object.h
+++ b/server/object.h
@@ -155,11 +155,6 @@
 
 int get_serial_async_timeout(struct object *obj, int type, int count);
 
-/* console functions */
-
-extern int alloc_console( struct process *process );
-extern int free_console( struct process *process );
-
 /* debugger functions */
 
 extern int set_process_debugger( struct process *process, struct thread *debugger );
diff --git a/server/process.c b/server/process.c
index b3196a9..f02f5b7 100644
--- a/server/process.c
+++ b/server/process.c
@@ -26,6 +26,7 @@
 #include "process.h"
 #include "thread.h"
 #include "request.h"
+#include "console.h"
 
 /* process structure */
 
@@ -101,12 +102,18 @@
 {
     if (process->create_flags & CREATE_NEW_CONSOLE)
     {
-        if (!alloc_console( process )) return 0;
+        /* let the process init do the allocation */
+        return 1;
     }
     else if (parent && !(process->create_flags & DETACHED_PROCESS))
     {
-        if (parent->console_in) process->console_in = grab_object( parent->console_in );
-        if (parent->console_out) process->console_out = grab_object( parent->console_out );
+        /* FIXME: some better error checking should be done...
+         * like if hConOut and hConIn are console handles, then they should be on the same
+         * physical console
+         */
+        inherit_console( parent, process,
+                         (info->inherit_all || (info->start_flags & STARTF_USESTDHANDLES)) ?
+                         info->hstdin : 0 );
     }
     if (parent)
     {
@@ -129,13 +136,20 @@
     }
     else
     {
-        /* no parent, use handles to the console for stdio */
-        req->hstdin  = alloc_handle( process, process->console_in,
-                                     GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
-        req->hstdout = alloc_handle( process, process->console_out,
-                                     GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
-        req->hstderr = alloc_handle( process, process->console_out,
-                                     GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+        if (process->console)
+        {
+            req->hstdin  = alloc_handle( process, process->console,
+                                         GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, 1 );
+            req->hstdout = alloc_handle( process, process->console->active,
+                                         GENERIC_READ | GENERIC_WRITE, 1 );
+            req->hstderr = alloc_handle( process, process->console->active,
+                                         GENERIC_READ | GENERIC_WRITE, 1 );
+        }
+        else
+        {
+            /* no parent, let the caller decide what to do */
+            req->hstdin = req->hstdout = req->hstderr = 0;
+        }
     }
     /* some handles above may have been invalid; this is not an error */
     if (get_error() == STATUS_INVALID_HANDLE) clear_error();
@@ -152,6 +166,7 @@
     if (!(process = alloc_object( &process_ops, fd ))) return NULL;
     process->next            = NULL;
     process->prev            = NULL;
+    process->parent          = NULL;
     process->thread_list     = NULL;
     process->debugger        = NULL;
     process->handles         = NULL;
@@ -161,8 +176,7 @@
     process->affinity        = 1;
     process->suspend         = 0;
     process->create_flags    = 0;
-    process->console_in      = NULL;
-    process->console_out     = NULL;
+    process->console         = NULL;
     process->init_event      = NULL;
     process->idle_event      = NULL;
     process->queue           = NULL;
@@ -173,6 +187,7 @@
     process->exe.file        = NULL;
     process->exe.dbg_offset  = 0;
     process->exe.dbg_size    = 0;
+
     gettimeofday( &process->start_time, NULL );
     if ((process->next = first_process) != NULL) process->next->prev = process;
     first_process = process;
@@ -222,10 +237,11 @@
             fatal_protocol_error( current, "init_process: called twice?\n" );
             return;
         }
+        process->parent = (struct process *)grab_object( parent );
     }
 
     /* set the process flags */
-    process->create_flags = info ? info->create_flags : CREATE_NEW_CONSOLE;
+    process->create_flags = info ? info->create_flags : 0;
 
     /* create the handle table */
     if (parent && info->inherit_all)
@@ -288,6 +304,8 @@
 
     /* we can't have a thread remaining */
     assert( !process->thread_list );
+    if (process->console) release_object( process->console );
+    if (process->parent) release_object( process->parent );
     if (process->next) process->next->prev = process->prev;
     if (process->prev) process->prev->next = process->next;
     else first_process = process->next;
@@ -304,9 +322,8 @@
     struct process *process = (struct process *)obj;
     assert( obj->ops == &process_ops );
 
-    fprintf( stderr, "Process next=%p prev=%p console=%p/%p handles=%p\n",
-             process->next, process->prev, process->console_in, process->console_out,
-             process->handles );
+    fprintf( stderr, "Process next=%p prev=%p handles=%p\n",
+             process->next, process->prev, process->handles );
 }
 
 static int process_signaled( struct object *obj, struct thread *thread )
@@ -418,6 +435,25 @@
     set_error( STATUS_INVALID_PARAMETER );
 }
 
+/* kill all processes being attached to a console renderer */
+static void kill_console_processes( struct process *renderer, int exit_code )
+{
+    for (;;)  /* restart from the beginning of the list every time */
+    {
+        struct process *process = first_process;
+
+        /* find the first process being attached to 'renderer' and still running */
+        while (process &&
+               (process == renderer || !process->console ||
+                process->console->renderer != renderer || !process->running_threads))
+        {
+            process = process->next;
+        }
+        if (!process) break;
+        kill_process( process, NULL, exit_code );
+    }
+}
+
 /* a process has been killed (i.e. its last thread died) */
 static void process_killed( struct process *process )
 {
@@ -425,7 +461,13 @@
     gettimeofday( &process->end_time, NULL );
     if (process->handles) release_object( process->handles );
     process->handles = NULL;
+
+    /* close the console attached to this process, if any */
     free_console( process );
+
+    /* close the processes using process as renderer, if any */
+    kill_console_processes( process, 0 );
+
     while (process->exe.next)
     {
         struct process_dll *dll = process->exe.next;
@@ -508,6 +550,7 @@
 void kill_process( struct process *process, struct thread *skip, int exit_code )
 {
     struct thread *thread = process->thread_list;
+
     while (thread)
     {
         struct thread *next = thread->proc_next;
@@ -532,6 +575,7 @@
     }
 }
 
+
 /* get all information about a process */
 static void get_process_info( struct process *process, struct get_process_info_request *req )
 {
diff --git a/server/process.h b/server/process.h
index 28fbd2e..d17cb11 100644
--- a/server/process.h
+++ b/server/process.h
@@ -30,6 +30,7 @@
     struct object        obj;             /* object header */
     struct process      *next;            /* system-wide process list */
     struct process      *prev;
+    struct process      *parent;          /* parent process */
     struct thread       *thread_list;     /* head of the thread list */
     struct thread       *debugger;        /* thread debugging this process */
     struct object       *handles;         /* handle entries */
@@ -41,8 +42,7 @@
     int                  affinity;        /* process affinity mask */
     int                  suspend;         /* global process suspend count */
     int                  create_flags;    /* process creation flags */
-    struct object       *console_in;      /* console input */
-    struct object       *console_out;     /* console output */
+    struct console_input*console;         /* console input */
     struct event        *init_event;      /* event for init done */
     struct event        *idle_event;      /* event for input idle */
     struct msg_queue    *queue;           /* main message queue */
@@ -55,7 +55,6 @@
 struct process_snapshot
 {
     struct process *process;  /* process ptr */
-    struct process *parent;   /* process parent */
     int             count;    /* process refcount */
     int             threads;  /* number of threads */
     int             priority; /* priority class */
diff --git a/server/protocol.def b/server/protocol.def
index e44ef52..f631297 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -533,6 +533,7 @@
 /* Allocate a file handle for a Unix fd */
 @REQ(alloc_file_handle)
     unsigned int access;        /* wanted access rights */
+    int          inherit;       /* inherit flag */
     int          fd;            /* file descriptor on the client side */
 @REPLY
     handle_t     handle;        /* handle to the file */
@@ -685,13 +686,14 @@
 @END
 
 
-/* Allocate a console for the current process */
+/* Allocate a console (only used by a console renderer) */
 @REQ(alloc_console)
     unsigned int access;        /* wanted access rights */
     int          inherit;       /* inherit flag */
+    void*        pid;           /* pid of process which shall be attached to the console */
 @REPLY
     handle_t     handle_in;     /* handle to console input */
-    handle_t     handle_out;    /* handle to console output */
+    handle_t     event;         /* handle to renderer events change notification */
 @END
 
 
@@ -700,22 +702,67 @@
 @END
 
 
-/* Open a handle to the process console */
-@REQ(open_console)
-    int          output;        /* input or output? */
-    unsigned int access;        /* wanted access rights */
-    int          inherit;       /* inherit flag */
+#define CONSOLE_RENDERER_NONE_EVENT        0x00
+#define CONSOLE_RENDERER_TITLE_EVENT       0x01
+#define CONSOLE_RENDERER_ACTIVE_SB_EVENT   0x02
+#define CONSOLE_RENDERER_SB_RESIZE_EVENT   0x03
+#define CONSOLE_RENDERER_UPDATE_EVENT      0x04
+#define CONSOLE_RENDERER_CURSOR_POS_EVENT  0x05
+#define CONSOLE_RENDERER_CURSOR_GEOM_EVENT 0x06
+#define CONSOLE_RENDERER_DISPLAY_EVENT     0x07
+#define CONSOLE_RENDERER_EXIT_EVENT        0x08
+struct console_renderer_event
+{
+    short event;
+    union
+    {
+        struct update
+        {
+            short top;
+            short bottom;
+        } update;
+        struct resize
+        {
+            short width;
+            short height;
+        } resize;
+        struct cursor_pos
+        {
+            short x;
+            short y;
+        } cursor_pos;
+        struct cursor_geom
+        {
+            short visible;
+            short size;
+        } cursor_geom;
+        struct display
+        {
+            short left;
+            short top;
+            short width;
+            short height;
+        } display;
+    } u;
+};
+
+/* retrieve console events for the renderer */
+@REQ(get_console_renderer_events)
+    handle_t     handle;        /* handle to console input events */
 @REPLY
-    handle_t     handle;        /* handle to the console */
+    VARARG(data,bytes);         /* the various console_renderer_events */
 @END
 
 
-/* Set a console file descriptor */
-@REQ(set_console_fd)
+/* Open a handle to the process console */
+@REQ(open_console)
+    int          from;          /* 0 (resp 1) input (resp output) of current process console */
+                                /* otherwise console_in handle to get active screen buffer? */
+    unsigned int access;        /* wanted access rights */
+    int          inherit;       /* inherit flag */
+    int          share;         /* share mask (only for output handles) */
+@REPLY
     handle_t     handle;        /* handle to the console */
-    int          fd_in;         /* file descriptor to use as input */
-    int          fd_out;        /* file descriptor to use as output */
-    int          pid;           /* pid of xterm (hack) */
 @END
 
 
@@ -734,28 +781,104 @@
 @END
 
 
+/* Set info about a console (input only) */
+@REQ(set_console_input_info)
+    handle_t     handle;        /* handle to console input, or 0 for process' console */
+    int          mask;          /* setting mask (see below) */
+    handle_t     active_sb;     /* active screen buffer */
+    int          history_mode;  /* whether we duplicate lines in history */
+    int          history_size;  /* number of lines in history */
+    VARARG(title,unicode_str);  /* console title */
+@END
+#define SET_CONSOLE_INPUT_INFO_ACTIVE_SB        0x01
+#define SET_CONSOLE_INPUT_INFO_TITLE            0x02
+#define SET_CONSOLE_INPUT_INFO_HISTORY_MODE     0x04
+#define SET_CONSOLE_INPUT_INFO_HISTORY_SIZE     0x08
+
+
+/* Get info about a console (input only) */
+@REQ(get_console_input_info)
+    handle_t     handle;        /* handle to console input, or 0 for process' console */
+@REPLY
+    int          history_mode;  /* whether we duplicate lines in history */
+    int          history_size;  /* number of lines in history */
+    int          history_index; /* number of used lines in history */
+    VARARG(title,unicode_str);  /* console title */
+@END
+
+
+/* appends a string to console's history */
+@REQ(append_console_input_history)
+    handle_t     handle;        /* handle to console input, or 0 for process' console */
+    VARARG(line,unicode_str);   /* line to add */
+@END
+
+
+/* appends a string to console's history */
+@REQ(get_console_input_history)
+    handle_t     handle;        /* handle to console input, or 0 for process' console */
+    int          index;         /* index to get line from */
+@REPLY
+    VARARG(line,unicode_str);   /* line to add */
+@END
+
+
+/* creates a new screen buffer on process' console */
+@REQ(create_console_output)
+    handle_t     handle_in;     /* handle to console input, or 0 for process' console */
+    int          access;        /* wanted access rights */
+    int          share;         /* sharing credentials */
+    int          inherit;       /* inherit flag */
+@REPLY
+    handle_t     handle_out;    /* handle to the screen buffer */
+@END
+
+
 /* Set info about a console (output only) */
-@REQ(set_console_info)
+@REQ(set_console_output_info)
     handle_t     handle;        /* handle to the console */
     int          mask;          /* setting mask (see below) */
-    int          cursor_size;   /* size of cursor (percentage filled) */
-    int          cursor_visible;/* cursor visibility flag */
-    VARARG(title,string);       /* console title */
+    short int    cursor_size;   /* size of cursor (percentage filled) */
+    short int    cursor_visible;/* cursor visibility flag */
+    short int    cursor_x;      /* position of cursor (x, y) */
+    short int    cursor_y;
+    short int    width;         /* width of the screen buffer */
+    short int    height;        /* height of the screen buffer */
+    short int    attr;          /* default attribute */
+    short int    win_left;      /* window actually displayed by renderer */
+    short int    win_top;       /* the rect area is expressed withing the */
+    short int    win_right;     /* boundaries of the screen buffer */
+    short int    win_bottom;
+    short int    max_width;     /* maximum size (width x height) for the window */
+    short int    max_height;
 @END
-#define SET_CONSOLE_INFO_CURSOR 0x01
-#define SET_CONSOLE_INFO_TITLE  0x02
+#define SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM     0x01
+#define SET_CONSOLE_OUTPUT_INFO_CURSOR_POS      0x02
+#define SET_CONSOLE_OUTPUT_INFO_SIZE            0x04
+#define SET_CONSOLE_OUTPUT_INFO_ATTR            0x08
+#define SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW  0x10
+#define SET_CONSOLE_OUTPUT_INFO_MAX_SIZE        0x20
+
 
 /* Get info about a console (output only) */
-@REQ(get_console_info)
+@REQ(get_console_output_info)
     handle_t     handle;        /* handle to the console */
 @REPLY
-    int          cursor_size;   /* size of cursor (percentage filled) */
-    int          cursor_visible;/* cursor visibility flag */
-    int          pid;           /* pid of xterm (hack) */
-    VARARG(title,string);       /* console title */
+    short int    cursor_size;   /* size of cursor (percentage filled) */
+    short int    cursor_visible;/* cursor visibility flag */
+    short int    cursor_x;      /* position of cursor (x, y) */
+    short int    cursor_y;
+    short int    width;         /* width of the screen buffer */
+    short int    height;        /* height of the screen buffer */
+    short int    attr;          /* default attribute */
+    short int    win_left;      /* window actually displayed by renderer */
+    short int    win_top;       /* the rect area is expressed withing the */
+    short int    win_right;     /* boundaries of the screen buffer */
+    short int    win_bottom;
+    short int    max_width;     /* maximum size (width x height) for the window */
+    short int    max_height;
 @END
 
-
 /* Add input records to a console input queue */
 @REQ(write_console_input)
     handle_t     handle;        /* handle to the console input */
@@ -764,6 +887,7 @@
     int          written;       /* number of records written */
 @END
 
+
 /* Fetch input records from a console input queue */
 @REQ(read_console_input)
     handle_t     handle;        /* handle to the console input */
@@ -774,6 +898,49 @@
 @END
 
 
+/* write data (chars and/or attributes) in a screen buffer */
+@REQ(write_console_output)
+    handle_t     handle;        /* handle to the console input */
+    int          mode;          /* 0 for text, 1, for attributes, 2 for both */
+                                /* bit3 (4) set if uniform pattern in data */
+    short int    x;             /* position where to start writing */
+    short int    y;
+    VARARG(data,bytes);         /* info to write */
+@REPLY
+    int          written;       /* number of bytes actually written */
+@END
+#define WRITE_CONSOLE_MODE_TEXT         0x00
+#define WRITE_CONSOLE_MODE_ATTR         0x01
+#define WRITE_CONSOLE_MODE_TEXTATTR     0x02
+#define WRITE_CONSOLE_MODE_TEXTSTDATTR  0x03
+#define WRITE_CONSOLE_MODE_UNIFORM      0x04
+
+
+/* read data (chars and/or attrubutes) from a screen buffer */
+@REQ(read_console_output)
+    handle_t     handle;        /* handle to the console input */
+    short int    x;             /* position (x,y) where to start reading from */
+    short int    y;
+    short int    w;             /* size of area to read from (width x height) */
+    short int    h;
+@REPLY
+    short int    eff_w;         /* effective width read */
+    short int    eff_h;         /* effective height read */
+    VARARG(data,bytes);
+@END
+
+/* move a rect (of data) in screen buffer content */
+@REQ(move_console_output)
+    handle_t     handle;        /* handle to the console output */
+    short int    x_src;         /* position (x, y) of rect to start moving from */
+    short int    y_src;
+    short int    x_dst;         /* position (x, y) of rect to move to */
+    short int    y_dst;
+    short int    w;             /* size of the rect (width, height) to move */
+    short int    h;
+@END
+
+
 /* Create a change notification */
 @REQ(create_change_notification)
     int          subtree;       /* watch all the subtree */
diff --git a/server/request.h b/server/request.h
index 87c224e..5866641 100644
--- a/server/request.h
+++ b/server/request.h
@@ -118,14 +118,22 @@
 DECL_HANDLER(enable_socket_event);
 DECL_HANDLER(alloc_console);
 DECL_HANDLER(free_console);
+DECL_HANDLER(get_console_renderer_events);
 DECL_HANDLER(open_console);
-DECL_HANDLER(set_console_fd);
 DECL_HANDLER(get_console_mode);
 DECL_HANDLER(set_console_mode);
-DECL_HANDLER(set_console_info);
-DECL_HANDLER(get_console_info);
+DECL_HANDLER(set_console_input_info);
+DECL_HANDLER(get_console_input_info);
+DECL_HANDLER(append_console_input_history);
+DECL_HANDLER(get_console_input_history);
+DECL_HANDLER(create_console_output);
+DECL_HANDLER(set_console_output_info);
+DECL_HANDLER(get_console_output_info);
 DECL_HANDLER(write_console_input);
 DECL_HANDLER(read_console_input);
+DECL_HANDLER(write_console_output);
+DECL_HANDLER(read_console_output);
+DECL_HANDLER(move_console_output);
 DECL_HANDLER(create_change_notification);
 DECL_HANDLER(create_mapping);
 DECL_HANDLER(open_mapping);
@@ -264,14 +272,22 @@
     (req_handler)req_enable_socket_event,
     (req_handler)req_alloc_console,
     (req_handler)req_free_console,
+    (req_handler)req_get_console_renderer_events,
     (req_handler)req_open_console,
-    (req_handler)req_set_console_fd,
     (req_handler)req_get_console_mode,
     (req_handler)req_set_console_mode,
-    (req_handler)req_set_console_info,
-    (req_handler)req_get_console_info,
+    (req_handler)req_set_console_input_info,
+    (req_handler)req_get_console_input_info,
+    (req_handler)req_append_console_input_history,
+    (req_handler)req_get_console_input_history,
+    (req_handler)req_create_console_output,
+    (req_handler)req_set_console_output_info,
+    (req_handler)req_get_console_output_info,
     (req_handler)req_write_console_input,
     (req_handler)req_read_console_input,
+    (req_handler)req_write_console_output,
+    (req_handler)req_read_console_output,
+    (req_handler)req_move_console_output,
     (req_handler)req_create_change_notification,
     (req_handler)req_create_mapping,
     (req_handler)req_open_mapping,
diff --git a/server/trace.c b/server/trace.c
index 2d144cf..df4617a 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -721,6 +721,7 @@
 static void dump_alloc_file_handle_request( const struct alloc_file_handle_request *req )
 {
     fprintf( stderr, " access=%08x,", req->access );
+    fprintf( stderr, " inherit=%d,", req->inherit );
     fprintf( stderr, " fd=%d", req->fd );
 }
 
@@ -881,24 +882,37 @@
 static void dump_alloc_console_request( const struct alloc_console_request *req )
 {
     fprintf( stderr, " access=%08x,", req->access );
-    fprintf( stderr, " inherit=%d", req->inherit );
+    fprintf( stderr, " inherit=%d,", req->inherit );
+    fprintf( stderr, " pid=%p", req->pid );
 }
 
 static void dump_alloc_console_reply( const struct alloc_console_request *req )
 {
     fprintf( stderr, " handle_in=%d,", req->handle_in );
-    fprintf( stderr, " handle_out=%d", req->handle_out );
+    fprintf( stderr, " event=%d", req->event );
 }
 
 static void dump_free_console_request( const struct free_console_request *req )
 {
 }
 
+static void dump_get_console_renderer_events_request( const struct get_console_renderer_events_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_get_console_renderer_events_reply( const struct get_console_renderer_events_request *req )
+{
+    fprintf( stderr, " data=" );
+    cur_pos += dump_varargs_bytes( req );
+}
+
 static void dump_open_console_request( const struct open_console_request *req )
 {
-    fprintf( stderr, " output=%d,", req->output );
+    fprintf( stderr, " from=%d,", req->from );
     fprintf( stderr, " access=%08x,", req->access );
-    fprintf( stderr, " inherit=%d", req->inherit );
+    fprintf( stderr, " inherit=%d,", req->inherit );
+    fprintf( stderr, " share=%d", req->share );
 }
 
 static void dump_open_console_reply( const struct open_console_request *req )
@@ -906,14 +920,6 @@
     fprintf( stderr, " handle=%d", req->handle );
 }
 
-static void dump_set_console_fd_request( const struct set_console_fd_request *req )
-{
-    fprintf( stderr, " handle=%d,", req->handle );
-    fprintf( stderr, " fd_in=%d,", req->fd_in );
-    fprintf( stderr, " fd_out=%d,", req->fd_out );
-    fprintf( stderr, " pid=%d", req->pid );
-}
-
 static void dump_get_console_mode_request( const struct get_console_mode_request *req )
 {
     fprintf( stderr, " handle=%d", req->handle );
@@ -930,28 +936,102 @@
     fprintf( stderr, " mode=%d", req->mode );
 }
 
-static void dump_set_console_info_request( const struct set_console_info_request *req )
+static void dump_set_console_input_info_request( const struct set_console_input_info_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " mask=%d,", req->mask );
+    fprintf( stderr, " active_sb=%d,", req->active_sb );
+    fprintf( stderr, " history_mode=%d,", req->history_mode );
+    fprintf( stderr, " history_size=%d,", req->history_size );
+    fprintf( stderr, " title=" );
+    cur_pos += dump_varargs_unicode_str( req );
+}
+
+static void dump_get_console_input_info_request( const struct get_console_input_info_request *req )
+{
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_get_console_input_info_reply( const struct get_console_input_info_request *req )
+{
+    fprintf( stderr, " history_mode=%d,", req->history_mode );
+    fprintf( stderr, " history_size=%d,", req->history_size );
+    fprintf( stderr, " history_index=%d,", req->history_index );
+    fprintf( stderr, " title=" );
+    cur_pos += dump_varargs_unicode_str( req );
+}
+
+static void dump_append_console_input_history_request( const struct append_console_input_history_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " line=" );
+    cur_pos += dump_varargs_unicode_str( req );
+}
+
+static void dump_get_console_input_history_request( const struct get_console_input_history_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " index=%d", req->index );
+}
+
+static void dump_get_console_input_history_reply( const struct get_console_input_history_request *req )
+{
+    fprintf( stderr, " line=" );
+    cur_pos += dump_varargs_unicode_str( req );
+}
+
+static void dump_create_console_output_request( const struct create_console_output_request *req )
+{
+    fprintf( stderr, " handle_in=%d,", req->handle_in );
+    fprintf( stderr, " access=%d,", req->access );
+    fprintf( stderr, " share=%d,", req->share );
+    fprintf( stderr, " inherit=%d", req->inherit );
+}
+
+static void dump_create_console_output_reply( const struct create_console_output_request *req )
+{
+    fprintf( stderr, " handle_out=%d", req->handle_out );
+}
+
+static void dump_set_console_output_info_request( const struct set_console_output_info_request *req )
 {
     fprintf( stderr, " handle=%d,", req->handle );
     fprintf( stderr, " mask=%d,", req->mask );
     fprintf( stderr, " cursor_size=%d,", req->cursor_size );
     fprintf( stderr, " cursor_visible=%d,", req->cursor_visible );
-    fprintf( stderr, " title=" );
-    cur_pos += dump_varargs_string( req );
+    fprintf( stderr, " cursor_x=%d,", req->cursor_x );
+    fprintf( stderr, " cursor_y=%d,", req->cursor_y );
+    fprintf( stderr, " width=%d,", req->width );
+    fprintf( stderr, " height=%d,", req->height );
+    fprintf( stderr, " attr=%d,", req->attr );
+    fprintf( stderr, " win_left=%d,", req->win_left );
+    fprintf( stderr, " win_top=%d,", req->win_top );
+    fprintf( stderr, " win_right=%d,", req->win_right );
+    fprintf( stderr, " win_bottom=%d,", req->win_bottom );
+    fprintf( stderr, " max_width=%d,", req->max_width );
+    fprintf( stderr, " max_height=%d", req->max_height );
 }
 
-static void dump_get_console_info_request( const struct get_console_info_request *req )
+static void dump_get_console_output_info_request( const struct get_console_output_info_request *req )
 {
     fprintf( stderr, " handle=%d", req->handle );
 }
 
-static void dump_get_console_info_reply( const struct get_console_info_request *req )
+static void dump_get_console_output_info_reply( const struct get_console_output_info_request *req )
 {
     fprintf( stderr, " cursor_size=%d,", req->cursor_size );
     fprintf( stderr, " cursor_visible=%d,", req->cursor_visible );
-    fprintf( stderr, " pid=%d,", req->pid );
-    fprintf( stderr, " title=" );
-    cur_pos += dump_varargs_string( req );
+    fprintf( stderr, " cursor_x=%d,", req->cursor_x );
+    fprintf( stderr, " cursor_y=%d,", req->cursor_y );
+    fprintf( stderr, " width=%d,", req->width );
+    fprintf( stderr, " height=%d,", req->height );
+    fprintf( stderr, " attr=%d,", req->attr );
+    fprintf( stderr, " win_left=%d,", req->win_left );
+    fprintf( stderr, " win_top=%d,", req->win_top );
+    fprintf( stderr, " win_right=%d,", req->win_right );
+    fprintf( stderr, " win_bottom=%d,", req->win_bottom );
+    fprintf( stderr, " max_width=%d,", req->max_width );
+    fprintf( stderr, " max_height=%d", req->max_height );
 }
 
 static void dump_write_console_input_request( const struct write_console_input_request *req )
@@ -979,6 +1059,49 @@
     cur_pos += dump_varargs_input_records( req );
 }
 
+static void dump_write_console_output_request( const struct write_console_output_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " mode=%d,", req->mode );
+    fprintf( stderr, " x=%d,", req->x );
+    fprintf( stderr, " y=%d,", req->y );
+    fprintf( stderr, " data=" );
+    cur_pos += dump_varargs_bytes( req );
+}
+
+static void dump_write_console_output_reply( const struct write_console_output_request *req )
+{
+    fprintf( stderr, " written=%d", req->written );
+}
+
+static void dump_read_console_output_request( const struct read_console_output_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " x=%d,", req->x );
+    fprintf( stderr, " y=%d,", req->y );
+    fprintf( stderr, " w=%d,", req->w );
+    fprintf( stderr, " h=%d", req->h );
+}
+
+static void dump_read_console_output_reply( const struct read_console_output_request *req )
+{
+    fprintf( stderr, " eff_w=%d,", req->eff_w );
+    fprintf( stderr, " eff_h=%d,", req->eff_h );
+    fprintf( stderr, " data=" );
+    cur_pos += dump_varargs_bytes( req );
+}
+
+static void dump_move_console_output_request( const struct move_console_output_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
+    fprintf( stderr, " x_src=%d,", req->x_src );
+    fprintf( stderr, " y_src=%d,", req->y_src );
+    fprintf( stderr, " x_dst=%d,", req->x_dst );
+    fprintf( stderr, " y_dst=%d,", req->y_dst );
+    fprintf( stderr, " w=%d,", req->w );
+    fprintf( stderr, " h=%d", req->h );
+}
+
 static void dump_create_change_notification_request( const struct create_change_notification_request *req )
 {
     fprintf( stderr, " subtree=%d,", req->subtree );
@@ -1955,14 +2078,22 @@
     (dump_func)dump_enable_socket_event_request,
     (dump_func)dump_alloc_console_request,
     (dump_func)dump_free_console_request,
+    (dump_func)dump_get_console_renderer_events_request,
     (dump_func)dump_open_console_request,
-    (dump_func)dump_set_console_fd_request,
     (dump_func)dump_get_console_mode_request,
     (dump_func)dump_set_console_mode_request,
-    (dump_func)dump_set_console_info_request,
-    (dump_func)dump_get_console_info_request,
+    (dump_func)dump_set_console_input_info_request,
+    (dump_func)dump_get_console_input_info_request,
+    (dump_func)dump_append_console_input_history_request,
+    (dump_func)dump_get_console_input_history_request,
+    (dump_func)dump_create_console_output_request,
+    (dump_func)dump_set_console_output_info_request,
+    (dump_func)dump_get_console_output_info_request,
     (dump_func)dump_write_console_input_request,
     (dump_func)dump_read_console_input_request,
+    (dump_func)dump_write_console_output_request,
+    (dump_func)dump_read_console_output_request,
+    (dump_func)dump_move_console_output_request,
     (dump_func)dump_create_change_notification_request,
     (dump_func)dump_create_mapping_request,
     (dump_func)dump_open_mapping_request,
@@ -2098,14 +2229,22 @@
     (dump_func)0,
     (dump_func)dump_alloc_console_reply,
     (dump_func)0,
+    (dump_func)dump_get_console_renderer_events_reply,
     (dump_func)dump_open_console_reply,
-    (dump_func)0,
     (dump_func)dump_get_console_mode_reply,
     (dump_func)0,
     (dump_func)0,
-    (dump_func)dump_get_console_info_reply,
+    (dump_func)dump_get_console_input_info_reply,
+    (dump_func)0,
+    (dump_func)dump_get_console_input_history_reply,
+    (dump_func)dump_create_console_output_reply,
+    (dump_func)0,
+    (dump_func)dump_get_console_output_info_reply,
     (dump_func)dump_write_console_input_reply,
     (dump_func)dump_read_console_input_reply,
+    (dump_func)dump_write_console_output_reply,
+    (dump_func)dump_read_console_output_reply,
+    (dump_func)0,
     (dump_func)dump_create_change_notification_reply,
     (dump_func)dump_create_mapping_reply,
     (dump_func)dump_open_mapping_reply,
@@ -2241,14 +2380,22 @@
     "enable_socket_event",
     "alloc_console",
     "free_console",
+    "get_console_renderer_events",
     "open_console",
-    "set_console_fd",
     "get_console_mode",
     "set_console_mode",
-    "set_console_info",
-    "get_console_info",
+    "set_console_input_info",
+    "get_console_input_info",
+    "append_console_input_history",
+    "get_console_input_history",
+    "create_console_output",
+    "set_console_output_info",
+    "get_console_output_info",
     "write_console_input",
     "read_console_input",
+    "write_console_output",
+    "read_console_output",
+    "move_console_output",
     "create_change_notification",
     "create_mapping",
     "open_mapping",
diff --git a/tools/make_requests b/tools/make_requests
index 3e2c536..ed3c59e 100755
--- a/tools/make_requests
+++ b/tools/make_requests
@@ -9,6 +9,7 @@
 %formats =
 (
     "int"           => "%d",
+    "short int"     => "%d",
     "char"          => "%c",
     "unsigned char" => "%02x",
     "unsigned short"=> "%04x",
diff --git a/win32/Makefile.in b/win32/Makefile.in
index 42c69a4..890c2e7 100644
--- a/win32/Makefile.in
+++ b/win32/Makefile.in
@@ -1,4 +1,4 @@
-DEFS      = @DLLFLAGS@ -D__WINE__
+DEFS      = @DLLFLAGS@ -D__WINE__ -DBINDIR="\"$(bindir)\""
 TOPSRCDIR = @top_srcdir@
 TOPOBJDIR = ..
 SRCDIR    = @srcdir@
@@ -8,6 +8,7 @@
 C_SRCS = \
 	console.c \
 	device.c \
+	editline.c \
 	except.c \
 	file.c \
 	init.c \
diff --git a/win32/console.c b/win32/console.c
index 2734e3f..9544d6c 100644
--- a/win32/console.c
+++ b/win32/console.c
@@ -5,13 +5,9 @@
  * Copyright 1997 Karl Garrison
  * Copyright 1998 John Richardson
  * Copyright 1998 Marcus Meissner
+ * Copyright 2001 Eric Pouech
  */
 
-/* FIXME:
- * - Completely lacks SCREENBUFFER interface.
- * - No abstraction for something other than xterm.
- * - Output sometimes is buffered (We switched off buffering by ~ICANON ?)
- */
 /* Reference applications:
  * -  IDA (interactive disassembler) full version 3.75. Works.
  * -  LYNX/W32. Works mostly, some keys crash it.
@@ -19,302 +15,221 @@
 
 #include "config.h"
 
-#include <stdlib.h>
 #include <stdio.h>
-#include <unistd.h>
-#include <termios.h>
 #include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <errno.h>
-#ifdef HAVE_SYS_ERRNO_H
-#include <sys/errno.h>
-#endif
-#include <signal.h>
+#include <unistd.h>
 #include <assert.h>
 
-#include "windef.h"
 #include "winbase.h"
 #include "winnls.h"
-#include "wingdi.h"
-#include "wine/winuser16.h"
-#include "thread.h"
 #include "winerror.h"
 #include "wincon.h"
 #include "heap.h"
 #include "wine/server.h"
+#include "wine/exception.h"
 #include "debugtools.h"
+#include "options.h"
 
 DEFAULT_DEBUG_CHANNEL(console);
 
-/* Ascii -> VK, generated by calling VkKeyScanA(i) */
-static int vkkeyscan_table[256] = {
-	0,0,0,0,0,0,0,0,8,9,0,0,0,13,0,0,0,0,0,19,145,556,0,0,0,0,0,27,0,0,0,
-	0,32,305,478,307,308,309,311,222,313,304,312,443,188,189,190,191,48,
-	49,50,51,52,53,54,55,56,57,442,186,444,187,446,447,306,321,322,323,
-	324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,
-	341,342,343,344,345,346,219,220,221,310,445,192,65,66,67,68,69,70,71,
-	72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,475,476,477,
-	448,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,400,0,0,0,0,0,0
-};
+/* editline.c */
+extern WCHAR* CONSOLE_Readline(HANDLE, int);
 
-static int mapvkey_0[256]={
-	0,0,0,0,0,0,0,0,14,15,0,0,0,28,0,0,42,29,56,69,58,0,0,0,0,0,0,1,0,0,
-	0,0,57,73,81,79,71,75,72,77,80,0,0,0,55,82,83,0,11,2,3,4,5,6,7,8,9,
-	10,0,0,0,0,0,0,0,30,48,46,32,18,33,34,35,23,36,37,38,50,49,24,25,16,
-	19,31,20,22,47,17,45,21,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,78,0,74,
-	0,53,59,60,61,62,63,64,65,66,67,68,87,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,69,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,13,51,12,52,53,41,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,43,27,40,76,96,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
+static WCHAR*	S_EditString /* = NULL */;
+static unsigned S_EditStrPos /* = 0 */;
 
-static int mapvkey_1[256]={
-	0,27,49,50,51,52,53,54,55,56,57,48,189,187,8,9,81,87,69,82,84,89,85,
-	73,79,80,219,221,13,17,65,83,68,70,71,72,74,75,76,186,222,192,16,220,
-	90,88,67,86,66,78,77,188,190,191,16,106,18,32,20,112,113,114,115,116,
-	117,118,119,120,121,144,145,36,38,33,109,37,223,39,107,35,40,34,45,
-	46,0,0,0,122,123,0,0,0,0,0,0,0,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0
-};
-
-/* FIXME:  Should be in an internal header file.  OK, so which one?
-   Used by CONSOLE_make_complex. */
-extern int wine_openpty(int *master, int *slave, char *name,
-                 struct termios *term, struct winsize *winsize);
-
-/****************************************************************************
- *		CONSOLE_GetPid
+/***********************************************************************
+ *            FreeConsole (KERNEL32.@)
  */
-static int CONSOLE_GetPid( HANDLE handle )
+BOOL WINAPI FreeConsole(VOID)
 {
-    int ret = 0;
-    SERVER_START_REQ( get_console_info )
+    BOOL ret;
+
+    SERVER_START_REQ(free_console)
     {
-        req->handle = handle;
-        if (!SERVER_CALL_ERR()) ret = req->pid;
+        ret = !SERVER_CALL_ERR();
     }
     SERVER_END_REQ;
     return ret;
 }
 
-/****************************************************************************
- *		XTERM_string_to_IR			[internal]
+/******************************************************************
+ *		start_console_renderer
  *
- * Transfers a string read from XTERM to INPUT_RECORDs and adds them to the
- * queue. Does translation of vt100 style function keys and xterm-mouse clicks.
+ * helper for AllocConsole
+ * starts the renderer process
  */
-static void
-CONSOLE_string_to_IR( HANDLE hConsoleInput,unsigned char *buf,int len) {
-    int			j,k;
-    INPUT_RECORD	ir;
-    DWORD		junk;
+static	BOOL	start_console_renderer(void)
+{
+    char		buffer[256];
+    STARTUPINFOA	si;
+    PROCESS_INFORMATION	pi;
+    HANDLE		hEvent = 0;
+    LPSTR		p, path = NULL;
+    OBJECT_ATTRIBUTES	attr;
 
-    for (j=0;j<len;j++) {
-    	unsigned char inchar = buf[j];
+    attr.Length                   = sizeof(attr);
+    attr.RootDirectory            = 0;
+    attr.Attributes               = OBJ_INHERIT;
+    attr.ObjectName               = NULL;
+    attr.SecurityDescriptor       = NULL;
+    attr.SecurityQualityOfService = NULL;
+    
+    NtCreateEvent(&hEvent, EVENT_ALL_ACCESS, &attr, TRUE, FALSE);
+    if (!hEvent) return FALSE;
 
-	if (inchar!=27) { /* no escape -> 'normal' keyboard event */
-	    ir.EventType = 1; /* Key_event */
+    memset(&si, 0, sizeof(si));
+    si.cb = sizeof(si);
 
-	    ir.Event.KeyEvent.bKeyDown		= 1;
-	    ir.Event.KeyEvent.wRepeatCount	= 0;
-
-	    ir.Event.KeyEvent.dwControlKeyState	= 0;
-	    if (inchar & 0x80) {
-		ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
-		inchar &= ~0x80;
-	    }
-	    ir.Event.KeyEvent.wVirtualKeyCode = vkkeyscan_table[inchar];
-	    if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0100)
-		ir.Event.KeyEvent.dwControlKeyState|=SHIFT_PRESSED;
-	    if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0200)
-		ir.Event.KeyEvent.dwControlKeyState|=LEFT_CTRL_PRESSED;
-	    if (ir.Event.KeyEvent.wVirtualKeyCode & 0x0400)
-		ir.Event.KeyEvent.dwControlKeyState|=LEFT_ALT_PRESSED;
-	    ir.Event.KeyEvent.wVirtualScanCode = mapvkey_0[
-	    	ir.Event.KeyEvent.wVirtualKeyCode & 0x00ff
-	    ]; /* VirtualKeyCodes to ScanCode */
-	    ir.Event.KeyEvent.uChar.AsciiChar = inchar;
-
-	    if ((inchar==127)||(inchar=='\b')) { /* backspace */
-	    	ir.Event.KeyEvent.uChar.AsciiChar = '\b'; /* FIXME: hmm */
-		ir.Event.KeyEvent.wVirtualScanCode = 0x0e;
-		ir.Event.KeyEvent.wVirtualKeyCode = VK_BACK;
-	    } else {
-		if ((inchar=='\n')||(inchar=='\r')) {
-		    ir.Event.KeyEvent.uChar.AsciiChar	= '\r';
-		    ir.Event.KeyEvent.wVirtualKeyCode	= VK_RETURN;
-		    ir.Event.KeyEvent.wVirtualScanCode	= 0x1c;
-		    ir.Event.KeyEvent.dwControlKeyState = 0;
-		} else {
-		    if (inchar<' ') {
-			/* FIXME: find good values for ^X */
-			ir.Event.KeyEvent.wVirtualKeyCode = 0xdead;
-			ir.Event.KeyEvent.wVirtualScanCode = 0xbeef;
-		    } 
-		}
-	    }
-
-	    assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
-	    ir.Event.KeyEvent.bKeyDown = 0;
-	    assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
-	    continue;
-	}
-	/* inchar is ESC */
-	if ((j==len-1) || (buf[j+1]!='[')) {/* add ESCape on its own */
-	    ir.EventType = 1; /* Key_event */
-	    ir.Event.KeyEvent.bKeyDown		= 1;
-	    ir.Event.KeyEvent.wRepeatCount	= 0;
-
-	    ir.Event.KeyEvent.wVirtualKeyCode	= VK_ESCAPE;
-	    ir.Event.KeyEvent.wVirtualScanCode	= mapvkey_0[
-	    	ir.Event.KeyEvent.wVirtualKeyCode
-	    ];
-	    ir.Event.KeyEvent.dwControlKeyState = 0;
-	    ir.Event.KeyEvent.uChar.AsciiChar	= 27;
-	    assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
-	    ir.Event.KeyEvent.bKeyDown = 0;
-	    assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
-	    continue;
-	}
-	for (k=j;k<len;k++) {
-	    if (((buf[k]>='A') && (buf[k]<='Z')) ||
-		((buf[k]>='a') && (buf[k]<='z')) ||
-	    	 (buf[k]=='~')
-	    )
-	    	break;
-	}
-	if (k<len) {
-	    int	subid,scancode=0;
-
-	    ir.EventType			= 1; /* Key_event */
-	    ir.Event.KeyEvent.bKeyDown		= 1;
-	    ir.Event.KeyEvent.wRepeatCount	= 0;
-	    ir.Event.KeyEvent.dwControlKeyState	= 0;
-
-	    ir.Event.KeyEvent.wVirtualKeyCode	= 0xad; /* FIXME */
-	    ir.Event.KeyEvent.wVirtualScanCode	= 0xad; /* FIXME */
-	    ir.Event.KeyEvent.uChar.AsciiChar	= 0;
-
-	    switch (buf[k]) {
-	    case '~':
-		sscanf(&buf[j+2],"%d",&subid);
-		switch (subid) {
-		case  2:/*INS */scancode = 0xe052;break;
-		case  3:/*DEL */scancode = 0xe053;break;
-		case  6:/*PGDW*/scancode = 0xe051;break;
-		case  5:/*PGUP*/scancode = 0xe049;break;
-		case 11:/*F1  */scancode = 0x003b;break;
-		case 12:/*F2  */scancode = 0x003c;break;
-		case 13:/*F3  */scancode = 0x003d;break;
-		case 14:/*F4  */scancode = 0x003e;break;
-		case 15:/*F5  */scancode = 0x003f;break;
-		case 17:/*F6  */scancode = 0x0040;break;
-		case 18:/*F7  */scancode = 0x0041;break;
-		case 19:/*F8  */scancode = 0x0042;break;
-		case 20:/*F9  */scancode = 0x0043;break;
-		case 21:/*F10 */scancode = 0x0044;break;
-		case 23:/*F11 */scancode = 0x00d9;break;
-		case 24:/*F12 */scancode = 0x00da;break;
-		/* FIXME: Shift-Fx */
-		default:
-			FIXME("parse ESC[%d~\n",subid);
-			break;
-		}
-		break;
-	    case 'A': /* Cursor Up    */scancode = 0xe048;break;
-	    case 'B': /* Cursor Down  */scancode = 0xe050;break;
-	    case 'D': /* Cursor Left  */scancode = 0xe04b;break;
-	    case 'C': /* Cursor Right */scancode = 0xe04d;break;
-	    case 'F': /* End          */scancode = 0xe04f;break;
-	    case 'H': /* Home         */scancode = 0xe047;break;
-	    case 'M':
-	    	/* Mouse Button Press  (ESCM<button+'!'><x+'!'><y+'!'>) or
-		 *              Release (ESCM#<x+'!'><y+'!'>
-		 */
-		if (k<len-3) {
-		    ir.EventType			= MOUSE_EVENT;
-		    ir.Event.MouseEvent.dwMousePosition.X = buf[k+2]-'!';
-		    ir.Event.MouseEvent.dwMousePosition.Y = buf[k+3]-'!';
-		    if (buf[k+1]=='#')
-			ir.Event.MouseEvent.dwButtonState = 0;
-		    else
-			ir.Event.MouseEvent.dwButtonState = 1<<(buf[k+1]-' ');
-		    ir.Event.MouseEvent.dwEventFlags	  = 0; /* FIXME */
-		    assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk));
-		    j=k+3;
-		}
-	    	break;
-	    case 'c':
-	    	j=k;
-		break;
-	    }
-	    if (scancode) {
-		ir.Event.KeyEvent.wVirtualScanCode = scancode;
-		ir.Event.KeyEvent.wVirtualKeyCode  = mapvkey_1[scancode];
-		assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
-		ir.Event.KeyEvent.bKeyDown		= 0;
-		assert(WriteConsoleInputA( hConsoleInput, &ir, 1, &junk ));
-		j=k;
-		continue;
-	    }
-	}
+    /* FIXME: use dynamic allocation for most of the buffers below */
+    /* first try environment variable */
+    if ((p = getenv("WINECONSOLE")) != NULL)
+    {
+	if (snprintf(buffer, sizeof(buffer), "%s %d", p, hEvent) > 0 &&
+	    CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
+	    goto succeed;
+	ERR("Couldn't launch Wine console from WINECONSOLE env var... trying default access\n");
     }
+
+    /* then the regular installation dir */
+    if (snprintf(buffer, sizeof(buffer), "%s %d", BINDIR "/wineconsole", hEvent) > 0 &&
+	CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
+	goto succeed;
+
+    /* then try the dir where we were started from */
+    if ((path = HeapAlloc(GetProcessHeap(), 0, strlen(full_argv0) + sizeof(buffer))))
+    {
+	int	n;
+
+	if ((p = strrchr(strcpy( path, full_argv0 ), '/')))
+	{
+	    p++;
+	    sprintf(p, "wineconsole %d", hEvent);
+	    if (CreateProcessA(NULL, path, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
+		goto succeed;
+	    sprintf(p, "programs/wineconsole/wineconsole %d", hEvent);
+	    if (CreateProcessA(NULL, path, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
+		goto succeed;
+	}
+
+	n = readlink(full_argv0, buffer, sizeof(buffer));
+	if (n != -1 && n < sizeof(buffer))
+	{
+	    buffer[n] = 0;
+	    if (buffer[0] == '/') /* absolute path ? */
+		strcpy(path, buffer);
+	    else if ((p = strrchr(strcpy( path, full_argv0 ), '/')))
+	    {
+		strcpy(p + 1, buffer);
+	    }
+	    else *path = 0;
+
+	    if ((p = strrchr(path, '/')))
+	    {
+		p++;
+		sprintf(p, "wineconsole %d", hEvent);
+		if (CreateProcessA(NULL, path, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
+		    goto succeed;
+		sprintf(p, "programs/wineconsole/wineconsole %d", hEvent);
+		if (CreateProcessA(NULL, path, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
+		    goto succeed;
+	    }
+	} else perror("readlink");
+
+	HeapFree(GetProcessHeap(), 0, path);	path = NULL;
+    }
+	
+    /* then try the regular PATH */
+    sprintf(buffer, "wineconsole %d\n", hEvent);
+    if (CreateProcessA(NULL, buffer, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &si, &pi))
+	goto succeed;
+
+    goto the_end;
+
+ succeed:    
+    if (path) HeapFree(GetProcessHeap(), 0, path);
+    if (WaitForSingleObject(hEvent, INFINITE) != WAIT_OBJECT_0) goto the_end;
+    CloseHandle(hEvent);
+    
+    TRACE("Started wineconsole pid=%08lx tid=%08lx\n", pi.dwProcessId, pi.dwThreadId);
+
+    return TRUE;
+
+ the_end:
+    ERR("Can't allocate console\n");
+    if (path) 		HeapFree(GetProcessHeap(), 0, path);
+    CloseHandle(hEvent);
+    return FALSE;
 }
 
-/****************************************************************************
- * 		CONSOLE_get_input		(internal)
+/***********************************************************************
+ *            AllocConsole (KERNEL32.@)
  *
- * Reads (nonblocking) as much input events as possible and stores them
- * in an internal queue.
+ * creates an xterm with a pty to our program
  */
-static void
-CONSOLE_get_input( HANDLE handle, BOOL blockwait )
+BOOL WINAPI AllocConsole(void)
 {
-    char	*buf = HeapAlloc(GetProcessHeap(),0,1);
-    int		len = 0, escape_seen = 0;
+    HANDLE 		handle_in = INVALID_HANDLE_VALUE;
+    HANDLE		handle_out = INVALID_HANDLE_VALUE;
+    HANDLE 		handle_err = INVALID_HANDLE_VALUE;
+    STARTUPINFOA	si;
 
-    while (1)
+    TRACE("()\n");
+
+    handle_in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, 
+			     0, NULL, OPEN_EXISTING, 0, 0 );
+
+    if (handle_in != INVALID_HANDLE_VALUE)
     {
-	DWORD res;
-	char inchar;
-
-	/* If we have at one time seen escape in this loop, we are 
-	 * within an Escape sequence, so wait for a bit more input for the
-	 * rest of the loop.
-	 */
-        if (WaitForSingleObject( handle, escape_seen*10 )) break;
-        if (!ReadFile( handle, &inchar, 1, &res, NULL )) break;
-	if (!res) /* res 0 but readable means EOF? Hmm. */
-		break;
-	buf = HeapReAlloc(GetProcessHeap(),0,buf,len+1);
-	buf[len++]=inchar;
-	if (inchar == 27) {
-		if (len>1) {
-			/* If we spot an ESC, we flush all up to it
-			 * since we can be sure that we have a complete
-			 * sequence.
-			 */
-			CONSOLE_string_to_IR(handle,buf,len-1);
-			buf = HeapReAlloc(GetProcessHeap(),0,buf,1);
-			buf[0] = 27;
-			len = 1;
-		}
-		escape_seen = 1;
-	}
+	/* we already have a console opened on this process, don't create a new one */
+	CloseHandle(handle_in);
+	return FALSE;
     }
-    CONSOLE_string_to_IR(handle,buf,len);
-    HeapFree(GetProcessHeap(),0,buf);
+
+    if (!start_console_renderer())
+	goto the_end;
+
+    handle_in = CreateFileA( "CONIN$", GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, 
+			     0, NULL, OPEN_EXISTING, 0, 0 );
+    if (handle_in == INVALID_HANDLE_VALUE) goto the_end;
+
+    handle_out = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, 
+			     0, NULL, OPEN_EXISTING, 0, 0 );
+    if (handle_out == INVALID_HANDLE_VALUE) goto the_end;
+
+    if (!DuplicateHandle(GetCurrentProcess(), handle_out, GetCurrentProcess(), &handle_err,
+			 0, TRUE, DUPLICATE_SAME_ACCESS))
+	goto the_end;
+    
+    /* NT resets the STD_*_HANDLEs on console alloc */
+    SetStdHandle(STD_INPUT_HANDLE,  handle_in);
+    SetStdHandle(STD_OUTPUT_HANDLE, handle_out);
+    SetStdHandle(STD_ERROR_HANDLE,  handle_err);
+
+    GetStartupInfoA(&si);
+    if (si.dwFlags & STARTF_USESIZE)
+    {
+	COORD	c;
+	c.X = si.dwXCountChars;
+	c.Y = si.dwYCountChars;
+	SetConsoleScreenBufferSize(handle_out, c);
+    }
+    if (si.dwFlags & STARTF_USEFILLATTRIBUTE)
+	SetConsoleTextAttribute(handle_out, si.dwFillAttribute);
+    if (si.lpTitle)
+	SetConsoleTitleA(si.lpTitle);
+
+    SetLastError(ERROR_SUCCESS);
+
+    return TRUE;
+
+ the_end:
+    ERR("Can't allocate console\n");
+    if (handle_in != INVALID_HANDLE_VALUE)	CloseHandle(handle_in);
+    if (handle_out != INVALID_HANDLE_VALUE)	CloseHandle(handle_out);
+    if (handle_err != INVALID_HANDLE_VALUE)	CloseHandle(handle_err);
+    FreeConsole();
+    return FALSE;
 }
 
 
@@ -323,28 +238,344 @@
  *
  * Helper function for ReadConsole, ReadConsoleInput and PeekConsoleInput
  */
-static BOOL read_console_input( HANDLE handle, LPINPUT_RECORD buffer, DWORD count,
-                                LPDWORD read, BOOL flush )
+static BOOL read_console_input(HANDLE handle, LPINPUT_RECORD buffer, DWORD count,
+			       LPDWORD pRead, BOOL flush)
 {
-    BOOL ret;
+    BOOL	ret;
+    unsigned	read = 0;
+    DWORD	mode;
 
-    count = min( count, REQUEST_MAX_VAR_SIZE/sizeof(INPUT_RECORD) );
-
-    SERVER_START_VAR_REQ( read_console_input, count*sizeof(INPUT_RECORD) )
+    count = min(count, REQUEST_MAX_VAR_SIZE/sizeof(INPUT_RECORD));
+    
+    SERVER_START_VAR_REQ(read_console_input, count*sizeof(INPUT_RECORD))
     {
         req->handle = handle;
         req->flush = flush;
         if ((ret = !SERVER_CALL_ERR()))
         {
-            if (count) memcpy( buffer, server_data_ptr(req), server_data_size(req) );
-            if (read) *read = req->read;
+            if (count) memcpy(buffer, server_data_ptr(req), server_data_size(req));
+            read = req->read;
         }
     }
     SERVER_END_VAR_REQ;
+    if (count && flush && GetConsoleMode(handle, &mode) && (mode & ENABLE_PROCESSED_INPUT))
+    {
+	int	i;
+
+	for (i = 0; i < read; i++)
+	{
+	    if (buffer[i].EventType == KEY_EVENT && buffer[i].Event.KeyEvent.bKeyDown &&
+		buffer[i].Event.KeyEvent.uChar.UnicodeChar == 'C' - 64 &&
+		!(buffer[i].Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
+	    {
+		GenerateConsoleCtrlEvent(CTRL_C_EVENT, GetCurrentProcessId());
+		/* FIXME: this is hackish, but it easily disables IR handling afterwards */
+		buffer[i].Event.KeyEvent.uChar.UnicodeChar = 0;
+	    }
+	}
+    }
+    if (pRead) *pRead = read;
     return ret;
 }
 
 
+/***********************************************************************
+ *            ReadConsoleA   (KERNEL32.@)
+ */
+BOOL WINAPI ReadConsoleA(HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead,
+			 LPDWORD lpNumberOfCharsRead, LPVOID lpReserved)
+{
+    LPWSTR	ptr = HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead * sizeof(WCHAR));
+    DWORD	ncr = 0;
+    BOOL	ret;
+
+    if ((ret = ReadConsoleW(hConsoleInput, ptr, nNumberOfCharsToRead, &ncr, 0)))
+	ncr = WideCharToMultiByte(CP_ACP, 0, ptr, ncr, lpBuffer, nNumberOfCharsToRead, NULL, NULL);
+
+    if (lpNumberOfCharsRead) *lpNumberOfCharsRead = ncr;
+    HeapFree(GetProcessHeap(), 0, ptr);
+
+    return ret;
+}
+
+/***********************************************************************
+ *            ReadConsoleW   (KERNEL32.@)
+ */
+BOOL WINAPI ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer,
+			 DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, LPVOID lpReserved)
+{
+    DWORD	charsread;
+    LPWSTR	xbuf = (LPWSTR)lpBuffer;
+    DWORD	mode;
+    
+    TRACE("(%d,%p,%ld,%p,%p)\n",
+	  hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, lpReserved);
+    
+    if (!GetConsoleMode(hConsoleInput, &mode))
+        return FALSE;
+    
+    if (mode & ENABLE_LINE_INPUT)
+    {
+	if (!S_EditString || S_EditString[S_EditStrPos] == 0)
+	{
+	    if (S_EditString) HeapFree(GetProcessHeap(), 0, S_EditString);
+	    if (!(S_EditString = CONSOLE_Readline(hConsoleInput, mode & WINE_ENABLE_LINE_INPUT_EMACS)))
+		return FALSE;
+	    S_EditStrPos = 0;
+	}
+	charsread = lstrlenW(&S_EditString[S_EditStrPos]);
+	if (charsread > nNumberOfCharsToRead) charsread = nNumberOfCharsToRead;
+	memcpy(xbuf, &S_EditString[S_EditStrPos], charsread * sizeof(WCHAR));
+	S_EditStrPos += charsread;
+    }
+    else
+    {
+	INPUT_RECORD 	ir;
+	DWORD 		count;
+	
+	/* FIXME: should we read at least 1 char? The SDK does not say */
+	/* wait for at least one available input record (it doesn't mean we'll have
+	 * chars stored in xbuf...
+	 */
+	WaitForSingleObject(hConsoleInput, INFINITE);
+	for (charsread = 0; charsread < nNumberOfCharsToRead;)
+	{
+	    if (!read_console_input(hConsoleInput, &ir, 1, &count, TRUE)) return FALSE;
+	    if (count && ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
+		ir.Event.KeyEvent.uChar.UnicodeChar &&
+		!(ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
+	    {
+		xbuf[charsread++] = ir.Event.KeyEvent.uChar.UnicodeChar;
+	    }
+	}
+    }
+
+    if (lpNumberOfCharsRead) *lpNumberOfCharsRead = charsread;
+
+    return TRUE;
+}
+
+
+/******************************************************************************
+ * ReadConsoleInputA [KERNEL32.@]  Reads data from a console
+ *
+ * PARAMS
+ *    hConsoleInput        [I] Handle to console input buffer
+ *    lpBuffer             [O] Address of buffer for read data
+ *    nLength              [I] Number of records to read
+ *    lpNumberOfEventsRead [O] Address of number of records read
+ *
+ * RETURNS
+ *    Success: TRUE
+ *    Failure: FALSE
+ */
+BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, LPINPUT_RECORD lpBuffer,
+                              DWORD nLength, LPDWORD lpNumberOfEventsRead)
+{
+    DWORD	nread;
+    
+    if (!ReadConsoleInputW(hConsoleInput, lpBuffer, nLength, &nread))
+	return FALSE;
+    
+    /* FIXME for now, the low part of unicode would do as ASCII */
+    if (lpNumberOfEventsRead) *lpNumberOfEventsRead = nread;
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *            ReadConsoleInputW   (KERNEL32.@)
+ */
+BOOL WINAPI ReadConsoleInputW(HANDLE hConsoleInput, LPINPUT_RECORD lpBuffer,
+                              DWORD nLength, LPDWORD lpNumberOfEventsRead)
+{
+    DWORD count;
+	
+    if (!nLength)
+    {
+        if (lpNumberOfEventsRead) *lpNumberOfEventsRead = 0;
+        return TRUE;
+    }
+    
+    /* loop until we get at least one event */
+    for (;;)
+    {
+        WaitForSingleObject(hConsoleInput, INFINITE);
+	if (!read_console_input(hConsoleInput, lpBuffer, nLength, &count, TRUE))
+	    return FALSE;
+        if (count)
+        {
+            if (lpNumberOfEventsRead) *lpNumberOfEventsRead = count;
+            return TRUE;
+        }
+    }
+}
+
+
+/***********************************************************************
+ *            FlushConsoleInputBuffer   (KERNEL32.@)
+ */
+BOOL WINAPI FlushConsoleInputBuffer(HANDLE handle)
+{
+    return read_console_input(handle, NULL, 0, NULL, TRUE);
+}
+
+
+/***********************************************************************
+ *            PeekConsoleInputA   (KERNEL32.@)
+ *
+ * Gets 'count' first events (or less) from input queue.
+ *
+ * Does not need a complex console.
+ */
+BOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput, LPINPUT_RECORD pirBuffer, 
+			      DWORD cInRecords, LPDWORD lpcRead)
+{
+    /* FIXME: Hmm. Fix this if we get UNICODE input. */
+    return PeekConsoleInputW(hConsoleInput, pirBuffer, cInRecords, lpcRead);
+}
+
+
+/***********************************************************************
+ *            PeekConsoleInputW   (KERNEL32.@)
+ */
+BOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput, LPINPUT_RECORD pirBuffer, 
+			      DWORD cInRecords, LPDWORD lpcRead)
+{
+    if (!cInRecords)
+    {
+        if (lpcRead) *lpcRead = 0;
+        return TRUE;
+    }
+    return read_console_input(hConsoleInput, pirBuffer, cInRecords, lpcRead, FALSE);
+}
+
+
+/***********************************************************************
+ *            GetNumberOfConsoleInputEvents   (KERNEL32.@)
+ */
+BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hcon, LPDWORD nrofevents)
+{
+    return read_console_input(hcon, NULL, 0, nrofevents, FALSE);
+}
+
+/***********************************************************************
+ *            GetNumberOfConsoleMouseButtons   (KERNEL32.@)
+ */
+BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
+{
+    FIXME("(%p): stub\n", nrofbuttons);
+    *nrofbuttons = 2;
+    return TRUE;
+}
+
+/******************************************************************************
+ * WriteConsoleInputA [KERNEL32.@]  Write data to a console input buffer
+ *
+ */
+BOOL WINAPI WriteConsoleInputA(HANDLE handle, INPUT_RECORD *buffer,
+			       DWORD count, LPDWORD written)
+{
+    BOOL ret = TRUE;
+
+    if (written) *written = 0;
+    /* FIXME should zero out the non ASCII part for key events */
+
+    while (count && ret)
+    {
+        DWORD len = min(count, REQUEST_MAX_VAR_SIZE/sizeof(INPUT_RECORD));
+        SERVER_START_VAR_REQ(write_console_input, len * sizeof(INPUT_RECORD))
+	{
+	    req->handle = handle;
+	    memcpy(server_data_ptr(req), buffer, len * sizeof(INPUT_RECORD));
+	    if ((ret = !SERVER_CALL_ERR()))
+	    {
+		if (written) *written += req->written;
+		count -= len;
+		buffer += len;
+	    }
+	}
+        SERVER_END_VAR_REQ;
+    }
+    return ret;
+}
+
+/******************************************************************************
+ * WriteConsoleInputW [KERNEL32.@]  Write data to a console input buffer
+ *
+ */
+BOOL WINAPI WriteConsoleInputW(HANDLE handle, INPUT_RECORD *buffer,
+			       DWORD count, LPDWORD written)
+{
+    BOOL ret = TRUE;
+    
+    TRACE("(%d,%p,%ld,%p)\n", handle, buffer, count, written);
+    
+    if (written) *written = 0;
+    while (count && ret)
+    {
+        DWORD len = min(count, REQUEST_MAX_VAR_SIZE/sizeof(INPUT_RECORD));
+        SERVER_START_VAR_REQ(write_console_input, len * sizeof(INPUT_RECORD))
+        {
+            req->handle = handle;
+            memcpy(server_data_ptr(req), buffer, len * sizeof(INPUT_RECORD));
+            if ((ret = !SERVER_CALL_ERR()))
+            {
+                if (written) *written += req->written;
+                count -= len;
+                buffer += len;
+            }
+        }
+        SERVER_END_VAR_REQ;
+    }
+
+    return ret;
+}
+
+
+/******************************************************************************
+ *  SetConsoleInputExeNameW	 [KERNEL32.@]
+ * 
+ * BUGS
+ *   Unimplemented
+ */
+BOOL WINAPI SetConsoleInputExeNameW(LPCWSTR name)
+{
+    FIXME("(%s): stub!\n", debugstr_w(name));
+
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return TRUE;
+}
+
+/******************************************************************************
+ *  SetConsoleInputExeNameA	 [KERNEL32.@]
+ * 
+ * BUGS
+ *   Unimplemented
+ */
+BOOL WINAPI SetConsoleInputExeNameA(LPCSTR name)
+{
+    int		len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
+    LPWSTR	xptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    BOOL	ret;
+
+    if (!xptr) return FALSE;
+
+    MultiByteToWideChar(CP_ACP, 0, name, -1, xptr, len);
+    ret = SetConsoleInputExeNameW(xptr);
+    HeapFree(GetProcessHeap(), 0, xptr);
+
+    return ret;
+}
+
+static BOOL WINAPI CONSOLE_DefaultHandler(DWORD dwCtrlType)
+{
+    FIXME("Terminating process %lx on event %lx\n", GetCurrentProcessId(), dwCtrlType);
+    ExitProcess(0);
+    /* should never go here */
+    return TRUE;
+}
+
 /******************************************************************************
  * SetConsoleCtrlHandler [KERNEL32.@]  Adds function to calling process list
  *
@@ -362,46 +593,56 @@
  * Does not yet do any error checking, or set LastError if failed.
  * This doesn't yet matter, since these handlers are not yet called...!
  */
-static unsigned int console_ignore_ctrl_c = 0;
-static PHANDLER_ROUTINE handlers[]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-BOOL WINAPI SetConsoleCtrlHandler( PHANDLER_ROUTINE func, BOOL add )
+static unsigned int console_ignore_ctrl_c = 0; /* FIXME: this should be inherited somehow */
+static PHANDLER_ROUTINE handlers[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,CONSOLE_DefaultHandler};
+
+BOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE func, BOOL add)
 {
-  unsigned int alloc_loop = sizeof(handlers)/sizeof(PHANDLER_ROUTINE);
-  unsigned int done = 0;
-  FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
-  if (!func)
+    int alloc_loop = sizeof(handlers)/sizeof(handlers[0]) - 1;
+    
+    FIXME("(%p,%i) - no error checking or testing yet\n", func, add);
+    
+    if (!func)
     {
-      console_ignore_ctrl_c = add;
-      return TRUE;
+	console_ignore_ctrl_c = add;
+	return TRUE;
     }
-  if (add)
-      {
-	for (;alloc_loop--;)
-	  if (!handlers[alloc_loop] && !done)
-	    {
-	      handlers[alloc_loop] = func;
-	      done++;
-	    }
-	if (!done)
-	   FIXME("Out of space on CtrlHandler table\n");
-	return(done);
-      }
+    if (add)
+    {
+	for (; alloc_loop >= 0 && handlers[alloc_loop]; alloc_loop--);
+	if (alloc_loop <= 0)
+	{
+	    FIXME("Out of space on CtrlHandler table\n");
+	    return FALSE;
+	}
+	handlers[alloc_loop] = func;
+    }
     else
-      {
-	for (;alloc_loop--;)
-	  if (handlers[alloc_loop] == func && !done)
-	    {
-	      handlers[alloc_loop] = 0;
-	      done++;
-	    }
-	if (!done)
-	   WARN("Attempt to remove non-installed CtrlHandler %p\n",
-		func);
-	return (done);
-      }
-    return (done);
+    {
+	for (; alloc_loop >= 0 && handlers[alloc_loop] != func; alloc_loop--);
+	if (alloc_loop <= 0)
+	{
+	    WARN("Attempt to remove non-installed CtrlHandler %p\n", func);
+	    return FALSE;
+	}
+	/* sanity check */
+	if (alloc_loop == sizeof(handlers)/sizeof(handlers[0]) - 1)
+	{
+	    ERR("Who's trying to remove default handler???\n");
+	    return FALSE;
+	}
+	if (alloc_loop)
+	    memmove(&handlers[1], &handlers[0], alloc_loop * sizeof(handlers[0]));
+	handlers[0] = 0;
+    }
+    return TRUE;
 }
 
+static WINE_EXCEPTION_FILTER(CONSOLE_CtrlEventHandler)
+{
+    TRACE("(%lx)\n", GetExceptionCode());
+    return EXCEPTION_EXECUTE_HANDLER;
+}
 
 /******************************************************************************
  * GenerateConsoleCtrlEvent [KERNEL32.@] Simulate a CTRL-C or CTRL-BREAK
@@ -417,24 +658,69 @@
  *    Success: True
  *    Failure: False (and *should* [but doesn't] set LastError)
  */
-BOOL WINAPI GenerateConsoleCtrlEvent( DWORD dwCtrlEvent,
-					DWORD dwProcessGroupID )
+BOOL WINAPI GenerateConsoleCtrlEvent(DWORD dwCtrlEvent,
+				     DWORD dwProcessGroupID)
 {
-  if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
+    BOOL	dbgOn = FALSE;
+
+    if (dwCtrlEvent != CTRL_C_EVENT && dwCtrlEvent != CTRL_BREAK_EVENT)
     {
-      ERR("invalid event %d for PGID %ld\n", 
-	   (unsigned short)dwCtrlEvent, dwProcessGroupID );
-      return FALSE;
+	ERR("invalid event %ld for PGID %ld\n", dwCtrlEvent, dwProcessGroupID);
+	return FALSE;
     }
-  if (dwProcessGroupID == GetCurrentProcessId() )
+
+    if (dwProcessGroupID == GetCurrentProcessId() || dwProcessGroupID == 0)
     {
-      FIXME("Attempt to send event %d to self - stub\n",
-	     (unsigned short)dwCtrlEvent );
-      return FALSE;
+	int	i;
+	
+	FIXME("Attempt to send event %ld to self groupID, doing locally only\n", dwCtrlEvent);
+	
+	/* this is only meaningfull when done locally, otherwise it will have to be done on
+	 * the 'receive' side of the event generation
+	 */
+	if (dwCtrlEvent == CTRL_C_EVENT && console_ignore_ctrl_c)
+	    return TRUE;
+
+	/* if the program is debugged, then generate an exception to the debugger first */
+	SERVER_START_REQ( get_process_info )
+	{
+	    req->handle = GetCurrentProcess();
+	    if (!SERVER_CALL_ERR()) dbgOn = req->debugged;
+	}
+	SERVER_END_REQ;
+
+	if (dbgOn && (dwCtrlEvent == CTRL_C_EVENT || dwCtrlEvent == CTRL_BREAK_EVENT))
+	{
+	    /* the debugger is running... so try to pass the exception to it
+	     * if it continues, there's nothing more to do
+	     * otherwise, we need to send the ctrl-event to the handlers
+	     */
+	    BOOL	seen;
+	    __TRY
+	    {
+		seen = TRUE;
+		RaiseException((dwCtrlEvent == CTRL_C_EVENT) ? DBG_CONTROL_C : DBG_CONTROL_BREAK, 0, 0, NULL);
+	    }
+	    __EXCEPT(CONSOLE_CtrlEventHandler)
+	    {
+		/* the debugger didn't continue... so, pass to ctrl handlers */
+		seen = FALSE;
+	    }
+	    __ENDTRY;
+	    if (seen) return TRUE;
+	}
+
+	/* proceed with installed handlers */
+	for (i = 0; i < sizeof(handlers)/sizeof(handlers[0]); i++)
+	{
+	    if (handlers[i] && (handlers[i])(dwCtrlEvent)) break;
+	}
+	
+	return TRUE;
     }
-  FIXME("event %d to external PGID %ld - not implemented yet\n",
-	 (unsigned short)dwCtrlEvent, dwProcessGroupID );
-  return FALSE;
+    FIXME("event %ld to external PGID %ld - not implemented yet\n", 
+	  dwCtrlEvent, dwProcessGroupID);
+    return FALSE;
 }
 
 
@@ -455,35 +741,64 @@
  *    Success: Handle to new console screen buffer
  *    Failure: INVALID_HANDLE_VALUE
  */
-HANDLE WINAPI CreateConsoleScreenBuffer( DWORD dwDesiredAccess,
-                DWORD dwShareMode, LPSECURITY_ATTRIBUTES sa,
-                DWORD dwFlags, LPVOID lpScreenBufferData )
+HANDLE WINAPI CreateConsoleScreenBuffer(DWORD dwDesiredAccess, DWORD dwShareMode, 
+					LPSECURITY_ATTRIBUTES sa, DWORD dwFlags, 
+					LPVOID lpScreenBufferData)
 {
-    FIXME("(%ld,%ld,%p,%ld,%p): stub\n",dwDesiredAccess,
-          dwShareMode, sa, dwFlags, lpScreenBufferData);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return INVALID_HANDLE_VALUE;
+    HANDLE	ret = INVALID_HANDLE_VALUE;
+    
+    TRACE("(%ld,%ld,%p,%ld,%p)\n", 
+	  dwDesiredAccess, dwShareMode, sa, dwFlags, lpScreenBufferData);
+    
+    if (dwFlags != CONSOLE_TEXTMODE_BUFFER || lpScreenBufferData != NULL)
+    {
+	SetLastError(ERROR_INVALID_PARAMETER);
+	return INVALID_HANDLE_VALUE;
+    }
+    
+    SERVER_START_REQ(create_console_output)
+    {
+	req->handle_in = 0;
+	req->access    = dwDesiredAccess;
+	req->share     = dwShareMode;
+	req->inherit   = (sa && sa->bInheritHandle);
+	if (!SERVER_CALL_ERR())
+	    ret = req->handle_out;
+    }
+    SERVER_END_REQ;
+    
+    return ret;
 }
 
 
 /***********************************************************************
  *           GetConsoleScreenBufferInfo   (KERNEL32.@)
  */
-BOOL WINAPI GetConsoleScreenBufferInfo( HANDLE hConsoleOutput,
-                                          LPCONSOLE_SCREEN_BUFFER_INFO csbi )
+BOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, LPCONSOLE_SCREEN_BUFFER_INFO csbi)
 {
-    csbi->dwSize.X = 80;
-    csbi->dwSize.Y = 24;
-    csbi->dwCursorPosition.X = 0;
-    csbi->dwCursorPosition.Y = 0;
-    csbi->wAttributes = 0;
-    csbi->srWindow.Left	= 0;
-    csbi->srWindow.Right	= 79;
-    csbi->srWindow.Top	= 0;
-    csbi->srWindow.Bottom	= 23;
-    csbi->dwMaximumWindowSize.X = 80;
-    csbi->dwMaximumWindowSize.Y = 24;
-    return TRUE;
+    BOOL	ret;
+
+    SERVER_START_REQ(get_console_output_info)
+    {
+	req->handle = (handle_t)hConsoleOutput;
+	if ((ret = !SERVER_CALL_ERR()))
+	{
+	    csbi->dwSize.X              = req->width;
+	    csbi->dwSize.Y              = req->height;
+	    csbi->dwCursorPosition.X    = req->cursor_x;
+	    csbi->dwCursorPosition.Y    = req->cursor_y;
+	    csbi->wAttributes           = req->attr;
+	    csbi->srWindow.Left	        = req->win_left;
+	    csbi->srWindow.Right        = req->win_right;
+	    csbi->srWindow.Top	        = req->win_top;
+	    csbi->srWindow.Bottom       = req->win_bottom;
+	    csbi->dwMaximumWindowSize.X = req->max_width;
+	    csbi->dwMaximumWindowSize.Y = req->max_height;
+	}
+    }
+    SERVER_END_REQ;
+
+    return ret;
 }
 
 
@@ -494,11 +809,23 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI SetConsoleActiveScreenBuffer(
-    HANDLE hConsoleOutput) /* [in] Handle to console screen buffer */
+BOOL WINAPI SetConsoleActiveScreenBuffer(HANDLE hConsoleOutput)
 {
-    FIXME("(%x): stub\n", hConsoleOutput);
-    return FALSE;
+    BOOL	ret;
+    
+    TRACE("(%x)\n", hConsoleOutput);
+    
+    SERVER_START_VAR_REQ(set_console_input_info, 0)
+    {
+	req->handle    = 0;
+	req->mask      = SET_CONSOLE_INPUT_INFO_ACTIVE_SB;
+	req->active_sb = hConsoleOutput;
+	
+	ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_VAR_REQ;
+    
+    return ret;
 }
 
 
@@ -513,7 +840,7 @@
  */
 #ifdef __i386__
 #undef GetLargestConsoleWindowSize
-DWORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
+DWORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput)
 {
     COORD c;
     c.X = 80;
@@ -533,7 +860,7 @@
  * VERSION: [!i386]
  */
 #ifndef __i386__
-COORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
+COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput)
 {
     COORD c;
     c.X = 80;
@@ -543,156 +870,6 @@
 #endif /* defined(__i386__) */
 
 
-/***********************************************************************
- *            FreeConsole (KERNEL32.@)
- */
-BOOL WINAPI FreeConsole(VOID)
-{
-    BOOL ret;
-    SERVER_START_REQ( free_console )
-    {
-        ret = !SERVER_CALL_ERR();
-    }
-    SERVER_END_REQ;
-    return ret;
-}
-
-
-/*************************************************************************
- * 		CONSOLE_make_complex			[internal]
- *
- * Turns a CONSOLE kernel object into a complex one.
- * (switches from output/input using the terminal where WINE was started to 
- * its own xterm).
- * 
- * This makes simple commandline tools pipeable, while complex commandline 
- * tools work without getting messed up by debug output.
- * 
- * All other functions should work independently from this call.
- *
- * To test for complex console: pid == 0 -> simple, otherwise complex.
- */
-static BOOL CONSOLE_make_complex(HANDLE handle)
-{
-	struct termios term;
-	char buf[256];
-	char c = '\0';
-	int i,xpid,master,slave;
-
-        if (CONSOLE_GetPid( handle )) return TRUE; /* already complex */
-
-	MESSAGE("Console: Making console complex (creating an xterm)...\n");
-
-	if (tcgetattr(0, &term) < 0) {
-		/* ignore failure, or we can't run from a script */
-	}
-	term.c_lflag = ~(ECHO|ICANON);
-
-        if (wine_openpty(&master, &slave, NULL, &term, NULL) < 0)
-            return FALSE;
-
-	if ((xpid=fork()) == 0) {
-		tcsetattr(slave, TCSADRAIN, &term);
-                close( slave );
-		sprintf(buf, "-Sxx%d", master);
-		/* "-fn vga" for VGA font. Harmless if vga is not present:
-		 *  xterm: unable to open font "vga", trying "fixed".... 
-		 */
-		execlp("xterm", "xterm", buf, "-fn","vga",NULL);
-		ERR("error creating AllocConsole xterm\n");
-		exit(1);
-	}
-        close( master );
-
-	/* most xterms like to print their window ID when used with -S;
-	 * read it and continue before the user has a chance...
-	 */
-        for (i = 0; i < 10000; i++)
-        {
-            if (read( slave, &c, 1 ) == 1)
-            {
-                if (c == '\n') break;
-            }
-            else usleep(100); /* wait for xterm to be created */
-        }
-        if (i == 10000)
-        {
-            ERR("can't read xterm WID\n");
-            close( slave );
-            return FALSE;
-	}
-
-        wine_server_send_fd( slave );
-        SERVER_START_REQ( set_console_fd )
-        {
-            req->handle = handle;
-            req->fd_in  = slave;
-            req->fd_out = slave;
-            req->pid    = xpid;
-            SERVER_CALL();
-            close( slave );
-        }
-        SERVER_END_REQ;
-
-	/* enable mouseclicks */
-	strcpy( buf, "\033[?1002h" );
-	WriteFile(handle,buf,strlen(buf),NULL,NULL);
-
-        strcpy( buf, "\033]2;" );
-        if (GetConsoleTitleA( buf + 4, sizeof(buf) - 5 ))
-        {
-            strcat( buf, "\a" );
-	    WriteFile(handle,buf,strlen(buf),NULL,NULL);
-	}
-	return TRUE;
-
-}
-
-
-/***********************************************************************
- *            AllocConsole (KERNEL32.@)
- *
- * creates an xterm with a pty to our program
- */
-BOOL WINAPI AllocConsole(VOID)
-{
-    BOOL ret;
-    HANDLE hStderr;
-    int handle_in, handle_out;
-
-    TRACE("()\n");
-
-    SERVER_START_REQ( alloc_console )
-    {
-        req->access  = GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE;
-        req->inherit = FALSE;
-        ret = !SERVER_CALL_ERR();
-        handle_in = req->handle_in;
-        handle_out = req->handle_out;
-    }
-    SERVER_END_REQ;
-    if (!ret) return FALSE;
-
-    if (!DuplicateHandle( GetCurrentProcess(), handle_out, GetCurrentProcess(), &hStderr,
-                          0, TRUE, DUPLICATE_SAME_ACCESS ))
-    {
-        CloseHandle( handle_in );
-        CloseHandle( handle_out );
-        FreeConsole();
-        return FALSE;
-    }
-
-    /* NT resets the STD_*_HANDLEs on console alloc */
-    SetStdHandle( STD_INPUT_HANDLE, handle_in );
-    SetStdHandle( STD_OUTPUT_HANDLE, handle_out );
-    SetStdHandle( STD_ERROR_HANDLE, hStderr );
-
-    SetLastError(ERROR_SUCCESS);
-    SetConsoleTitleA("Wine Console");
-    return TRUE;
-}
-
-
 /******************************************************************************
  * GetConsoleCP [KERNEL32.@]  Returns the OEM code page for the console
  *
@@ -705,6 +882,20 @@
 }
 
 
+/******************************************************************************
+ *  SetConsoleCP	 [KERNEL32.@]
+ * 
+ * BUGS
+ *   Unimplemented
+ */
+BOOL WINAPI SetConsoleCP(UINT cp)
+{
+    FIXME("(%d): stub\n", cp);
+    
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
 /***********************************************************************
  *            GetConsoleOutputCP   (KERNEL32.@)
  */
@@ -713,17 +904,35 @@
     return GetConsoleCP();
 }
 
+/******************************************************************************
+ * SetConsoleOutputCP [KERNEL32.@]  Set the output codepage used by the console
+ *
+ * PARAMS
+ *    cp [I] code page to set
+ *
+ * RETURNS
+ *    Success: TRUE
+ *    Failure: FALSE
+ */
+BOOL WINAPI SetConsoleOutputCP(UINT cp)
+{
+    FIXME("stub\n");
+    return TRUE;
+}
+
+
 /***********************************************************************
  *            GetConsoleMode   (KERNEL32.@)
  */
-BOOL WINAPI GetConsoleMode(HANDLE hcon,LPDWORD mode)
+BOOL WINAPI GetConsoleMode(HANDLE hcon, LPDWORD mode)
 {
     BOOL ret;
-    SERVER_START_REQ( get_console_mode )
+    
+    SERVER_START_REQ(get_console_mode)
     {
-        req->handle = hcon;
-        ret = !SERVER_CALL_ERR();
-        if (ret && mode) *mode = req->mode;
+	req->handle = hcon;
+	ret = !SERVER_CALL_ERR();
+	if (ret && mode) *mode = req->mode;
     }
     SERVER_END_REQ;
     return ret;
@@ -741,466 +950,26 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI SetConsoleMode( HANDLE hcon, DWORD mode )
+BOOL WINAPI SetConsoleMode(HANDLE hcon, DWORD mode)
 {
     BOOL ret;
-    SERVER_START_REQ( set_console_mode )
+    
+    TRACE("(%x,%lx)\n", hcon, mode);
+    
+    SERVER_START_REQ(set_console_mode)
     {
-        req->handle = hcon;
-        req->mode = mode;
-        ret = !SERVER_CALL_ERR();
+	req->handle = hcon;
+	req->mode = mode;
+	ret = !SERVER_CALL_ERR();
     }
     SERVER_END_REQ;
+    /* FIXME: when resetting a console input to editline mode, I think we should
+     * empty the S_EditString buffer
+     */
     return ret;
 }
 
 
-/******************************************************************************
- * SetConsoleOutputCP [KERNEL32.@]  Set the output codepage used by the console
- *
- * PARAMS
- *    cp [I] code page to set
- *
- * RETURNS
- *    Success: TRUE
- *    Failure: FALSE
- */
-BOOL WINAPI SetConsoleOutputCP( UINT cp )
-{
-    FIXME("stub\n");
-    return TRUE;
-}
-
-
-/***********************************************************************
- *            GetConsoleTitleA   (KERNEL32.@)
- */
-DWORD WINAPI GetConsoleTitleA(LPSTR title,DWORD size)
-{
-    DWORD ret = 0;
-    HANDLE hcon;
-
-    if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ, 0, NULL,
-                               OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
-        return 0;
-    SERVER_START_VAR_REQ( get_console_info, REQUEST_MAX_VAR_SIZE )
-    {
-        req->handle = hcon;
-        if (!SERVER_CALL_ERR())
-        {
-            ret = server_data_size(req);
-            size = min( size-1, ret );
-            memcpy( title, server_data_ptr(req), size );
-            title[size] = 0;
-        }
-    }
-    SERVER_END_VAR_REQ;
-    CloseHandle( hcon );
-    return ret;
-}
-
-
-/******************************************************************************
- * GetConsoleTitleW [KERNEL32.@]  Retrieves title string for console
- *
- * PARAMS
- *    title [O] Address of buffer for title
- *    size  [I] Size of buffer
- *
- * RETURNS
- *    Success: Length of string copied
- *    Failure: 0
- */
-DWORD WINAPI GetConsoleTitleW( LPWSTR title, DWORD size )
-{
-    char *tmp;
-    DWORD ret;
-
-    if (!(tmp = HeapAlloc( GetProcessHeap(), 0, size*sizeof(WCHAR) ))) return 0;
-    GetConsoleTitleA( tmp, size*sizeof(WCHAR) );
-    ret = MultiByteToWideChar( CP_ACP, 0, tmp, -1, title, size );
-    HeapFree( GetProcessHeap(), 0, tmp );
-    return ret;
-}
-
-
-/***********************************************************************
- *            WriteConsoleA   (KERNEL32.@)
- */
-BOOL WINAPI WriteConsoleA( HANDLE hConsoleOutput,
-                               LPCVOID lpBuffer,
-                               DWORD nNumberOfCharsToWrite,
-                               LPDWORD lpNumberOfCharsWritten,
-                               LPVOID lpReserved )
-{
-	/* FIXME: should I check if this is a console handle? */
-	return WriteFile(hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
-			 lpNumberOfCharsWritten, NULL);
-}
-
-
-#define CADD(c) 							\
-	if (bufused==curbufsize-1)					\
-	    buffer = HeapReAlloc(GetProcessHeap(),0,buffer,(curbufsize+=100));\
-	buffer[bufused++]=c;
-#define SADD(s) { char *x=s;while (*x) {CADD(*x);x++;}}
-
-/***********************************************************************
- *            WriteConsoleOutputA   (KERNEL32.@)
- */
-BOOL WINAPI WriteConsoleOutputA( HANDLE hConsoleOutput,
-                                     LPCHAR_INFO lpBuffer,
-                                     COORD dwBufferSize,
-                                     COORD dwBufferCoord,
-                                     LPSMALL_RECT lpWriteRegion)
-{
-    int i,j,off=0,lastattr=-1;
-    int offbase;
-    char	sbuf[20],*buffer=NULL;
-    int		bufused=0,curbufsize = 100;
-    DWORD	res;
-    CONSOLE_SCREEN_BUFFER_INFO csbi;
-    const int colormap[8] = {
-    	0,4,2,6,
-	1,5,3,7,
-    };
-    CONSOLE_make_complex(hConsoleOutput);
-    buffer = HeapAlloc(GetProcessHeap(),0,curbufsize);
-    offbase = (dwBufferCoord.Y - 1) * dwBufferSize.X +
-              (dwBufferCoord.X - lpWriteRegion->Left);
-
-    TRACE("orig rect top = %d, bottom=%d, left=%d, right=%d\n",
-    	lpWriteRegion->Top,
-    	lpWriteRegion->Bottom,
-    	lpWriteRegion->Left,
-    	lpWriteRegion->Right
-    );
-
-    GetConsoleScreenBufferInfo(hConsoleOutput, &csbi);
-    sprintf(sbuf,"%c7",27);SADD(sbuf);
-
-    /* Step 1. Make (Bottom,Right) offset of intersection with
-       Screen Buffer                                              */
-    lpWriteRegion->Bottom = min(lpWriteRegion->Bottom, csbi.dwSize.Y-1) - 
-                                lpWriteRegion->Top;
-    lpWriteRegion->Right = min(lpWriteRegion->Right, csbi.dwSize.X-1) -
-                                lpWriteRegion->Left;
-
-    /* Step 2. If either offset is negative, then no action 
-       should be performed. (Implies that requested rectangle is
-       outside the current screen buffer rectangle.)              */
-    if ((lpWriteRegion->Bottom < 0) ||
-        (lpWriteRegion->Right < 0)) {
-        /* readjust (Bottom Right) for rectangle */
-        lpWriteRegion->Bottom += lpWriteRegion->Top;
-        lpWriteRegion->Right += lpWriteRegion->Left;
-
-        TRACE("invisible rect top = %d, bottom=%d, left=%d, right=%d\n",
-            lpWriteRegion->Top,
-    	    lpWriteRegion->Bottom,
-    	    lpWriteRegion->Left,
-    	    lpWriteRegion->Right
-        );
-
-        HeapFree(GetProcessHeap(),0,buffer);
-        return TRUE;
-    }
-
-    /* Step 3. Intersect with source rectangle                    */
-    lpWriteRegion->Bottom = lpWriteRegion->Top - dwBufferCoord.Y +
-             min(lpWriteRegion->Bottom + dwBufferCoord.Y, dwBufferSize.Y-1);
-    lpWriteRegion->Right = lpWriteRegion->Left - dwBufferCoord.X +
-             min(lpWriteRegion->Right + dwBufferCoord.X, dwBufferSize.X-1);
-
-    TRACE("clipped rect top = %d, bottom=%d, left=%d,right=%d\n",
-    	lpWriteRegion->Top,
-    	lpWriteRegion->Bottom,
-    	lpWriteRegion->Left,
-    	lpWriteRegion->Right
-    );
-
-    /* Validate above computations made sense, if not then issue
-       error and fudge to single character rectangle                  */
-    if ((lpWriteRegion->Bottom < lpWriteRegion->Top) ||
-        (lpWriteRegion->Right < lpWriteRegion->Left)) {
-       ERR("Invalid clipped rectangle top = %d, bottom=%d, left=%d,right=%d\n",
-    	      lpWriteRegion->Top,
-    	      lpWriteRegion->Bottom,
-    	      lpWriteRegion->Left,
-    	      lpWriteRegion->Right
-          );
-       lpWriteRegion->Bottom = lpWriteRegion->Top;
-       lpWriteRegion->Right = lpWriteRegion->Left;
-    }
-
-    /* Now do the real processing and move the characters    */
-    for (i=lpWriteRegion->Top;i<=lpWriteRegion->Bottom;i++) {
-        offbase += dwBufferSize.X;
-    	sprintf(sbuf,"%c[%d;%dH",27,i+1,lpWriteRegion->Left+1);
-	SADD(sbuf);
-	for (j=lpWriteRegion->Left;j<=lpWriteRegion->Right;j++) {
-            off = j + offbase;
-	    if (lastattr!=lpBuffer[off].Attributes) {
-		lastattr = lpBuffer[off].Attributes;
-		sprintf(sbuf,"%c[0;%s3%d;4%dm",
-			27,
-			(lastattr & FOREGROUND_INTENSITY)?"1;":"",
-			colormap[lastattr&7],
-			colormap[(lastattr&0x70)>>4]
-		);
-		/* FIXME: BACKGROUND_INTENSITY */
-		SADD(sbuf);
-	    }
-	    CADD(lpBuffer[off].Char.AsciiChar);
-	}
-    }
-    sprintf(sbuf,"%c[0m%c8",27,27);SADD(sbuf);
-    WriteFile(hConsoleOutput,buffer,bufused,&res,NULL);
-    HeapFree(GetProcessHeap(),0,buffer);
-    return TRUE;
-}
-
-/***********************************************************************
- *            WriteConsoleOutputW   (KERNEL32.@)
- */
-BOOL WINAPI WriteConsoleOutputW( HANDLE hConsoleOutput,
-                                     LPCHAR_INFO lpBuffer,
-                                     COORD dwBufferSize,
-                                     COORD dwBufferCoord,
-                                     LPSMALL_RECT lpWriteRegion)
-{
-    FIXME("(%d,%p,%dx%d,%dx%d,%p): stub\n", hConsoleOutput, lpBuffer,
-	  dwBufferSize.X,dwBufferSize.Y,dwBufferCoord.X,dwBufferCoord.Y,lpWriteRegion);
-    
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;   
-}
-
-/***********************************************************************
- *            WriteConsoleW   (KERNEL32.@)
- */
-BOOL WINAPI WriteConsoleW( HANDLE hConsoleOutput,
-                               LPCVOID lpBuffer,
-                               DWORD nNumberOfCharsToWrite,
-                               LPDWORD lpNumberOfCharsWritten,
-                               LPVOID lpReserved )
-{
-        BOOL ret;
-        LPSTR xstring;
-	DWORD n;
-
-	n = WideCharToMultiByte(CP_ACP,0,lpBuffer,nNumberOfCharsToWrite,NULL,0,NULL,NULL);
-	xstring=HeapAlloc( GetProcessHeap(), 0, n );
-
-	n = WideCharToMultiByte(CP_ACP,0,lpBuffer,nNumberOfCharsToWrite,xstring,n,NULL,NULL);
-
-	/* FIXME: should I check if this is a console handle? */
-	ret= WriteFile(hConsoleOutput, xstring, n,
-			 lpNumberOfCharsWritten, NULL);
-	/* FIXME: lpNumberOfCharsWritten should be converted to numofchars in UNICODE */ 
-	HeapFree( GetProcessHeap(), 0, xstring );
-	return ret;
-}
-
-
-/***********************************************************************
- *            ReadConsoleA   (KERNEL32.@)
- */
-BOOL WINAPI ReadConsoleA( HANDLE hConsoleInput,
-                              LPVOID lpBuffer,
-                              DWORD nNumberOfCharsToRead,
-                              LPDWORD lpNumberOfCharsRead,
-                              LPVOID lpReserved )
-{
-    DWORD	charsread = 0;
-    LPSTR	xbuf = (LPSTR)lpBuffer;
-
-    TRACE("(%d,%p,%ld,%p,%p)\n",
-	    hConsoleInput,lpBuffer,nNumberOfCharsToRead,
-	    lpNumberOfCharsRead,lpReserved
-    );
-
-    CONSOLE_get_input(hConsoleInput,FALSE);
-
-    /* FIXME: should we read at least 1 char? The SDK does not say */
-    while (charsread<nNumberOfCharsToRead)
-    {
-        INPUT_RECORD ir;
-        DWORD count;
-        if (!read_console_input( hConsoleInput, &ir, 1, &count, TRUE )) return FALSE;
-        if (!count) break;
-        if (ir.EventType != KEY_EVENT) continue;
-        if (!ir.Event.KeyEvent.bKeyDown) continue;
-        *xbuf++ = ir.Event.KeyEvent.uChar.AsciiChar;
-        charsread++;
-    }
-    if (lpNumberOfCharsRead)
-    	*lpNumberOfCharsRead = charsread;
-    return TRUE;
-}
-
-/***********************************************************************
- *            ReadConsoleW   (KERNEL32.@)
- */
-BOOL WINAPI ReadConsoleW( HANDLE hConsoleInput,
-                              LPVOID lpBuffer,
-                              DWORD nNumberOfCharsToRead,
-                              LPDWORD lpNumberOfCharsRead,
-                              LPVOID lpReserved )
-{
-    BOOL ret;
-    LPSTR buf = (LPSTR)HeapAlloc(GetProcessHeap(), 0, nNumberOfCharsToRead);
-
-    ret = ReadConsoleA(
-    	hConsoleInput,
-	buf,
-	nNumberOfCharsToRead,
-	lpNumberOfCharsRead,
-	lpReserved
-    );
-    if (ret)
-        MultiByteToWideChar( CP_ACP, 0, buf, -1, lpBuffer, nNumberOfCharsToRead );
-
-    HeapFree( GetProcessHeap(), 0, buf );
-    return ret;
-}
-
-
-/******************************************************************************
- * ReadConsoleInputA [KERNEL32.@]  Reads data from a console
- *
- * PARAMS
- *    hConsoleInput        [I] Handle to console input buffer
- *    lpBuffer             [O] Address of buffer for read data
- *    nLength              [I] Number of records to read
- *    lpNumberOfEventsRead [O] Address of number of records read
- *
- * RETURNS
- *    Success: TRUE
- *    Failure: FALSE
- */
-BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, LPINPUT_RECORD lpBuffer,
-                              DWORD nLength, LPDWORD lpNumberOfEventsRead)
-{
-    if (!nLength)
-    {
-        if (lpNumberOfEventsRead) *lpNumberOfEventsRead = 0;
-        return TRUE;
-    }
-
-    /* loop until we get at least one event */
-    for (;;)
-    {
-        DWORD count;
-        BOOL ret = read_console_input( hConsoleInput, lpBuffer, nLength, &count, TRUE );
-
-        if (!ret) return FALSE;
-        if (count)
-        {
-            if (lpNumberOfEventsRead) *lpNumberOfEventsRead = count;
-            return TRUE;
-        }
-        CONSOLE_get_input(hConsoleInput,TRUE);
-        /*WaitForSingleObject( hConsoleInput, INFINITE32 );*/
-    }
-}
-
-
-/***********************************************************************
- *            ReadConsoleInputW   (KERNEL32.@)
- */
-BOOL WINAPI ReadConsoleInputW( HANDLE handle, LPINPUT_RECORD buffer,
-                                   DWORD count, LPDWORD read )
-{
-    /* FIXME: Fix this if we get UNICODE input. */
-    return ReadConsoleInputA( handle, buffer, count, read );
-}
-
-
-/***********************************************************************
- *            FlushConsoleInputBuffer   (KERNEL32.@)
- */
-BOOL WINAPI FlushConsoleInputBuffer( HANDLE handle )
-{
-    return read_console_input( handle, NULL, 0, NULL, TRUE );
-}
-
-
-/***********************************************************************
- *            PeekConsoleInputA   (KERNEL32.@)
- *
- * Gets 'count' first events (or less) from input queue.
- *
- * Does not need a complex console.
- */
-BOOL WINAPI PeekConsoleInputA( HANDLE handle, LPINPUT_RECORD buffer, DWORD count, LPDWORD read )
-{
-    CONSOLE_get_input(handle,FALSE);
-    if (!count)
-    {
-        if (read) *read = 0;
-        return TRUE;
-    }
-    return read_console_input( handle, buffer, count, read, FALSE );
-}
-
-
-/***********************************************************************
- *            PeekConsoleInputW   (KERNEL32.@)
- */
-BOOL WINAPI PeekConsoleInputW(HANDLE hConsoleInput,
-                                  LPINPUT_RECORD pirBuffer,
-                                  DWORD cInRecords,
-                                  LPDWORD lpcRead)
-{
-    /* FIXME: Hmm. Fix this if we get UNICODE input. */
-    return PeekConsoleInputA(hConsoleInput,pirBuffer,cInRecords,lpcRead);
-}
-
-
-/******************************************************************************
- * WriteConsoleInputA [KERNEL32.@]  Write data to a console input buffer
- *
- */
-BOOL WINAPI WriteConsoleInputA( HANDLE handle, INPUT_RECORD *buffer,
-                                DWORD count, LPDWORD written )
-{
-    BOOL ret = TRUE;
-
-    if (written) *written = 0;
-    while (count && ret)
-    {
-        DWORD len = min( count, REQUEST_MAX_VAR_SIZE/sizeof(INPUT_RECORD) );
-        SERVER_START_VAR_REQ( write_console_input, len * sizeof(INPUT_RECORD) )
-        {
-            req->handle = handle;
-            memcpy( server_data_ptr(req), buffer, len * sizeof(INPUT_RECORD) );
-            if ((ret = !SERVER_CALL_ERR()))
-            {
-                if (written) *written += req->written;
-                count -= len;
-                buffer += len;
-            }
-        }
-        SERVER_END_VAR_REQ;
-    }
-    return ret;
-}
-
-/******************************************************************************
- * WriteConsoleInputW [KERNEL32.@]  Write data to a console input buffer
- *
- */
-BOOL WINAPI WriteConsoleInputW( HANDLE handle, INPUT_RECORD *buffer,
-                                DWORD count, LPDWORD written )
-{
-    FIXME("(%d,%p,%ld,%p): stub!\n", handle, buffer, count, written);
-
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;    
-}
-
-
 /***********************************************************************
  *            SetConsoleTitleA   (KERNEL32.@)
  *
@@ -1212,33 +981,18 @@
  */
 BOOL WINAPI SetConsoleTitleA(LPCSTR title)
 {
-    size_t len = strlen(title);
-    HANDLE hcon;
-    DWORD written;
-    BOOL ret;
-
-    if ((hcon = CreateFileA( "CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL,
-                               OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
-        return FALSE;
-
-    len = min( len, REQUEST_MAX_VAR_SIZE );
-    SERVER_START_VAR_REQ( set_console_info, len )
-    {
-        req->handle = hcon;
-        req->mask = SET_CONSOLE_INFO_TITLE;
-        memcpy( server_data_ptr(req), title, len );
-        ret = !SERVER_CALL_ERR();
-    }
-    SERVER_END_VAR_REQ;
-
-    if (ret && CONSOLE_GetPid( hcon ))
-    {
-        /* only set title for complex console (own xterm) */
-        WriteFile( hcon, "\033]2;", 4, &written, NULL );
-        WriteFile( hcon, title, strlen(title), &written, NULL );
-        WriteFile( hcon, "\a", 1, &written, NULL );
-    }
-    CloseHandle( hcon );
+    LPWSTR	titleW = NULL;
+    BOOL	ret;
+    DWORD	len;
+    
+    len = MultiByteToWideChar(CP_ACP, 0, title, -1, NULL, 0);
+    titleW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!titleW) return FALSE;
+    
+    MultiByteToWideChar(CP_ACP, 0, title, -1, titleW, len);
+    ret = SetConsoleTitleW(titleW);
+    
+    HeapFree(GetProcessHeap(), 0, titleW);
     return ret;
 }
 
@@ -1256,13 +1010,364 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI SetConsoleTitleW( LPCWSTR title )
+BOOL WINAPI SetConsoleTitleW(LPCWSTR title)
 {
-    BOOL ret;
+    size_t	len = strlenW(title) * sizeof(WCHAR);
+    BOOL 	ret;
 
-    LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
-    ret = SetConsoleTitleA(titleA);
-    HeapFree( GetProcessHeap(), 0, titleA );
+    len = min(len, REQUEST_MAX_VAR_SIZE);
+    SERVER_START_VAR_REQ(set_console_input_info, len)
+    {
+	req->handle = 0;
+        req->mask = SET_CONSOLE_INPUT_INFO_TITLE;
+        memcpy(server_data_ptr(req), title, len);
+        ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_VAR_REQ;
+
+    return ret;
+}
+
+/***********************************************************************
+ *            GetConsoleTitleA   (KERNEL32.@)
+ */
+DWORD WINAPI GetConsoleTitleA(LPSTR title, DWORD size)
+{
+    WCHAR*	ptr = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * size);
+    DWORD	ret;
+
+    if (!ptr) return 0;
+    
+    ret = GetConsoleTitleW(ptr, size);
+    if (ret) WideCharToMultiByte(CP_ACP, 0, ptr, ret + 1, title, size, NULL, NULL);
+
+    return ret;
+}
+
+
+/******************************************************************************
+ * GetConsoleTitleW [KERNEL32.@]  Retrieves title string for console
+ *
+ * PARAMS
+ *    title [O] Address of buffer for title
+ *    size  [I] Size of buffer
+ *
+ * RETURNS
+ *    Success: Length of string copied
+ *    Failure: 0
+ */
+DWORD WINAPI GetConsoleTitleW(LPWSTR title, DWORD size)
+{
+    DWORD ret = 0;
+
+    SERVER_START_VAR_REQ(get_console_input_info, REQUEST_MAX_VAR_SIZE)
+    {
+	req->handle = 0;
+        if (!SERVER_CALL_ERR())
+        {
+            ret = server_data_size(req) / sizeof(WCHAR);
+            size = min(size - 1, ret);
+            memcpy(title, server_data_ptr(req), size * sizeof(WCHAR));
+            title[size] = 0;
+        }
+    }
+    SERVER_END_VAR_REQ;
+
+    return ret;
+}
+
+/******************************************************************
+ *		write_char
+ *
+ * WriteConsoleOutput helper: hides server call semantics
+ */
+static	int	write_char(HANDLE hCon, LPCVOID lpBuffer, int nc, COORD* pos)
+{
+    BOOL	ret;
+    int		written = -1;
+
+    if (!nc) return 0;
+
+    assert(nc * sizeof(WCHAR) <= REQUEST_MAX_VAR_SIZE);
+
+    SERVER_START_VAR_REQ(write_console_output, nc * sizeof(WCHAR))
+    {
+	req->handle = hCon;
+	req->x      = pos->X;
+	req->y      = pos->Y;
+	req->mode   = WRITE_CONSOLE_MODE_TEXTSTDATTR;
+	memcpy(server_data_ptr(req), lpBuffer, nc * sizeof(WCHAR));
+	if ((ret = !SERVER_CALL_ERR()))
+	{
+	    written = req->written;
+	}
+    }
+    SERVER_END_VAR_REQ;
+    
+    if (written > 0) pos->X += written;
+
+    return written;
+}
+
+/******************************************************************
+ *		next_line
+ *
+ * WriteConsoleOutput helper: handles passing to next line (+scrolling if necessary)
+ *
+ */
+static int	next_line(HANDLE hCon, CONSOLE_SCREEN_BUFFER_INFO* csbi)
+{
+    SMALL_RECT	src; 
+    CHAR_INFO	ci;
+    COORD	dst;
+
+    csbi->dwCursorPosition.X = 0;
+    csbi->dwCursorPosition.Y++;
+
+    if (csbi->dwCursorPosition.Y < csbi->dwSize.Y) return 1;
+
+    src.Top    = 1; 
+    src.Bottom = csbi->dwSize.Y - 1; 
+    src.Left   = 0; 
+    src.Right  = csbi->dwSize.X - 1; 
+    
+    dst.X      = 0; 
+    dst.Y      = 0;
+	
+    ci.Attributes = csbi->wAttributes;
+    ci.Char.UnicodeChar = ' '; 
+    
+    csbi->dwCursorPosition.Y--;
+    if (!ScrollConsoleScreenBufferW(hCon, &src, NULL, dst, &ci))
+	return 0;
+    return 1;
+}
+
+/******************************************************************
+ *		write_block
+ *
+ * WriteConsoleOutput helper: writes a block of non special characters
+ *
+ */
+static int     	write_block(HANDLE hCon, CONSOLE_SCREEN_BUFFER_INFO* csbi,
+			    DWORD mode, LPWSTR ptr, int len)
+{
+    int	blk;	/* number of chars to write on first line */
+
+    if (len <= 0) return 1;
+
+    blk = min(len, csbi->dwSize.X - csbi->dwCursorPosition.X);
+
+    if (write_char(hCon, ptr, blk, &csbi->dwCursorPosition) != blk)
+	return 0;
+
+    if (blk < len) /* special handling for right border */
+    {
+	if (mode & ENABLE_WRAP_AT_EOL_OUTPUT) /* writes remaining on next line */
+	{
+	    if (!next_line(hCon, csbi) ||
+		write_char(hCon, ptr + blk, len - blk, &csbi->dwCursorPosition) != len - blk)
+		return 0;
+	}
+	else /* all remaining chars should be written on last column, so only write the last one */
+	{
+	    csbi->dwCursorPosition.X = csbi->dwSize.X - 1;
+	    if (write_char(hCon, ptr + len - 1, 1, &csbi->dwCursorPosition) != 1)
+		return 0;
+	    csbi->dwCursorPosition.X = csbi->dwSize.X - 1;
+	}
+    }
+    return 1;
+}   
+
+/***********************************************************************
+ *            WriteConsoleW   (KERNEL32.@)
+ */
+BOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumberOfCharsToWrite,
+			  LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved)
+{
+    DWORD			mode;
+    DWORD			nw = 0;
+    WCHAR*			psz = (WCHAR*)lpBuffer;
+    CONSOLE_SCREEN_BUFFER_INFO	csbi;
+    int				k, first = 0;
+    
+    TRACE("%d %s %ld %p %p\n", 
+	  hConsoleOutput, debugstr_wn(lpBuffer, nNumberOfCharsToWrite),
+	  nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved);
+    
+    if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0;
+    
+    if (!GetConsoleMode(hConsoleOutput, &mode) || 
+	!GetConsoleScreenBufferInfo(hConsoleOutput, &csbi))
+	return FALSE;
+    
+    if (mode & ENABLE_PROCESSED_OUTPUT)
+    {
+	int	i;
+	
+	for (i = 0; i < nNumberOfCharsToWrite; i++)
+	{
+	    switch (psz[i])
+	    {
+	    case '\b': case '\t': case '\n': case '\a': case '\r':
+		/* don't handle here the i-th char... done below */
+		if ((k = i - first) > 0)
+		{
+		    if (!write_block(hConsoleOutput, &csbi, mode, &psz[first], k))
+			goto the_end;
+		    nw += k;
+		}
+		first = i + 1;
+		nw++;
+	    }
+	    switch (psz[i])
+	    {
+	    case '\b':
+		if (csbi.dwCursorPosition.X > 0) csbi.dwCursorPosition.X--;
+		break;
+	    case '\t':
+	        {
+		    WCHAR tmp[8] = {' ',' ',' ',' ',' ',' ',' ',' '};
+		    
+		    if (!write_block(hConsoleOutput, &csbi, mode, tmp, 
+				     ((csbi.dwCursorPosition.X + 8) & ~7) - csbi.dwCursorPosition.X))
+			goto the_end;
+		}
+		break;
+	    case '\n':
+		next_line(hConsoleOutput, &csbi);
+		break;
+ 	    case '\a':
+		Beep(400, 300);
+ 		break; 
+	    case '\r':
+		csbi.dwCursorPosition.X = 0;
+		break;
+	    default:
+		break;
+	    }
+	}
+    }
+    
+    /* write the remaining block (if any) if processed output is enabled, or the
+     * entire buffer otherwise
+     */
+    if ((k = nNumberOfCharsToWrite - first) > 0)
+    {
+	if (!write_block(hConsoleOutput, &csbi, mode, &psz[first], k))
+	    goto the_end;
+	nw += k;
+    }
+    
+ the_end:
+    SetConsoleCursorPosition(hConsoleOutput, csbi.dwCursorPosition);
+    if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = nw;
+    return nw != 0;
+}
+
+
+/***********************************************************************
+ *            WriteConsoleA   (KERNEL32.@)
+ */
+BOOL WINAPI WriteConsoleA(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumberOfCharsToWrite,
+			  LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved)
+{
+    BOOL	ret;
+    LPWSTR	xstring;
+    DWORD 	n;
+    
+    n = MultiByteToWideChar(CP_ACP, 0, lpBuffer, nNumberOfCharsToWrite, NULL, 0);
+    
+    if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0;
+    xstring = HeapAlloc(GetProcessHeap(), 0, n * sizeof(WCHAR));
+    if (!xstring) return 0;
+    
+    MultiByteToWideChar(CP_ACP, 0, lpBuffer, nNumberOfCharsToWrite, xstring, n);
+    
+    ret = WriteConsoleW(hConsoleOutput, xstring, n, lpNumberOfCharsWritten, 0);
+    
+    HeapFree(GetProcessHeap(), 0, xstring);
+    
+    return ret;
+}
+
+/***********************************************************************
+ *            WriteConsoleOutputA   (KERNEL32.@)
+ */
+BOOL WINAPI WriteConsoleOutputA(HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COORD dwBufferSize,
+				COORD dwBufferCoord, LPSMALL_RECT lpWriteRegion)
+{
+    CHAR_INFO	*ciw;
+    int		i;
+    BOOL	ret;
+    
+    ciw = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR_INFO) * dwBufferSize.X * dwBufferSize.Y);
+    if (!ciw) return FALSE;
+    
+    for (i = 0; i < dwBufferSize.X * dwBufferSize.Y; i++)
+    {
+	ciw[i].Attributes = lpBuffer[i].Attributes;
+	MultiByteToWideChar(CP_ACP, 0, &lpBuffer[i].Char.AsciiChar, 1, &ciw[i].Char.UnicodeChar, 1);
+    }
+    ret = WriteConsoleOutputW(hConsoleOutput, ciw, dwBufferSize, dwBufferCoord, lpWriteRegion);
+    HeapFree(GetProcessHeap(), 0, ciw);
+    
+    return ret;
+}
+
+/***********************************************************************
+ *            WriteConsoleOutputW   (KERNEL32.@)
+ */
+BOOL WINAPI WriteConsoleOutputW(HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COORD dwBufferSize,
+				COORD dwBufferCoord, LPSMALL_RECT lpWriteRegion)
+{
+    short int	w, h;
+    unsigned	y;
+    DWORD	ret = TRUE;
+    DWORD	actual_width;
+    
+    TRACE("(%x,%p,(%d,%d),(%d,%d),(%d,%dx%d,%d)\n", 
+	  hConsoleOutput, lpBuffer, dwBufferSize.X, dwBufferSize.Y, dwBufferCoord.X, dwBufferCoord.Y,
+	  lpWriteRegion->Left, lpWriteRegion->Top, lpWriteRegion->Right, lpWriteRegion->Bottom);
+    
+    w = min(lpWriteRegion->Right - lpWriteRegion->Left + 1, dwBufferSize.X - dwBufferCoord.X);
+    h = min(lpWriteRegion->Bottom - lpWriteRegion->Top + 1, dwBufferSize.Y - dwBufferCoord.Y);
+    
+    if (w <= 0 || h <= 0)
+    {
+	memset(lpWriteRegion, 0, sizeof(SMALL_RECT));
+	return FALSE;
+    }
+    
+    /* this isn't supported for now, even if hConsoleOutput's row size fits in a single
+     * server's request... it would request cropping on client side
+     */
+    if (w * sizeof(CHAR_INFO) > REQUEST_MAX_VAR_SIZE)
+    {
+	FIXME("This isn't supported yet, too wide CHAR_INFO array (%d)\n", w);
+	memset(lpWriteRegion, 0, sizeof(SMALL_RECT));
+	return FALSE;
+    }
+
+    actual_width = w;
+    for (y = 0; ret && y < h; y++)
+    {
+	SERVER_START_VAR_REQ(write_console_output, w * sizeof(CHAR_INFO))
+	{
+	    req->handle = hConsoleOutput;
+	    req->mode = WRITE_CONSOLE_MODE_TEXTATTR;
+	    req->x = lpWriteRegion->Left;
+	    req->y = lpWriteRegion->Top + y;
+	    memcpy(server_data_ptr(req), &lpBuffer[(y + dwBufferCoord.Y) * dwBufferSize.X + dwBufferCoord.X], w * sizeof(CHAR_INFO));
+	    if ((ret = !SERVER_CALL()))
+		actual_width = min(actual_width, req->written);
+	}
+	SERVER_END_VAR_REQ;
+    }
+    lpWriteRegion->Bottom = lpWriteRegion->Top + h;
+    lpWriteRegion->Right = lpWriteRegion->Left + actual_width;
+
     return ret;
 }
 
@@ -1276,46 +1381,58 @@
  *
  * RETURNS STD
  */
-BOOL WINAPI SetConsoleCursorPosition( HANDLE hcon, COORD pos )
+BOOL WINAPI SetConsoleCursorPosition(HANDLE hcon, COORD pos)
 {
-    char 	xbuf[20];
-    DWORD	xlen;
+    BOOL 			ret;
+    CONSOLE_SCREEN_BUFFER_INFO	csbi;
+    int				do_move = 0;
+    int				w, h;
 
-    /* make console complex only if we change lines, not just in the line */
-    if (pos.Y)
-    	CONSOLE_make_complex(hcon);
+    TRACE("%x %d %d\n", hcon, pos.X, pos.Y);
 
-    TRACE("%d (%dx%d)\n", hcon, pos.X , pos.Y );
-    /* x are columns, y rows */
-    if (pos.Y) 
-    	/* full screen cursor absolute positioning */
-	sprintf(xbuf,"%c[%d;%dH", 0x1B, pos.Y+1, pos.X+1);
-    else
-    	/* relative cursor positioning in line (\r to go to 0) */
-	sprintf(xbuf,"\r%c[%dC", 0x1B, pos.X);
-    /* FIXME: store internal if we start using own console buffers */
-    WriteFile(hcon,xbuf,strlen(xbuf),&xlen,NULL);
-    return TRUE;
-}
+    SERVER_START_REQ(set_console_output_info)
+    {
+        req->handle         = hcon;
+        req->cursor_x       = pos.X;
+        req->cursor_y       = pos.Y;
+        req->mask           = SET_CONSOLE_OUTPUT_INFO_CURSOR_POS;
+        ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
 
-/***********************************************************************
- *            GetNumberOfConsoleInputEvents   (KERNEL32.@)
- */
-BOOL WINAPI GetNumberOfConsoleInputEvents(HANDLE hcon,LPDWORD nrofevents)
-{
-    CONSOLE_get_input (hcon, FALSE);
+    if (!ret || !GetConsoleScreenBufferInfo(hcon, &csbi))
+	return FALSE;
 
-    return read_console_input( hcon, NULL, 0, nrofevents, FALSE );
-}
+    /* if cursor is no longer visible, scroll the visible window... */
+    w = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+    h = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+    if (pos.X < csbi.srWindow.Left)
+    {
+	csbi.srWindow.Left   = min(pos.X, csbi.dwSize.X - w);
+	do_move++;
+    } 
+    else if (pos.X > csbi.srWindow.Right)
+    {
+	csbi.srWindow.Left   = max(pos.X, w) - w + 1;
+	do_move++;
+    }
+    csbi.srWindow.Right  = csbi.srWindow.Left + w - 1;
 
-/***********************************************************************
- *            GetNumberOfConsoleMouseButtons   (KERNEL32.@)
- */
-BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
-{
-    FIXME("(%p): stub\n", nrofbuttons);
-    *nrofbuttons = 2;
-    return TRUE;
+    if (pos.Y < csbi.srWindow.Top)
+    {
+	csbi.srWindow.Top    = min(pos.Y, csbi.dwSize.Y - h);
+	do_move++;
+    }
+    else if (pos.Y > csbi.srWindow.Bottom)
+    {
+	csbi.srWindow.Top   = max(pos.Y, h) - h + 1;
+	do_move++;
+    }
+    csbi.srWindow.Bottom = csbi.srWindow.Top + h - 1;
+
+    ret = (do_move) ? SetConsoleWindowInfo(hcon, TRUE, &csbi.srWindow) : TRUE;
+
+    return ret;
 }
 
 /******************************************************************************
@@ -1329,11 +1446,11 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI GetConsoleCursorInfo( HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo )
+BOOL WINAPI GetConsoleCursorInfo(HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo)
 {
     BOOL ret;
 
-    SERVER_START_REQ( get_console_info )
+    SERVER_START_REQ(get_console_output_info)
     {
         req->handle = hcon;
         ret = !SERVER_CALL_ERR();
@@ -1351,28 +1468,23 @@
 /******************************************************************************
  * SetConsoleCursorInfo [KERNEL32.@]  Sets size and visibility of cursor
  *
+ * PARAMS
+ * 	hcon	[I] Handle to console screen buffer
+ * 	cinfo	[I] Address of cursor information
  * RETURNS
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI SetConsoleCursorInfo( 
-    HANDLE hcon,                /* [in] Handle to console screen buffer */
-    LPCONSOLE_CURSOR_INFO cinfo)  /* [in] Address of cursor information */
+BOOL WINAPI SetConsoleCursorInfo(HANDLE hCon, LPCONSOLE_CURSOR_INFO cinfo)
 {
-    char	buf[8];
-    DWORD	xlen;
     BOOL ret;
 
-    CONSOLE_make_complex(hcon);
-    sprintf(buf,"\033[?25%c",cinfo->bVisible?'h':'l');
-    WriteFile(hcon,buf,strlen(buf),&xlen,NULL);
-
-    SERVER_START_REQ( set_console_info )
+    SERVER_START_REQ(set_console_output_info)
     {
-        req->handle         = hcon;
+        req->handle         = hCon;
         req->cursor_size    = cinfo->dwSize;
         req->cursor_visible = cinfo->bVisible;
-        req->mask           = SET_CONSOLE_INFO_CURSOR;
+        req->mask           = SET_CONSOLE_OUTPUT_INFO_CURSOR_GEOM;
         ret = !SERVER_CALL_ERR();
     }
     SERVER_END_REQ;
@@ -1383,17 +1495,42 @@
 /******************************************************************************
  * SetConsoleWindowInfo [KERNEL32.@]  Sets size and position of console
  *
+ * PARAMS
+ *	hcon	        [I] Handle to console screen buffer
+ *	bAbsolute	[I] Coordinate type flag
+ *	window		[I] Address of new window rectangle
  * RETURNS
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI SetConsoleWindowInfo(
-    HANDLE hcon,       /* [in] Handle to console screen buffer */
-    BOOL bAbsolute,    /* [in] Coordinate type flag */
-    LPSMALL_RECT window) /* [in] Address of new window rectangle */
+BOOL WINAPI SetConsoleWindowInfo(HANDLE hCon, BOOL bAbsolute, LPSMALL_RECT window)
 {
-    FIXME("(%x,%d,%p): stub\n", hcon, bAbsolute, window);
-    return TRUE;
+    SMALL_RECT	p = *window;
+    BOOL	ret;
+
+    if (!bAbsolute)
+    {
+	CONSOLE_SCREEN_BUFFER_INFO	csbi;
+	if (!GetConsoleScreenBufferInfo(hCon, &csbi))
+	    return FALSE;
+	p.Left   += csbi.srWindow.Left;
+	p.Top    += csbi.srWindow.Top;
+	p.Right  += csbi.srWindow.Left;
+	p.Bottom += csbi.srWindow.Top;
+    }
+    SERVER_START_REQ(set_console_output_info)
+    {
+        req->handle         = hCon;
+	req->win_left       = p.Left;
+	req->win_top        = p.Top;
+	req->win_right      = p.Right;
+	req->win_bottom     = p.Bottom;
+        req->mask           = SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW;
+        ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+
+    return ret;
 }
 
 
@@ -1407,24 +1544,19 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttr)
+BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttr)
 {
-    const int colormap[8] = {
-    	0,4,2,6,
-	1,5,3,7,
-    };
-    DWORD xlen;
-    char buffer[20];
+    BOOL ret;
 
-    TRACE("(%d,%d)\n",hConsoleOutput,wAttr);
-    sprintf(buffer,"%c[0;%s3%d;4%dm",
-	27,
-	(wAttr & FOREGROUND_INTENSITY)?"1;":"",
-	colormap[wAttr&7],
-	colormap[(wAttr&0x70)>>4]
-    );
-    WriteFile(hConsoleOutput,buffer,strlen(buffer),&xlen,NULL);
-    return TRUE;
+    SERVER_START_REQ(set_console_output_info)
+    {
+        req->handle         = hConsoleOutput;
+        req->attr	    = wAttr;
+        req->mask           = SET_CONSOLE_OUTPUT_INFO_ATTR;
+        ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+    return ret;
 }
 
 
@@ -1439,11 +1571,30 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI SetConsoleScreenBufferSize( HANDLE hConsoleOutput, 
-                                          COORD dwSize )
+BOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput, COORD dwSize)
 {
-    FIXME("(%d,%dx%d): stub\n",hConsoleOutput,dwSize.X,dwSize.Y);
-    return TRUE;
+    BOOL ret;
+
+    /* FIXME: most code relies on the fact we can transfer a complete row at a time...
+     * so check if it's possible...
+     */
+    if (dwSize.X > REQUEST_MAX_VAR_SIZE / 4)
+    {
+	FIXME("too wide width not supported\n");
+	SetLastError(STATUS_INVALID_PARAMETER);
+	return FALSE;
+    }
+
+    SERVER_START_REQ(set_console_output_info)
+    {
+        req->handle	= hConsoleOutput;
+        req->width	= dwSize.X;
+        req->height	= dwSize.Y;
+	req->mask       = SET_CONSOLE_OUTPUT_INFO_SIZE;
+        ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+    return ret;
 }
 
 
@@ -1461,21 +1612,14 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI FillConsoleOutputCharacterA(
-    HANDLE hConsoleOutput,
-    BYTE cCharacter,
-    DWORD nLength,
-    COORD dwCoord,
-    LPDWORD lpNumCharsWritten)
+BOOL WINAPI FillConsoleOutputCharacterA(HANDLE hConsoleOutput, BYTE cCharacter,
+					DWORD nLength, COORD dwCoord, LPDWORD lpNumCharsWritten)
 {
-    DWORD 	count;
-    DWORD	xlen;
+    WCHAR	wch;
 
-    SetConsoleCursorPosition(hConsoleOutput,dwCoord);
-    for(count=0;count<nLength;count++)
-	WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
-    *lpNumCharsWritten = nLength;
-    return TRUE;
+    MultiByteToWideChar(CP_ACP, 0, &cCharacter, 1, &wch, 1);
+
+    return FillConsoleOutputCharacterW(hConsoleOutput, wch, nLength, dwCoord, lpNumCharsWritten);
 }
 
 
@@ -1493,23 +1637,42 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,
-                                            WCHAR cCharacter,
-                                            DWORD nLength,
-                                           COORD dwCoord, 
-                                            LPDWORD lpNumCharsWritten)
+BOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput, WCHAR cCharacter,
+					DWORD nLength, COORD dwCoord, LPDWORD lpNumCharsWritten)
 {
-    DWORD	count;
-    DWORD	xlen;
+    CONSOLE_SCREEN_BUFFER_INFO	csbi;
+    int				written;
+    DWORD			initLen = nLength;
 
-    SetConsoleCursorPosition(hConsoleOutput,dwCoord);
-    /* FIXME: not quite correct ... but the lower part of UNICODE char comes
-     * first 
-     */
-    for(count=0;count<nLength;count++)
-	WriteFile(hConsoleOutput,&cCharacter,1,&xlen,NULL);
-    *lpNumCharsWritten = nLength;
-    return TRUE;
+    TRACE("(%d,%s,%ld,(%dx%d),%p)\n", 
+	  hConsoleOutput, debugstr_wn(&cCharacter, 1), nLength, 
+	  dwCoord.X, dwCoord.Y, lpNumCharsWritten);
+
+    if (!GetConsoleScreenBufferInfo(hConsoleOutput, &csbi))
+	return FALSE;
+
+    while (nLength)
+    {
+	SERVER_START_VAR_REQ(write_console_output, 
+			     min(csbi.dwSize.X - dwCoord.X, nLength) * sizeof(WCHAR))
+	{
+	    req->handle = hConsoleOutput;
+	    req->x      = dwCoord.X;
+	    req->y      = dwCoord.Y;
+	    req->mode   = WRITE_CONSOLE_MODE_TEXTSTDATTR|WRITE_CONSOLE_MODE_UNIFORM;
+	    memcpy(server_data_ptr(req), &cCharacter, sizeof(WCHAR));
+	    written = SERVER_CALL_ERR() ? 0 : req->written;
+	}
+	SERVER_END_VAR_REQ;
+
+	if (!written) break;
+	nLength -= written;
+	dwCoord.X = 0;
+	if (++dwCoord.Y == csbi.dwSize.Y) break;
+    }
+    
+    if (lpNumCharsWritten) *lpNumCharsWritten = initLen - nLength;
+    return initLen != nLength;
 }
 
 
@@ -1527,178 +1690,384 @@
  *    Success: TRUE
  *    Failure: FALSE
  */
-BOOL WINAPI FillConsoleOutputAttribute( HANDLE hConsoleOutput, 
-              WORD wAttribute, DWORD nLength, COORD dwCoord, 
-              LPDWORD lpNumAttrsWritten)
+BOOL WINAPI FillConsoleOutputAttribute(HANDLE hConsoleOutput, WORD wAttribute, 
+				       DWORD nLength, COORD dwCoord, LPDWORD lpNumAttrsWritten)
 {
-    FIXME("(%d,%d,%ld,%dx%d,%p): stub\n", hConsoleOutput,
-          wAttribute,nLength,dwCoord.X,dwCoord.Y,lpNumAttrsWritten);
-    *lpNumAttrsWritten = nLength;
+    CONSOLE_SCREEN_BUFFER_INFO	csbi;
+    int				written;
+    DWORD			initLen = nLength;
+    
+    TRACE("(%d,%d,%ld,(%dx%d),%p)\n", 
+	  hConsoleOutput, wAttribute, nLength, dwCoord.X, dwCoord.Y, lpNumAttrsWritten);
+    
+    if (!GetConsoleScreenBufferInfo(hConsoleOutput, &csbi))
+	return FALSE;
+
+    while (nLength)
+    {
+	SERVER_START_VAR_REQ(write_console_output, 
+			     min(csbi.dwSize.X - dwCoord.X, nLength) * sizeof(WCHAR))
+	{
+	    req->handle = hConsoleOutput;
+	    req->x      = dwCoord.X;
+	    req->y      = dwCoord.Y;
+	    req->mode   = WRITE_CONSOLE_MODE_ATTR|WRITE_CONSOLE_MODE_UNIFORM;
+	    memcpy(server_data_ptr(req), &wAttribute, sizeof(WORD));
+	    written = SERVER_CALL_ERR() ? 0 : req->written;
+	}
+	SERVER_END_VAR_REQ;
+
+	if (!written) break;
+	nLength -= written;
+	dwCoord.X = 0;
+	if (++dwCoord.Y == csbi.dwSize.Y) break;
+    }
+
+    if (lpNumAttrsWritten) *lpNumAttrsWritten = initLen - nLength;
+    return initLen != nLength;
+}
+
+/******************************************************************************
+ * ScrollConsoleScreenBufferA [KERNEL32.@]
+ * 
+ */
+BOOL WINAPI ScrollConsoleScreenBufferA(HANDLE hConsoleOutput, LPSMALL_RECT lpScrollRect, 
+				       LPSMALL_RECT lpClipRect, COORD dwDestOrigin, 
+				       LPCHAR_INFO lpFill)
+{
+    CHAR_INFO	ciw;
+    
+    ciw.Attributes = lpFill->Attributes;
+    MultiByteToWideChar(CP_ACP, 0, &lpFill->Char.AsciiChar, 1, &ciw.Char.UnicodeChar, 1);
+    
+    return ScrollConsoleScreenBufferW(hConsoleOutput, lpScrollRect, lpClipRect, 
+				      dwDestOrigin, &ciw);
+}
+
+/******************************************************************
+ *		fill_line_uniform
+ *
+ * Helper function for ScrollConsoleScreenBufferW
+ * Fills a part of a line with a constant character info
+ */
+static void fill_line_uniform(HANDLE hConsoleOutput, int i, int j, int len, LPCHAR_INFO lpFill)
+{
+    SERVER_START_VAR_REQ(write_console_output, len * sizeof(CHAR_INFO))
+    {
+	req->handle = hConsoleOutput;
+	req->x      = i;
+	req->y      = j;
+	req->mode   = WRITE_CONSOLE_MODE_TEXTATTR|WRITE_CONSOLE_MODE_UNIFORM;
+	memcpy(server_data_ptr(req), lpFill, sizeof(CHAR_INFO));
+	SERVER_CALL_ERR();
+    }
+    SERVER_END_VAR_REQ;
+}
+
+/******************************************************************************
+ * ScrollConsoleScreenBufferW [KERNEL32.@]
+ * 
+ */
+
+BOOL WINAPI ScrollConsoleScreenBufferW(HANDLE hConsoleOutput, LPSMALL_RECT lpScrollRect, 
+				       LPSMALL_RECT lpClipRect, COORD dwDestOrigin, 
+				       LPCHAR_INFO lpFill)
+{
+    SMALL_RECT			dst;
+    DWORD			ret;
+    int				i, j;
+    int				start = -1;
+    SMALL_RECT			clip;
+    CONSOLE_SCREEN_BUFFER_INFO	csbi;
+    BOOL			inside;
+	
+    if (lpClipRect)
+	TRACE("(%d,(%d,%d-%d,%d),(%d,%d-%d,%d),%d-%d,%p)\n", hConsoleOutput, 
+	      lpScrollRect->Left, lpScrollRect->Top,
+	      lpScrollRect->Right, lpScrollRect->Bottom,
+	      lpClipRect->Left, lpClipRect->Top,
+	      lpClipRect->Right, lpClipRect->Bottom,
+	      dwDestOrigin.X, dwDestOrigin.Y, lpFill);
+    else
+	TRACE("(%d,(%d,%d-%d,%d),(nil),%d-%d,%p)\n", hConsoleOutput, 
+	      lpScrollRect->Left, lpScrollRect->Top,
+	      lpScrollRect->Right, lpScrollRect->Bottom,
+	      dwDestOrigin.X, dwDestOrigin.Y, lpFill);
+    
+    if (!GetConsoleScreenBufferInfo(hConsoleOutput, &csbi))
+	return FALSE;
+
+    /* step 1: get dst rect */
+    dst.Left = dwDestOrigin.X;
+    dst.Top = dwDestOrigin.Y;
+    dst.Right = dst.Left + (lpScrollRect->Right - lpScrollRect->Left);
+    dst.Bottom = dst.Top + (lpScrollRect->Bottom - lpScrollRect->Top);
+    
+    /* step 2a: compute the final clip rect (optional passed clip and screen buffer limits */
+    if (lpClipRect)
+    {
+	clip.Left   = max(0, lpClipRect->Left);
+	clip.Right  = min(csbi.dwSize.X - 1, lpClipRect->Right);
+	clip.Top    = max(0, lpClipRect->Top);
+	clip.Bottom = min(csbi.dwSize.Y - 1, lpClipRect->Bottom);
+    }
+    else
+    {
+	clip.Left   = 0;
+	clip.Right  = csbi.dwSize.X - 1;
+	clip.Top    = 0;
+	clip.Bottom = csbi.dwSize.Y - 1;
+    }
+    if (clip.Left > clip.Right || clip.Top > clip.Bottom) return FALSE;
+
+    /* step 2b: clip dst rect */
+    if (dst.Left   < clip.Left  ) dst.Left   = clip.Left;
+    if (dst.Top    < clip.Top   ) dst.Top    = clip.Top;
+    if (dst.Right  > clip.Right ) dst.Right  = clip.Right;
+    if (dst.Bottom > clip.Bottom) dst.Bottom = clip.Bottom;
+    
+    /* step 3: transfer the bits */
+    SERVER_START_REQ(move_console_output)
+    {
+        req->handle = hConsoleOutput;
+	req->x_src = lpScrollRect->Left;
+	req->y_src = lpScrollRect->Top;
+	req->x_dst = dst.Left;
+	req->y_dst = dst.Top;
+	req->w = dst.Right - dst.Left + 1;
+	req->h = dst.Bottom - dst.Top + 1;
+	ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_REQ;
+
+    if (!ret) return FALSE;
+
+    /* step 4: clean out the exposed part */
+
+    /* have to write celll [i,j] if it is not in dst rect (because it has already
+     * been written to by the scroll) and is in clip (we shall not write
+     * outside of clip)
+     */
+    for (j = max(lpScrollRect->Top, clip.Top); j <= min(lpScrollRect->Bottom, clip.Bottom); j++)
+    {
+	inside = dst.Top <= j && j <= dst.Bottom;
+	start = -1;
+	for (i = max(lpScrollRect->Left, clip.Left); i <= min(lpScrollRect->Right, clip.Right); i++)
+	{
+	    if (inside && dst.Left <= i && i <= dst.Right)
+	    {
+		if (start != -1)
+		{
+		    fill_line_uniform(hConsoleOutput, start, j, i - start, lpFill);
+		    start = -1;
+		}
+	    }
+	    else
+	    {
+		if (start == -1) start = i;
+	    }
+	}
+	if (start != -1)
+	    fill_line_uniform(hConsoleOutput, start, j, i - start, lpFill);
+    }
+
     return TRUE;
 }
 
 /******************************************************************************
  * ReadConsoleOutputCharacterA [KERNEL32.@]
  * 
- * BUGS
- *   Unimplemented
  */
-BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput, 
-	      LPSTR lpstr, DWORD dword, COORD coord, LPDWORD lpdword)
+BOOL WINAPI ReadConsoleOutputCharacterA(HANDLE hConsoleOutput, LPSTR lpstr, DWORD toRead, 
+					COORD coord, LPDWORD lpdword)
 {
-    FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,lpstr,
-	  dword,coord.X,coord.Y,lpdword);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD	read;
+    LPWSTR	wptr = HeapAlloc(GetProcessHeap(), 0, toRead * sizeof(WCHAR));
+    BOOL	ret;
+
+    if (lpdword) *lpdword = 0;
+    if (!wptr) return FALSE;
+
+    ret = ReadConsoleOutputCharacterW(hConsoleOutput, wptr, toRead, coord, &read);
+
+    read = WideCharToMultiByte(CP_ACP, 0, wptr, read, lpstr, toRead, NULL, NULL);
+    if (lpdword) *lpdword = read;
+
+    HeapFree(GetProcessHeap(), 0, wptr);
+
+    return ret;
 }
 
 /******************************************************************************
  * ReadConsoleOutputCharacterW [KERNEL32.@]
  * 
- * BUGS
- *   Unimplemented
  */
-BOOL WINAPI ReadConsoleOutputCharacterW(HANDLE hConsoleOutput, 
-	      LPWSTR lpstr, DWORD dword, COORD coord, LPDWORD lpdword)
+BOOL WINAPI ReadConsoleOutputCharacterW(HANDLE hConsoleOutput, LPWSTR lpstr, DWORD toRead, 
+					COORD coord, LPDWORD lpdword)
 {
-    FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,lpstr,
-	  dword,coord.X,coord.Y,lpdword);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD	read = 0;
+    DWORD	ret = TRUE;
+    int		i;
+    DWORD*	ptr;
+
+    TRACE("(%d,%p,%ld,%dx%d,%p)\n", hConsoleOutput, lpstr, toRead, coord.X, coord.Y, lpdword);
+
+    while (ret && (read < toRead))
+    {
+	SERVER_START_VAR_REQ(read_console_output, REQUEST_MAX_VAR_SIZE)
+	{
+	    req->handle       = (handle_t)hConsoleOutput;
+	    req->x            = coord.X;
+	    req->y            = coord.Y;
+	    req->w            = REQUEST_MAX_VAR_SIZE / 4;
+	    req->h            = 1;
+	    if ((ret = !SERVER_CALL_ERR()))
+	    {
+		ptr = server_data_ptr(req);
+		
+		for (i = 0; i < req->eff_w && read < toRead; i++)
+		{
+		    lpstr[read++] = LOWORD(ptr[i]);
+		}
+		coord.X = 0;	coord.Y++;
+	    }
+	}
+	SERVER_END_VAR_REQ;
+    }
+    if (lpdword) *lpdword = read;
+    
+    TRACE("=> %lu %s\n", read, debugstr_wn(lpstr, read));
+    
+    return ret;
 }
 
 
 /******************************************************************************
- * ScrollConsoleScreenBufferA [KERNEL32.@]
- * 
- * BUGS
- *   Unimplemented
- */
-BOOL WINAPI ScrollConsoleScreenBufferA( HANDLE hConsoleOutput, 
-	      LPSMALL_RECT lpScrollRect, LPSMALL_RECT lpClipRect,
-              COORD dwDestOrigin, LPCHAR_INFO lpFill)
-{
-    FIXME("(%d,%p,%p,%dx%d,%p): stub\n", hConsoleOutput,lpScrollRect,
-	  lpClipRect,dwDestOrigin.X,dwDestOrigin.Y,lpFill);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-
-/******************************************************************************
- * ScrollConsoleScreenBufferW [KERNEL32.@]
- * 
- * BUGS
- *   Unimplemented
- */
-BOOL WINAPI ScrollConsoleScreenBufferW( HANDLE hConsoleOutput, 
-	      LPSMALL_RECT lpScrollRect, LPSMALL_RECT lpClipRect,
-              COORD dwDestOrigin, LPCHAR_INFO lpFill)
-{
-    FIXME("(%d,%p,%p,%dx%d,%p): stub\n", hConsoleOutput,lpScrollRect,
-	  lpClipRect,dwDestOrigin.X,dwDestOrigin.Y,lpFill);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-
-/******************************************************************************
  *  ReadConsoleOutputA [KERNEL32.@]
  * 
- * BUGS
- *   Unimplemented
  */
-BOOL WINAPI ReadConsoleOutputA( HANDLE hConsoleOutput, 
-				LPCHAR_INFO lpBuffer,
-				COORD dwBufferSize,
-				COORD dwBufferCoord,
-				LPSMALL_RECT lpReadRegion )
+BOOL WINAPI ReadConsoleOutputA(HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COORD dwBufferSize,
+			       COORD dwBufferCoord, LPSMALL_RECT lpReadRegion)
 {
-    FIXME("(%d,%p,%dx%d,%dx%d,%p): stub\n", hConsoleOutput, lpBuffer,
-	  dwBufferSize.X, dwBufferSize.Y, dwBufferSize.X, dwBufferSize.Y, 
-	  lpReadRegion);
+    BOOL	ret;
+    int		x, y;
+    int		pos;
     
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    ret = ReadConsoleOutputW(hConsoleOutput, lpBuffer, dwBufferSize, dwBufferCoord, lpReadRegion);
+    if (!ret) return FALSE;
+    for (y = 0; y <= lpReadRegion->Bottom - lpReadRegion->Top; y++)
+    {
+	for (x = 0; x <= lpReadRegion->Right - lpReadRegion->Left; x++)
+	{
+	    pos = (dwBufferCoord.Y + y) * dwBufferSize.X + dwBufferCoord.X + x;
+	    WideCharToMultiByte(CP_ACP, 0, &lpBuffer[pos].Char.UnicodeChar, 1, 
+				&lpBuffer[pos].Char.AsciiChar, 1, NULL, NULL);
+	}
+    }
+    return TRUE;
 }
 
 /******************************************************************************
  *  ReadConsoleOutputW [KERNEL32.@]
  * 
- * BUGS
- *   Unimplemented
  */
-BOOL WINAPI ReadConsoleOutputW( HANDLE hConsoleOutput, 
-				LPCHAR_INFO lpBuffer,
-				COORD dwBufferSize,
-				COORD dwBufferCoord,
-				LPSMALL_RECT lpReadRegion )
+BOOL WINAPI ReadConsoleOutputW(HANDLE hConsoleOutput, LPCHAR_INFO lpBuffer, COORD dwBufferSize,
+			       COORD dwBufferCoord, LPSMALL_RECT lpReadRegion)
 {
-    FIXME("(%d,%p,%dx%d,%dx%d,%p): stub\n", hConsoleOutput, lpBuffer,
-	  dwBufferSize.X, dwBufferSize.Y, dwBufferSize.X, dwBufferSize.Y, 
-	  lpReadRegion);
+    int		w, h;
+    int		actual_width;
+    int		y;
+    BOOL	ret = TRUE;
     
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    w = min(lpReadRegion->Right - lpReadRegion->Left + 1, dwBufferSize.X - dwBufferCoord.X);
+    h = min(lpReadRegion->Bottom - lpReadRegion->Top + 1, dwBufferSize.Y - dwBufferCoord.Y);
+    
+    if (w <= 0 || h <= 0) goto got_err;
+
+    /* this isn't supported for now, even if hConsoleOutput's row size fits in a single
+     * server's request... it would request cropping on client side
+     */
+    if (w * sizeof(CHAR_INFO) > REQUEST_MAX_VAR_SIZE)
+    {
+	FIXME("This isn't supported yet, too wide CHAR_INFO array (%d)\n", w);
+	goto got_err;
+    }
+
+    actual_width = w;
+    for (y = 0; ret && y < h; y++)
+    {
+	SERVER_START_VAR_REQ(read_console_output, w * sizeof(CHAR_INFO))
+	{
+	    req->handle = hConsoleOutput;
+	    req->x = lpReadRegion->Left;
+	    req->y = lpReadRegion->Top;
+	    req->w = w;
+	    req->h = 1;
+	    if ((ret = !SERVER_CALL()))
+	    {
+		actual_width = min(actual_width, req->eff_w);
+		memcpy(&lpBuffer[(y + dwBufferCoord.Y) * dwBufferSize.X + dwBufferCoord.X], 
+		       server_data_ptr(req), 
+		       req->eff_w * sizeof(CHAR_INFO));
+	    }
+	}
+	SERVER_END_VAR_REQ;
+    }
+    if (!ret) goto got_err;
+    
+    lpReadRegion->Bottom = lpReadRegion->Top + y;
+    lpReadRegion->Right = lpReadRegion->Left + actual_width;
+    
+    return ret;
+ got_err:
+    memset(lpReadRegion, 0, sizeof(SMALL_RECT));
     return FALSE;
 }
 
 /******************************************************************************
  *  ReadConsoleOutputAttribute [KERNEL32.@]
  * 
- * BUGS
- *   Unimplemented
  */
-BOOL WINAPI ReadConsoleOutputAttribute( HANDLE hConsoleOutput, 
-					LPWORD lpAttribute,
-					DWORD nLength,
-					COORD dwReadCoord,
-					LPDWORD lpNumberOfAttrsRead)
+BOOL WINAPI ReadConsoleOutputAttribute(HANDLE hConsoleOutput, LPWORD lpAttribute, DWORD nLength,
+				       COORD coord, LPDWORD lpNumberOfAttrsRead)
 {
-    FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput, lpAttribute,
-	  nLength, dwReadCoord.X, dwReadCoord.Y, lpNumberOfAttrsRead);
+    DWORD	read = 0;
+    DWORD	ret = TRUE;
+    int		i;
+    DWORD*	ptr;
     
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-
-/******************************************************************************
- *  SetConsoleCP	 [KERNEL32.@]
- * 
- * BUGS
- *   Unimplemented
- */
-BOOL WINAPI SetConsoleCP( UINT cp )
-{
-    FIXME("(%d): stub\n", cp);
+    TRACE("(%d,%p,%ld,%dx%d,%p)\n", 
+	  hConsoleOutput, lpAttribute, nLength, coord.X, coord.Y, lpNumberOfAttrsRead);
     
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-
-/******************************************************************************
- *  SetConsoleInputExeNameW	 [KERNEL32.@]
- * 
- * BUGS
- *   Unimplemented
- */
-BOOL WINAPI SetConsoleInputExeNameW( LPCWSTR name )
-{
-    FIXME("(%s): stub!\n", debugstr_w(name));
-
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return TRUE;
-}
-
-/******************************************************************************
- *  SetConsoleInputExeNameA	 [KERNEL32.@]
- * 
- * BUGS
- *   Unimplemented
- */
-BOOL WINAPI SetConsoleInputExeNameA( LPCSTR name )
-{
-    FIXME("(%s): stub!\n", name);
-
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return TRUE;
+    while (ret && (read < nLength))
+    {
+	SERVER_START_VAR_REQ(read_console_output, REQUEST_MAX_VAR_SIZE)
+	{
+	    req->handle       = (handle_t)hConsoleOutput;
+	    req->x            = coord.X;
+	    req->y            = coord.Y;
+	    req->w            = REQUEST_MAX_VAR_SIZE / 4;
+	    req->h            = 1;
+	    if (SERVER_CALL_ERR()) 
+	    {
+		ret = FALSE;
+	    }
+	    else
+	    {
+		ptr = server_data_ptr(req);
+		
+		for (i = 0; i < req->eff_w && read < nLength; i++)
+		{
+		    lpAttribute[read++] = HIWORD(ptr[i]);
+		}
+		coord.X = 0;	coord.Y++;
+	    }
+	}
+	SERVER_END_VAR_REQ;
+    }
+    if (lpNumberOfAttrsRead) *lpNumberOfAttrsRead = read;
+    
+    return ret;
 }
 
 /******************************************************************************
@@ -1716,17 +2085,44 @@
  *    Success: TRUE
  *    Failure: FALSE
  * 
- * BUGS
- *   Unimplemented
  */
-BOOL WINAPI WriteConsoleOutputAttribute( HANDLE hConsoleOutput, 
-              CONST WORD *lpAttribute, DWORD nLength, COORD dwCoord, 
-              LPDWORD lpNumAttrsWritten)
+BOOL WINAPI WriteConsoleOutputAttribute(HANDLE hConsoleOutput, CONST WORD *lpAttribute, 
+					DWORD nLength, COORD dwCoord, LPDWORD lpNumAttrsWritten)
 {
-    FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,
+    int		written = 0;
+    int		len;
+    BOOL	ret = TRUE;
+    DWORD	init_len = nLength;
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    
+    TRACE("(%d,%p,%ld,%dx%d,%p)\n", hConsoleOutput,
           lpAttribute,nLength,dwCoord.X,dwCoord.Y,lpNumAttrsWritten);
-    *lpNumAttrsWritten = nLength;
-    return TRUE;
+    
+    if (!GetConsoleScreenBufferInfo(hConsoleOutput, & csbi))
+	return FALSE;
+    
+    while (ret && nLength)
+    {	
+	len = min(nLength * sizeof(WORD), REQUEST_MAX_VAR_SIZE);
+	SERVER_START_VAR_REQ(write_console_output, len)
+	{
+	    req->handle = hConsoleOutput;
+	    req->x      = dwCoord.X;
+	    req->y      = dwCoord.Y;
+	    req->mode   = WRITE_CONSOLE_MODE_ATTR;
+	    memcpy(server_data_ptr(req), &lpAttribute[written],  len);
+	    written = (SERVER_CALL_ERR()) ? 0 : req->written;
+	}
+	SERVER_END_VAR_REQ;
+
+	if (!written) break;
+	nLength -= written;
+	dwCoord.X = 0;
+	if (++dwCoord.Y == csbi.dwSize.Y) break;
+    }
+
+    if (lpNumAttrsWritten) *lpNumAttrsWritten = init_len - nLength;
+    return nLength != init_len;
 }
 
 /******************************************************************************
@@ -1739,18 +2135,30 @@
  *    nLength           [I] Number of cells to write to
  *    dwCoord           [I] Coords of first cell
  *    lpNumCharsWritten [O] Pointer to number of cells written
- * 
- * BUGS
- *   Unimplemented
  */
-BOOL WINAPI WriteConsoleOutputCharacterA( HANDLE hConsoleOutput, 
-              LPCSTR lpCharacter, DWORD nLength, COORD dwCoord, 
-              LPDWORD lpNumCharsWritten)
+BOOL WINAPI WriteConsoleOutputCharacterA(HANDLE hConsoleOutput, LPCSTR lpCharacter, DWORD nLength, 
+					 COORD dwCoord, LPDWORD lpNumCharsWritten)
 {
-    FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,
-          lpCharacter,nLength,dwCoord.X,dwCoord.Y,lpNumCharsWritten);
-    *lpNumCharsWritten = nLength;
-    return TRUE;
+    BOOL	ret;
+    LPWSTR	xstring;
+    DWORD 	n;
+    
+    TRACE("(%d,%s,%ld,%dx%d,%p)\n", hConsoleOutput,
+          debugstr_an(lpCharacter, nLength), nLength, dwCoord.X, dwCoord.Y, lpNumCharsWritten);
+    
+    n = MultiByteToWideChar(CP_ACP, 0, lpCharacter, nLength, NULL, 0);
+    
+    if (lpNumCharsWritten) *lpNumCharsWritten = 0;
+    xstring = HeapAlloc(GetProcessHeap(), 0, n * sizeof(WCHAR));
+    if (!xstring) return FALSE;
+    
+    MultiByteToWideChar(CP_ACP, 0, lpCharacter, nLength, xstring, n);
+    
+    ret = WriteConsoleOutputCharacterW(hConsoleOutput, xstring, n, dwCoord, lpNumCharsWritten);
+    
+    HeapFree(GetProcessHeap(), 0, xstring);
+    
+    return ret;
 }
 
 /******************************************************************************
@@ -1768,15 +2176,123 @@
  *    Success: TRUE
  *    Failure: FALSE
  * 
- * BUGS
- *   Unimplemented
  */
-BOOL WINAPI WriteConsoleOutputCharacterW( HANDLE hConsoleOutput, 
-              LPCWSTR lpCharacter, DWORD nLength, COORD dwCoord, 
-              LPDWORD lpNumCharsWritten)
+BOOL WINAPI WriteConsoleOutputCharacterW(HANDLE hConsoleOutput, LPCWSTR lpCharacter, DWORD nLength, 
+					 COORD dwCoord, LPDWORD lpNumCharsWritten)
 {
-    FIXME("(%d,%p,%ld,%dx%d,%p): stub\n", hConsoleOutput,
-          lpCharacter,nLength,dwCoord.X,dwCoord.Y,lpNumCharsWritten);
-    *lpNumCharsWritten = nLength;
-    return TRUE;
+    int		written = 0;
+    int		len;
+    DWORD	init_len = nLength;
+    CONSOLE_SCREEN_BUFFER_INFO csbi;
+    
+    TRACE("(%d,%s,%ld,%dx%d,%p)\n", hConsoleOutput,
+          debugstr_wn(lpCharacter, nLength), nLength, dwCoord.X, dwCoord.Y, lpNumCharsWritten);
+    
+    if (!GetConsoleScreenBufferInfo(hConsoleOutput, &csbi))
+	return FALSE;
+    
+    while (nLength)
+    {	
+	len = min(nLength * sizeof(WCHAR), REQUEST_MAX_VAR_SIZE);
+	SERVER_START_VAR_REQ(write_console_output, len)
+	{
+	    req->handle = hConsoleOutput;
+	    req->x      = dwCoord.X;
+	    req->y      = dwCoord.Y;
+	    req->mode   = WRITE_CONSOLE_MODE_TEXT;
+	    memcpy(server_data_ptr(req), &lpCharacter[written], len);
+	    written = (SERVER_CALL_ERR()) ? 0 : req->written;
+	}
+	SERVER_END_VAR_REQ;
+
+	if (!written) break;
+	nLength -= written;
+	dwCoord.X += written;
+	if (dwCoord.X >= csbi.dwSize.X)
+	{
+	    dwCoord.X = 0;
+	    if (++dwCoord.Y == csbi.dwSize.Y) break;
+	}
+    }
+
+    if (lpNumCharsWritten) *lpNumCharsWritten = init_len - nLength;
+    return nLength != init_len;
 }
+
+/* ====================================================================
+ *
+ * Console manipulation functions
+ *
+ * ====================================================================*/
+/* some missing functions...
+ * FIXME: those are likely to be defined as undocumented function in kernel32 (or part of them)
+ * should get the right API and implement them
+ *	GetConsoleCommandHistory[AW] (dword dword dword)
+ *	GetConsoleCommandHistoryLength[AW]
+ *	SetConsoleCommandHistoryMode
+ *	SetConsoleNumberOfCommands[AW]
+ */
+int	CONSOLE_GetHistory(int idx, WCHAR* buf, int buf_len)
+{
+    int		len = 0;
+
+    SERVER_START_VAR_REQ(get_console_input_history, REQUEST_MAX_VAR_SIZE)
+    {
+	req->handle = 0;
+	req->index = idx;
+	if (!SERVER_CALL_ERR())
+	{
+	    len = server_data_size(req) / sizeof(WCHAR) + 1;
+	    if (buf)
+	    {
+		len = min(len, buf_len);
+		memcpy(buf, server_data_ptr(req), len * sizeof(WCHAR));
+		buf[len - 1] = 0;
+	    }
+	}
+    }		
+    SERVER_END_VAR_REQ;
+    return len;
+}
+
+/******************************************************************
+ *		CONSOLE_AppendHistory
+ *
+ *
+ */
+BOOL	CONSOLE_AppendHistory(const WCHAR* ptr)
+{
+    size_t	len = strlenW(ptr);
+    BOOL	ret;
+
+    while (len && (ptr[len - 1] == '\n' || ptr[len - 1] == '\r'))
+	len--;
+
+    len *= sizeof(WCHAR);
+    SERVER_START_VAR_REQ(append_console_input_history, len)
+    {
+	req->handle = 0;
+	memcpy(server_data_ptr(req), ptr, len);
+	ret = !SERVER_CALL_ERR();
+    }
+    SERVER_END_VAR_REQ;
+    return ret;
+}
+
+/******************************************************************
+ *		CONSOLE_GetNumHistoryEntries
+ *
+ *
+ */
+unsigned CONSOLE_GetNumHistoryEntries(void)
+{
+    unsigned ret = 0;
+    SERVER_START_REQ(get_console_input_info)
+    {
+	req->handle = 0;
+	if (!SERVER_CALL_ERR()) ret = req->history_index;
+    }
+    SERVER_END_REQ;
+    return ret;
+}
+
diff --git a/win32/editline.c b/win32/editline.c
new file mode 100644
index 0000000..739743c
--- /dev/null
+++ b/win32/editline.c
@@ -0,0 +1,708 @@
+/*
+ * line edition function for Win32 console
+ *
+ * Copyright 2001 Eric Pouech
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wincon.h"
+#include "wine/unicode.h"
+#include "winnls.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(console);
+
+/* console.c */
+extern int CONSOLE_GetHistory(int idx, WCHAR* buf, int buf_len);
+extern BOOL CONSOLE_AppendHistory(const WCHAR *p);
+extern unsigned int CONSOLE_GetNumHistoryEntries(void);
+
+struct WCEL_Context;
+
+typedef struct 
+{
+    WCHAR			val;		/* vk or unicode char */
+    void			(*func)(struct WCEL_Context* ctx);
+} KeyEntry;
+
+typedef struct 
+{
+    DWORD			keyState;	/* keyState (from INPUT_RECORD) to match */
+    BOOL			chkChar;	/* check vk or char */
+    KeyEntry*			entries;	/* array of entries */
+} KeyMap;
+
+typedef struct WCEL_Context {
+    WCHAR*			line;		/* the line being edited */
+    size_t			alloc;		/* number of WCHAR in line */
+    unsigned    		len;		/* number of chars in line */
+    unsigned			ofs;		/* offset for cursor in current line */
+    WCHAR*			yanked;		/* yanked line */
+    unsigned			mark;		/* marked point (emacs mode only) */
+    CONSOLE_SCREEN_BUFFER_INFO	csbi;		/* current state (initial cursor, window size, attribute) */
+    HANDLE			hConIn;
+    HANDLE			hConOut;
+    unsigned			done : 1,	/* to 1 when we're done with editing */
+	                        error : 1;	/* to 1 when an error occurred in the editing */
+    unsigned			histSize;
+    unsigned			histPos;
+    WCHAR*			histCurr;
+} WCEL_Context;
+
+#if 0
+static void WCEL_Dump(WCEL_Context* ctx, const char* pfx)
+{
+    MESSAGE("%s: [line=%s[alloc=%u] ofs=%u len=%u start=(%d,%d) mask=%c%c\n"
+	    "\t\thist=(size=%u pos=%u curr=%s)\n", 
+	    pfx, debugstr_w(ctx->line), ctx->alloc, ctx->ofs, ctx->len, 
+	    ctx->csbi.dwCursorPosition.X, ctx->csbi.dwCursorPosition.Y, 
+	    ctx->done ? 'D' : 'd', ctx->error ? 'E' : 'e',
+	    ctx->histSize, ctx->histPos, debugstr_w(ctx->histCurr));
+}
+#endif
+
+/* ====================================================================
+ *
+ * Console helper functions
+ *
+ * ====================================================================*/
+
+static BOOL WCEL_Get(WCEL_Context* ctx, INPUT_RECORD* ir)
+{
+    DWORD		retv;
+
+    for (;;) 
+    {
+	/* data available ? */
+	if (ReadConsoleInputW(ctx->hConIn, ir, 1, &retv) && retv == 1)
+	    return TRUE;
+	/* then wait... */
+	switch (WaitForSingleObject(ctx->hConIn, INFINITE)) 
+	{
+	case WAIT_OBJECT_0:
+	    break;
+	default:
+	    /* we have checked that hConIn was a console handle (could be sb) */
+	    ERR("Shouldn't happen\n");
+	    /* fall thru */
+	case WAIT_ABANDONED:
+	case WAIT_TIMEOUT:
+	    ctx->error = 1;
+	    ERR("hmm bad situation\n");
+	    return FALSE;
+	}
+    }
+}
+
+static inline void WCEL_Beep(WCEL_Context* ctx)
+{
+    Beep(400, 300);
+}
+
+static inline COORD WCEL_GetCoord(WCEL_Context* ctx, int ofs)
+{
+    COORD c;
+    c.X = ctx->csbi.dwCursorPosition.X + ofs;
+    c.Y = ctx->csbi.dwCursorPosition.Y;
+    return c;
+}
+
+static inline void WCEL_GetRect(WCEL_Context* ctx, LPSMALL_RECT sr, int beg, int end)
+{
+    sr->Left = ctx->csbi.dwCursorPosition.X + beg;
+    sr->Top = ctx->csbi.dwCursorPosition.Y;
+    sr->Right = ctx->csbi.dwCursorPosition.X + end;
+    sr->Bottom = ctx->csbi.dwCursorPosition.Y;
+}
+
+/* ====================================================================
+ *
+ * context manipulation functions
+ *
+ * ====================================================================*/
+
+static BOOL WCEL_Grow(WCEL_Context* ctx, size_t len)
+{
+    if (ctx->csbi.dwCursorPosition.X + ctx->ofs + len >= ctx->csbi.dwSize.X)
+    {
+	FIXME("Current implementation doesn't allow edition to spray across several lines\n");
+	return FALSE;
+    }
+
+    if (ctx->len + len >= ctx->alloc)
+    {
+	WCHAR*	newline;
+	newline = HeapReAlloc(GetProcessHeap(), 0, ctx->line, sizeof(WCHAR) * (ctx->alloc + 32));
+	if (!newline) return FALSE;
+	ctx->line = newline;
+	ctx->alloc += 32;
+    }
+    return TRUE;
+}
+
+static void WCEL_DeleteString(WCEL_Context* ctx, int beg, int end)
+{
+    SMALL_RECT	scl, clp;
+    CHAR_INFO	ci;
+
+    if (end < ctx->len)
+	memmove(&ctx->line[beg], &ctx->line[end], (ctx->len - end) * sizeof(WCHAR));
+    /* make the source rect bigger than the actual rect to that the part outside the clip
+     * rect (before the scroll) will get redrawn after the scroll
+     */
+    WCEL_GetRect(ctx, &scl, end, ctx->len + end - beg);
+    WCEL_GetRect(ctx, &clp, beg, ctx->len);
+
+    ci.Char.UnicodeChar = ' ';
+    ci.Attributes = ctx->csbi.wAttributes;
+    ScrollConsoleScreenBufferW(ctx->hConOut, &scl, &clp, WCEL_GetCoord(ctx, beg), &ci);
+
+    ctx->len -= end - beg;
+    ctx->line[ctx->len] = 0;
+}
+
+static void WCEL_InsertString(WCEL_Context* ctx, const WCHAR* str)
+{
+    size_t	len = lstrlenW(str);
+
+    if (!len || !WCEL_Grow(ctx, len)) return;
+    if (ctx->len > ctx->ofs)
+	memmove(&ctx->line[ctx->ofs + len], &ctx->line[ctx->ofs], (ctx->len - ctx->ofs) * sizeof(WCHAR));
+    memcpy(&ctx->line[ctx->ofs], str, len * sizeof(WCHAR));
+    ctx->len += len;
+    ctx->line[ctx->len] = 0;
+    WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], ctx->len - ctx->ofs, 
+				 WCEL_GetCoord(ctx, ctx->ofs), NULL);
+    ctx->ofs += len;
+}
+
+static void WCEL_InsertChar(WCEL_Context* ctx, WCHAR c)
+{
+    WCHAR	buffer[2];
+
+    /* do not insert 0..31 control characters */
+    if (c < ' ') 
+    {
+	if (c != '\t') return;
+    }
+    buffer[0] = c;
+    buffer[1] = 0;
+    WCEL_InsertString(ctx, buffer);
+}
+
+static void WCEL_SaveYank(WCEL_Context* ctx, int beg, int end)
+{
+    int len = end - beg;
+    ctx->yanked = HeapReAlloc(GetProcessHeap(), 0, ctx->yanked, (len + 1) * sizeof(WCHAR));
+    if (!ctx->yanked) return;
+    memcpy(ctx->yanked, &ctx->line[beg], len * sizeof(WCHAR));
+    ctx->yanked[len] = 0;
+}
+
+/* FIXME NTDLL doesn't export iswalnum, and I don't want to link in msvcrt when most
+ * of the data lay in unicode lib
+ */
+static inline BOOL WCEL_iswalnum(WCHAR wc)
+{
+    return get_char_typeW(wc) & (C1_ALPHA|C1_DIGIT|C1_LOWER|C1_UPPER);
+}
+
+static int WCEL_GetLeftWordTransition(WCEL_Context* ctx, int ofs)
+{
+    ofs--;
+    while (ofs >= 0 && !WCEL_iswalnum(ctx->line[ofs])) ofs--;
+    while (ofs >= 0 && WCEL_iswalnum(ctx->line[ofs])) ofs--;
+    if (ofs >= 0) ofs++;
+    return max(ofs, 0);
+}
+
+static int WCEL_GetRightWordTransition(WCEL_Context* ctx, int ofs)
+{
+    ofs++;
+    while (ofs <= ctx->len && !WCEL_iswalnum(ctx->line[ofs])) ofs++;
+    while (ofs <= ctx->len && WCEL_iswalnum(ctx->line[ofs])) ofs++;
+    return min(ofs, ctx->len);
+}
+
+static WCHAR* WCEL_GetHistory(WCEL_Context* ctx, int idx)
+{
+    WCHAR*	ptr;
+
+    if (idx == ctx->histSize - 1) 
+    {
+	ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(ctx->histCurr) + 1) * sizeof(WCHAR));
+	lstrcpyW(ptr, ctx->histCurr);
+    }
+    else
+    {
+	int	len = CONSOLE_GetHistory(idx, NULL, 0);
+	
+	if ((ptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
+	{
+	    CONSOLE_GetHistory(idx, ptr, len);
+	}
+    }
+    return ptr;
+}
+
+static void	WCEL_HistoryInit(WCEL_Context* ctx)
+{
+    ctx->histPos = CONSOLE_GetNumHistoryEntries();
+    ctx->histSize = ctx->histPos + 1;
+    ctx->histCurr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR));
+}
+
+static void    WCEL_MoveToHist(WCEL_Context* ctx, int idx)
+{
+    WCHAR*	data = WCEL_GetHistory(ctx, idx);
+    int		len = lstrlenW(data) + 1;
+
+    /* save current line edition for recall when needed (FIXME seems broken to me) */
+    if (ctx->histPos == ctx->histSize - 1)
+    {
+	if (ctx->histCurr) HeapFree(GetProcessHeap(), 0, ctx->histCurr);
+	ctx->histCurr = HeapAlloc(GetProcessHeap(), 0, (ctx->len + 1) * sizeof(WCHAR));
+	memcpy(ctx->histCurr, ctx->line, (ctx->len + 1) * sizeof(WCHAR));
+    }
+    /* need to clean also the screen if new string is shorter than old one */
+    WCEL_DeleteString(ctx, 0, ctx->len);
+    ctx->ofs = 0;
+    /* insert new string */
+    if (WCEL_Grow(ctx, len))
+    {
+	WCEL_InsertString(ctx, data);
+	HeapFree(GetProcessHeap(), 0, data);
+	ctx->histPos = idx;
+    }
+}
+
+/* ====================================================================
+ *
+ * basic edition functions
+ *
+ * ====================================================================*/
+
+static void WCEL_Done(WCEL_Context* ctx)
+{
+    if (!WCEL_Grow(ctx, 1)) return;
+    ctx->line[ctx->len++] = '\n';
+    ctx->line[ctx->len] = 0;
+    WriteConsoleA(ctx->hConOut, "\n", 1, NULL, NULL);
+    ctx->done = 1;
+}
+
+static void WCEL_MoveLeft(WCEL_Context* ctx)
+{
+    if (ctx->ofs > 0) ctx->ofs--;
+}
+
+static void WCEL_MoveRight(WCEL_Context* ctx)
+{
+    if (ctx->ofs < ctx->len) ctx->ofs++;
+}
+
+static void WCEL_MoveToLeftWord(WCEL_Context* ctx)
+{
+    int	new_ofs = WCEL_GetLeftWordTransition(ctx, ctx->ofs);
+    if (new_ofs != ctx->ofs) ctx->ofs = new_ofs;
+}
+
+static void WCEL_MoveToRightWord(WCEL_Context* ctx)
+{
+    int	new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
+    if (new_ofs != ctx->ofs) ctx->ofs = new_ofs;
+}
+
+static void WCEL_MoveToBeg(WCEL_Context* ctx)
+{
+    ctx->ofs = 0;
+}
+
+static void WCEL_MoveToEnd(WCEL_Context* ctx)
+{
+    ctx->ofs = ctx->len;
+}
+
+static void WCEL_SetMark(WCEL_Context* ctx)
+{
+    ctx->mark = ctx->ofs;
+}
+
+static void WCEL_ExchangeMark(WCEL_Context* ctx)
+{   
+    unsigned tmp;
+
+    if (ctx->mark > ctx->len) return;
+    tmp = ctx->ofs;
+    ctx->ofs = ctx->mark;
+    ctx->mark = tmp;
+}
+
+static void WCEL_CopyMarkedZone(WCEL_Context* ctx)
+{
+    unsigned beg, end;
+
+    if (ctx->mark > ctx->len || ctx->mark == ctx->ofs) return;
+    if (ctx->mark > ctx->ofs)
+    {
+	beg = ctx->ofs;		end = ctx->mark;
+    }
+    else
+    {
+	beg = ctx->mark;	end = ctx->ofs;
+    }
+    WCEL_SaveYank(ctx, beg, end);
+}
+
+static void WCEL_TransposeChar(WCEL_Context* ctx)
+{
+    WCHAR	c;
+
+    if (!ctx->ofs || ctx->ofs == ctx->len) return;
+
+    c = ctx->line[ctx->ofs];
+    ctx->line[ctx->ofs] = ctx->line[ctx->ofs - 1];
+    ctx->line[ctx->ofs - 1] = c;
+
+    WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs - 1], 2, WCEL_GetCoord(ctx, ctx->ofs - 1), NULL);
+    ctx->ofs++;
+}
+
+static void WCEL_TransposeWords(WCEL_Context* ctx)
+{
+    FIXME("NIY\n");
+}
+
+static void WCEL_LowerCaseWord(WCEL_Context* ctx)
+{
+    int	new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
+    if (new_ofs != ctx->ofs)
+    {
+	int	i;
+	for (i = ctx->ofs; i <= new_ofs; i++)
+	    ctx->line[i] = tolowerW(ctx->line[i]);
+	WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1, 
+				     WCEL_GetCoord(ctx, ctx->ofs), NULL);
+	ctx->ofs = new_ofs;
+    }
+}
+
+static void WCEL_UpperCaseWord(WCEL_Context* ctx)
+{
+    int	new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
+    if (new_ofs != ctx->ofs)
+    {
+	int	i;
+	for (i = ctx->ofs; i <= new_ofs; i++)
+	    ctx->line[i] = toupperW(ctx->line[i]);
+	WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1, 
+				     WCEL_GetCoord(ctx, ctx->ofs), NULL);
+	ctx->ofs = new_ofs;
+    }
+}
+
+static void WCEL_CapitalizeWord(WCEL_Context* ctx)
+{
+    int	new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
+    if (new_ofs != ctx->ofs)
+    {
+	int	i;
+	
+	ctx->line[ctx->ofs] = toupperW(ctx->line[ctx->ofs]);
+	for (i = ctx->ofs + 1; i <= new_ofs; i++)
+	    ctx->line[i] = tolowerW(ctx->line[i]);
+	WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1, 
+				     WCEL_GetCoord(ctx, ctx->ofs), NULL);
+	ctx->ofs = new_ofs;
+    }
+}
+
+static void WCEL_Yank(WCEL_Context* ctx)
+{
+    WCEL_InsertString(ctx, ctx->yanked);
+    HeapFree(GetProcessHeap(), 0, ctx->yanked);
+    ctx->yanked = NULL;
+}
+
+static void WCEL_KillToEndOfLine(WCEL_Context* ctx)
+{
+    WCEL_SaveYank(ctx, ctx->ofs, ctx->len);
+    WCEL_DeleteString(ctx, ctx->ofs, ctx->len);
+}
+
+static void WCEL_KillMarkedZone(WCEL_Context* ctx)
+{
+    unsigned beg, end;
+
+    if (ctx->mark > ctx->len || ctx->mark == ctx->ofs) return;
+    if (ctx->mark > ctx->ofs)
+    {
+	beg = ctx->ofs;		end = ctx->mark;
+    }
+    else
+    {
+	beg = ctx->mark;	end = ctx->ofs;
+    }
+    WCEL_SaveYank(ctx, beg, end);
+    WCEL_DeleteString(ctx, beg, end);
+    ctx->ofs = beg;
+}
+
+static void WCEL_DeletePrevChar(WCEL_Context* ctx)
+{
+    if (ctx->ofs)
+    {
+	WCEL_DeleteString(ctx, ctx->ofs - 1, ctx->ofs);
+	ctx->ofs--;
+    }
+}
+
+static void WCEL_DeleteCurrChar(WCEL_Context* ctx)
+{
+    if (ctx->ofs < ctx->len)
+	WCEL_DeleteString(ctx, ctx->ofs, ctx->ofs + 1);
+}
+
+static void WCEL_DeleteLeftWord(WCEL_Context* ctx)
+{
+    int	new_ofs = WCEL_GetLeftWordTransition(ctx, ctx->ofs);
+    if (new_ofs != ctx->ofs)
+    {
+	WCEL_DeleteString(ctx, new_ofs, ctx->ofs);
+	ctx->ofs = new_ofs;
+    }
+}
+
+static void WCEL_DeleteRightWord(WCEL_Context* ctx)
+{
+    int	new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
+    if (new_ofs != ctx->ofs)
+    {
+	WCEL_DeleteString(ctx, ctx->ofs, new_ofs);
+    }
+}
+
+static void WCEL_MoveToPrevHist(WCEL_Context* ctx)
+{
+    if (ctx->histPos) WCEL_MoveToHist(ctx, ctx->histPos - 1);
+}
+
+static void WCEL_MoveToNextHist(WCEL_Context* ctx)
+{
+    if (ctx->histPos < ctx->histSize - 1) WCEL_MoveToHist(ctx, ctx->histPos + 1);
+}
+
+static void WCEL_MoveToFirstHist(WCEL_Context* ctx)
+{
+    if (ctx->histPos != 0) WCEL_MoveToHist(ctx, 0);
+}
+
+static void WCEL_MoveToLastHist(WCEL_Context* ctx)
+{
+    if (ctx->histPos != ctx->histSize - 1) WCEL_MoveToHist(ctx, ctx->histSize - 1);
+}
+
+/* ====================================================================
+ *
+ * 		Key Maps
+ *
+ * ====================================================================*/
+
+#define CTRL(x)	((x) - '@')
+static KeyEntry StdKeyMap[] = 
+{
+    {/*BACK*/0x08,	WCEL_DeletePrevChar 	},
+    {/*RETURN*/0x0d,	WCEL_Done		},
+    {/*DEL*/127,	WCEL_DeleteCurrChar 	},
+    {	0,		NULL			}
+};
+
+static	KeyEntry EmacsKeyMapCtrl[] = 
+{
+    {	CTRL('@'),	WCEL_SetMark		},
+    {	CTRL('A'),	WCEL_MoveToBeg		},
+    {	CTRL('B'),	WCEL_MoveLeft		},
+    /* C */
+    {	CTRL('D'),	WCEL_DeleteCurrChar	},
+    {	CTRL('E'),	WCEL_MoveToEnd		},
+    {	CTRL('F'),	WCEL_MoveRight		},
+    {	CTRL('G'),	WCEL_Beep		},
+    {	CTRL('H'),	WCEL_DeletePrevChar	},
+    /* I: meaningless (or tab ???) */
+    {	CTRL('J'),	WCEL_Done		},
+    {	CTRL('K'),	WCEL_KillToEndOfLine	},
+    /* L: [NIY] redraw the whole stuff */
+    {	CTRL('M'),	WCEL_Done		},
+    {	CTRL('N'),	WCEL_MoveToNextHist	},
+    /* O; insert line... meaningless */
+    {	CTRL('P'),	WCEL_MoveToPrevHist	},
+    /* Q: [NIY] quoting... */
+    /* R: [NIY] search backwards... */
+    /* S: [NIY] search forwards... */
+    {	CTRL('T'),	WCEL_TransposeChar	},
+    /* U: [NIY] set repeat count... */
+    /* V: paragraph down... meaningless */
+    {	CTRL('W'),	WCEL_KillMarkedZone	},
+    {	CTRL('X'),	WCEL_ExchangeMark	},
+    {	CTRL('Y'),	WCEL_Yank		},
+    /* Z: meaningless */
+    {	0,		NULL			}
+};
+
+static KeyEntry EmacsKeyMapAlt[] = 
+{
+    {/*DEL*/127,	WCEL_DeleteLeftWord	},
+    {	'<',		WCEL_MoveToFirstHist	},
+    {	'>',		WCEL_MoveToLastHist	},
+    {	'?',		WCEL_Beep		},
+    {	'b',		WCEL_MoveToLeftWord	},
+    {   'c',		WCEL_CapitalizeWord	},
+    {	'd',		WCEL_DeleteRightWord	},
+    {	'f',		WCEL_MoveToRightWord	},
+    {	'l',		WCEL_LowerCaseWord	},
+    {   't',		WCEL_TransposeWords	},
+    {	'u',		WCEL_UpperCaseWord	},
+    {	'w', 		WCEL_CopyMarkedZone	},
+    {	0,		NULL			}
+};
+
+static KeyEntry EmacsKeyMapExtended[] = 
+{
+    {/*VK_PRIOR*/0x21, 	WCEL_MoveToPrevHist	},
+    {/*VK_NEXT*/0x22,	WCEL_MoveToNextHist 	},
+    {/*VK_RIGHT*/0x27,	WCEL_MoveRight 		},
+    {/*VK_LEFT*/0x25,	WCEL_MoveLeft 		},
+    {	0,		NULL 			}
+};
+
+static KeyMap	EmacsKeyMap[] = 
+{
+    {0x00000000, 1, StdKeyMap},
+    {0x00000001, 1, EmacsKeyMapAlt},	/* left  alt  */
+    {0x00000002, 1, EmacsKeyMapAlt},	/* right alt  */
+    {0x00000004, 1, EmacsKeyMapCtrl},	/* left  ctrl */
+    {0x00000008, 1, EmacsKeyMapCtrl},	/* right ctrl */
+    {0x00000100, 0, EmacsKeyMapExtended},
+    {0,		 0, 0}
+};
+
+static	KeyEntry Win32KeyMapExtended[] = 
+{
+    {/*VK_LEFT*/ 0x25, 	WCEL_MoveLeft 		},
+    {/*VK_RIGHT*/0x27,	WCEL_MoveRight		},
+    {/*VK_HOME*/ 0x24,	WCEL_MoveToBeg 		},
+    {/*VK_END*/  0x23,	WCEL_MoveToEnd 		},
+    {/*VK_UP*/   0x26, 	WCEL_MoveToPrevHist 	},
+    {/*VK_DOWN*/ 0x28,	WCEL_MoveToNextHist	},
+    {	0,		NULL 			}
+};
+
+static	KeyEntry Win32KeyMapCtrlExtended[] = 
+{
+    {/*VK_LEFT*/ 0x25, 	WCEL_MoveToLeftWord 	},
+    {/*VK_RIGHT*/0x27,	WCEL_MoveToRightWord	},
+    {	0,		NULL 			}
+};
+
+KeyMap	Win32KeyMap[] = 
+{
+    {0x00000000, 1, StdKeyMap},
+    {0x00000100, 0, Win32KeyMapExtended},
+    {0x00000104, 0, Win32KeyMapCtrlExtended},
+    {0x00000108, 0, Win32KeyMapCtrlExtended},
+    {0,		 0, 0}
+};
+#undef CTRL
+
+/* ====================================================================
+ *
+ * 		Read line master function
+ *
+ * ====================================================================*/
+
+WCHAR* CONSOLE_Readline(HANDLE hConsoleIn, int use_emacs)
+{
+    WCEL_Context	ctx;
+    INPUT_RECORD	ir;
+    KeyMap*		km;
+    KeyEntry*		ke;
+    unsigned		ofs;
+    void		(*func)(struct WCEL_Context* ctx);
+
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.hConIn = hConsoleIn;
+    WCEL_HistoryInit(&ctx);
+    if ((ctx.hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL, 
+				    OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE ||
+	!GetConsoleScreenBufferInfo(ctx.hConOut, &ctx.csbi))
+	return NULL;
+    if (!WCEL_Grow(&ctx, 1))
+    {
+	CloseHandle(ctx.hConOut);
+	return NULL;
+    }
+    ctx.line[0] = 0;
+
+/* EPP     WCEL_Dump(&ctx, "init"); */
+
+    while (!ctx.done && !ctx.error && WCEL_Get(&ctx, &ir))
+    {	
+	if (ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown) continue;
+	TRACE("key%s repeatCount=%u, keyCode=%02x scanCode=%02x char=%02x keyState=%08lx\n",
+	      ir.Event.KeyEvent.bKeyDown ? "Down" : "Up  ", ir.Event.KeyEvent.wRepeatCount,
+	      ir.Event.KeyEvent.wVirtualKeyCode, ir.Event.KeyEvent.wVirtualScanCode,
+	      ir.Event.KeyEvent.uChar.UnicodeChar, ir.Event.KeyEvent.dwControlKeyState);
+
+/* EPP 	WCEL_Dump(&ctx, "before func"); */
+	ofs = ctx.ofs;
+
+	func = NULL;
+	for (km = (use_emacs) ? EmacsKeyMap : Win32KeyMap; km->entries != NULL; km++)
+	{	
+	    if (km->keyState != ir.Event.KeyEvent.dwControlKeyState)
+		continue;
+	    if (km->chkChar)
+	    {
+		for (ke = &km->entries[0]; ke->func != 0; ke++)
+		    if (ke->val == ir.Event.KeyEvent.uChar.UnicodeChar) break;
+	    }
+	    else
+	    {
+		for (ke = &km->entries[0]; ke->func != 0; ke++)
+		    if (ke->val == ir.Event.KeyEvent.wVirtualKeyCode) break;
+
+	    }
+	    if (ke->func)
+	    {
+		func = ke->func;
+		break;
+	    }
+	}
+
+	if (func)
+	    (func)(&ctx);
+	else if (!(ir.Event.KeyEvent.dwControlKeyState & (ENHANCED_KEY|LEFT_ALT_PRESSED)))
+	    WCEL_InsertChar(&ctx, ir.Event.KeyEvent.uChar.UnicodeChar);
+	else TRACE("Dropped event\n");
+
+/* EPP 	WCEL_Dump(&ctx, "after func"); */
+	if (ctx.ofs != ofs)
+	    SetConsoleCursorPosition(ctx.hConOut, WCEL_GetCoord(&ctx, ctx.ofs));
+    }
+    if (ctx.error) 
+    {
+	HeapFree(GetProcessHeap(), 0, ctx.line);
+	ctx.line = NULL;
+    }
+    if (ctx.line)
+	CONSOLE_AppendHistory(ctx.line);
+
+    CloseHandle(ctx.hConOut);
+    if (ctx.histCurr) HeapFree(GetProcessHeap(), 0, ctx.histCurr);
+    return ctx.line;
+}
+