diff --git a/Makefile.in b/Makefile.in
index 1ea3e0433c7..40f2aa89df0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -28,7 +28,8 @@ PROGRAMS = \
# Programs that link with libwine
LIBPROGRAMS = \
- debugger/winedbg
+ debugger/winedbg \
+ programs/wineconsole/wineconsole
# Libraries (not dlls) to build
LIBRARIES = \
@@ -59,6 +60,7 @@ INSTALLSUBDIRS = \
include \
library \
ole \
+ programs/wineconsole \
server \
tools \
tsx11 \
diff --git a/configure b/configure
index 3fffe36a9b9..52f9d8248f9 100755
--- a/configure
+++ b/configure
@@ -7166,6 +7166,7 @@ programs/regtest/Makefile
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/regtest/Makefile
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 333b38aacdf..aaee28082c4 100644
--- a/configure.in
+++ b/configure.in
@@ -1336,6 +1336,7 @@ programs/regtest/Makefile
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 476eba62f33..202e92116fe 100644
--- a/dlls/x11drv/x11drv_main.c
+++ b/dlls/x11drv/x11drv_main.c
@@ -444,7 +444,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void)
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 4dd950e1b42..e1277c6360d 100644
--- a/documentation/running.sgml
+++ b/documentation/running.sgml
@@ -93,6 +93,17 @@ Options:
options that affect the Windows program should come
after it.
+
+
+ If you want to run a console program (aka a CUI executable), use
+ wineconsole instead of wine
+ 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.
+
diff --git a/documentation/wine.man.in b/documentation/wine.man.in
index e87c1561476..88da2db0f26 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 @@ For debugging wine, use
.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 @@ The
.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 b9e3fb00d6d..42f69e7509f 100644
--- a/files/file.c
+++ b/files/file.c
@@ -182,7 +182,7 @@ void FILE_SetDosError(void)
* 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 @@ HANDLE FILE_DupUnixHandle( int fd, DWORD access )
SERVER_START_REQ( alloc_file_handle )
{
req->access = access;
+ req->inherit = inherit;
req->fd = fd;
SERVER_CALL();
ret = req->handle;
@@ -255,14 +256,15 @@ int FILE_GetUnixHandle( HANDLE handle, DWORD access )
* 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 @@ HANDLE WINAPI CreateFileA( LPCSTR filename, DWORD access, DWORD sharing,
/* 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 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
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 @@ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
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 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
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 @@ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
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 260f8dd113a..5efc9a5c5b6 100644
--- a/include/file.h
+++ b/include/file.h
@@ -71,7 +71,7 @@ inline static int FILE_contains_path (LPCSTR name)
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 016e0d10020..233acda2005 100644
--- a/include/wincon.h
+++ b/include/wincon.h
@@ -17,6 +17,8 @@ extern "C" {
#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 b83ca78eeae..94f40d6927d 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -577,6 +577,7 @@ struct alloc_file_handle_request
{
struct request_header __header;
unsigned int access;
+ int inherit;
int fd;
handle_t handle;
};
@@ -755,8 +756,9 @@ struct alloc_console_request
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 @@ struct free_console_request
};
+#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_mode_request
-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 write_console_input_request
};
+
struct read_console_input_request
{
struct request_header __header;
@@ -853,6 +983,53 @@ struct read_console_input_request
+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 @@ enum request
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 @@ union generic_request
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 @@ union generic_request
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 2e9d8872a43..fa6fc0fe31b 100644
--- a/loader/module.c
+++ b/loader/module.c
@@ -1052,10 +1052,6 @@ BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
/* 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 a0c47c7c68c..5a73a09e244 100644
--- a/programs/Makefile.in
+++ b/programs/Makefile.in
@@ -17,6 +17,7 @@ SUBDIRS = \
uninstaller \
view \
wcmd \
+ wineconsole \
winemine \
winetest \
winhelp \
diff --git a/programs/wineconsole/.cvsignore b/programs/wineconsole/.cvsignore
new file mode 100644
index 00000000000..ad904a9bb32
--- /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 00000000000..672de8f1590
--- /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 00000000000..04220ac40f5
--- /dev/null
+++ b/programs/wineconsole/dialog.c
@@ -0,0 +1,515 @@
+/* dialog management for wineconsole
+ * (c) 2001 Eric Pouech
+ */
+
+#include
+#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 00000000000..2d25c664701
--- /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
+#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 00000000000..b444164dba7
--- /dev/null
+++ b/programs/wineconsole/winecon_private.h
@@ -0,0 +1,75 @@
+#include
+#include
+#include
+#include
+
+#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 00000000000..38ba58d424a
--- /dev/null
+++ b/programs/wineconsole/wineconsole.c
@@ -0,0 +1,479 @@
+/*
+ * an application for displaying Win32 console
+ *
+ * Copyright 2001 Eric Pouech
+ */
+
+#include
+#include
+#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 ... 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 used when a new console is created (AllocConsole)
+ * wineconsole used to start the program 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 , 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 00000000000..a5c6544203b
--- /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 00000000000..50b6f6dbd7e
--- /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 00000000000..d5a78417acd
--- /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 00000000000..17c8cbaee86
--- /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 00000000000..6ebc40c8add
--- /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 ab5db91ef72..755dd396cda 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 @@ void PROCESS_CallUserSignalProc( UINT uCode, HMODULE16 hModule )
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 @@ static BOOL process_init( char *argv[] )
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 @@ static BOOL process_init( char *argv[] )
/* 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 6aab56367ac..bd6dd39e869 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
-#include
-#include
#include
#include
-#include
-#include
-#include
-#include
#include
#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 screen_buffer
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 @@ static int get_console_mode( handle_t handle )
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 @@ static int set_console_mode( handle_t handle, int mode )
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 @@ static int write_console_input( handle_t handle, int count, INPUT_RECORD *record
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 @@ static int read_console_input( handle_t handle, int count, INPUT_RECORD *rec, in
{
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 @@ static int read_console_input( handle_t handle, int count, INPUT_RECORD *rec, in
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 int console_get_info( struct object *obj, struct get_file_info_request *r
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 @@ DECL_HANDLER(free_console)
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 @@ DECL_HANDLER(set_console_mode)
/* 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 @@ DECL_HANDLER(read_console_input)
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 00000000000..88999a15bbb
--- /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 bde34444f64..09b4240cab4 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 @@ static int debugger_attach( struct process *process, struct thread *debugger )
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 4ed9eac4c3d..6dde94cdd53 100644
--- a/server/file.c
+++ b/server/file.c
@@ -494,7 +494,7 @@ DECL_HANDLER(alloc_file_handle)
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 50fef3eba10..ac4235ffd04 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -355,6 +355,7 @@ struct object *get_handle_obj( struct process *process, handle_t handle,
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 @@ int get_handle_fd( struct process *process, handle_t handle, unsigned int access
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 32fa3461595..09641d3f3aa 100644
--- a/server/object.h
+++ b/server/object.h
@@ -155,11 +155,6 @@ extern void file_set_error(void);
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 b3196a90b50..f02f5b79077 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 @@ static int set_process_console( struct process *process, struct process *parent,
{
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 @@ static int set_process_console( struct process *process, struct process *parent,
}
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 @@ struct thread *create_process( int fd )
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 @@ struct thread *create_process( int fd )
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 @@ struct thread *create_process( int fd )
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 @@ static void init_process( int ppid, struct init_process_request *req )
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 @@ static void process_destroy( struct object *obj )
/* 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 @@ static void process_dump( struct object *obj, int verbose )
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 @@ static void process_unload_dll( struct process *process, void *base )
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 @@ static void process_killed( struct process *process )
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 resume_process( struct process *process )
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 @@ void kill_debugged_processes( struct thread *debugger, int exit_code )
}
}
+
/* 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 28fbd2e8759..d17cb1115a8 100644
--- a/server/process.h
+++ b/server/process.h
@@ -30,6 +30,7 @@ struct process
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 @@ struct process
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
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 e44ef528cbb..f631297dc7b 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -533,6 +533,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
/* 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 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@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 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@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 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@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 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
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 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
@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 87c224e055c..58666416e07 100644
--- a/server/request.h
+++ b/server/request.h
@@ -118,14 +118,22 @@ DECL_HANDLER(get_socket_event);
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 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(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 2d144cf1120..df4617a313a 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -721,6 +721,7 @@ static void dump_create_file_reply( const struct create_file_request *req )
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_enable_socket_event_request( const struct enable_socket_event_r
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 @@ static void dump_open_console_reply( const struct open_console_request *req )
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 @@ static void dump_set_console_mode_request( const struct set_console_mode_request
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 @@ static void dump_read_console_input_reply( const struct read_console_input_reque
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 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(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 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(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 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"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 3e2c536635e..ed3c59ecf26 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 42c69a40cb3..890c2e745af 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 @@ MODULE = win32
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 2734e3f55a9..9544d6c03d5 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
#include
-#include
-#include
#include
-#include
-#include
-#include
-#include
-#include
-#ifdef HAVE_SYS_ERRNO_H
-#include
-#endif
-#include
+#include
#include
-#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 '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='A') && (buf[k]<='Z')) ||
- ((buf[k]>='a') && (buf[k]<='z')) ||
- (buf[k]=='~')
- )
- break;
- }
- if (k) or
- * Release (ESCM#
- */
- if (k 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 @@ CONSOLE_get_input( HANDLE handle, BOOL blockwait )
*
* 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 @@ static BOOL read_console_input( HANDLE handle, LPINPUT_RECORD buffer, DWORD coun
* 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 >= 0 && handlers[alloc_loop]; alloc_loop--);
+ if (alloc_loop <= 0)
+ {
+ FIXME("Out of space on CtrlHandler table\n");
+ return FALSE;
+ }
+ handlers[alloc_loop] = func;
}
- 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);
- }
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 @@ BOOL WINAPI SetConsoleCtrlHandler( PHANDLER_ROUTINE func, BOOL add )
* 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 @@ BOOL WINAPI GenerateConsoleCtrlEvent( DWORD dwCtrlEvent,
* 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 @@ BOOL WINAPI GetConsoleScreenBufferInfo( HANDLE hConsoleOutput,
* 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 @@ BOOL WINAPI SetConsoleActiveScreenBuffer(
*/
#ifdef __i386__
#undef GetLargestConsoleWindowSize
-DWORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
+DWORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput)
{
COORD c;
c.X = 80;
@@ -533,7 +860,7 @@ DWORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
* VERSION: [!i386]
*/
#ifndef __i386__
-COORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
+COORD WINAPI GetLargestConsoleWindowSize(HANDLE hConsoleOutput)
{
COORD c;
c.X = 80;
@@ -543,156 +870,6 @@ COORD WINAPI GetLargestConsoleWindowSize( HANDLE hConsoleOutput )
#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 @@ UINT WINAPI GetConsoleCP(VOID)
}
+/******************************************************************************
+ * 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 @@ UINT WINAPI GetConsoleOutputCP(VOID)
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 @@ BOOL WINAPI GetConsoleMode(HANDLE hcon,LPDWORD mode)
* 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 (charsreadhandle = 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 WriteConsoleInputW( HANDLE handle, INPUT_RECORD *buffer,
*/
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 @@ BOOL WINAPI SetConsoleTitleA(LPCSTR title)
* 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;
+
+ 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;
- LPSTR titleA = HEAP_strdupWtoA( GetProcessHeap(), 0, title );
- ret = SetConsoleTitleA(titleA);
- HeapFree( GetProcessHeap(), 0, titleA );
return ret;
}
@@ -1276,46 +1381,58 @@ BOOL WINAPI SetConsoleTitleW( LPCWSTR title )
*
* 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 @@ BOOL WINAPI GetNumberOfConsoleMouseButtons(LPDWORD nrofbuttons)
* 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 @@ BOOL WINAPI GetConsoleCursorInfo( HANDLE hcon, LPCONSOLE_CURSOR_INFO cinfo )
/******************************************************************************
* 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 @@ BOOL WINAPI SetConsoleCursorInfo(
/******************************************************************************
* 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 @@ BOOL WINAPI SetConsoleWindowInfo(
* 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 @@ BOOL WINAPI SetConsoleTextAttribute(HANDLE hConsoleOutput,WORD wAttr)
* 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 @@ BOOL WINAPI SetConsoleScreenBufferSize( HANDLE hConsoleOutput,
* 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;counthandle = 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 @@ BOOL WINAPI FillConsoleOutputCharacterW(HANDLE hConsoleOutput,
* 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 @@ BOOL WINAPI SetConsoleInputExeNameA( LPCSTR name )
* 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 @@ BOOL WINAPI WriteConsoleOutputAttribute( HANDLE hConsoleOutput,
* 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 @@ BOOL WINAPI WriteConsoleOutputCharacterA( HANDLE hConsoleOutput,
* 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 00000000000..739743c4342
--- /dev/null
+++ b/win32/editline.c
@@ -0,0 +1,708 @@
+/*
+ * line edition function for Win32 console
+ *
+ * Copyright 2001 Eric Pouech
+ */
+
+#include "config.h"
+#include
+
+#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;
+}
+