The RIM_TYPEHID messages will have to carry the variable length HID report.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v3: Split / reorder / small rewrite of patches, plus:
* Add a VARARG parameter to send_rawinput_buffer to hold the HID reports. Its length is rawinput.hid.count * rawinput.hid.length, checked against request data size on reception.
* Add count field to rawinput union, as it needs to have the length for get_rawinput_buffer implementation, and so needs to be padded to have a consistent size anyway.
* Support HID reports count > 1.
server/queue.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 5d65e030112..c43386ee317 100644 --- a/server/queue.c +++ b/server/queue.c @@ -348,13 +348,13 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_
/* allocate a hardware message and its data */ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_source source, - unsigned int time ) + unsigned int time, data_size_t extra_len ) { struct hardware_msg_data *msg_data; struct message *msg;
if (!(msg = mem_alloc( sizeof(*msg) ))) return NULL; - if (!(msg_data = mem_alloc( sizeof(*msg_data) ))) + if (!(msg_data = mem_alloc( sizeof(*msg_data) + extra_len ))) { free( msg ); return NULL; @@ -363,9 +363,9 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour msg->type = MSG_HARDWARE; msg->time = time; msg->data = msg_data; - msg->data_size = sizeof(*msg_data); + msg->data_size = sizeof(*msg_data) + extra_len;
- memset( msg_data, 0, sizeof(*msg_data) ); + memset( msg_data, 0, sizeof(*msg_data) + extra_len ); msg_data->info = info; msg_data->source = source; return msg; @@ -398,7 +398,7 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) return; }
- if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; + if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
msg->msg = WM_MOUSEMOVE; msg->x = x; @@ -1664,6 +1664,8 @@ struct rawinput_message unsigned int time; unsigned int message; struct hardware_msg_data data; + const void *extra; + data_size_t extra_len; };
/* check if process is supposed to receive a WM_INPUT message and eventually queue it */ @@ -1702,7 +1704,7 @@ static int queue_rawinput_message( struct process* process, void *arg ) wparam = RIM_INPUTSINK; }
- if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time ))) + if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time, raw_msg->extra_len ))) goto done;
msg->win = device->target; @@ -1710,6 +1712,7 @@ static int queue_rawinput_message( struct process* process, void *arg ) msg->wparam = wparam; msg->lparam = 0; memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) ); + if (raw_msg->extra) memcpy( (struct hardware_msg_data *)msg->data + 1, raw_msg->extra, raw_msg->extra_len );
if (raw_msg->message == WM_INPUT_DEVICE_CHANGE && raw_msg->data.rawinput.type == RIM_TYPEHID) { @@ -1791,6 +1794,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons raw_msg.source = source; raw_msg.time = time; raw_msg.message = WM_INPUT; + raw_msg.extra = NULL; + raw_msg.extra_len = 0;
msg_data = &raw_msg.data; msg_data->info = input->mouse.info; @@ -1816,7 +1821,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons if (!(flags & (1 << i))) continue; flags &= ~(1 << i);
- if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; + if (!(msg = alloc_hardware_message( input->mouse.info, source, time, 0 ))) return 0; msg_data = msg->data;
msg->win = get_user_full_handle( win ); @@ -1926,6 +1931,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c raw_msg.source = source; raw_msg.time = time; raw_msg.message = WM_INPUT; + raw_msg.extra = NULL; + raw_msg.extra_len = 0;
msg_data = &raw_msg.data; msg_data->info = input->kbd.info; @@ -1945,7 +1952,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c return 0; }
- if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; + if (!(msg = alloc_hardware_message( input->kbd.info, source, time, 0 ))) return 0; msg_data = msg->data;
msg->win = get_user_full_handle( win ); @@ -1993,6 +2000,8 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ raw_msg.source = source; raw_msg.time = get_tick_count(); raw_msg.message = input->hw.msg; + raw_msg.extra = NULL; + raw_msg.extra_len = 0;
msg_data = &raw_msg.data; msg_data->info = 0; @@ -2005,7 +2014,7 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ return; }
- if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return; + if (!(msg = alloc_hardware_message( 0, source, get_tick_count(), 0 ))) return;
msg->win = get_user_full_handle( win ); msg->msg = input->hw.msg;
And send HID reports data in send_hardware_message request, then append the reports after hardware_msg_data.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/message.c | 4 +++- server/protocol.def | 3 +++ server/queue.c | 11 +++++++++-- server/trace.c | 4 ++-- tools/make_requests | 2 +- 5 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 9af33c3291e..71d0be8913e 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -3288,11 +3288,13 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r switch (rawinput->header.dwType) { case RIM_TYPEHID: - assert( rawinput->data.hid.dwCount <= 1 ); req->input.hw.rawinput.hid.device = HandleToUlong( rawinput->header.hDevice ); req->input.hw.rawinput.hid.param = rawinput->header.wParam; req->input.hw.rawinput.hid.usage_page = hid_usage_page; req->input.hw.rawinput.hid.usage = hid_usage; + req->input.hw.rawinput.hid.count = rawinput->data.hid.dwCount; + req->input.hw.rawinput.hid.length = rawinput->data.hid.dwSizeHid; + wine_server_add_data( req, rawinput->data.hid.bRawData, rawinput->data.hid.dwCount * rawinput->data.hid.dwSizeHid ); break; default: assert( 0 ); diff --git a/server/protocol.def b/server/protocol.def index 6d8208b128b..924dc406a49 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -302,6 +302,8 @@ union rawinput unsigned int param; /* rawinput message param */ unsigned short usage_page;/* HID usage page */ unsigned short usage; /* HID usage */ + unsigned int count; /* HID report count */ + unsigned int length; /* HID report length */ } hid; };
@@ -2030,6 +2032,7 @@ enum message_type user_handle_t win; /* window handle */ hw_input_t input; /* input data */ unsigned int flags; /* flags (see below) */ + VARARG(report,bytes); /* HID report data */ @REPLY int wait; /* do we need to wait for a reply? */ int prev_x; /* previous cursor position */ diff --git a/server/queue.c b/server/queue.c index c43386ee317..4f1695c92cc 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2000,8 +2000,15 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ raw_msg.source = source; raw_msg.time = get_tick_count(); raw_msg.message = input->hw.msg; - raw_msg.extra = NULL; - raw_msg.extra_len = 0; + raw_msg.extra = get_req_data(); + raw_msg.extra_len = get_req_data_size(); + + if (input->hw.rawinput.type == RIM_TYPEHID && + raw_msg.extra_len != input->hw.rawinput.hid.length * input->hw.rawinput.hid.count) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + }
msg_data = &raw_msg.data; msg_data->info = 0; diff --git a/server/trace.c b/server/trace.c index ad7236dd393..3cb601e774d 100644 --- a/server/trace.c +++ b/server/trace.c @@ -408,9 +408,9 @@ static void dump_rawinput( const char *prefix, const union rawinput *rawinput ) rawinput->kbd.message, rawinput->kbd.vkey, rawinput->kbd.scan ); break; case RIM_TYPEHID: - fprintf( stderr, "%s{type=HID,device=%04x,param=%04x,page=%04hx,usage=%04hx}", + fprintf( stderr, "%s{type=HID,device=%04x,param=%04x,page=%04hx,usage=%04hx,count=%u,length=%u}", prefix, rawinput->hid.device, rawinput->hid.param, rawinput->hid.usage_page, - rawinput->hid.usage ); + rawinput->hid.usage, rawinput->hid.count, rawinput->hid.length ); break; default: fprintf( stderr, "%s{type=%04x}", prefix, rawinput->type ); diff --git a/tools/make_requests b/tools/make_requests index a70b29df3d2..1c4e5977c8b 100755 --- a/tools/make_requests +++ b/tools/make_requests @@ -52,7 +52,7 @@ my %formats = "luid_t" => [ 8, 4, "&dump_luid" ], "generic_map_t" => [ 16, 4, "&dump_generic_map" ], "ioctl_code_t" => [ 4, 4, "&dump_ioctl_code" ], - "hw_input_t" => [ 32, 8, "&dump_hw_input" ], + "hw_input_t" => [ 40, 8, "&dump_hw_input" ], );
my @requests = ();
Returned by get_rawinput_buffer request after each hardware_msg_data.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/rawinput.c | 28 +++++++++++++++++++++++++--- server/queue.c | 11 ++++++----- 2 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index e4e7bad508f..716047b4599 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -280,6 +280,8 @@ struct rawinput_thread_data *rawinput_thread_data(void)
BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_msg_data *msg_data) { + SIZE_T size; + rawinput->header.dwType = msg_data->rawinput.type; if (msg_data->rawinput.type == RIM_TYPEMOUSE) { @@ -371,6 +373,23 @@ BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_ms rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message; rawinput->data.keyboard.ExtraInformation = msg_data->info; } + else if (msg_data->rawinput.type == RIM_TYPEHID) + { + size = msg_data->rawinput.hid.count * msg_data->rawinput.hid.length; + if (size > RAWINPUT_BUFFER_SIZE - sizeof(*rawinput)) + { + ERR( "Dropping unexpectedly large HID hardware message.\n" ); + return FALSE; + } + + rawinput->header.dwSize = FIELD_OFFSET( RAWINPUT, data.hid.bRawData ) + size; + rawinput->header.hDevice = ULongToHandle( msg_data->rawinput.hid.device ); + rawinput->header.wParam = 0; + + rawinput->data.hid.dwCount = msg_data->rawinput.hid.count; + rawinput->data.hid.dwSizeHid = msg_data->rawinput.hid.length; + memcpy( rawinput->data.hid.bRawData, msg_data + 1, size ); + } else { FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type); @@ -564,7 +583,7 @@ UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, struct hardware_msg_data *msg_data; struct rawinput_thread_data *thread_data; RAWINPUT *rawinput; - UINT count = 0, rawinput_size, next_size, overhead; + UINT count = 0, rawinput_size, msg_size, next_size, overhead; BOOL is_wow64; int i;
@@ -619,12 +638,15 @@ UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size,
for (i = 0; i < count; ++i) { - rawinput_from_hardware_message(data, msg_data); + if (!rawinput_from_hardware_message(data, msg_data)) break; if (overhead) memmove((char *)&data->data + overhead, &data->data, data->header.dwSize - sizeof(RAWINPUTHEADER)); data->header.dwSize += overhead; data = NEXTRAWINPUTBLOCK(data); - msg_data++; + msg_size = sizeof(*msg_data); + if (msg_data->rawinput.type == RIM_TYPEHID) + msg_size += msg_data->rawinput.hid.count * msg_data->rawinput.hid.length; + msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_size); }
if (count == 0 && next_size == 0) *data_size = 0; diff --git a/server/queue.c b/server/queue.c index 4f1695c92cc..ebbe4049ae8 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3311,16 +3311,17 @@ DECL_HANDLER(get_rawinput_buffer) { struct message *msg = LIST_ENTRY( ptr, struct message, entry ); struct hardware_msg_data *data = msg->data; + data_size_t hid_size = data->rawinput.type != RIM_TYPEHID ? 0 : msg->data_size - sizeof(*data);
ptr = list_next( &input->msg_list, ptr ); if (msg->msg != WM_INPUT) continue;
- next_size = req->rawinput_size; + next_size = req->rawinput_size + hid_size; if (size + next_size > req->buffer_size) break; - if (cur + sizeof(*data) > buf + get_reply_max_size()) break; - if (cur + sizeof(*data) > buf + buf_size) + if (cur + msg->data_size > buf + get_reply_max_size()) break; + if (cur + msg->data_size > buf + buf_size) { - buf_size += buf_size / 2; + buf_size += buf_size / 2 + hid_size; if (!(tmp = realloc( buf, buf_size ))) { set_error( STATUS_NO_MEMORY ); @@ -3330,7 +3331,7 @@ DECL_HANDLER(get_rawinput_buffer) buf = tmp; }
- memcpy(cur, data, sizeof(*data)); + memcpy( cur, data, msg->data_size ); list_remove( &msg->entry ); free_message( msg );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=90564
Your paranoid android.
=== debiant2 (32 bit WoW report) ===
user32: menu.c:2337: Test failed: test 25
The messages are of variable size and carry the corresponding HID report data after each RAWINPUT struct.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/message.c | 9 +++++++++ dlls/user32/rawinput.c | 15 +++++++++++++++ dlls/user32/user_private.h | 2 ++ server/queue.c | 1 + server/trace.c | 1 + 5 files changed, 28 insertions(+)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 71d0be8913e..a80fb8c57ea 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -3254,6 +3254,14 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r hid_usage_page = ((USAGE *)rawinput->data.hid.bRawData)[0]; hid_usage = ((USAGE *)rawinput->data.hid.bRawData)[1]; } + if (input->u.hi.uMsg == WM_INPUT) + { + if (!rawinput_device_get_usages( rawinput->header.hDevice, &hid_usage_page, &hid_usage )) + { + WARN( "unable to get HID usages for device %p\n", rawinput->header.hDevice ); + return STATUS_INVALID_HANDLE; + } + } }
SERVER_START_REQ( send_hardware_message ) @@ -3283,6 +3291,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r req->input.hw.lparam = MAKELONG( input->u.hi.wParamL, input->u.hi.wParamH ); switch (input->u.hi.uMsg) { + case WM_INPUT: case WM_INPUT_DEVICE_CHANGE: req->input.hw.rawinput.type = rawinput->header.dwType; switch (rawinput->header.dwType) diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index 716047b4599..103f2bb8a55 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -267,6 +267,21 @@ static struct device *find_device_from_handle(HANDLE handle) }
+BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage) +{ + struct device *device; + + *usage_page = *usage = 0; + + if (!(device = find_device_from_handle(handle))) return FALSE; + if (device->info.dwType != RIM_TYPEHID) return FALSE; + + *usage_page = device->info.u.hid.usUsagePage; + *usage = device->info.u.hid.usUsage; + return TRUE; +} + + struct rawinput_thread_data *rawinput_thread_data(void) { struct user_thread_info *thread_info = get_user_thread_info(); diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 974d18be482..96cc01af2e9 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -28,6 +28,7 @@ #include "winuser.h" #include "winreg.h" #include "winternl.h" +#include "hidusage.h" #include "wine/heap.h"
#define GET_WORD(ptr) (*(const WORD *)(ptr)) @@ -239,6 +240,7 @@ struct tagWND;
struct hardware_msg_data; extern BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_msg_data *msg_data); +extern BOOL rawinput_device_get_usages(HANDLE handle, USAGE *usage_page, USAGE *usage); extern struct rawinput_thread_data *rawinput_thread_data(void);
extern void keyboard_init(void) DECLSPEC_HIDDEN; diff --git a/server/queue.c b/server/queue.c index ebbe4049ae8..3e6050686ae 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1994,6 +1994,7 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_
switch (input->hw.msg) { + case WM_INPUT: case WM_INPUT_DEVICE_CHANGE: raw_msg.foreground = NULL; raw_msg.desktop = NULL; diff --git a/server/trace.c b/server/trace.c index 3cb601e774d..9b552454cf6 100644 --- a/server/trace.c +++ b/server/trace.c @@ -440,6 +440,7 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input ) dump_uint64( ",lparam=", &input->hw.lparam ); switch (input->hw.msg) { + case WM_INPUT: case WM_INPUT_DEVICE_CHANGE: dump_rawinput( ",rawinput=", &input->hw.rawinput ); }