Jacek Caban : server: Introduce IOCTL_CONDRV_READ_INPUT and IOCTL_CONDRV_PEEK ioctls.

Alexandre Julliard julliard at winehq.org
Mon Jul 6 16:20:46 CDT 2020


Module: wine
Branch: master
Commit: af9a8b1b0890cad21b23279d7f0dae083859e960
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=af9a8b1b0890cad21b23279d7f0dae083859e960

Author: Jacek Caban <jacek at codeweavers.com>
Date:   Mon Jul  6 19:28:40 2020 +0200

server: Introduce IOCTL_CONDRV_READ_INPUT and IOCTL_CONDRV_PEEK ioctls.

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 include/wine/condrv.h |  2 ++
 server/console.c      | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 98 insertions(+), 3 deletions(-)

diff --git a/include/wine/condrv.h b/include/wine/condrv.h
index dc1250a43f..0107da1f2f 100644
--- a/include/wine/condrv.h
+++ b/include/wine/condrv.h
@@ -24,6 +24,8 @@
 #include "winioctl.h"
 
 /* console input ioctls */
+#define IOCTL_CONDRV_READ_INPUT            CTL_CODE(FILE_DEVICE_CONSOLE, 10, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CONDRV_PEEK                  CTL_CODE(FILE_DEVICE_CONSOLE, 12, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_CONDRV_GET_INPUT_INFO        CTL_CODE(FILE_DEVICE_CONSOLE, 13, METHOD_BUFFERED, FILE_READ_PROPERTIES)
 
 /* IOCTL_CONDRV_GET_INPUT_INFO result */
diff --git a/server/console.c b/server/console.c
index 8902943776..841fc839d1 100644
--- a/server/console.c
+++ b/server/console.c
@@ -71,6 +71,7 @@ struct console_input
     user_handle_t                win;           /* window handle if backend supports it */
     struct event                *event;         /* event to wait on for input queue */
     struct fd                   *fd;            /* for bare console, attached input fd */
+    struct async_queue           read_q;        /* read queue */
 };
 
 static void console_input_dump( struct object *obj, int verbose );
@@ -389,6 +390,7 @@ static struct object *create_console_input( struct thread* renderer, int fd )
     console_input->win           = 0;
     console_input->event         = create_event( NULL, NULL, 0, 1, 0, NULL );
     console_input->fd            = NULL;
+    init_async_queue( &console_input->read_q );
 
     if (!console_input->history || (renderer && !console_input->evt) || !console_input->event)
     {
@@ -697,11 +699,61 @@ static int set_console_mode( obj_handle_t handle, int mode )
     return ret;
 }
 
+/* retrieve a pointer to the console input records */
+static int read_console_input( struct console_input *console, struct async *async, int flush )
+{
+    struct iosb *iosb = async_get_iosb( async );
+    data_size_t count;
+
+    count = min( iosb->out_size / sizeof(INPUT_RECORD), console->recnum );
+    if (count)
+    {
+        if (!(iosb->out_data = malloc( count * sizeof(INPUT_RECORD) )))
+        {
+            set_error( STATUS_NO_MEMORY );
+            release_object( iosb );
+            return 0;
+        }
+        iosb->out_size = iosb->result = count * sizeof(INPUT_RECORD);
+        memcpy( iosb->out_data, console->records, iosb->result );
+        iosb->status = STATUS_SUCCESS;
+        async_terminate( async, STATUS_ALERTED );
+    }
+    else
+    {
+        async_terminate( async, STATUS_SUCCESS );
+    }
+
+    release_object( iosb );
+
+    if (flush && count)
+    {
+        if (console->recnum > count)
+        {
+            INPUT_RECORD *new_rec;
+            memmove( console->records, console->records + count, (console->recnum - count) * sizeof(*console->records) );
+            console->recnum -= count;
+            new_rec = realloc( console->records, console->recnum * sizeof(*console->records) );
+            if (new_rec) console->records = new_rec;
+        }
+        else
+        {
+            console->recnum = 0;
+            free( console->records );
+            console->records = NULL;
+            reset_event( console->event );
+        }
+    }
+
+    return 1;
+}
+
 /* add input events to a console input queue */
 static int write_console_input( struct console_input* console, int count,
                                 const INPUT_RECORD *records )
 {
     INPUT_RECORD *new_rec;
+    struct async *async;
 
     if (!count) return 0;
     if (!(new_rec = realloc( console->records,
@@ -736,13 +788,18 @@ static int write_console_input( struct console_input* console, int count,
             else i++;
         }
     }
-    if (!console->recnum && count) set_event( console->event );
     console->recnum += count;
+    while (console->recnum && (async = find_pending_async( &console->read_q )))
+    {
+        read_console_input( console, async, 1 );
+        release_object( async );
+    }
+    if (console->recnum) set_event( console->event );
     return count;
 }
 
 /* retrieve a pointer to the console input records */
-static int read_console_input( obj_handle_t handle, int count, int flush )
+static int read_console_input_req( obj_handle_t handle, int count, int flush )
 {
     struct console_input *console;
 
@@ -1197,6 +1254,7 @@ static void console_input_destroy( struct object *obj )
         if (curr->input == console_in) curr->input = NULL;
     }
 
+    free_async_queue( &console_in->read_q );
     if (console_in->evt)
     {
         release_object( console_in->evt );
@@ -1495,6 +1553,41 @@ static int console_ioctl( struct fd *fd, ioctl_code_t code, struct async *async
 
     switch (code)
     {
+    case IOCTL_CONDRV_READ_INPUT:
+        {
+            int blocking = 0;
+            if (get_reply_max_size() % sizeof(INPUT_RECORD))
+            {
+                set_error( STATUS_INVALID_PARAMETER );
+                return 0;
+            }
+            if (get_req_data_size())
+            {
+                if (get_req_data_size() != sizeof(int))
+                {
+                    set_error( STATUS_INVALID_PARAMETER );
+                    return 0;
+                }
+                blocking = *(int *)get_req_data();
+            }
+            set_error( STATUS_PENDING );
+            if (blocking && !console->recnum)
+            {
+                queue_async( &console->read_q, async );
+                return 1;
+            }
+            return read_console_input( console, async, 1 );
+        }
+
+    case IOCTL_CONDRV_PEEK:
+        if (get_reply_max_size() % sizeof(INPUT_RECORD))
+        {
+            set_error( STATUS_INVALID_PARAMETER );
+            return 0;
+        }
+        set_error( STATUS_PENDING );
+        return read_console_input( console, async, 0 );
+
     case IOCTL_CONDRV_GET_INPUT_INFO:
         {
             struct condrv_input_info info;
@@ -1806,7 +1899,7 @@ DECL_HANDLER(write_console_input)
 DECL_HANDLER(read_console_input)
 {
     int count = get_reply_max_size() / sizeof(INPUT_RECORD);
-    reply->read = read_console_input( req->handle, count, req->flush );
+    reply->read = read_console_input_req( req->handle, count, req->flush );
 }
 
 /* appends a string to console's history */




More information about the wine-cvs mailing list