[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