server: Introduce IOCTL_CONDRV_WRITE_OUTPUT ioctl.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2020-07-23 17:31:12 +02:00 committed by Alexandre Julliard
parent 29288c0bc0
commit 5b795b658d
3 changed files with 108 additions and 3 deletions

View File

@ -37,6 +37,7 @@
#define IOCTL_CONDRV_SET_TITLE CTL_CODE(FILE_DEVICE_CONSOLE, 16, METHOD_BUFFERED, FILE_WRITE_PROPERTIES)
/* console output ioctls */
#define IOCTL_CONDRV_WRITE_OUTPUT CTL_CODE(FILE_DEVICE_CONSOLE, 31, METHOD_BUFFERED, FILE_WRITE_DATA)
#define IOCTL_CONDRV_GET_OUTPUT_INFO CTL_CODE(FILE_DEVICE_CONSOLE, 32, METHOD_BUFFERED, FILE_READ_PROPERTIES)
#define IOCTL_CONDRV_SET_OUTPUT_INFO CTL_CODE(FILE_DEVICE_CONSOLE, 33, METHOD_BUFFERED, FILE_WRITE_PROPERTIES)
#define IOCTL_CONDRV_ACTIVATE CTL_CODE(FILE_DEVICE_CONSOLE, 34, METHOD_BUFFERED, FILE_WRITE_DATA)
@ -82,6 +83,16 @@ struct condrv_input_info_params
struct condrv_input_info info; /* input_info */
};
/* IOCTL_CONDRV_WRITE_OUTPUT */
struct condrv_write_output_params
{
unsigned int x; /* destination position */
unsigned int y;
unsigned int mode; /* char info mode */
unsigned int width; /* width of output rectangle, 0 for wrapped mode */
/* followed by an array of data with type depending on mode */
};
/* IOCTL_CONDRV_GET_OUTPUT_INFO result */
struct condrv_output_info
{

View File

@ -1249,7 +1249,85 @@ static struct fd *screen_buffer_get_fd( struct object *obj )
}
/* write data into a screen buffer */
static int write_console_output( struct screen_buffer *screen_buffer, data_size_t size,
static void write_console_output( struct screen_buffer *screen_buffer, const struct condrv_write_output_params *params,
data_size_t size )
{
unsigned int i, entry_size, entry_cnt, x, y;
char_info_t *dest;
char *src;
entry_size = params->mode == CHAR_INFO_MODE_TEXTATTR ? sizeof(char_info_t) : sizeof(WCHAR);
if (size % entry_size)
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
if (params->x >= screen_buffer->width) return;
entry_cnt = size / entry_size;
for (i = 0, src = (char *)(params + 1); i < entry_cnt; i++, src += entry_size)
{
if (params->width)
{
x = params->x + i % params->width;
y = params->y + i / params->width;
if (x >= screen_buffer->width) continue;
}
else
{
x = (params->x + i) % screen_buffer->width;
y = params->y + (params->x + i) / screen_buffer->width;
}
if (y >= screen_buffer->height) break;
dest = &screen_buffer->data[y * screen_buffer->width + x];
switch(params->mode)
{
case CHAR_INFO_MODE_TEXT:
dest->ch = *(const WCHAR *)src;
break;
case CHAR_INFO_MODE_ATTR:
dest->attr = *(const unsigned short *)src;
break;
case CHAR_INFO_MODE_TEXTATTR:
*dest = *(const char_info_t *)src;
break;
case CHAR_INFO_MODE_TEXTSTDATTR:
dest->ch = *(const WCHAR *)src;
dest->attr = screen_buffer->attr;
break;
default:
set_error( STATUS_INVALID_PARAMETER );
return;
}
}
if (i && screen_buffer == screen_buffer->input->active)
{
struct condrv_renderer_event evt;
evt.event = CONSOLE_RENDERER_UPDATE_EVENT;
memset(&evt.u, 0, sizeof(evt.u));
evt.u.update.top = params->y;
evt.u.update.bottom = params->width
? min( params->y + entry_cnt / params->width, screen_buffer->height ) - 1
: params->y + (params->x + i - 1) / screen_buffer->width;
console_input_events_append( screen_buffer->input, &evt );
}
if (get_reply_max_size() == sizeof(SMALL_RECT))
{
SMALL_RECT region;
region.Left = params->x;
region.Top = params->y;
region.Right = min( params->x + params->width, screen_buffer->width ) - 1;
region.Bottom = min( params->y + entry_cnt / params->width, screen_buffer->height ) - 1;
set_reply_data( &region, sizeof(region) );
}
else set_reply_data( &i, sizeof(i) );
}
/* write data into a screen buffer */
static int write_console_output_req( struct screen_buffer *screen_buffer, data_size_t size,
const void* data, enum char_info_mode mode,
int x, int y, int wrap )
{
@ -1660,6 +1738,21 @@ static int screen_buffer_ioctl( struct fd *fd, ioctl_code_t code, struct async *
screen_buffer->mode = *(unsigned int *)get_req_data();
return 1;
case IOCTL_CONDRV_WRITE_OUTPUT:
if (get_req_data_size() < sizeof(struct condrv_write_output_params) ||
(get_reply_max_size() != sizeof(SMALL_RECT) && get_reply_max_size() != sizeof(unsigned int)))
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
if (console_input_is_bare( screen_buffer->input ))
{
set_error( STATUS_OBJECT_TYPE_MISMATCH );
return 0;
}
write_console_output( screen_buffer, get_req_data(), get_req_data_size() - sizeof(struct condrv_write_output_params) );
return !get_error();
case IOCTL_CONDRV_GET_OUTPUT_INFO:
{
struct condrv_output_info *info;
@ -2140,7 +2233,7 @@ DECL_HANDLER(write_console_output)
release_object( screen_buffer );
return;
}
reply->written = write_console_output( screen_buffer, get_req_data_size(), get_req_data(),
reply->written = write_console_output_req( screen_buffer, get_req_data_size(), get_req_data(),
req->mode, req->x, req->y, req->wrap );
reply->width = screen_buffer->width;
reply->height = screen_buffer->height;

View File

@ -127,6 +127,7 @@ static void dump_ioctl_code( const char *prefix, const ioctl_code_t *code )
CASE(IOCTL_CONDRV_SET_MODE);
CASE(IOCTL_CONDRV_SET_OUTPUT_INFO);
CASE(IOCTL_CONDRV_WRITE_INPUT);
CASE(IOCTL_CONDRV_WRITE_OUTPUT);
CASE(FSCTL_DISMOUNT_VOLUME);
CASE(FSCTL_PIPE_DISCONNECT);
CASE(FSCTL_PIPE_LISTEN);