CoD: WWII uses it to read mouse motion instead of listening to WM_INPUT messages.
Signed-off-by: Rémi Bernon rbernon@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 */ +@REQ(get_rawinput_buffer) + data_size_t rawinput_size; /* size of RAWINPUT structure */ + data_size_t buffer_size; /* size of output buffer */ +@REPLY + data_size_t next_size; /* minimum size to get next message data */ + unsigned int count; + VARARG(data,bytes); +@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();