The messages are of variable size and carry the corresponding HID report data after each RAWINPUT struct.
For now hDevice is set to 0 but it will need to be a pseudo-handle that will be used to uniquely identify the device and possibly query its information using GetRawInputDeviceInfo.
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 ++- dlls/user32/rawinput.c | 24 +++++++++++++++-- server/protocol.def | 26 ++++++++++++++++--- server/queue.c | 58 ++++++++++++++++++++++++++++++++++-------- server/trace.c | 10 +++++--- 5 files changed, 103 insertions(+), 19 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index f7ce262f90d..01d1a0eed97 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -3240,10 +3240,10 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) { req->win = wine_server_user_handle( hwnd ); req->flags = flags; - req->input.type = input->type; switch (input->type) { case INPUT_MOUSE: + req->input.type = HW_INPUT_MOUSE; req->input.mouse.x = input->u.mi.dx; req->input.mouse.y = input->u.mi.dy; req->input.mouse.data = input->u.mi.mouseData; @@ -3252,6 +3252,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) req->input.mouse.info = input->u.mi.dwExtraInfo; break; case INPUT_KEYBOARD: + req->input.type = HW_INPUT_KEYBOARD; req->input.kbd.vkey = input->u.ki.wVk; req->input.kbd.scan = input->u.ki.wScan; req->input.kbd.flags = input->u.ki.dwFlags; @@ -3259,6 +3260,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, UINT flags ) req->input.kbd.info = input->u.ki.dwExtraInfo; break; case INPUT_HARDWARE: + req->input.type = HW_INPUT_HARDWARE; req->input.hw.msg = input->u.hi.uMsg; req->input.hw.lparam = MAKELONG( input->u.hi.wParamL, input->u.hi.wParamH ); break; diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index ba11a121bc5..107b7d48d34 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -326,6 +326,22 @@ 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) + { + if (sizeof(*rawinput) + msg_data->rawinput.hid.length > RAWINPUT_BUFFER_SIZE) + { + ERR("unexpectedly large hardware message dropped\n"); + return FALSE; + } + + rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data.hid.bRawData) + msg_data->rawinput.hid.length; + rawinput->header.hDevice = 0; /* FIXME */ + rawinput->header.wParam = 0; + + rawinput->data.hid.dwSizeHid = msg_data->rawinput.hid.length; + rawinput->data.hid.dwCount = 1; + memcpy(rawinput->data.hid.bRawData, msg_data + 1, msg_data->rawinput.hid.length); + } else { FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type); @@ -524,7 +540,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;
@@ -584,7 +600,10 @@ UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, 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.length; + msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_size); }
if (count == 0 && next_size == 0) *data_size = 0; @@ -657,6 +676,7 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE handle, UINT command, void *data, UINT handle, command, data, data_size);
if (!data_size) return ~0U; + if (!device) return ~0U;
/* each case below must set: * *data_size: length (meaning defined by command) of data we want to copy diff --git a/server/protocol.def b/server/protocol.def index 13cac237a89..136971596c9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -312,6 +312,13 @@ struct hardware_msg_data int y; /* y coordinate */ unsigned int data; /* mouse data */ } mouse; + struct + { + int type; /* RIM_TYPEHID */ + obj_handle_t device; + unsigned int length; /* HID report length */ + /* followed by length bytes of HID report data */ + } hid; } rawinput; };
@@ -335,7 +342,7 @@ typedef union int type; struct { - int type; /* INPUT_KEYBOARD */ + int type; /* HW_INPUT_KEYBOARD */ unsigned short vkey; /* virtual key code */ unsigned short scan; /* scan code */ unsigned int flags; /* event flags */ @@ -344,7 +351,7 @@ typedef union } kbd; struct { - int type; /* INPUT_MOUSE */ + int type; /* HW_INPUT_MOUSE */ int x; /* coordinates */ int y; unsigned int data; /* mouse data */ @@ -354,11 +361,23 @@ typedef union } mouse; struct { - int type; /* INPUT_HARDWARE */ + int type; /* HW_INPUT_HARDWARE */ unsigned int msg; /* message code */ lparam_t lparam; /* message param */ } hw; + struct + { + int type; /* HW_INPUT_HID */ + obj_handle_t device; + unsigned char usage_page; + unsigned char usage; + unsigned int length; + } hid; } hw_input_t; +#define HW_INPUT_MOUSE 0 +#define HW_INPUT_KEYBOARD 1 +#define HW_INPUT_HARDWARE 2 +#define HW_INPUT_HID 3
typedef union { @@ -2044,6 +2063,7 @@ enum message_type user_handle_t win; /* window handle */ hw_input_t input; /* input data */ unsigned int flags; /* flags (see below) */ + VARARG(data,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 ca71f9ee3b4..ed11c69e879 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1608,7 +1608,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa struct msg_queue *queue; struct message *msg; timeout_t timeout = 2000 * -10000; /* FIXME: load from registry */ - int id = (input->type == INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL; + int id = (input->type == HW_INPUT_MOUSE) ? WH_MOUSE_LL : WH_KEYBOARD_LL;
if (!(hook_thread = get_first_global_hook( id ))) return 0; if (!(queue = hook_thread->queue)) return 0; @@ -1626,7 +1626,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa msg->data_size = hardware_msg->data_size; msg->result = NULL;
- if (input->type == INPUT_KEYBOARD) + if (input->type == HW_INPUT_KEYBOARD) { unsigned short vkey = input->kbd.vkey; if (input->kbd.flags & KEYEVENTF_UNICODE) vkey = VK_PACKET; @@ -1662,6 +1662,8 @@ struct rawinput_message struct desktop *desktop; struct hw_msg_source source; unsigned int time; + unsigned char usage_page; + unsigned char usage; struct hardware_msg_data data; const void *extra; data_size_t extra_len; @@ -1671,6 +1673,7 @@ struct rawinput_message static int queue_rawinput_message( struct process* process, void *arg ) { const struct rawinput_message* raw_msg = arg; + const struct rawinput_device_entry *entry; const struct rawinput_device *device = NULL; struct desktop *target_desktop = NULL; struct thread *target_thread = NULL; @@ -1682,6 +1685,8 @@ static int queue_rawinput_message( struct process* process, void *arg ) device = process->rawinput_mouse; else if (raw_msg->data.rawinput.type == RIM_TYPEKEYBOARD) device = process->rawinput_kbd; + else if ((entry = find_rawinput_device( process, raw_msg->usage_page, raw_msg->usage ))) + device = &entry->device; if (!device) return 0;
if (process != raw_msg->foreground->process) @@ -1984,6 +1989,34 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ queue_hardware_message( desktop, msg, 1 ); }
+/* queue a hardware message for an hid event */ +static void queue_hid_message( user_handle_t win, const hw_input_t *input, + unsigned int origin, struct msg_queue *sender, + const void *report, data_size_t report_len ) +{ + struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; + struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; + + /* send to all desktops */ + raw_msg.foreground = NULL; + raw_msg.desktop = NULL; + raw_msg.source = source; + raw_msg.time = get_tick_count(); + raw_msg.usage_page = input->hid.usage_page; + raw_msg.usage = input->hid.usage; + raw_msg.extra = report; + raw_msg.extra_len = report_len; + + msg_data = &raw_msg.data; + msg_data->flags = 0; + msg_data->rawinput.type = RIM_TYPEHID; + msg_data->rawinput.hid.device = input->hid.device; + msg_data->rawinput.hid.length = report_len; + + enum_processes( queue_rawinput_message, &raw_msg ); +} + /* check message filter for a hardware message */ static int check_hw_message_filter( user_handle_t win, unsigned int msg_code, user_handle_t filter_win, unsigned int first, unsigned int last ) @@ -2489,15 +2522,18 @@ DECL_HANDLER(send_hardware_message)
switch (req->input.type) { - case INPUT_MOUSE: + case HW_INPUT_MOUSE: reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); break; - case INPUT_KEYBOARD: + case HW_INPUT_KEYBOARD: reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender ); break; - case INPUT_HARDWARE: + case HW_INPUT_HARDWARE: queue_custom_hardware_message( desktop, req->win, origin, &req->input ); break; + case HW_INPUT_HID: + queue_hid_message( req->win, &req->input, origin, sender, get_req_data(), get_req_data_size() ); + break; default: set_error( STATUS_INVALID_PARAMETER ); } @@ -3279,16 +3315,18 @@ 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 : data->rawinput.hid.length; + data_size_t data_size = sizeof(*data) + hid_size;
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 + data_size > buf + get_reply_max_size()) break; + if (cur + 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 ); @@ -3298,7 +3336,7 @@ DECL_HANDLER(get_rawinput_buffer) buf = tmp; }
- memcpy(cur, data, sizeof(*data)); + memcpy( cur, data, data_size ); list_remove( &msg->entry ); free_message( msg );
diff --git a/server/trace.c b/server/trace.c index c6ef3fb9773..4434bb1893f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -398,24 +398,28 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input ) { switch (input->type) { - case INPUT_MOUSE: + case HW_INPUT_MOUSE: fprintf( stderr, "%s{type=MOUSE,x=%d,y=%d,data=%08x,flags=%08x,time=%u", prefix, input->mouse.x, input->mouse.y, input->mouse.data, input->mouse.flags, input->mouse.time ); dump_uint64( ",info=", &input->mouse.info ); fputc( '}', stderr ); break; - case INPUT_KEYBOARD: + case HW_INPUT_KEYBOARD: fprintf( stderr, "%s{type=KEYBOARD,vkey=%04hx,scan=%04hx,flags=%08x,time=%u", prefix, input->kbd.vkey, input->kbd.scan, input->kbd.flags, input->kbd.time ); dump_uint64( ",info=", &input->kbd.info ); fputc( '}', stderr ); break; - case INPUT_HARDWARE: + case HW_INPUT_HARDWARE: fprintf( stderr, "%s{type=HARDWARE,msg=%04x", prefix, input->hw.msg ); dump_uint64( ",lparam=", &input->hw.lparam ); fputc( '}', stderr ); break; + case HW_INPUT_HID: + fprintf( stderr, "%s{type=HID,device=%04x,usage_page=%02x,usage=%02x,length=%04x}", + prefix, input->hid.device, input->hid.usage_page, input->hid.usage, input->hid.length ); + break; default: fprintf( stderr, "%s{type=%04x}", prefix, input->type ); break;