We need to be able to iterate all registered rawinput devices for foreign processes, not only the current one.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
This series implements rawinput message support for HID gamepads, needed by several games when not using XInput compatible gamepads (such as DualShock or Wiimotes controllers).
It will allow us to read HID reports in a more efficient way than reading the device files, as the rawinput messages are pushed by winedevice.exe to the listening applications instead of requiring ioctl roundtrips between the application, wineserver, and winedevice.exe.
It could help for instance, for DInput over HID, or to optimize XInput, which I believe is currently also reading HID reports.
The series has been tested in Wine Staging and Proton for a while now.
server/queue.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/server/queue.c b/server/queue.c index e47980a4aa8..1735d0d6d26 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1489,11 +1489,11 @@ static user_handle_t find_hardware_message_window( struct desktop *desktop, stru return win; }
-static struct rawinput_device_entry *find_rawinput_device( unsigned short usage_page, unsigned short usage ) +static struct rawinput_device_entry *find_rawinput_device( struct process *process, unsigned short usage_page, unsigned short usage ) { struct rawinput_device_entry *e;
- LIST_FOR_EACH_ENTRY( e, ¤t->process->rawinput_devices, struct rawinput_device_entry, entry ) + LIST_FOR_EACH_ENTRY( e, &process->rawinput_devices, struct rawinput_device_entry, entry ) { if (e->device.usage_page != usage_page || e->device.usage != usage) continue; return e; @@ -1506,7 +1506,7 @@ static void update_rawinput_device(const struct rawinput_device *device) { struct rawinput_device_entry *e;
- if (!(e = find_rawinput_device( device->usage_page, device->usage ))) + if (!(e = find_rawinput_device( current->process, device->usage_page, device->usage ))) { if (!(e = mem_alloc( sizeof(*e) ))) return; list_add_tail( ¤t->process->rawinput_devices, &e->entry ); @@ -3313,9 +3313,9 @@ DECL_HANDLER(update_rawinput_devices) update_rawinput_device(&devices[i]); }
- e = find_rawinput_device( 1, 2 ); + e = find_rawinput_device( current->process, 1, 2 ); current->process->rawinput_mouse = e ? &e->device : NULL; - e = find_rawinput_device( 1, 6 ); + e = find_rawinput_device( current->process, 1, 6 ); current->process->rawinput_kbd = e ? &e->device : NULL; }
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 --- server/queue.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 1735d0d6d26..ca71f9ee3b4 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; @@ -1663,6 +1663,8 @@ struct rawinput_message struct hw_msg_source source; unsigned int time; 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 */ @@ -1673,6 +1675,7 @@ static int queue_rawinput_message( struct process* process, void *arg ) struct desktop *target_desktop = NULL; struct thread *target_thread = NULL; struct message *msg; + struct hardware_msg_data *msg_data; int wparam = RIM_INPUT;
if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) @@ -1690,14 +1693,18 @@ 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_data = msg->data;
msg->win = device->target; msg->msg = WM_INPUT; msg->wparam = wparam; msg->lparam = 0; - memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) ); + + memcpy( msg_data, &raw_msg->data, sizeof(*msg_data) ); + if (raw_msg->extra_len && raw_msg->extra) + memcpy( msg_data + 1, raw_msg->extra, raw_msg->extra_len );
queue_hardware_message( raw_msg->desktop, msg, 1 );
@@ -1770,6 +1777,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons raw_msg.desktop = desktop; raw_msg.source = source; raw_msg.time = time; + raw_msg.extra = NULL; + raw_msg.extra_len = 0;
msg_data = &raw_msg.data; msg_data->info = input->mouse.info; @@ -1795,7 +1804,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 ); @@ -1904,6 +1913,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c raw_msg.desktop = desktop; raw_msg.source = source; raw_msg.time = time; + raw_msg.extra = NULL; + raw_msg.extra_len = 0;
msg_data = &raw_msg.data; msg_data->info = input->kbd.info; @@ -1923,7 +1934,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 ); @@ -1961,7 +1972,7 @@ static void queue_custom_hardware_message( struct desktop *desktop, user_handle_ struct hw_msg_source source = { IMDT_UNAVAILABLE, origin }; struct message *msg;
- 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;
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;
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=85384
Your paranoid android.
=== debiant2 (64 bit WoW report) ===
user32: win.c:10097: Test failed: Expected foreground window 0, got 00E10102 win.c:10103: Test failed: Expected foreground window 001B0140, got 00E10102
HID rawinput messages are sent from winedevice.exe, which is not attached to any desktop. We need to broadcast the messages to all desktops in that case.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/server/queue.c b/server/queue.c index ed11c69e879..d1561ec81e8 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1675,8 +1675,8 @@ 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; + struct desktop *target_desktop = NULL, *desktop = NULL; + struct thread *target_thread = NULL, *foreground = NULL; struct message *msg; struct hardware_msg_data *msg_data; int wparam = RIM_INPUT; @@ -1689,12 +1689,18 @@ static int queue_rawinput_message( struct process* process, void *arg ) device = &entry->device; if (!device) return 0;
- if (process != raw_msg->foreground->process) + if (raw_msg->desktop) desktop = (struct desktop *)grab_object( raw_msg->desktop ); + else if (!(desktop = get_desktop_obj( process, process->desktop, 0 ))) goto done; + + if (raw_msg->foreground) foreground = (struct thread *)grab_object( raw_msg->foreground ); + else if (!(foreground = get_foreground_thread( desktop, 0 ))) goto done; + + if (process != foreground->process) { if (!(device->flags & RIDEV_INPUTSINK)) goto done; if (!(target_thread = get_window_thread( device->target ))) goto done; if (!(target_desktop = get_thread_desktop( target_thread, 0 ))) goto done; - if (target_desktop != raw_msg->desktop) goto done; + if (target_desktop != desktop) goto done; wparam = RIM_INPUTSINK; }
@@ -1711,11 +1717,13 @@ static int queue_rawinput_message( struct process* process, void *arg ) if (raw_msg->extra_len && raw_msg->extra) memcpy( msg_data + 1, raw_msg->extra, raw_msg->extra_len );
- queue_hardware_message( raw_msg->desktop, msg, 1 ); + queue_hardware_message( desktop, msg, 1 );
done: if (target_thread) release_object( target_thread ); if (target_desktop) release_object( target_desktop ); + if (foreground) release_object( foreground ); + if (desktop) release_object( desktop ); return 0; }
@@ -2499,15 +2507,14 @@ DECL_HANDLER(send_message) DECL_HANDLER(send_hardware_message) { struct thread *thread = NULL; - struct desktop *desktop; + struct desktop *desktop = get_thread_desktop( current, 0 ); unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE); struct msg_queue *sender = get_current_queue(); data_size_t size = min( 256, get_reply_max_size() );
- if (!(desktop = get_thread_desktop( current, 0 ))) return; - if (req->win) { + if (!desktop) return; if (!(thread = get_window_thread( req->win ))) return; if (desktop != thread->queue->input->desktop) { @@ -2517,18 +2524,24 @@ DECL_HANDLER(send_hardware_message) } }
- reply->prev_x = desktop->cursor.x; - reply->prev_y = desktop->cursor.y; + if (desktop) + { + reply->prev_x = desktop->cursor.x; + reply->prev_y = desktop->cursor.y; + }
switch (req->input.type) { case HW_INPUT_MOUSE: + if (!desktop) return; reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); break; case HW_INPUT_KEYBOARD: + if (!desktop) return; reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender ); break; case HW_INPUT_HARDWARE: + if (!desktop) return; queue_custom_hardware_message( desktop, req->win, origin, &req->input ); break; case HW_INPUT_HID: @@ -2539,10 +2552,13 @@ DECL_HANDLER(send_hardware_message) } if (thread) release_object( thread );
- reply->new_x = desktop->cursor.x; - reply->new_y = desktop->cursor.y; - set_reply_data( desktop->keystate, size ); - release_object( desktop ); + if (desktop) + { + reply->new_x = desktop->cursor.x; + reply->new_y = desktop->cursor.y; + set_reply_data( desktop->keystate, size ); + release_object( desktop ); + } }
/* post a quit message to the current queue */
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/device.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index fc1dfd07db1..8d7bae5cafa 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -26,6 +26,7 @@ #include "winuser.h" #include "setupapi.h"
+#include "wine/server.h" #include "wine/debug.h" #include "ddk/hidsdi.h" #include "ddk/hidtypes.h" @@ -237,6 +238,25 @@ static NTSTATUS copy_packet_into_buffer(HID_XFER_PACKET *packet, BYTE* buffer, U return STATUS_BUFFER_OVERFLOW; }
+static void HID_Device_sendRawInput(DEVICE_OBJECT *device, HID_XFER_PACKET *packet) +{ + BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + + SERVER_START_REQ(send_hardware_message) + { + req->win = 0; + req->flags = 0; + req->input.type = HW_INPUT_HID; + req->input.hid.device = 0; /* FIXME */ + req->input.hid.usage_page = ext->preparseData->caps.UsagePage; + req->input.hid.usage = ext->preparseData->caps.Usage; + req->input.hid.length = packet->reportBufferLen; + wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen); + wine_server_call(req); + } + SERVER_END_REQ; +} + static void HID_Device_processQueue(DEVICE_OBJECT *device) { IRP *irp; @@ -320,6 +340,7 @@ static DWORD CALLBACK hid_device_thread(void *args) if (irp->IoStatus.u.Status == STATUS_SUCCESS) { RingBuffer_Write(ext->ring_buffer, packet); + HID_Device_sendRawInput(device, packet); HID_Device_processQueue(device); }
@@ -366,6 +387,7 @@ static DWORD CALLBACK hid_device_thread(void *args) else packet->reportId = 0; RingBuffer_Write(ext->ring_buffer, packet); + HID_Device_sendRawInput(device, packet); HID_Device_processQueue(device); }
On 2/10/21 1:23 PM, Rémi Bernon wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/hidclass.sys/device.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index fc1dfd07db1..8d7bae5cafa 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -26,6 +26,7 @@ #include "winuser.h" #include "setupapi.h"
+#include "wine/server.h" #include "wine/debug.h" #include "ddk/hidsdi.h" #include "ddk/hidtypes.h" @@ -237,6 +238,25 @@ static NTSTATUS copy_packet_into_buffer(HID_XFER_PACKET *packet, BYTE* buffer, U return STATUS_BUFFER_OVERFLOW; }
+static void HID_Device_sendRawInput(DEVICE_OBJECT *device, HID_XFER_PACKET *packet) +{
- BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
- SERVER_START_REQ(send_hardware_message)
- {
req->win = 0;
req->flags = 0;
req->input.type = HW_INPUT_HID;
req->input.hid.device = 0; /* FIXME */
req->input.hid.usage_page = ext->preparseData->caps.UsagePage;
req->input.hid.usage = ext->preparseData->caps.Usage;
req->input.hid.length = packet->reportBufferLen;
wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen);
wine_server_call(req);
- }
- SERVER_END_REQ;
+}
- static void HID_Device_processQueue(DEVICE_OBJECT *device) { IRP *irp;
@@ -320,6 +340,7 @@ static DWORD CALLBACK hid_device_thread(void *args) if (irp->IoStatus.u.Status == STATUS_SUCCESS) { RingBuffer_Write(ext->ring_buffer, packet);
HID_Device_sendRawInput(device, packet); HID_Device_processQueue(device); }
@@ -366,6 +387,7 @@ static DWORD CALLBACK hid_device_thread(void *args) else packet->reportId = 0; RingBuffer_Write(ext->ring_buffer, packet);
HID_Device_sendRawInput(device, packet); HID_Device_processQueue(device); }
There's apparently some outstanding issue related to the HID report carried by WM_INPUT, possibly making this patch not entirely correct.
I think it only impacts this last patch though, not the previous changes that are required to send WM_INPUT messages with HID data.
On Wed, Feb 10, 2021 at 08:07:17PM +0100, Rémi Bernon wrote:
On 2/10/21 1:23 PM, Rémi Bernon wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50506 Signed-off-by: Rémi Bernon rbernon@codeweavers.com
dlls/hidclass.sys/device.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index fc1dfd07db1..8d7bae5cafa 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -26,6 +26,7 @@ #include "winuser.h" #include "setupapi.h" +#include "wine/server.h" #include "wine/debug.h" #include "ddk/hidsdi.h" #include "ddk/hidtypes.h" @@ -237,6 +238,25 @@ static NTSTATUS copy_packet_into_buffer(HID_XFER_PACKET *packet, BYTE* buffer, U return STATUS_BUFFER_OVERFLOW; } +static void HID_Device_sendRawInput(DEVICE_OBJECT *device, HID_XFER_PACKET *packet) +{
- BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
- SERVER_START_REQ(send_hardware_message)
- {
req->win = 0;
req->flags = 0;
req->input.type = HW_INPUT_HID;
req->input.hid.device = 0; /* FIXME */
req->input.hid.usage_page = ext->preparseData->caps.UsagePage;
req->input.hid.usage = ext->preparseData->caps.Usage;
req->input.hid.length = packet->reportBufferLen;
wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen);
wine_server_call(req);
- }
- SERVER_END_REQ;
+}
- static void HID_Device_processQueue(DEVICE_OBJECT *device) { IRP *irp;
@@ -320,6 +340,7 @@ static DWORD CALLBACK hid_device_thread(void *args) if (irp->IoStatus.u.Status == STATUS_SUCCESS) { RingBuffer_Write(ext->ring_buffer, packet);
HID_Device_sendRawInput(device, packet); HID_Device_processQueue(device); }
@@ -366,6 +387,7 @@ static DWORD CALLBACK hid_device_thread(void *args) else packet->reportId = 0; RingBuffer_Write(ext->ring_buffer, packet);
HID_Device_sendRawInput(device, packet); HID_Device_processQueue(device); }
There's apparently some outstanding issue related to the HID report carried by WM_INPUT, possibly making this patch not entirely correct.
I think it only impacts this last patch though, not the previous changes that are required to send WM_INPUT messages with HID data.
Hey,
WM_INPUT / GetRawInputData() uses the same format for reports as HidD_GetInputReport(), i.e.: the first byte is always used for the report id even if the device is not using report ids, in which case it is set to zero (reserved by the HID spec).
HID_XFER_PACKET contains the reports verbatim, so at times we have to prepend that zero.
Add something like this before the wine_server_add_data() call:
if (ext->preparseData->reports[0].reportID == 0) { BYTE zero_byte = 0; req->input.hid.length++; wine_server_add_data(req, &zero_byte, sizeof(zero_byte)); }
Note that this is only for HID devices, which doesn't cover mouse or keyboard so far, so it should not have the same issues with focus inconsistencies than mouse and keyboard rawinput patches may have.
I believe applications can already read HID reports from gamepad devices anytime through the device files, even when they are not foreground or when they incorrectly believe they have foreground. This only adds support for HID reports published through WM_INPUT messages.