server: Introduce IOCTL_CONDRV_READ_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-28 17:10:23 +02:00 committed by Alexandre Julliard
parent 7a31d40139
commit 44052219aa
3 changed files with 90 additions and 4 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_READ_OUTPUT CTL_CODE(FILE_DEVICE_CONSOLE, 30, METHOD_BUFFERED, FILE_READ_DATA)
#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)
@ -83,7 +84,7 @@ struct condrv_input_info_params
struct condrv_input_info info; /* input_info */
};
/* IOCTL_CONDRV_WRITE_OUTPUT */
/* IOCTL_CONDRV_WRITE_OUTPUT and IOCTL_CONDRV_READ_OUTPUT params */
struct condrv_output_params
{
unsigned int x; /* destination position */

View File

@ -1248,6 +1248,73 @@ static struct fd *screen_buffer_get_fd( struct object *obj )
return NULL;
}
/* read data from a screen buffer */
static void read_console_output( struct screen_buffer *screen_buffer, unsigned int x, unsigned int y,
enum char_info_mode mode, unsigned int width )
{
unsigned int i, count;
char_info_t *src;
if (x >= screen_buffer->width || y >= screen_buffer->height)
{
if (width) set_error( STATUS_INVALID_PARAMETER );
return;
}
src = screen_buffer->data + y * screen_buffer->width + x;
switch(mode)
{
case CHAR_INFO_MODE_TEXT:
{
WCHAR *data;
count = min( screen_buffer->data + screen_buffer->height * screen_buffer->width - src,
get_reply_max_size() / sizeof(*data) );
if ((data = set_reply_data_size( count * sizeof(*data) )))
{
for (i = 0; i < count; i++) data[i] = src[i].ch;
}
}
break;
case CHAR_INFO_MODE_ATTR:
{
unsigned short *data;
count = min( screen_buffer->data + screen_buffer->height * screen_buffer->width - src,
get_reply_max_size() / sizeof(*data) );
if ((data = set_reply_data_size( count * sizeof(*data) )))
{
for (i = 0; i < count; i++) data[i] = src[i].attr;
}
}
break;
case CHAR_INFO_MODE_TEXTATTR:
{
char_info_t *data;
SMALL_RECT *region;
if (!width || get_reply_max_size() < sizeof(*region))
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
count = min( (get_reply_max_size() - sizeof(*region)) / (width * sizeof(*data)), screen_buffer->height - y );
width = min( width, screen_buffer->width - x );
if (!(region = set_reply_data_size( sizeof(*region) + width * count * sizeof(*data) ))) return;
region->Left = x;
region->Top = y;
region->Right = x + width - 1;
region->Bottom = y + count - 1;
data = (char_info_t *)(region + 1);
for (i = 0; i < count; i++)
{
memcpy( &data[i * width], &src[i * screen_buffer->width], width * sizeof(*data) );
}
}
break;
default:
set_error( STATUS_INVALID_PARAMETER );
break;
}
}
/* write data into a screen buffer */
static void write_console_output( struct screen_buffer *screen_buffer, const struct condrv_output_params *params,
data_size_t size )
@ -1378,8 +1445,8 @@ static int fill_console_output( struct screen_buffer *screen_buffer, char_info_t
}
/* read data from a screen buffer */
static void read_console_output( struct screen_buffer *screen_buffer, int x, int y,
enum char_info_mode mode, int wrap )
static void read_console_output_req( struct screen_buffer *screen_buffer, int x, int y,
enum char_info_mode mode, int wrap )
{
int i;
char_info_t *end, *src = screen_buffer->data + y * screen_buffer->width + x;
@ -1676,6 +1743,23 @@ 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_READ_OUTPUT:
{
const struct condrv_output_params *params = get_req_data();
if (get_req_data_size() != sizeof(*params))
{
set_error( STATUS_INVALID_PARAMETER );
return 0;
}
if (console_input_is_bare( screen_buffer->input ))
{
set_error( STATUS_OBJECT_TYPE_MISMATCH );
return 0;
}
read_console_output( screen_buffer, params->x, params->y, params->mode, params->width );
return !get_error();
}
case IOCTL_CONDRV_WRITE_OUTPUT:
if (get_req_data_size() < sizeof(struct condrv_output_params) ||
(get_reply_max_size() != sizeof(SMALL_RECT) && get_reply_max_size() != sizeof(unsigned int)))
@ -2150,7 +2234,7 @@ DECL_HANDLER(read_console_output)
release_object( screen_buffer );
return;
}
read_console_output( screen_buffer, req->x, req->y, req->mode, req->wrap );
read_console_output_req( screen_buffer, req->x, req->y, req->mode, req->wrap );
reply->width = screen_buffer->width;
reply->height = screen_buffer->height;
release_object( screen_buffer );

View File

@ -124,6 +124,7 @@ static void dump_ioctl_code( const char *prefix, const ioctl_code_t *code )
CASE(IOCTL_CONDRV_GET_TITLE);
CASE(IOCTL_CONDRV_PEEK);
CASE(IOCTL_CONDRV_READ_INPUT);
CASE(IOCTL_CONDRV_READ_OUTPUT);
CASE(IOCTL_CONDRV_SET_MODE);
CASE(IOCTL_CONDRV_SET_OUTPUT_INFO);
CASE(IOCTL_CONDRV_WRITE_INPUT);