New console code based on Win32 windows.

This commit is contained in:
Eric Pouech 2001-11-23 23:04:58 +00:00 committed by Alexandre Julliard
parent 6b6596a1e3
commit 0b83d4cbc6
39 changed files with 6525 additions and 1655 deletions

View File

@ -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 \

2
configure vendored
View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -93,6 +93,17 @@ Options:
options that affect the Windows program should come
<emphasis>after</emphasis> it.
</para>
<para>
If you want to run a console program (aka a CUI executable), use
<command>wineconsole</command> instead of <command>wine</command>
to start it. It will display the program in a separate Window
(this requires X11 to be run). If you don't, you'll still be able
to run able your program, in the Unix console were you're started
your program, but with very limited capacities (so, your program
might work, but your mileage may vary). This shall be improved
in the future.
</para>
</sect1>
<sect1 id="command-line-options">

View File

@ -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

View File

@ -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,12 +1454,11 @@ 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)
{
case FD_TYPE_OVERLAPPED:
if (unix_handle == -1) return FALSE;
if (!overlapped)
{
close(unix_handle);
@ -1493,7 +1494,12 @@ 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:
/* normal unix files */
if (unix_handle == -1)
return FALSE;
if (overlapped)
{
close(unix_handle);
@ -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)

View File

@ -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 );

View File

@ -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

View File

@ -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 */

View File

@ -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)

View File

@ -17,6 +17,7 @@ SUBDIRS = \
uninstaller \
view \
wcmd \
wineconsole \
winemine \
winetest \
winhelp \

View File

@ -0,0 +1,3 @@
Makefile
wineconsole.spec.c
wineconsole_res.res

View File

@ -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:

View File

@ -0,0 +1,515 @@
/* dialog management for wineconsole
* (c) 2001 Eric Pouech
*/
#include <stdio.h>
#include "winecon_private.h"
#include "commctrl.h"
#include "prsht.h"
/* FIXME: so far, part of the code is made in ASCII because the Uncode property sheet functions
* are not implemented yet
*/
struct dialog_info
{
struct inner_data* data; /* pointer to current winecon info */
HWND hDlg; /* handle to window dialog */
int nFont; /* number of font size in size LB */
struct font_info
{
TEXTMETRIC tm;
LOGFONT lf;
} *font; /* array of nFont. index sync'ed with SIZE LB */
};
/******************************************************************
* WCUSER_OptionDlgProc
*
* Dialog prop for the option property sheet
*/
static BOOL WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct dialog_info* di;
unsigned idc;
switch (msg)
{
case WM_INITDIALOG:
di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
di->hDlg = hDlg;
SetWindowLongA(hDlg, DWL_USER, (DWORD)di);
if (di->data->cursor_size < 33) idc = IDC_OPT_CURSOR_SMALL;
else if (di->data->cursor_size < 66) idc = IDC_OPT_CURSOR_MEDIUM;
else idc = IDC_OPT_CURSOR_LARGE;
SendDlgItemMessage(hDlg, idc, BM_SETCHECK, BST_CHECKED, 0L);
SetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, WINECON_GetHistorySize(di->data->hConIn), FALSE);
if (WINECON_GetHistoryMode(di->data->hConIn))
SendDlgItemMessage(hDlg, IDC_OPT_HIST_DOUBLE, BM_SETCHECK, BST_CHECKED, 0L);
return FALSE; /* because we set the focus */
case WM_COMMAND:
break;
case WM_NOTIFY:
{
NMHDR* nmhdr = (NMHDR*)lParam;
di = (struct dialog_info*)GetWindowLongA(hDlg, DWL_USER);
switch (nmhdr->code)
{
case PSN_SETACTIVE:
/* needed in propsheet to keep properly the selected radio button
* otherwise, the focus would be set to the first tab stop in the
* propsheet, which would always activate the first radio button
*/
if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED)
idc = IDC_OPT_CURSOR_SMALL;
else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED)
idc = IDC_OPT_CURSOR_MEDIUM;
else
idc = IDC_OPT_CURSOR_LARGE;
PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, idc), TRUE);
break;
case PSN_APPLY:
{
int curs_size;
int hist_size;
BOOL done;
if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED) curs_size = 33;
else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED) curs_size = 66;
else curs_size = 99;
if (curs_size != di->data->cursor_size)
{
CONSOLE_CURSOR_INFO cinfo;
cinfo.dwSize = curs_size;
cinfo.bVisible = di->data->cursor_visible;
SetConsoleCursorInfo(di->data->hConOut, &cinfo);
}
hist_size = GetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, &done, FALSE);
if (done) WINECON_SetHistorySize(di->data->hConIn, hist_size);
SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
WINECON_SetHistoryMode(di->data->hConIn,
IsDlgButtonChecked(hDlg, IDC_OPT_HIST_DOUBLE) & BST_CHECKED);
return TRUE;
}
default:
return FALSE;
}
break;
}
default:
return FALSE;
}
return TRUE;
}
/******************************************************************
* WCUSER_FontPreviewProc
*
* Window proc for font previewer in font property sheet
*/
static LRESULT WINAPI WCUSER_FontPreviewProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
int font_idx;
int size_idx;
struct dialog_info* di;
di = (struct dialog_info*)GetWindowLong(GetParent(hWnd), DWL_USER);
BeginPaint(hWnd, &ps);
font_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
size_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
if (font_idx >= 0 && size_idx >= 0 && size_idx < di->nFont)
{
HFONT hFont, hOldFont;
WCHAR buf1[256];
WCHAR buf2[256];
int len1, len2;
hFont = CreateFontIndirect(&di->font[size_idx].lf);
len1 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_1,
buf1, sizeof(buf1) / sizeof(WCHAR));
len2 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_2,
buf2, sizeof(buf2) / sizeof(WCHAR));
if (hFont && len1)
{
hOldFont = SelectObject(ps.hdc, hFont);
SetBkColor(ps.hdc, RGB(0x00, 0x00, 0x00));
SetTextColor(ps.hdc, RGB(0xFF, 0xFF, 0xFF));
TextOut(ps.hdc, 0, 0, buf1, len1);
if (len2)
TextOut(ps.hdc, 0, di->font[size_idx].tm.tmHeight, buf2, len2);
SelectObject(ps.hdc, hOldFont);
DeleteObject(hFont);
}
}
EndPaint(hWnd, &ps);
break;
}
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0L;
}
/******************************************************************
* font_enum
*
*
*/
static int CALLBACK font_enum_size2(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct dialog_info* di = (struct dialog_info*)lParam;
if (WCUSER_ValidateFontMetric(di->data, tm))
{
di->nFont++;
}
return 1;
}
static int CALLBACK font_enum(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct dialog_info* di = (struct dialog_info*)lParam;
HDC hdc;
if (WCUSER_ValidateFont(di->data, lf) && (hdc = GetDC(di->hDlg)))
{
di->nFont = 0;
EnumFontFamilies(hdc, lf->lfFaceName, font_enum_size2, (LPARAM)di);
if (di->nFont)
{
int idx;
idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_ADDSTRING,
0, (LPARAM)lf->lfFaceName);
}
ReleaseDC(di->hDlg, hdc);
}
return 1;
}
/******************************************************************
* font_enum_size
*
*
*/
static int CALLBACK font_enum_size(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct dialog_info* di = (struct dialog_info*)lParam;
if (WCUSER_ValidateFontMetric(di->data, tm))
{
WCHAR buf[32];
WCHAR fmt[] = {'%','l','d',0};
int idx;
/* we want the string to be sorted with a numeric order, not a lexicographic...
* do the job by hand... get where to insert the new string
*/
for (idx = 0; idx < di->nFont && tm->tmHeight > di->font[idx].tm.tmHeight; idx++);
wsprintfW(buf, fmt, tm->tmHeight);
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, idx, (LPARAM)buf);
/* now grow our arrays and insert to values at the same index than in the list box */
di->font = HeapReAlloc(GetProcessHeap(), 0, di->font, sizeof(*di->font) * (di->nFont + 1));
if (idx != di->nFont)
memmove(&di->font[idx + 1], &di->font[idx], (di->nFont - idx) * sizeof(*di->font));
di->font[idx].tm = *tm;
di->font[idx].lf = *lf;
di->nFont++;
}
return 1;
}
/******************************************************************
* select_font
*
*
*/
static BOOL select_font(struct dialog_info* di)
{
int idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
WCHAR buf[256];
WCHAR fmt[128];
if (idx < 0 || idx >= di->nFont)
return FALSE;
LoadString(GetModuleHandle(NULL), IDS_FNT_DISPLAY, fmt, sizeof(fmt) / sizeof(WCHAR));
wsprintfW(buf, fmt, di->font[idx].tm.tmMaxCharWidth, di->font[idx].tm.tmHeight);
SendDlgItemMessage(di->hDlg, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf);
InvalidateRect(GetDlgItem(di->hDlg, IDC_FNT_PREVIEW), NULL, TRUE);
UpdateWindow(GetDlgItem(di->hDlg, IDC_FNT_PREVIEW));
return TRUE;
}
/******************************************************************
* fill_list_size
*
* fills the size list box according to selected family in font LB
*/
static BOOL fill_list_size(struct dialog_info* di, BOOL doInit)
{
HDC hdc;
int idx;
WCHAR lfFaceName[LF_FACESIZE];
idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
if (idx < 0) return FALSE;
hdc = GetDC(di->hDlg);
if (!hdc) return FALSE;
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETTEXT, idx, (LPARAM)lfFaceName);
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_RESETCONTENT, 0L, 0L);
if (di->font) HeapFree(GetProcessHeap(), 0, di->font);
di->nFont = 0;
di->font = NULL;
EnumFontFamilies(hdc, lfFaceName, font_enum_size, (LPARAM)di);
ReleaseDC(di->hDlg, hdc);
if (doInit)
{
for (idx = 0; idx < di->nFont; idx++)
{
if (memcmp(&di->data->logFont, &di->font[idx].lf, sizeof(LOGFONT)) == 0)
break;
}
if (idx == di->nFont) idx = 0;
}
else
idx = 0;
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0L);
select_font(di);
return TRUE;
}
/******************************************************************
* fill_list_font
*
* Fills the font LB
*/
static BOOL fill_list_font(struct dialog_info* di)
{
HDC hdc;
hdc = GetDC(di->hDlg);
if (!hdc) return FALSE;
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_RESETCONTENT, 0L, 0L);
EnumFontFamilies(hdc, NULL, font_enum, (LPARAM)di);
ReleaseDC(di->hDlg, hdc);
if (SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
(WPARAM)-1, (LPARAM)di->data->logFont.lfFaceName) == LB_ERR)
SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0L, 0L);
fill_list_size(di, TRUE);
return TRUE;
}
/******************************************************************
* WCUSER_FontDlgProc
*
* Dialog proc for the Font property sheet
*/
static BOOL WINAPI WCUSER_FontDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct dialog_info* di;
switch (msg)
{
case WM_INITDIALOG:
di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
di->hDlg = hDlg;
SetWindowLong(hDlg, DWL_USER, (DWORD)di);
fill_list_font(di);
break;
case WM_COMMAND:
di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
switch (LOWORD(wParam))
{
case IDC_FNT_LIST_FONT:
if (HIWORD(wParam) == LBN_SELCHANGE)
{
fill_list_size(di, FALSE);
}
break;
case IDC_FNT_LIST_SIZE:
if (HIWORD(wParam) == LBN_SELCHANGE)
{
select_font(di);
}
break;
}
break;
case WM_NOTIFY:
{
NMHDR* nmhdr = (NMHDR*)lParam;
di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
switch (nmhdr->code)
{
case PSN_APPLY:
{
int idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
if (idx >= 0 && idx < di->nFont)
{
WCUSER_SetFont(di->data, &di->font[idx].lf, &di->font[idx].tm);
}
SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
return TRUE;
}
default:
return FALSE;
}
break;
}
default:
return FALSE;
}
return TRUE;
}
/******************************************************************
* WCUSER_ConfigDlgProc
*
* Dialog proc for the config property sheet
*/
static BOOL WINAPI WCUSER_ConfigDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
struct dialog_info* di;
switch (msg)
{
case WM_INITDIALOG:
di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
di->hDlg = hDlg;
SetWindowLong(hDlg, DWL_USER, (DWORD)di);
SetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH, di->data->sb_width, FALSE);
SetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT, di->data->sb_height, FALSE);
SetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH, di->data->win_width, FALSE);
SetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, di->data->win_height, FALSE);
break;
case WM_COMMAND:
di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
switch (LOWORD(wParam))
{
}
break;
case WM_NOTIFY:
{
NMHDR* nmhdr = (NMHDR*)lParam;
di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
switch (nmhdr->code)
{
case PSN_APPLY:
{
COORD sb;
SMALL_RECT pos;
BOOL st_w, st_h;
sb.X = GetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH, &st_w, FALSE);
sb.Y = GetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT, &st_h, FALSE);
if (st_w && st_h && (sb.X != di->data->sb_width || sb.Y != di->data->sb_height))
{
SetConsoleScreenBufferSize(di->data->hConOut, sb);
}
pos.Right = GetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH, &st_w, FALSE);
pos.Bottom = GetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, &st_h, FALSE);
if (st_w && st_h &&
(pos.Right != di->data->win_width || pos.Bottom != di->data->win_height))
{
pos.Left = pos.Top = 0;
pos.Right--; pos.Bottom--;
SetConsoleWindowInfo(di->data->hConOut, FALSE, &pos);
}
SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
return TRUE;
}
default:
return FALSE;
}
break;
}
default:
return FALSE;
}
return TRUE;
}
/******************************************************************
* WCUSER_GetProperties
*
* Runs the dialog box to set up the winconsole options
*/
BOOL WCUSER_GetProperties(struct inner_data* data)
{
HPROPSHEETPAGE psPage[3];
PROPSHEETPAGEA psp;
PROPSHEETHEADERA psHead;
WNDCLASS wndclass;
static WCHAR szFntPreview[] = {'W','i','n','e','C','o','n','F','o','n','t','P','r','e','v','i','e','w',0};
struct dialog_info di;
InitCommonControls();
di.data = data;
di.nFont = 0;
di.font = NULL;
wndclass.style = 0;
wndclass.lpfnWndProc = WCUSER_FontPreviewProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = GetModuleHandle(NULL);
wndclass.hIcon = 0;
wndclass.hCursor = LoadCursor(0, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szFntPreview;
RegisterClass(&wndclass);
memset(&psp, 0, sizeof(psp));
psp.dwSize = sizeof(psp);
psp.dwFlags = 0;
psp.hInstance = wndclass.hInstance;
psp.lParam = (LPARAM)&di;
psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_OPTION);
psp.pfnDlgProc = WCUSER_OptionDlgProc;
psPage[0] = CreatePropertySheetPageA(&psp);
psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_FONT);
psp.pfnDlgProc = WCUSER_FontDlgProc;
psPage[1] = CreatePropertySheetPageA(&psp);
psp.u.pszTemplate = MAKEINTRESOURCEA(IDD_CONFIG);
psp.pfnDlgProc = WCUSER_ConfigDlgProc;
psPage[2] = CreatePropertySheetPageA(&psp);
memset(&psHead, 0, sizeof(psHead));
psHead.dwSize = sizeof(psHead);
psHead.pszCaption = "Setup";
psHead.nPages = 3;
psHead.hwndParent = data->hWnd;
psHead.u3.phpage = psPage;
PropertySheetA(&psHead);
return TRUE;
}

957
programs/wineconsole/user.c Normal file
View File

@ -0,0 +1,957 @@
/*
* a GUI application for displaying a console
* USER32 back end
* Copyright 2001 Eric Pouech
*/
#include <stdio.h>
#include "winecon_private.h"
/* mapping console colors to RGB values */
static COLORREF color_map[16] =
{
RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0x80), RGB(0x00, 0x80, 0x00), RGB(0x00, 0x80, 0x80),
RGB(0x80, 0x00, 0x00), RGB(0x80, 0x00, 0x80), RGB(0x80, 0x80, 0x00), RGB(0x80, 0x80, 0x80),
RGB(0x00, 0x00, 0x00), RGB(0x00, 0x00, 0xFF), RGB(0x00, 0xFF, 0x00), RGB(0x00, 0xFF, 0xFF),
RGB(0xFF, 0x00, 0x00), RGB(0xFF, 0x00, 0xFF), RGB(0xFF, 0xFF, 0x00), RGB(0xFF, 0xFF, 0xFF),
};
/******************************************************************
* WCUSER_FillMemDC
*
* Fills the Mem DC with current cells values
*/
static void WCUSER_FillMemDC(const struct inner_data* data, int upd_tp, int upd_bm)
{
unsigned i, j, k;
CHAR_INFO* cell;
HFONT hOldFont;
WORD attr;
WCHAR* line;
if (!(line = HeapAlloc(GetProcessHeap(), 0, data->sb_width * sizeof(WCHAR))))
{Trace(0, "OOM\n"); return;}
hOldFont = SelectObject(data->hMemDC, data->hFont);
for (j = upd_tp; j <= upd_bm; j++)
{
cell = &data->cells[j * data->sb_width];
for (i = 0; i < data->win_width; i++)
{
attr = cell[i].Attributes;
SetBkColor(data->hMemDC, color_map[attr & 0x0F]);
SetTextColor(data->hMemDC, color_map[(attr >> 4) & 0x0F]);
for (k = i; k < data->win_width && cell[k].Attributes == attr; k++)
{
line[k - i] = cell[k].Char.UnicodeChar;
}
TextOut(data->hMemDC, i * data->cell_width, j * data->cell_height,
line, k - i);
i = k - 1;
}
}
SelectObject(data->hMemDC, hOldFont);
HeapFree(GetProcessHeap(), 0, line);
}
/******************************************************************
* WCUSER_NewBitmap
*
* Either the font geometry or the sb geometry has changed. we need to recreate the
* bitmap geometry
*/
static void WCUSER_NewBitmap(struct inner_data* data, BOOL fill)
{
HBITMAP hnew, hold;
if (!data->sb_width || !data->sb_height)
return;
hnew = CreateCompatibleBitmap(data->hMemDC,
data->sb_width * data->cell_width,
data->sb_height * data->cell_height);
hold = SelectObject(data->hMemDC, hnew);
if (data->hBitmap)
{
if (hold == data->hBitmap)
DeleteObject(data->hBitmap);
else
Trace(0, "leak\n");
}
data->hBitmap = hnew;
if (fill)
WCUSER_FillMemDC(data, 0, data->sb_height - 1);
}
/******************************************************************
* WCUSER_ResizeScreenBuffer
*
*
*/
static void WCUSER_ResizeScreenBuffer(struct inner_data* data)
{
WCUSER_NewBitmap(data, FALSE);
}
/******************************************************************
* WCUSER_PosCursor
*
* Set a new position for the cursor
*/
static void WCUSER_PosCursor(const struct inner_data* data)
{
if (data->hWnd != GetFocus() || !data->cursor_visible) return;
SetCaretPos((data->cursor.X - data->win_pos.X) * data->cell_width,
(data->cursor.Y - data->win_pos.Y) * data->cell_height);
ShowCaret(data->hWnd);
}
/******************************************************************
* WCUSER_ShapeCursor
*
* Sets a new shape for the cursor
*/
void WCUSER_ShapeCursor(struct inner_data* data, int size, int vis, BOOL force)
{
if (force || size != data->cursor_size)
{
if (data->cursor_visible && data->hWnd == GetFocus()) DestroyCaret();
if (data->cursor_bitmap) DeleteObject(data->cursor_bitmap);
data->cursor_bitmap = (HBITMAP)0;
if (size != 100)
{
int w16b; /* number of byets per row, aligned on word size */
BYTE* ptr;
int i, j, nbl;
w16b = ((data->cell_width + 15) & ~15) / 8;
ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, w16b * data->cell_height);
if (!ptr) {Trace(0, "OOM\n"); return;}
nbl = max((data->cell_height * size) / 100, 1);
for (j = data->cell_height - nbl; j < data->cell_height; j++)
{
for (i = 0; i < data->cell_width; i++)
{
ptr[w16b * j + (i / 8)] |= 0x80 >> (i & 7);
}
}
data->cursor_bitmap = CreateBitmap(data->cell_width, data->cell_height, 1, 1, ptr);
HeapFree(GetProcessHeap(), 0, ptr);
}
data->cursor_size = size;
data->cursor_visible = -1;
}
vis = (vis) ? TRUE : FALSE;
if (force || vis != data->cursor_visible)
{
data->cursor_visible = vis;
if (data->hWnd == GetFocus())
{
if (vis)
{
CreateCaret(data->hWnd, data->cursor_bitmap, data->cell_width, data->cell_height);
WCUSER_PosCursor(data);
}
else
{
DestroyCaret();
}
}
}
}
/******************************************************************
* INECON_ComputePositions
*
* Recomputes all the components (mainly scroll bars) positions
*/
void WCUSER_ComputePositions(struct inner_data* data)
{
RECT r;
int dx, dy;
/* compute window size from desired client size */
r.left = r.top = 0;
r.right = data->win_width * data->cell_width;
r.bottom = data->win_height * data->cell_height;
if (IsRectEmpty(&r))
{
ShowWindow(data->hWnd, SW_HIDE);
return;
}
AdjustWindowRect(&r, GetWindowLong(data->hWnd, GWL_STYLE), FALSE);
dx = dy = 0;
if (data->sb_width > data->win_width)
{
dy = GetSystemMetrics(SM_CYHSCROLL);
SetScrollRange(data->hWnd, SB_HORZ, 0, data->sb_width - data->win_width, FALSE);
SetScrollPos(data->hWnd, SB_HORZ, 0, FALSE); /* FIXME */
ShowScrollBar(data->hWnd, SB_HORZ, TRUE);
}
else
{
ShowScrollBar(data->hWnd, SB_HORZ, FALSE);
}
if (data->sb_height > data->win_height)
{
dx = GetSystemMetrics(SM_CXVSCROLL);
SetScrollRange(data->hWnd, SB_VERT, 0, data->sb_height - data->win_height, FALSE);
SetScrollPos(data->hWnd, SB_VERT, 0, FALSE); /* FIXME */
ShowScrollBar(data->hWnd, SB_VERT, TRUE);
}
else
{
ShowScrollBar(data->hWnd, SB_VERT, FALSE);
}
SetWindowPos(data->hWnd, 0, 0, 0, r.right - r.left + dx, r.bottom - r.top + dy,
SWP_NOMOVE|SWP_NOZORDER|SWP_SHOWWINDOW);
WCUSER_ShapeCursor(data, data->cursor_size, data->cursor_visible, TRUE);
WCUSER_PosCursor(data);
}
/******************************************************************
* WCUSER_SetTitle
*
* Sets the title to the wine console
*/
static void WCUSER_SetTitle(const struct inner_data* data)
{
WCHAR buffer[256];
if (WINECON_GetConsoleTitle(data->hConIn, buffer, sizeof(buffer)))
SetWindowText(data->hWnd, buffer);
}
/******************************************************************
* WCUSER_SetFont
*
*
*/
BOOL WCUSER_SetFont(struct inner_data* data, const LOGFONT* logfont, const TEXTMETRIC* tm)
{
if (!memcmp(logfont, &data->logFont, sizeof(LOGFONT))) return TRUE;
if (data->hFont) DeleteObject(data->hFont);
data->hFont = CreateFontIndirect(logfont);
if (!data->hFont) {Trace(0, "wrong font\n");return FALSE;}
data->cell_width = tm->tmMaxCharWidth; /* font is fixed Avg == Max */
data->cell_height = tm->tmHeight;
data->logFont = *logfont;
WCUSER_ComputePositions(data);
WCUSER_NewBitmap(data, TRUE);
InvalidateRect(data->hWnd, NULL, FALSE);
UpdateWindow(data->hWnd);
return TRUE;
}
/******************************************************************
* WCUSER_GetCell
*
* Get a cell from the a relative coordinate in window (takes into
* account the scrolling)
*/
static COORD WCUSER_GetCell(const struct inner_data* data, LPARAM lParam)
{
COORD c;
c.X = data->win_pos.X + (short)LOWORD(lParam) / data->cell_width;
c.Y = data->win_pos.Y + (short)HIWORD(lParam) / data->cell_height;
return c;
}
/******************************************************************
* WCUSER_GetSelectionRect
*
* Get the selection rectangle
*/
static void WCUSER_GetSelectionRect(const struct inner_data* data, LPRECT r)
{
r->left = (min(data->selectPt1.X, data->selectPt2.X) ) * data->cell_width;
r->top = (min(data->selectPt1.Y, data->selectPt2.Y) ) * data->cell_height;
r->right = (max(data->selectPt1.X, data->selectPt2.X) + 1) * data->cell_width;
r->bottom = (max(data->selectPt1.Y, data->selectPt2.Y) + 1) * data->cell_height;
}
/******************************************************************
* WCUSER_SetSelection
*
*
*/
static void WCUSER_SetSelection(const struct inner_data* data, HDC hRefDC)
{
HDC hDC;
RECT r;
WCUSER_GetSelectionRect(data, &r);
hDC = hRefDC ? hRefDC : GetDC(data->hWnd);
if (hDC)
{
if (data->hWnd == GetFocus() && data->cursor_visible)
HideCaret(data->hWnd);
InvertRect(hDC, &r);
if (hDC != hRefDC)
ReleaseDC(data->hWnd, hDC);
if (data->hWnd == GetFocus() && data->cursor_visible)
ShowCaret(data->hWnd);
}
}
/******************************************************************
* WCUSER_MoveSelection
*
*
*/
static void WCUSER_MoveSelection(struct inner_data* data, COORD dst, BOOL final)
{
RECT r;
HDC hDC;
WCUSER_GetSelectionRect(data, &r);
hDC = GetDC(data->hWnd);
if (hDC)
{
if (data->hWnd == GetFocus() && data->cursor_visible)
HideCaret(data->hWnd);
InvertRect(hDC, &r);
}
data->selectPt2 = dst;
if (hDC)
{
WCUSER_GetSelectionRect(data, &r);
InvertRect(hDC, &r);
ReleaseDC(data->hWnd, hDC);
if (data->hWnd == GetFocus() && data->cursor_visible)
ShowCaret(data->hWnd);
}
if (final)
{
ReleaseCapture();
data->hasSelection = TRUE;
}
}
/******************************************************************
* WCUSER_CopySelectionToClipboard
*
* Copies the current selection into the clipboard
*/
static void WCUSER_CopySelectionToClipboard(const struct inner_data* data)
{
HANDLE hMem;
LPWSTR p;
unsigned w, h;
w = abs(data->selectPt1.X - data->selectPt2.X) + 2;
h = abs(data->selectPt1.Y - data->selectPt2.Y) + 1;
if (!OpenClipboard(data->hWnd)) return;
EmptyClipboard();
hMem = GlobalAlloc(GMEM_MOVEABLE, (w * h - 1) * sizeof(WCHAR));
if (hMem && (p = GlobalLock(hMem)))
{
COORD c;
int y;
c.X = data->win_pos.X + min(data->selectPt1.X, data->selectPt2.X);
c.Y = data->win_pos.Y + min(data->selectPt1.Y, data->selectPt2.Y);
for (y = 0; y < h; y++, c.Y++)
{
ReadConsoleOutputCharacter(data->hConOut, &p[y * w], w - 1, c, NULL);
if (y < h - 1) p[y * w + w - 1] = '\n';
}
GlobalUnlock(hMem);
SetClipboardData(CF_UNICODETEXT, hMem);
}
CloseClipboard();
}
/******************************************************************
* WCUSER_PasteFromClipboard
*
*
*/
static void WCUSER_PasteFromClipboard(struct inner_data* data)
{
HANDLE h;
WCHAR* ptr;
if (!OpenClipboard(data->hWnd)) return;
h = GetClipboardData(CF_UNICODETEXT);
if (h && (ptr = GlobalLock(h)))
{
int i, len = GlobalSize(h) / sizeof(WCHAR);
INPUT_RECORD ir[2];
DWORD n;
SHORT sh;
ir[0].EventType = KEY_EVENT;
ir[0].Event.KeyEvent.wRepeatCount = 0;
ir[0].Event.KeyEvent.dwControlKeyState = 0;
ir[0].Event.KeyEvent.bKeyDown = TRUE;
/* generate the corresponding input records */
for (i = 0; i < len; i++)
{
/* FIXME: the modifying keys are not generated (shift, ctrl...) */
sh = VkKeyScan(ptr[i]);
ir[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(sh);
ir[0].Event.KeyEvent.wVirtualScanCode = MapVirtualKey(LOBYTE(sh), 0);
ir[0].Event.KeyEvent.uChar.UnicodeChar = ptr[i];
ir[1] = ir[0];
ir[1].Event.KeyEvent.bKeyDown = FALSE;
WriteConsoleInput(data->hConIn, ir, 2, &n);
}
GlobalUnlock(h);
}
CloseClipboard();
}
static void WCUSER_Refresh(const struct inner_data* data, int tp, int bm)
{
if (data->win_pos.Y <= bm && data->win_pos.Y + data->win_height >= tp)
{
RECT r;
r.left = 0;
r.right = data->win_width * data->cell_width;
r.top = (tp - data->win_pos.Y) * data->cell_height;
r.bottom = (bm - data->win_pos.Y + 1) * data->cell_height;
InvalidateRect(data->hWnd, &r, FALSE);
WCUSER_FillMemDC(data, tp, bm);
UpdateWindow(data->hWnd);
}
}
/******************************************************************
* WCUSER_Paint
*
*
*/
static void WCUSER_Paint(const struct inner_data* data)
{
PAINTSTRUCT ps;
BeginPaint(data->hWnd, &ps);
BitBlt(ps.hdc, 0, 0, data->win_width * data->cell_width, data->win_height * data->cell_height,
data->hMemDC, data->win_pos.X * data->cell_width, data->win_pos.Y * data->cell_height,
SRCCOPY);
if (data->hasSelection)
WCUSER_SetSelection(data, ps.hdc);
EndPaint(data->hWnd, &ps);
}
/******************************************************************
* WCUSER_Scroll
*
*
*/
static void WCUSER_Scroll(struct inner_data* data, int pos, BOOL horz)
{
if (horz)
{
SetScrollPos(data->hWnd, SB_HORZ, pos, TRUE);
data->win_pos.X = pos;
InvalidateRect(data->hWnd, NULL, FALSE);
}
else
{
SetScrollPos(data->hWnd, SB_VERT, pos, TRUE);
data->win_pos.Y = pos;
}
InvalidateRect(data->hWnd, NULL, FALSE);
}
struct font_chooser {
struct inner_data* data;
int done;
};
/******************************************************************
* WCUSER_ValidateFontMetric
*
* Returns true if the font described in tm is usable as a font for the renderer
*/
BOOL WCUSER_ValidateFontMetric(const struct inner_data* data, const TEXTMETRIC* tm)
{
return tm->tmMaxCharWidth * data->win_width < GetSystemMetrics(SM_CXSCREEN) &&
tm->tmHeight * data->win_height < GetSystemMetrics(SM_CYSCREEN) &&
!tm->tmItalic && !tm->tmUnderlined && !tm->tmStruckOut;
}
/******************************************************************
* WCUSER_ValidateFont
*
* Returns true if the font family described in lf is usable as a font for the renderer
*/
BOOL WCUSER_ValidateFont(const struct inner_data* data, const LOGFONT* lf)
{
return (lf->lfPitchAndFamily & 3) == FIXED_PITCH && (lf->lfPitchAndFamily & 0xF0) == FF_MODERN;
}
/******************************************************************
* get_first_font_enum_2
* get_first_font_enum
*
* Helper functions to get a decent font for the renderer
*/
static int CALLBACK get_first_font_enum_2(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct font_chooser* fc = (struct font_chooser*)lParam;
if (WCUSER_ValidateFontMetric(fc->data, tm))
{
WCUSER_SetFont(fc->data, lf, tm);
fc->done = 1;
return 0;
}
return 1;
}
static int CALLBACK get_first_font_enum(const LOGFONT* lf, const TEXTMETRIC* tm,
DWORD FontType, LPARAM lParam)
{
struct font_chooser* fc = (struct font_chooser*)lParam;
if (WCUSER_ValidateFont(fc->data, lf))
{
EnumFontFamilies(fc->data->hMemDC, lf->lfFaceName, get_first_font_enum_2, lParam);
return !fc->done; /* we just need the first matching one... */
}
return 1;
}
/******************************************************************
* WCUSER_Create
*
* Creates the window for the rendering
*/
static LRESULT WCUSER_Create(HWND hWnd, LPCREATESTRUCT lpcs)
{
struct inner_data* data;
HMENU hMenu;
HMENU hSubMenu;
WCHAR buff[256];
HINSTANCE hInstance = GetModuleHandle(NULL);
data = lpcs->lpCreateParams;
SetWindowLong(hWnd, 0L, (DWORD)data);
data->hWnd = hWnd;
data->cursor_size = 101; /* invalid value, will trigger a complete cleanup */
/* FIXME: error handling & memory cleanup */
hSubMenu = CreateMenu();
if (!hSubMenu) return 0;
hMenu = GetSystemMenu(hWnd, FALSE);
if (!hMenu) return 0;
LoadString(hInstance, IDS_MARK, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_MARK, buff);
LoadString(hInstance, IDS_COPY, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_COPY, buff);
LoadString(hInstance, IDS_PASTE, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PASTE, buff);
LoadString(hInstance, IDS_SELECTALL, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SELECTALL, buff);
LoadString(hInstance, IDS_SCROLL, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SCROLL, buff);
LoadString(hInstance, IDS_SEARCH, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hSubMenu, -1, MF_BYPOSITION|MF_STRING, IDS_SEARCH, buff);
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
LoadString(hInstance, IDS_EDIT, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR)hSubMenu, buff);
LoadString(hInstance, IDS_DEFAULT, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_DEFAULT, buff);
LoadString(hInstance, IDS_PROPERTY, buff, sizeof(buff) / sizeof(WCHAR));
InsertMenu(hMenu, -1, MF_BYPOSITION|MF_STRING, IDS_PROPERTY, buff);
data->hMemDC = CreateCompatibleDC(0);
if (!data->hMemDC) {Trace(0, "no mem dc\n");return 0;}
return 0;
}
/******************************************************************
* WCUSER_SetMenuDetails
*
* Grays / ungrays the menu items according to their state
*/
static void WCUSER_SetMenuDetails(const struct inner_data* data)
{
HMENU hMenu = GetSystemMenu(data->hWnd, FALSE);
if (!hMenu) {Trace(0, "Issue in getting menu bits\n");return;}
/* FIXME: set the various menu items to their state (if known) */
EnableMenuItem(hMenu, IDS_DEFAULT, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hMenu, IDS_MARK, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hMenu, IDS_COPY, MF_BYCOMMAND|(data->hasSelection ? MF_ENABLED : MF_GRAYED));
EnableMenuItem(hMenu, IDS_PASTE,
MF_BYCOMMAND|(IsClipboardFormatAvailable(CF_UNICODETEXT)
? MF_ENABLED : MF_GRAYED));
/* Select all: always active */
EnableMenuItem(hMenu, IDS_SCROLL, MF_BYCOMMAND|MF_GRAYED);
EnableMenuItem(hMenu, IDS_SEARCH, MF_BYCOMMAND|MF_GRAYED);
}
/******************************************************************
* WCUSER_GenerateInputRecord
*
* generates input_record from windows WM_KEYUP/WM_KEYDOWN messages
*/
static void WCUSER_GenerateInputRecord(struct inner_data* data, BOOL down,
WPARAM wParam, LPARAM lParam, BOOL sys)
{
INPUT_RECORD ir;
DWORD n;
WCHAR buf[2];
BYTE keyState[256];
static WCHAR last; /* keep last char seen as feed for key up message */
ir.EventType = KEY_EVENT;
ir.Event.KeyEvent.bKeyDown = down;
ir.Event.KeyEvent.wRepeatCount = LOWORD(lParam);
ir.Event.KeyEvent.wVirtualKeyCode = wParam;
ir.Event.KeyEvent.wVirtualScanCode = HIWORD(lParam) & 0xFF;
GetKeyboardState(keyState);
ir.Event.KeyEvent.uChar.UnicodeChar = 0;
ir.Event.KeyEvent.dwControlKeyState = 0;
if (lParam & (1L << 24)) ir.Event.KeyEvent.dwControlKeyState |= ENHANCED_KEY;
if (keyState[VK_SHIFT] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
if (keyState[VK_CONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; /* FIXME: gotta choose one */
if (keyState[VK_LCONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED;
if (keyState[VK_RCONTROL] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED;
if (sys) ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; /* FIXME: gotta choose one */
if (keyState[VK_LMENU] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED;
if (keyState[VK_RMENU] & 0x80) ir.Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED;
if (keyState[VK_CAPITAL] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= CAPSLOCK_ON;
if (keyState[VK_NUMLOCK] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= NUMLOCK_ON;
if (keyState[VK_SCROLL] & 0x01) ir.Event.KeyEvent.dwControlKeyState |= SCROLLLOCK_ON;
if (data->hasSelection && ir.Event.KeyEvent.dwControlKeyState == 0 &&
ir.Event.KeyEvent.wVirtualKeyCode == VK_RETURN)
{
data->hasSelection = FALSE;
WCUSER_SetSelection(data, 0);
WCUSER_CopySelectionToClipboard(data);
return;
}
if (!(ir.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY))
{
if (down)
{
switch (ToUnicode(wParam, HIWORD(lParam), keyState, buf, 2, 0))
{
case 2:
/* FIXME... should generate two events... */
/* fall thru */
case 1:
last = buf[0];
break;
default:
last = 0;
break;
}
}
ir.Event.KeyEvent.uChar.UnicodeChar = last; /* FIXME HACKY... and buggy 'coz it should be a stack, not a single value */
if (!down) last = 0;
}
WriteConsoleInput(data->hConIn, &ir, 1, &n);
}
/******************************************************************
* WCUSER_Proc
*
*
*/
static LRESULT CALLBACK WCUSER_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
struct inner_data* data = (struct inner_data*)GetWindowLong(hWnd, 0);
switch (uMsg)
{
case WM_CREATE:
return WCUSER_Create(hWnd, (LPCREATESTRUCT)lParam);
case WM_DESTROY:
data->hWnd = 0;
PostQuitMessage(0);
break;
case WM_PAINT:
WCUSER_Paint(data);
break;
case WM_KEYDOWN:
case WM_KEYUP:
WCUSER_GenerateInputRecord(data, uMsg == WM_KEYDOWN, wParam, lParam, FALSE);
break;
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
WCUSER_GenerateInputRecord(data, uMsg == WM_SYSKEYDOWN, wParam, lParam, TRUE);
break;
case WM_LBUTTONDOWN:
/* EPP if (wParam != MK_LBUTTON) */
if (data->hasSelection)
{
data->hasSelection = FALSE;
}
else
{
data->selectPt1 = data->selectPt2 = WCUSER_GetCell(data, lParam);
SetCapture(data->hWnd);
}
WCUSER_SetSelection(data, 0);
break;
case WM_MOUSEMOVE:
/* EPP if (wParam != MK_LBUTTON) */
if (GetCapture() == data->hWnd)
{
WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), FALSE);
}
break;
case WM_LBUTTONUP:
/* EPP if (wParam != MK_LBUTTON) */
if (GetCapture() == data->hWnd)
{
WCUSER_MoveSelection(data, WCUSER_GetCell(data, lParam), TRUE);
}
break;
case WM_SETFOCUS:
if (data->cursor_visible)
{
CreateCaret(data->hWnd, data->cursor_bitmap, data->cell_width, data->cell_height);
WCUSER_PosCursor(data);
}
break;
case WM_KILLFOCUS:
if (data->cursor_visible)
DestroyCaret();
break;
case WM_HSCROLL:
{
int pos = data->win_pos.X;
switch (LOWORD(wParam))
{
case SB_PAGEUP: pos -= 8; break;
case SB_PAGEDOWN: pos += 8; break;
case SB_LINEUP: pos--; break;
case SB_LINEDOWN: pos++; break;
case SB_THUMBTRACK: pos = HIWORD(wParam); break;
default: break;
}
if (pos < 0) pos = 0;
if (pos > data->sb_width - data->win_width) pos = data->sb_width - data->win_width;
if (pos != data->win_pos.X)
{
ScrollWindow(hWnd, (data->win_pos.X - pos) * data->cell_width, 0, NULL, NULL);
data->win_pos.X = pos;
SetScrollPos(hWnd, SB_HORZ, pos, TRUE);
UpdateWindow(hWnd);
WCUSER_PosCursor(data);
WINECON_NotifyWindowChange(data);
}
}
break;
case WM_VSCROLL:
{
int pos = data->win_pos.Y;
switch (LOWORD(wParam))
{
case SB_PAGEUP: pos -= 8; break;
case SB_PAGEDOWN: pos += 8; break;
case SB_LINEUP: pos--; break;
case SB_LINEDOWN: pos++; break;
case SB_THUMBTRACK: pos = HIWORD(wParam); break;
default: break;
}
if (pos < 0) pos = 0;
if (pos > data->sb_height - data->win_height) pos = data->sb_height - data->win_height;
if (pos != data->win_pos.Y)
{
ScrollWindow(hWnd, 0, (data->win_pos.Y - pos) * data->cell_height, NULL, NULL);
data->win_pos.Y = pos;
SetScrollPos(hWnd, SB_VERT, pos, TRUE);
UpdateWindow(hWnd);
WCUSER_PosCursor(data);
WINECON_NotifyWindowChange(data);
}
}
break;
case WM_SYSCOMMAND:
switch (wParam)
{
case IDS_DEFAULT:
Trace(0, "unhandled yet command: %x\n", wParam);
break;
case IDS_PROPERTY:
WCUSER_GetProperties(data);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
break;
case WM_RBUTTONDOWN:
WCUSER_GetProperties(data);
break;
case WM_COMMAND:
switch (wParam)
{
case IDS_MARK:
goto niy;
case IDS_COPY:
data->hasSelection = FALSE;
WCUSER_SetSelection(data, 0);
WCUSER_CopySelectionToClipboard(data);
break;
case IDS_PASTE:
WCUSER_PasteFromClipboard(data);
break;
case IDS_SELECTALL:
data->selectPt1.X = data->selectPt1.Y = 0;
data->selectPt2.X = (data->sb_width - 1) * data->cell_width;
data->selectPt2.Y = (data->sb_height - 1) * data->cell_height;
WCUSER_SetSelection(data, 0);
data->hasSelection = TRUE;
break;
case IDS_SCROLL:
case IDS_SEARCH:
niy:
Trace(0, "unhandled yet command: %x\n", wParam);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
break;
case WM_INITMENUPOPUP:
if (!HIWORD(lParam)) return DefWindowProc(hWnd, uMsg, wParam, lParam);
WCUSER_SetMenuDetails(data);
break;
default:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
/******************************************************************
* WCUSER_DeleteBackend
*
*
*/
void WCUSER_DeleteBackend(struct inner_data* data)
{
if (data->hWnd) DestroyWindow(data->hWnd);
if (data->hFont) DeleteObject(data->hFont);
if (data->cursor_bitmap) DeleteObject(data->cursor_bitmap);
if (data->hMemDC) DeleteDC(data->hMemDC);
if (data->hBitmap) DeleteObject(data->hBitmap);
}
/******************************************************************
* WCUSER_MainLoop
*
*
*/
static int WCUSER_MainLoop(struct inner_data* data)
{
MSG msg;
for (;;)
{
switch (MsgWaitForMultipleObjects(1, &data->hSynchro, FALSE, INFINITE, QS_ALLINPUT))
{
case WAIT_OBJECT_0:
if (!WINECON_GrabChanges(data))
PostQuitMessage(0);
break;
case WAIT_OBJECT_0+1:
switch (GetMessage(&msg, 0, 0, 0))
{
case -1: /* the event handle became invalid, so exit */
return -1;
case 0: /* WM_QUIT has been posted */
return 0;
default:
DispatchMessage(&msg);
break;
}
break;
default:
Trace(0, "got pb\n");
/* err */
break;
}
}
}
/******************************************************************
* WCUSER_InitBackend
*
* Initialisation part II: creation of window.
*
*/
BOOL WCUSER_InitBackend(struct inner_data* data)
{
static WCHAR wClassName[] = {'W','i','n','e','C','o','n','s','o','l','e','C','l','a','s','s',0};
WNDCLASS wndclass;
struct font_chooser fc;
data->fnMainLoop = WCUSER_MainLoop;
data->fnPosCursor = WCUSER_PosCursor;
data->fnShapeCursor = WCUSER_ShapeCursor;
data->fnComputePositions = WCUSER_ComputePositions;
data->fnRefresh = WCUSER_Refresh;
data->fnResizeScreenBuffer = WCUSER_ResizeScreenBuffer;
data->fnSetTitle = WCUSER_SetTitle;
data->fnScroll = WCUSER_Scroll;
data->fnDeleteBackend = WCUSER_DeleteBackend;
wndclass.style = 0;
wndclass.lpfnWndProc = WCUSER_Proc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(DWORD);
wndclass.hInstance = GetModuleHandle(NULL);
wndclass.hIcon = LoadIcon(0, IDI_WINLOGO);
wndclass.hCursor = LoadCursor(0, IDC_ARROW);
wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = wClassName;
RegisterClass(&wndclass);
CreateWindow(wndclass.lpszClassName, NULL,
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_HSCROLL|WS_VSCROLL,
CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, 0, 0, wndclass.hInstance, data);
if (!data->hWnd) return FALSE;
/* force update of current data */
WINECON_GrabChanges(data);
/* try to find an acceptable font */
fc.data = data;
fc.done = 0;
EnumFontFamilies(data->hMemDC, NULL, get_first_font_enum, (LPARAM)&fc);
return fc.done;
}

View File

@ -0,0 +1,75 @@
#include <winbase.h>
#include <wingdi.h>
#include <winuser.h>
#include <wincon.h>
#include "wineconsole_res.h"
struct inner_data {
unsigned sb_width; /* active screen buffer width */
unsigned sb_height; /* active screen buffer height */
CHAR_INFO* cells; /* local copy of cells (sb_width * sb_height) */
COORD win_pos; /* position (in cells) of visible part of screen buffer in window */
unsigned win_width; /* size (in cells) of visible part of window (width & height) */
unsigned win_height;
COORD cursor; /* position in cells of cursor */
int cursor_visible;
int cursor_size; /* in % of cell height */
HANDLE hConIn; /* console input handle */
HANDLE hConOut; /* screen buffer handle: has to be changed when active sb changes */
HANDLE hSynchro; /* waitable handle signalled by server when something in server has been modified */
int (*fnMainLoop)(struct inner_data* data);
void (*fnPosCursor)(const struct inner_data* data);
void (*fnShapeCursor)(struct inner_data* data, int size, int vis, BOOL force);
void (*fnComputePositions)(struct inner_data* data);
void (*fnRefresh)(const struct inner_data* data, int tp, int bm);
void (*fnResizeScreenBuffer)(struct inner_data* data);
void (*fnSetTitle)(const struct inner_data* data);
void (*fnScroll)(struct inner_data* data, int pos, BOOL horz);
void (*fnDeleteBackend)(struct inner_data* data);
/* the following fields are only user by the USER backend (should be hidden in user) */
HWND hWnd; /* handle to windows for rendering */
HFONT hFont; /* font used for rendering, usually fixed */
LOGFONT logFont; /* logFont dscription for used hFont */
unsigned cell_width; /* width in pixels of a character */
unsigned cell_height; /* height in pixels of a character */
HDC hMemDC; /* memory DC holding the bitmap below */
HBITMAP hBitmap; /* bitmap of display window content */
HBITMAP cursor_bitmap; /* bitmap used for the caret */
BOOL hasSelection; /* a rectangular mouse selection has taken place */
COORD selectPt1; /* start (and end) point of a mouse selection */
COORD selectPt2;
};
# ifdef __GNUC__
extern void XTracer(int level, const char* format, ...) __attribute__((format (printf,2,3)));
# else
extern void XTracer(int level, const char* format, ...);
# endif
#if 0
/* Trace mode */
# define Trace XTracer
#else
/* non trace mode */
# define Trace (1) ? (void)0 : XTracer
#endif
extern void WINECON_NotifyWindowChange(struct inner_data* data);
extern int WINECON_GetHistorySize(HANDLE hConIn);
extern BOOL WINECON_SetHistorySize(HANDLE hConIn, int size);
extern int WINECON_GetHistoryMode(HANDLE hConIn);
extern BOOL WINECON_SetHistoryMode(HANDLE hConIn, int mode);
extern BOOL WINECON_GetConsoleTitle(HANDLE hConIn, WCHAR* buffer, size_t len);
extern void WINECON_FetchCells(struct inner_data* data, int upd_tp, int upd_bm);
extern int WINECON_GrabChanges(struct inner_data* data);
extern BOOL WCUSER_GetProperties(struct inner_data*);
extern BOOL WCUSER_SetFont(struct inner_data* data, const LOGFONT* font, const TEXTMETRIC* tm);
extern BOOL WCUSER_ValidateFont(const struct inner_data* data, const LOGFONT* lf);
extern BOOL WCUSER_ValidateFontMetric(const struct inner_data* data, const TEXTMETRIC* tm);
extern BOOL WCUSER_InitBackend(struct inner_data* data);

View File

@ -0,0 +1,479 @@
/*
* an application for displaying Win32 console
*
* Copyright 2001 Eric Pouech
*/
#include <stdio.h>
#include <wine/server.h>
#include "winecon_private.h"
static int trace_level = 1;
void XTracer(int level, const char* format, ...)
{
char buf[1024];
va_list valist;
int len;
if (level > trace_level) return;
va_start(valist, format);
len = wvsnprintfA(buf, sizeof(buf), format, valist);
va_end(valist);
if (len <= -1)
{
len = sizeof(buf) - 1;
buf[len] = 0;
buf[len - 1] = buf[len - 2] = buf[len - 3] = '.';
}
fprintf(stderr, buf);
}
/******************************************************************
* WINECON_FetchCells
*
* updates the local copy of cells (band to update)
*/
void WINECON_FetchCells(struct inner_data* data, int upd_tp, int upd_bm)
{
int step;
int j, nr;
step = REQUEST_MAX_VAR_SIZE / (data->sb_width * 4);
for (j = upd_tp; j <= upd_bm; j += step)
{
nr = min(step, upd_bm - j + 1);
SERVER_START_VAR_REQ( read_console_output, 4 * nr * data->sb_width )
{
req->handle = (handle_t)data->hConOut;
req->x = 0;
req->y = j;
req->w = data->sb_width;
req->h = nr;
if (!SERVER_CALL_ERR())
{
if (data->sb_width != req->eff_w || nr != req->eff_h)
Trace(0, "pb here... wrong eff_w %d/%d or eff_h %d/%d\n",
req->eff_w, data->sb_width, req->eff_h, nr);
memcpy(&data->cells[j * data->sb_width], server_data_ptr(req),
4 * nr * data->sb_width);
}
}
SERVER_END_VAR_REQ;
}
data->fnRefresh(data, upd_tp, upd_bm);
}
/******************************************************************
* WINECON_NotifyWindowChange
*
* Inform server that visible window on sb has changed
*/
void WINECON_NotifyWindowChange(struct inner_data* data)
{
SERVER_START_REQ( set_console_output_info )
{
req->handle = (handle_t)data->hConOut;
req->win_left = data->win_pos.X;
req->win_top = data->win_pos.Y;
req->win_right = data->win_pos.X + data->win_width - 1;
req->win_bottom = data->win_pos.Y + data->win_height - 1;
req->mask = SET_CONSOLE_OUTPUT_INFO_DISPLAY_WINDOW;
if (!SERVER_CALL_ERR())
{
}
}
SERVER_END_REQ;
}
/******************************************************************
* WINECON_GetHistorySize
*
*
*/
int WINECON_GetHistorySize(HANDLE hConIn)
{
int ret = 0;
SERVER_START_REQ(get_console_input_info)
{
req->handle = (handle_t)hConIn;
if (!SERVER_CALL_ERR()) ret = req->history_size;
}
SERVER_END_REQ;
return ret;
}
/******************************************************************
* WINECON_SetHistorySize
*
*
*/
BOOL WINECON_SetHistorySize(HANDLE hConIn, int size)
{
BOOL ret;
SERVER_START_REQ(set_console_input_info)
{
req->handle = (handle_t)hConIn;
req->mask = SET_CONSOLE_INPUT_INFO_HISTORY_SIZE;
req->history_size = size;
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
return ret;
}
/******************************************************************
* WINECON_GetHistoryMode
*
*
*/
int WINECON_GetHistoryMode(HANDLE hConIn)
{
int ret = 0;
SERVER_START_REQ(get_console_input_info)
{
req->handle = (handle_t)hConIn;
if (!SERVER_CALL_ERR()) ret = req->history_mode;
}
SERVER_END_REQ;
return ret;
}
/******************************************************************
* WINECON_SetHistoryMode
*
*
*/
BOOL WINECON_SetHistoryMode(HANDLE hConIn, int mode)
{
BOOL ret;
SERVER_START_REQ(set_console_input_info)
{
req->handle = (handle_t)hConIn;
req->mask = SET_CONSOLE_INPUT_INFO_HISTORY_MODE;
req->history_mode = mode;
ret = !SERVER_CALL_ERR();
}
SERVER_END_REQ;
return ret;
}
/******************************************************************
* WINECON_GetConsoleTitle
*
*
*/
BOOL WINECON_GetConsoleTitle(HANDLE hConIn, WCHAR* buffer, size_t len)
{
BOOL ret;
DWORD size = 0;
SERVER_START_VAR_REQ(get_console_input_info, sizeof(buffer))
{
req->handle = (handle_t)hConIn;
if ((ret = !SERVER_CALL_ERR()))
{
size = min(len - sizeof(WCHAR), server_data_size(req));
memcpy(buffer, server_data_ptr(req), size);
buffer[size / sizeof(WCHAR)] = 0;
}
}
SERVER_END_VAR_REQ;
return ret;
}
/******************************************************************
* WINECON_GrabChanges
*
* A change occurs, try to figure out which
*/
int WINECON_GrabChanges(struct inner_data* data)
{
struct console_renderer_event evts[16];
int i, num;
HANDLE h;
SERVER_START_VAR_REQ( get_console_renderer_events, sizeof(evts) )
{
req->handle = (handle_t)data->hSynchro;
if (!SERVER_CALL_ERR())
{
num = server_data_size(req);
memcpy(evts, server_data_ptr(req), num);
num /= sizeof(evts[0]);
}
else num = 0;
}
SERVER_END_VAR_REQ;
if (!num) {Trace(0, "hmm renderer signaled but no events available\n"); return 1;}
/* FIXME: should do some event compression here (cursor pos, update) */
Trace(1, "Change notification:");
for (i = 0; i < num; i++)
{
switch (evts[i].event)
{
case CONSOLE_RENDERER_TITLE_EVENT:
data->fnSetTitle(data);
break;
case CONSOLE_RENDERER_ACTIVE_SB_EVENT:
SERVER_START_REQ( open_console )
{
req->from = (int)data->hConIn;
req->access = GENERIC_READ | GENERIC_WRITE;
req->share = FILE_SHARE_READ | FILE_SHARE_WRITE;
req->inherit = FALSE;
h = SERVER_CALL_ERR() ? 0 : (HANDLE)req->handle;
}
SERVER_END_REQ;
Trace(1, " active(%d)", (int)h);
if (h)
{
CloseHandle(data->hConOut);
data->hConOut = h;
}
break;
case CONSOLE_RENDERER_SB_RESIZE_EVENT:
if (data->sb_width != evts[i].u.resize.width ||
data->sb_height != evts[i].u.resize.height)
{
Trace(1, " resize(%d,%d)", evts[i].u.resize.width, evts[i].u.resize.height);
data->sb_width = evts[i].u.resize.width;
data->sb_height = evts[i].u.resize.height;
data->cells = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, data->cells,
data->sb_width * data->sb_height * sizeof(CHAR_INFO));
if (!data->cells) {Trace(0, "OOM\n"); exit(0);}
data->fnResizeScreenBuffer(data);
data->fnComputePositions(data);
}
break;
case CONSOLE_RENDERER_UPDATE_EVENT:
Trace(1, " update(%d,%d)", evts[i].u.update.top, evts[i].u.update.bottom);
WINECON_FetchCells(data, evts[i].u.update.top, evts[i].u.update.bottom);
break;
case CONSOLE_RENDERER_CURSOR_POS_EVENT:
if (evts[i].u.cursor_pos.x != data->cursor.X || evts[i].u.cursor_pos.y != data->cursor.Y)
{
data->cursor.X = evts[i].u.cursor_pos.x;
data->cursor.Y = evts[i].u.cursor_pos.y;
data->fnPosCursor(data);
Trace(1, " curs-pos(%d,%d)",evts[i].u.cursor_pos.x, evts[i].u.cursor_pos.y);
}
break;
case CONSOLE_RENDERER_CURSOR_GEOM_EVENT:
if (evts[i].u.cursor_geom.size != data->cursor_size ||
evts[i].u.cursor_geom.visible != data->cursor_visible)
{
data->fnShapeCursor(data, evts[i].u.cursor_geom.size,
evts[i].u.cursor_geom.visible, FALSE);
Trace(1, " curs-geom(%d,%d)",
evts[i].u.cursor_geom.size, evts[i].u.cursor_geom.visible);
}
break;
case CONSOLE_RENDERER_DISPLAY_EVENT:
if (evts[i].u.display.left != data->win_pos.X)
{
data->fnScroll(data, evts[i].u.display.left, TRUE);
data->fnPosCursor(data);
Trace(1, " h-scroll(%d)", evts[i].u.display.left);
}
if (evts[i].u.display.top != data->win_pos.Y)
{
data->fnScroll(data, evts[i].u.display.top, FALSE);
data->fnPosCursor(data);
Trace(1, " v-scroll(%d)", evts[i].u.display.top);
}
if (evts[i].u.display.width != data->win_width ||
evts[i].u.display.height != data->win_height)
{
Trace(1, " win-size(%d,%d)", evts[i].u.display.width, evts[i].u.display.height);
data->win_width = evts[i].u.display.width;
data->win_height = evts[i].u.display.height;
data->fnComputePositions(data);
}
break;
case CONSOLE_RENDERER_EXIT_EVENT:
Trace(1, ". Exit!!\n");
return 0;
default:
Trace(0, "Unknown event type (%d)\n", evts[i].event);
}
}
Trace(1, ". Done\n");
return 1;
}
/******************************************************************
* WINECON_Delete
*
* Destroy wineconsole internal data
*/
static void WINECON_Delete(struct inner_data* data)
{
if (!data) return;
if (data->hConIn) CloseHandle(data->hConIn);
if (data->hConOut) CloseHandle(data->hConOut);
if (data->hSynchro) CloseHandle(data->hSynchro);
if (data->cells) HeapFree(GetProcessHeap(), 0, data->cells);
data->fnDeleteBackend(data);
HeapFree(GetProcessHeap(), 0, data);
}
/******************************************************************
* WINECON_Init
*
* Initialisation part I. Creation of server object (console input and
* active screen buffer)
*/
static struct inner_data* WINECON_Init(HINSTANCE hInst, void* pid)
{
struct inner_data* data = NULL;
DWORD ret;
WCHAR szTitle[] = {'W','i','n','e',' ','c','o','n','s','o','l','e',0};
size_t len;
data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
if (!data) return 0;
/* the handles here are created without the whistles and bells required by console
* (mainly because wineconsole doesn't need it)
* - there are not inheritable
* - hConIn is not synchronizable
*/
SERVER_START_REQ(alloc_console)
{
req->access = GENERIC_READ | GENERIC_WRITE;
req->inherit = FALSE;
req->pid = pid;
ret = !SERVER_CALL_ERR();
data->hConIn = (HANDLE)req->handle_in;
data->hSynchro = (HANDLE)req->event;
}
SERVER_END_REQ;
if (!ret) goto error;
len = lstrlenW(szTitle) * sizeof(WCHAR);
len = min(len, REQUEST_MAX_VAR_SIZE);
SERVER_START_VAR_REQ(set_console_input_info, len)
{
req->handle = (handle_t)data->hConIn;
req->mask = SET_CONSOLE_INPUT_INFO_TITLE;
memcpy(server_data_ptr(req), szTitle, len);
ret = !SERVER_CALL_ERR();
}
SERVER_END_VAR_REQ;
if (ret)
{
SERVER_START_REQ(create_console_output)
{
req->handle_in = (handle_t)data->hConIn;
req->access = GENERIC_WRITE|GENERIC_READ;
req->share = FILE_SHARE_READ|FILE_SHARE_WRITE;
req->inherit = FALSE;
data->hConOut = (HANDLE)(SERVER_CALL_ERR() ? 0 : req->handle_out);
}
SERVER_END_REQ;
if (data->hConOut) return data;
}
error:
WINECON_Delete(data);
return NULL;
}
/******************************************************************
* WINECON_Spawn
*
* Spawn the child processus when invoked with wineconsole foo bar
*/
static BOOL WINECON_Spawn(struct inner_data* data, LPCSTR lpCmdLine)
{
PROCESS_INFORMATION info;
STARTUPINFO startup;
LPWSTR ptr = GetCommandLine(); /* we're unicode... */
BOOL done;
/* we're in the case wineconsole <exe> <options>... spawn the new process */
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
startup.wShowWindow = SW_SHOWNORMAL;
/* the attributes of wineconsole's handles are not adequate for inheritance, so
* get them with the correct attributes before process creation
*/
if (!DuplicateHandle(GetCurrentProcess(), data->hConIn, GetCurrentProcess(),
&startup.hStdInput, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, TRUE, 0) ||
!DuplicateHandle(GetCurrentProcess(), data->hConOut, GetCurrentProcess(),
&startup.hStdOutput, GENERIC_READ|GENERIC_WRITE, TRUE, 0) ||
!DuplicateHandle(GetCurrentProcess(), data->hConOut, GetCurrentProcess(),
&startup.hStdError, GENERIC_READ|GENERIC_WRITE, TRUE, 0))
{
Trace(0, "can't dup handles\n");
/* no need to delete handles, we're exiting the programm anyway */
return FALSE;
}
/* we could have several ' ' in process command line... so try first space...
* FIXME:
* the correct way would be to check the existence of the left part of ptr
* (to be a file)
*/
while (*ptr && *ptr++ != ' ');
done = *ptr && CreateProcess(NULL, ptr, NULL, NULL, TRUE, 0L, NULL, NULL, &startup, &info);
/* we no longer need the handles passed to the child for the console */
CloseHandle(startup.hStdInput);
CloseHandle(startup.hStdOutput);
CloseHandle(startup.hStdError);
return done;
}
/******************************************************************
* WINECON_WinMain
*
* wineconsole can either be started as:
* wineconsole <int> used when a new console is created (AllocConsole)
* wineconsole <pgm> <arguments> used to start the program <pgm> from the command line in
* a freshly created console
*/
int PASCAL WINECON_WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPCSTR lpCmdLine, UINT nCmdShow)
{
struct inner_data* data;
int ret = 1;
unsigned evt;
/* case of wineconsole <evt>, signal process that created us that we're up and running */
if (sscanf(lpCmdLine, "%d", &evt) == 1)
{
if (!(data = WINECON_Init(hInst, 0))) return 0;
ret = SetEvent((HANDLE)evt);
}
else
{
if (!(data = WINECON_Init(hInst, (void*)GetCurrentProcessId()))) return 0;
ret = WINECON_Spawn(data, lpCmdLine);
}
if (ret && WCUSER_InitBackend(data))
{
ret = data->fnMainLoop(data);
}
WINECON_Delete(data);
return ret;
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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"

View File

@ -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,14 +265,27 @@ static BOOL process_init( char *argv[] )
SERVER_END_VAR_REQ;
if (!ret) return FALSE;
/* 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 );
if (create_flags & CREATE_NEW_CONSOLE)
set_console_handles( current_startupinfo.hStdOutput );
/* Create the process heap */
current_process.heap = HeapCreate( HEAP_GROWABLE, 0, 0 );
}
/* 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;
}

File diff suppressed because it is too large Load Diff

35
server/console.h Normal file
View File

@ -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 */

View File

@ -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 */

View File

@ -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 );
}
}

View File

@ -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;
}

View File

@ -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 );

View File

@ -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,
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 )
{

View File

@ -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 */

View File

@ -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 */

View File

@ -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,

View File

@ -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",

View File

@ -9,6 +9,7 @@
%formats =
(
"int" => "%d",
"short int" => "%d",
"char" => "%c",
"unsigned char" => "%02x",
"unsigned short"=> "%04x",

View File

@ -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 \

File diff suppressed because it is too large Load Diff

708
win32/editline.c Normal file
View File

@ -0,0 +1,708 @@
/*
* line edition function for Win32 console
*
* Copyright 2001 Eric Pouech
*/
#include "config.h"
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wincon.h"
#include "wine/unicode.h"
#include "winnls.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(console);
/* console.c */
extern int CONSOLE_GetHistory(int idx, WCHAR* buf, int buf_len);
extern BOOL CONSOLE_AppendHistory(const WCHAR *p);
extern unsigned int CONSOLE_GetNumHistoryEntries(void);
struct WCEL_Context;
typedef struct
{
WCHAR val; /* vk or unicode char */
void (*func)(struct WCEL_Context* ctx);
} KeyEntry;
typedef struct
{
DWORD keyState; /* keyState (from INPUT_RECORD) to match */
BOOL chkChar; /* check vk or char */
KeyEntry* entries; /* array of entries */
} KeyMap;
typedef struct WCEL_Context {
WCHAR* line; /* the line being edited */
size_t alloc; /* number of WCHAR in line */
unsigned len; /* number of chars in line */
unsigned ofs; /* offset for cursor in current line */
WCHAR* yanked; /* yanked line */
unsigned mark; /* marked point (emacs mode only) */
CONSOLE_SCREEN_BUFFER_INFO csbi; /* current state (initial cursor, window size, attribute) */
HANDLE hConIn;
HANDLE hConOut;
unsigned done : 1, /* to 1 when we're done with editing */
error : 1; /* to 1 when an error occurred in the editing */
unsigned histSize;
unsigned histPos;
WCHAR* histCurr;
} WCEL_Context;
#if 0
static void WCEL_Dump(WCEL_Context* ctx, const char* pfx)
{
MESSAGE("%s: [line=%s[alloc=%u] ofs=%u len=%u start=(%d,%d) mask=%c%c\n"
"\t\thist=(size=%u pos=%u curr=%s)\n",
pfx, debugstr_w(ctx->line), ctx->alloc, ctx->ofs, ctx->len,
ctx->csbi.dwCursorPosition.X, ctx->csbi.dwCursorPosition.Y,
ctx->done ? 'D' : 'd', ctx->error ? 'E' : 'e',
ctx->histSize, ctx->histPos, debugstr_w(ctx->histCurr));
}
#endif
/* ====================================================================
*
* Console helper functions
*
* ====================================================================*/
static BOOL WCEL_Get(WCEL_Context* ctx, INPUT_RECORD* ir)
{
DWORD retv;
for (;;)
{
/* data available ? */
if (ReadConsoleInputW(ctx->hConIn, ir, 1, &retv) && retv == 1)
return TRUE;
/* then wait... */
switch (WaitForSingleObject(ctx->hConIn, INFINITE))
{
case WAIT_OBJECT_0:
break;
default:
/* we have checked that hConIn was a console handle (could be sb) */
ERR("Shouldn't happen\n");
/* fall thru */
case WAIT_ABANDONED:
case WAIT_TIMEOUT:
ctx->error = 1;
ERR("hmm bad situation\n");
return FALSE;
}
}
}
static inline void WCEL_Beep(WCEL_Context* ctx)
{
Beep(400, 300);
}
static inline COORD WCEL_GetCoord(WCEL_Context* ctx, int ofs)
{
COORD c;
c.X = ctx->csbi.dwCursorPosition.X + ofs;
c.Y = ctx->csbi.dwCursorPosition.Y;
return c;
}
static inline void WCEL_GetRect(WCEL_Context* ctx, LPSMALL_RECT sr, int beg, int end)
{
sr->Left = ctx->csbi.dwCursorPosition.X + beg;
sr->Top = ctx->csbi.dwCursorPosition.Y;
sr->Right = ctx->csbi.dwCursorPosition.X + end;
sr->Bottom = ctx->csbi.dwCursorPosition.Y;
}
/* ====================================================================
*
* context manipulation functions
*
* ====================================================================*/
static BOOL WCEL_Grow(WCEL_Context* ctx, size_t len)
{
if (ctx->csbi.dwCursorPosition.X + ctx->ofs + len >= ctx->csbi.dwSize.X)
{
FIXME("Current implementation doesn't allow edition to spray across several lines\n");
return FALSE;
}
if (ctx->len + len >= ctx->alloc)
{
WCHAR* newline;
newline = HeapReAlloc(GetProcessHeap(), 0, ctx->line, sizeof(WCHAR) * (ctx->alloc + 32));
if (!newline) return FALSE;
ctx->line = newline;
ctx->alloc += 32;
}
return TRUE;
}
static void WCEL_DeleteString(WCEL_Context* ctx, int beg, int end)
{
SMALL_RECT scl, clp;
CHAR_INFO ci;
if (end < ctx->len)
memmove(&ctx->line[beg], &ctx->line[end], (ctx->len - end) * sizeof(WCHAR));
/* make the source rect bigger than the actual rect to that the part outside the clip
* rect (before the scroll) will get redrawn after the scroll
*/
WCEL_GetRect(ctx, &scl, end, ctx->len + end - beg);
WCEL_GetRect(ctx, &clp, beg, ctx->len);
ci.Char.UnicodeChar = ' ';
ci.Attributes = ctx->csbi.wAttributes;
ScrollConsoleScreenBufferW(ctx->hConOut, &scl, &clp, WCEL_GetCoord(ctx, beg), &ci);
ctx->len -= end - beg;
ctx->line[ctx->len] = 0;
}
static void WCEL_InsertString(WCEL_Context* ctx, const WCHAR* str)
{
size_t len = lstrlenW(str);
if (!len || !WCEL_Grow(ctx, len)) return;
if (ctx->len > ctx->ofs)
memmove(&ctx->line[ctx->ofs + len], &ctx->line[ctx->ofs], (ctx->len - ctx->ofs) * sizeof(WCHAR));
memcpy(&ctx->line[ctx->ofs], str, len * sizeof(WCHAR));
ctx->len += len;
ctx->line[ctx->len] = 0;
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], ctx->len - ctx->ofs,
WCEL_GetCoord(ctx, ctx->ofs), NULL);
ctx->ofs += len;
}
static void WCEL_InsertChar(WCEL_Context* ctx, WCHAR c)
{
WCHAR buffer[2];
/* do not insert 0..31 control characters */
if (c < ' ')
{
if (c != '\t') return;
}
buffer[0] = c;
buffer[1] = 0;
WCEL_InsertString(ctx, buffer);
}
static void WCEL_SaveYank(WCEL_Context* ctx, int beg, int end)
{
int len = end - beg;
ctx->yanked = HeapReAlloc(GetProcessHeap(), 0, ctx->yanked, (len + 1) * sizeof(WCHAR));
if (!ctx->yanked) return;
memcpy(ctx->yanked, &ctx->line[beg], len * sizeof(WCHAR));
ctx->yanked[len] = 0;
}
/* FIXME NTDLL doesn't export iswalnum, and I don't want to link in msvcrt when most
* of the data lay in unicode lib
*/
static inline BOOL WCEL_iswalnum(WCHAR wc)
{
return get_char_typeW(wc) & (C1_ALPHA|C1_DIGIT|C1_LOWER|C1_UPPER);
}
static int WCEL_GetLeftWordTransition(WCEL_Context* ctx, int ofs)
{
ofs--;
while (ofs >= 0 && !WCEL_iswalnum(ctx->line[ofs])) ofs--;
while (ofs >= 0 && WCEL_iswalnum(ctx->line[ofs])) ofs--;
if (ofs >= 0) ofs++;
return max(ofs, 0);
}
static int WCEL_GetRightWordTransition(WCEL_Context* ctx, int ofs)
{
ofs++;
while (ofs <= ctx->len && !WCEL_iswalnum(ctx->line[ofs])) ofs++;
while (ofs <= ctx->len && WCEL_iswalnum(ctx->line[ofs])) ofs++;
return min(ofs, ctx->len);
}
static WCHAR* WCEL_GetHistory(WCEL_Context* ctx, int idx)
{
WCHAR* ptr;
if (idx == ctx->histSize - 1)
{
ptr = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(ctx->histCurr) + 1) * sizeof(WCHAR));
lstrcpyW(ptr, ctx->histCurr);
}
else
{
int len = CONSOLE_GetHistory(idx, NULL, 0);
if ((ptr = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
{
CONSOLE_GetHistory(idx, ptr, len);
}
}
return ptr;
}
static void WCEL_HistoryInit(WCEL_Context* ctx)
{
ctx->histPos = CONSOLE_GetNumHistoryEntries();
ctx->histSize = ctx->histPos + 1;
ctx->histCurr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WCHAR));
}
static void WCEL_MoveToHist(WCEL_Context* ctx, int idx)
{
WCHAR* data = WCEL_GetHistory(ctx, idx);
int len = lstrlenW(data) + 1;
/* save current line edition for recall when needed (FIXME seems broken to me) */
if (ctx->histPos == ctx->histSize - 1)
{
if (ctx->histCurr) HeapFree(GetProcessHeap(), 0, ctx->histCurr);
ctx->histCurr = HeapAlloc(GetProcessHeap(), 0, (ctx->len + 1) * sizeof(WCHAR));
memcpy(ctx->histCurr, ctx->line, (ctx->len + 1) * sizeof(WCHAR));
}
/* need to clean also the screen if new string is shorter than old one */
WCEL_DeleteString(ctx, 0, ctx->len);
ctx->ofs = 0;
/* insert new string */
if (WCEL_Grow(ctx, len))
{
WCEL_InsertString(ctx, data);
HeapFree(GetProcessHeap(), 0, data);
ctx->histPos = idx;
}
}
/* ====================================================================
*
* basic edition functions
*
* ====================================================================*/
static void WCEL_Done(WCEL_Context* ctx)
{
if (!WCEL_Grow(ctx, 1)) return;
ctx->line[ctx->len++] = '\n';
ctx->line[ctx->len] = 0;
WriteConsoleA(ctx->hConOut, "\n", 1, NULL, NULL);
ctx->done = 1;
}
static void WCEL_MoveLeft(WCEL_Context* ctx)
{
if (ctx->ofs > 0) ctx->ofs--;
}
static void WCEL_MoveRight(WCEL_Context* ctx)
{
if (ctx->ofs < ctx->len) ctx->ofs++;
}
static void WCEL_MoveToLeftWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetLeftWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs) ctx->ofs = new_ofs;
}
static void WCEL_MoveToRightWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs) ctx->ofs = new_ofs;
}
static void WCEL_MoveToBeg(WCEL_Context* ctx)
{
ctx->ofs = 0;
}
static void WCEL_MoveToEnd(WCEL_Context* ctx)
{
ctx->ofs = ctx->len;
}
static void WCEL_SetMark(WCEL_Context* ctx)
{
ctx->mark = ctx->ofs;
}
static void WCEL_ExchangeMark(WCEL_Context* ctx)
{
unsigned tmp;
if (ctx->mark > ctx->len) return;
tmp = ctx->ofs;
ctx->ofs = ctx->mark;
ctx->mark = tmp;
}
static void WCEL_CopyMarkedZone(WCEL_Context* ctx)
{
unsigned beg, end;
if (ctx->mark > ctx->len || ctx->mark == ctx->ofs) return;
if (ctx->mark > ctx->ofs)
{
beg = ctx->ofs; end = ctx->mark;
}
else
{
beg = ctx->mark; end = ctx->ofs;
}
WCEL_SaveYank(ctx, beg, end);
}
static void WCEL_TransposeChar(WCEL_Context* ctx)
{
WCHAR c;
if (!ctx->ofs || ctx->ofs == ctx->len) return;
c = ctx->line[ctx->ofs];
ctx->line[ctx->ofs] = ctx->line[ctx->ofs - 1];
ctx->line[ctx->ofs - 1] = c;
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs - 1], 2, WCEL_GetCoord(ctx, ctx->ofs - 1), NULL);
ctx->ofs++;
}
static void WCEL_TransposeWords(WCEL_Context* ctx)
{
FIXME("NIY\n");
}
static void WCEL_LowerCaseWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
int i;
for (i = ctx->ofs; i <= new_ofs; i++)
ctx->line[i] = tolowerW(ctx->line[i]);
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1,
WCEL_GetCoord(ctx, ctx->ofs), NULL);
ctx->ofs = new_ofs;
}
}
static void WCEL_UpperCaseWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
int i;
for (i = ctx->ofs; i <= new_ofs; i++)
ctx->line[i] = toupperW(ctx->line[i]);
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1,
WCEL_GetCoord(ctx, ctx->ofs), NULL);
ctx->ofs = new_ofs;
}
}
static void WCEL_CapitalizeWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
int i;
ctx->line[ctx->ofs] = toupperW(ctx->line[ctx->ofs]);
for (i = ctx->ofs + 1; i <= new_ofs; i++)
ctx->line[i] = tolowerW(ctx->line[i]);
WriteConsoleOutputCharacterW(ctx->hConOut, &ctx->line[ctx->ofs], new_ofs - ctx->ofs + 1,
WCEL_GetCoord(ctx, ctx->ofs), NULL);
ctx->ofs = new_ofs;
}
}
static void WCEL_Yank(WCEL_Context* ctx)
{
WCEL_InsertString(ctx, ctx->yanked);
HeapFree(GetProcessHeap(), 0, ctx->yanked);
ctx->yanked = NULL;
}
static void WCEL_KillToEndOfLine(WCEL_Context* ctx)
{
WCEL_SaveYank(ctx, ctx->ofs, ctx->len);
WCEL_DeleteString(ctx, ctx->ofs, ctx->len);
}
static void WCEL_KillMarkedZone(WCEL_Context* ctx)
{
unsigned beg, end;
if (ctx->mark > ctx->len || ctx->mark == ctx->ofs) return;
if (ctx->mark > ctx->ofs)
{
beg = ctx->ofs; end = ctx->mark;
}
else
{
beg = ctx->mark; end = ctx->ofs;
}
WCEL_SaveYank(ctx, beg, end);
WCEL_DeleteString(ctx, beg, end);
ctx->ofs = beg;
}
static void WCEL_DeletePrevChar(WCEL_Context* ctx)
{
if (ctx->ofs)
{
WCEL_DeleteString(ctx, ctx->ofs - 1, ctx->ofs);
ctx->ofs--;
}
}
static void WCEL_DeleteCurrChar(WCEL_Context* ctx)
{
if (ctx->ofs < ctx->len)
WCEL_DeleteString(ctx, ctx->ofs, ctx->ofs + 1);
}
static void WCEL_DeleteLeftWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetLeftWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
WCEL_DeleteString(ctx, new_ofs, ctx->ofs);
ctx->ofs = new_ofs;
}
}
static void WCEL_DeleteRightWord(WCEL_Context* ctx)
{
int new_ofs = WCEL_GetRightWordTransition(ctx, ctx->ofs);
if (new_ofs != ctx->ofs)
{
WCEL_DeleteString(ctx, ctx->ofs, new_ofs);
}
}
static void WCEL_MoveToPrevHist(WCEL_Context* ctx)
{
if (ctx->histPos) WCEL_MoveToHist(ctx, ctx->histPos - 1);
}
static void WCEL_MoveToNextHist(WCEL_Context* ctx)
{
if (ctx->histPos < ctx->histSize - 1) WCEL_MoveToHist(ctx, ctx->histPos + 1);
}
static void WCEL_MoveToFirstHist(WCEL_Context* ctx)
{
if (ctx->histPos != 0) WCEL_MoveToHist(ctx, 0);
}
static void WCEL_MoveToLastHist(WCEL_Context* ctx)
{
if (ctx->histPos != ctx->histSize - 1) WCEL_MoveToHist(ctx, ctx->histSize - 1);
}
/* ====================================================================
*
* Key Maps
*
* ====================================================================*/
#define CTRL(x) ((x) - '@')
static KeyEntry StdKeyMap[] =
{
{/*BACK*/0x08, WCEL_DeletePrevChar },
{/*RETURN*/0x0d, WCEL_Done },
{/*DEL*/127, WCEL_DeleteCurrChar },
{ 0, NULL }
};
static KeyEntry EmacsKeyMapCtrl[] =
{
{ CTRL('@'), WCEL_SetMark },
{ CTRL('A'), WCEL_MoveToBeg },
{ CTRL('B'), WCEL_MoveLeft },
/* C */
{ CTRL('D'), WCEL_DeleteCurrChar },
{ CTRL('E'), WCEL_MoveToEnd },
{ CTRL('F'), WCEL_MoveRight },
{ CTRL('G'), WCEL_Beep },
{ CTRL('H'), WCEL_DeletePrevChar },
/* I: meaningless (or tab ???) */
{ CTRL('J'), WCEL_Done },
{ CTRL('K'), WCEL_KillToEndOfLine },
/* L: [NIY] redraw the whole stuff */
{ CTRL('M'), WCEL_Done },
{ CTRL('N'), WCEL_MoveToNextHist },
/* O; insert line... meaningless */
{ CTRL('P'), WCEL_MoveToPrevHist },
/* Q: [NIY] quoting... */
/* R: [NIY] search backwards... */
/* S: [NIY] search forwards... */
{ CTRL('T'), WCEL_TransposeChar },
/* U: [NIY] set repeat count... */
/* V: paragraph down... meaningless */
{ CTRL('W'), WCEL_KillMarkedZone },
{ CTRL('X'), WCEL_ExchangeMark },
{ CTRL('Y'), WCEL_Yank },
/* Z: meaningless */
{ 0, NULL }
};
static KeyEntry EmacsKeyMapAlt[] =
{
{/*DEL*/127, WCEL_DeleteLeftWord },
{ '<', WCEL_MoveToFirstHist },
{ '>', WCEL_MoveToLastHist },
{ '?', WCEL_Beep },
{ 'b', WCEL_MoveToLeftWord },
{ 'c', WCEL_CapitalizeWord },
{ 'd', WCEL_DeleteRightWord },
{ 'f', WCEL_MoveToRightWord },
{ 'l', WCEL_LowerCaseWord },
{ 't', WCEL_TransposeWords },
{ 'u', WCEL_UpperCaseWord },
{ 'w', WCEL_CopyMarkedZone },
{ 0, NULL }
};
static KeyEntry EmacsKeyMapExtended[] =
{
{/*VK_PRIOR*/0x21, WCEL_MoveToPrevHist },
{/*VK_NEXT*/0x22, WCEL_MoveToNextHist },
{/*VK_RIGHT*/0x27, WCEL_MoveRight },
{/*VK_LEFT*/0x25, WCEL_MoveLeft },
{ 0, NULL }
};
static KeyMap EmacsKeyMap[] =
{
{0x00000000, 1, StdKeyMap},
{0x00000001, 1, EmacsKeyMapAlt}, /* left alt */
{0x00000002, 1, EmacsKeyMapAlt}, /* right alt */
{0x00000004, 1, EmacsKeyMapCtrl}, /* left ctrl */
{0x00000008, 1, EmacsKeyMapCtrl}, /* right ctrl */
{0x00000100, 0, EmacsKeyMapExtended},
{0, 0, 0}
};
static KeyEntry Win32KeyMapExtended[] =
{
{/*VK_LEFT*/ 0x25, WCEL_MoveLeft },
{/*VK_RIGHT*/0x27, WCEL_MoveRight },
{/*VK_HOME*/ 0x24, WCEL_MoveToBeg },
{/*VK_END*/ 0x23, WCEL_MoveToEnd },
{/*VK_UP*/ 0x26, WCEL_MoveToPrevHist },
{/*VK_DOWN*/ 0x28, WCEL_MoveToNextHist },
{ 0, NULL }
};
static KeyEntry Win32KeyMapCtrlExtended[] =
{
{/*VK_LEFT*/ 0x25, WCEL_MoveToLeftWord },
{/*VK_RIGHT*/0x27, WCEL_MoveToRightWord },
{ 0, NULL }
};
KeyMap Win32KeyMap[] =
{
{0x00000000, 1, StdKeyMap},
{0x00000100, 0, Win32KeyMapExtended},
{0x00000104, 0, Win32KeyMapCtrlExtended},
{0x00000108, 0, Win32KeyMapCtrlExtended},
{0, 0, 0}
};
#undef CTRL
/* ====================================================================
*
* Read line master function
*
* ====================================================================*/
WCHAR* CONSOLE_Readline(HANDLE hConsoleIn, int use_emacs)
{
WCEL_Context ctx;
INPUT_RECORD ir;
KeyMap* km;
KeyEntry* ke;
unsigned ofs;
void (*func)(struct WCEL_Context* ctx);
memset(&ctx, 0, sizeof(ctx));
ctx.hConIn = hConsoleIn;
WCEL_HistoryInit(&ctx);
if ((ctx.hConOut = CreateFileA("CONOUT$", GENERIC_READ|GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE ||
!GetConsoleScreenBufferInfo(ctx.hConOut, &ctx.csbi))
return NULL;
if (!WCEL_Grow(&ctx, 1))
{
CloseHandle(ctx.hConOut);
return NULL;
}
ctx.line[0] = 0;
/* EPP WCEL_Dump(&ctx, "init"); */
while (!ctx.done && !ctx.error && WCEL_Get(&ctx, &ir))
{
if (ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown) continue;
TRACE("key%s repeatCount=%u, keyCode=%02x scanCode=%02x char=%02x keyState=%08lx\n",
ir.Event.KeyEvent.bKeyDown ? "Down" : "Up ", ir.Event.KeyEvent.wRepeatCount,
ir.Event.KeyEvent.wVirtualKeyCode, ir.Event.KeyEvent.wVirtualScanCode,
ir.Event.KeyEvent.uChar.UnicodeChar, ir.Event.KeyEvent.dwControlKeyState);
/* EPP WCEL_Dump(&ctx, "before func"); */
ofs = ctx.ofs;
func = NULL;
for (km = (use_emacs) ? EmacsKeyMap : Win32KeyMap; km->entries != NULL; km++)
{
if (km->keyState != ir.Event.KeyEvent.dwControlKeyState)
continue;
if (km->chkChar)
{
for (ke = &km->entries[0]; ke->func != 0; ke++)
if (ke->val == ir.Event.KeyEvent.uChar.UnicodeChar) break;
}
else
{
for (ke = &km->entries[0]; ke->func != 0; ke++)
if (ke->val == ir.Event.KeyEvent.wVirtualKeyCode) break;
}
if (ke->func)
{
func = ke->func;
break;
}
}
if (func)
(func)(&ctx);
else if (!(ir.Event.KeyEvent.dwControlKeyState & (ENHANCED_KEY|LEFT_ALT_PRESSED)))
WCEL_InsertChar(&ctx, ir.Event.KeyEvent.uChar.UnicodeChar);
else TRACE("Dropped event\n");
/* EPP WCEL_Dump(&ctx, "after func"); */
if (ctx.ofs != ofs)
SetConsoleCursorPosition(ctx.hConOut, WCEL_GetCoord(&ctx, ctx.ofs));
}
if (ctx.error)
{
HeapFree(GetProcessHeap(), 0, ctx.line);
ctx.line = NULL;
}
if (ctx.line)
CONSOLE_AppendHistory(ctx.line);
CloseHandle(ctx.hConOut);
if (ctx.histCurr) HeapFree(GetProcessHeap(), 0, ctx.histCurr);
return ctx.line;
}