[PATCH 4/5] user32: Implement GetRawInputBuffer.

Rémi Bernon rbernon at codeweavers.com
Thu Jun 25 12:08:43 CDT 2020


CoD: WWII uses it to read mouse motion instead of listening to WM_INPUT
messages.

Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---

I first tried to implement it without a new request, but it was much
more complicated, and this is way simpler. It also avoid messing with
message processing, and only removes WM_INPUT messages from the queues

 dlls/user32/rawinput.c     | 91 +++++++++++++++++++++++++++++++++++++-
 dlls/user32/tests/input.c  | 27 -----------
 dlls/user32/user_private.h |  2 +-
 server/protocol.def        | 10 +++++
 server/queue.c             | 40 +++++++++++++++++
 5 files changed, 140 insertions(+), 30 deletions(-)

diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c
index 7092c01c659..fa0c5070b03 100644
--- a/dlls/user32/rawinput.c
+++ b/dlls/user32/rawinput.c
@@ -484,14 +484,101 @@ UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *
     return s;
 }
 
+#ifdef _WIN64
+typedef RAWINPUT RAWINPUT64;
+#else
+typedef struct
+{
+    RAWINPUTHEADER header;
+    char pad[8];
+    union {
+        RAWMOUSE    mouse;
+        RAWKEYBOARD keyboard;
+        RAWHID      hid;
+    } data;
+} RAWINPUT64;
+#endif
+
 /***********************************************************************
  *              GetRawInputBuffer   (USER32.@)
  */
 UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, UINT header_size)
 {
-    FIXME("data %p, data_size %p, header_size %u stub!\n", data, data_size, header_size);
+    struct hardware_msg_data *msg_data;
+    RAWINPUT *rawinput;
+    UINT count = 0, rawinput_size, next_size, overhead;
+    BOOL is_wow64;
+    int i;
+
+    if (IsWow64Process( GetCurrentProcess(), &is_wow64 ) && is_wow64)
+        rawinput_size = sizeof(RAWINPUT64);
+    else
+        rawinput_size = sizeof(RAWINPUT);
+    overhead = rawinput_size - sizeof(RAWINPUT);
 
-    return 0;
+    if (header_size != sizeof(RAWINPUTHEADER))
+    {
+        WARN("Invalid structure size %u.\n", header_size);
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return ~0U;
+    }
+
+    if (!data_size)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return ~0U;
+    }
+
+    if (!data)
+    {
+        TRACE("data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size);
+        SERVER_START_REQ( get_rawinput_buffer )
+        {
+            req->rawinput_size = rawinput_size;
+            req->buffer_size = 0;
+            if (wine_server_call( req )) return ~0U;
+            *data_size = reply->next_size;
+        }
+        SERVER_END_REQ;
+        return 0;
+    }
+
+    if (!(rawinput = rawinput_thread_data())) return ~0U;
+
+    msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput);
+    SERVER_START_REQ( get_rawinput_buffer )
+    {
+        req->rawinput_size = rawinput_size;
+        req->buffer_size = *data_size;
+        wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize );
+        if (wine_server_call( req )) return ~0U;
+        next_size = reply->next_size;
+        count = reply->count;
+    }
+    SERVER_END_REQ;
+
+    for (i = 0; i < count; ++i)
+    {
+        rawinput_from_hardware_message(data, msg_data);
+        if (overhead) memmove((char *)&data->data + overhead, &data->data,
+                              data->header.dwSize - sizeof(RAWINPUTHEADER));
+        data->header.dwSize += overhead;
+        data = NEXTRAWINPUTBLOCK(data);
+        msg_data++;
+    }
+
+    if (count == 0 && next_size == 0) *data_size = 0;
+    else if (next_size == 0) next_size = rawinput_size;
+
+    if (next_size && *data_size <= next_size)
+    {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        *data_size = next_size;
+        count = ~0U;
+    }
+
+    if (count) TRACE("data %p, data_size %p (%u), header_size %u, count %u\n", data, data_size, *data_size, header_size, count);
+    return count;
 }
 
 /***********************************************************************
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c
index 8b98c3f5c57..9c35b1e36bd 100644
--- a/dlls/user32/tests/input.c
+++ b/dlls/user32/tests/input.c
@@ -1863,26 +1863,20 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara
     if (msg == WM_INPUT)
     {
         count = GetRawInputBuffer(NULL, NULL, sizeof(RAWINPUTHEADER));
-        todo_wine
         ok(count == ~0U, "GetRawInputBuffer succeeded\n");
 
         size = sizeof(buffer);
         count = GetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER));
         ok(count == 0, "GetRawInputBuffer returned %u\n", count);
-        todo_wine
         ok(size == rawinput_size, "GetRawInputBuffer returned unexpected size: %u\n", size);
 
         size = sizeof(buffer);
         memset(buffer, 0, sizeof(buffer));
         count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
-        todo_wine
         ok(count == 3, "GetRawInputBuffer returned %u\n", count);
         ok(size == sizeof(buffer), "GetRawInputBuffer returned unexpected size: %u\n", size);
-        todo_wine
         ok(rawinput_buffer_mouse_x(buffer, 0) == 2, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0));
-        todo_wine
         ok(rawinput_buffer_mouse_x(buffer, 1) == 3, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 1));
-        todo_wine
         ok(rawinput_buffer_mouse_x(buffer, 2) == 4, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 2));
 
         /* the first event should be removed by the next GetRawInputBuffer call
@@ -1900,9 +1894,7 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara
             size = rawinput_size + 1;
             memset(buffer, 0, sizeof(buffer));
             count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
-            todo_wine
             ok(count == 1, "GetRawInputBuffer returned %u\n", count);
-            todo_wine
             ok(rawinput_buffer_mouse_x(buffer, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0));
 
             /* peek the messages now, they should still arrive in the correct order */
@@ -1917,7 +1909,6 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara
         if (iteration == 1)
         {
             ok(count == sizeof(ri), "GetRawInputData failed\n");
-            todo_wine
             ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %d\n", ri.data.mouse.lLastX);
         }
         else
@@ -1959,15 +1950,12 @@ static void test_GetRawInputBuffer(void)
 
     SetLastError(0xdeadbeef);
     count = GetRawInputBuffer(NULL, NULL, sizeof(RAWINPUTHEADER));
-    todo_wine
     ok(count == ~0U, "GetRawInputBuffer succeeded\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08x\n", GetLastError());
 
     size = sizeof(buffer);
     count = GetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER));
     ok(count == 0U, "GetRawInputBuffer returned %u\n", count);
-    todo_wine
     ok(size == 0U, "GetRawInputBuffer returned unexpected size: %u\n", size);
 
     size = 0;
@@ -1978,15 +1966,12 @@ static void test_GetRawInputBuffer(void)
     SetLastError(0xdeadbeef);
     size = sizeof(buffer);
     count = GetRawInputBuffer((RAWINPUT*)buffer, &size, 0);
-    todo_wine
     ok(count == ~0U, "GetRawInputBuffer succeeded\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08x\n", GetLastError());
 
     size = sizeof(buffer);
     count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
     ok(count == 0U, "GetRawInputBuffer returned %u\n", count);
-    todo_wine
     ok(size == 0U, "GetRawInputBuffer returned unexpected size: %u\n", size);
 
     mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0);
@@ -1994,34 +1979,26 @@ static void test_GetRawInputBuffer(void)
     SetLastError(0xdeadbeef);
     size = 0;
     count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
-    todo_wine
     ok(count == ~0U, "GetRawInputBuffer succeeded\n");
-    todo_wine
     ok(size == rawinput_size, "GetRawInputBuffer returned unexpected size: %u\n", size);
-    todo_wine
     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRawInputBuffer returned %08x\n", GetLastError());
 
     size = 0;
     count = GetRawInputBuffer(NULL, &size, sizeof(RAWINPUTHEADER));
     ok(count == 0, "GetRawInputBuffer returned %u\n", count);
-    todo_wine
     ok(size == rawinput_size, "GetRawInputBuffer returned unexpected size: %u\n", size);
 
     SetLastError(0xdeadbeef);
     size = sizeof(buffer);
     count = GetRawInputBuffer((RAWINPUT*)buffer, &size, 0);
-    todo_wine
     ok(count == ~0U, "GetRawInputBuffer succeeded\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputBuffer returned %08x\n", GetLastError());
 
     size = sizeof(buffer);
     memset(buffer, 0, sizeof(buffer));
     count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
-    todo_wine
     ok(count == 1U, "GetRawInputBuffer returned %u\n", count);
     ok(size == sizeof(buffer), "GetRawInputBuffer returned unexpected size: %u\n", size);
-    todo_wine
     ok(rawinput_buffer_mouse_x(buffer, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0));
 
 
@@ -2033,11 +2010,8 @@ static void test_GetRawInputBuffer(void)
     size = rawinput_size;
     memset(buffer, 0, sizeof(buffer));
     count = GetRawInputBuffer((RAWINPUT*)buffer, &size, sizeof(RAWINPUTHEADER));
-    todo_wine
     ok(count == ~0U, "GetRawInputBuffer succeeded\n");
-    todo_wine
     ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRawInputBuffer returned %08x\n", GetLastError());
-    todo_wine
     ok(rawinput_buffer_mouse_x(buffer, 0) == 5, "Unexpected rawinput data: %d\n", rawinput_buffer_mouse_x(buffer, 0));
 
     size = sizeof(buffer);
@@ -2051,7 +2025,6 @@ static void test_GetRawInputBuffer(void)
     mouse_event(MOUSEEVENTF_MOVE, 3, 0, 0, 0);
     mouse_event(MOUSEEVENTF_MOVE, 4, 0, 0, 0);
     empty_message_queue();
-    todo_wine
     ok(rawinputbuffer_wndproc_count == 2, "Spurious WM_INPUT messages\n");
 
     raw_devices[0].dwFlags = RIDEV_REMOVE;
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index d7f4741ebe6..eb828203597 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -196,7 +196,7 @@ struct user_thread_info
     struct user_key_state_info   *key_state;              /* Cache of global key state */
     HWND                          top_window;             /* Desktop window */
     HWND                          msg_window;             /* HWND_MESSAGE parent window */
-    RAWINPUT                     *rawinput;               /* Rawinput buffer */
+    RAWINPUT                     *rawinput;
 };
 
 C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) );
diff --git a/server/protocol.def b/server/protocol.def
index c3442c06e9b..d1f20497e1d 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3880,6 +3880,16 @@ struct handle_info
 #define SET_CURSOR_NOCLIP 0x10
 
 
+/* Batch read rawinput message data */
+ at REQ(get_rawinput_buffer)
+    data_size_t rawinput_size; /* size of RAWINPUT structure */
+    data_size_t buffer_size;   /* size of output buffer */
+ at REPLY
+    data_size_t next_size; /* minimum size to get next message data */
+    unsigned int count;
+    VARARG(data,bytes);
+ at END
+
 /* Modify the list of registered rawinput devices */
 @REQ(update_rawinput_devices)
     VARARG(devices,rawinput_devices);
diff --git a/server/queue.c b/server/queue.c
index 84ee0f9a4ea..88fc415bfaa 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -3112,6 +3112,46 @@ DECL_HANDLER(set_cursor)
     reply->last_change = input->desktop->cursor.last_change;
 }
 
+DECL_HANDLER(get_rawinput_buffer)
+{
+    struct thread_input *input = current->queue->input;
+    data_size_t size = 0, next_size = 0;
+    struct list *ptr;
+    char *buf, *cur;
+    int count = 0;
+
+    if (!req->buffer_size) buf = NULL;
+    else if (!(buf = mem_alloc( get_reply_max_size() )))
+        return;
+
+    cur = buf;
+    ptr = list_head( &input->msg_list );
+    while (ptr)
+    {
+        struct message *msg = LIST_ENTRY( ptr, struct message, entry );
+        struct hardware_msg_data *data = msg->data;
+
+        ptr = list_next( &input->msg_list, ptr );
+        if (msg->msg != WM_INPUT) continue;
+
+        next_size = req->rawinput_size;
+        if (size + next_size > req->buffer_size) break;
+        if (cur + sizeof(*data) > buf + get_reply_max_size()) break;
+
+        memcpy(cur, data, sizeof(*data));
+        list_remove( &msg->entry );
+        free_message( msg );
+
+        size += next_size;
+        cur += sizeof(*data);
+        count++;
+    }
+
+    reply->next_size = next_size;
+    reply->count = count;
+    set_reply_data_ptr( buf, cur - buf );
+}
+
 DECL_HANDLER(update_rawinput_devices)
 {
     const struct rawinput_device *devices = get_req_data();
-- 
2.27.0




More information about the wine-devel mailing list