Several games use RawInput API to get input data from controllers, this is the case for instance for all the games that use the Rewired input framework with a DualShock 4 controller.
This patch series add WM_INPUT messages for HID devices, that can then be subscribed to using the RawInput API. The first two patches are also useful as ground work for my other keyboard and mouse rawinput/dinput related patches.
Rémi Bernon (7): server: Add send_hardware_message flags for rawinput translation. server: Implement rawinput hardware message broadcast. server: Add process argument to find_rawinput_device. server: Allow extra data for hardware_msg_data message. server: Add HID input message type to send_hardware_message request. user32: Implement WM_INPUT/RIM_TYPEHID message handling. hidclass.sys: Send input message to server when HID report is received.
dlls/hidclass.sys/device.c | 30 ++++++ dlls/hidclass.sys/hid.h | 1 + dlls/hidclass.sys/pnp.c | 16 ++++ dlls/user32/message.c | 19 +++- dlls/user32/rawinput.c | 37 +++++++ dlls/user32/user_private.h | 2 + server/protocol.def | 31 +++++- server/queue.c | 191 +++++++++++++++++++++++++++++-------- 8 files changed, 281 insertions(+), 46 deletions(-)
-- 2.23.0
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/protocol.def | 2 ++ server/queue.c | 20 ++++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 6af0ae0cff8..ab3af90545b 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2315,6 +2315,8 @@ enum message_type VARARG(keystate,bytes); /* global state array for all the keys */ @END #define SEND_HWMSG_INJECTED 0x01 +#define SEND_HWMSG_ONLY_RAW 0x02 +#define SEND_HWMSG_SKIP_RAW 0x04
/* Get a message from the current queue */ diff --git a/server/queue.c b/server/queue.c index 96587d11d1e..a18f3cdea00 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1598,7 +1598,7 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa
/* queue a hardware message for a mouse event */ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, - unsigned int origin, struct msg_queue *sender ) + unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) { const struct rawinput_device *device; struct hardware_msg_data *msg_data; @@ -1651,7 +1651,8 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons y = desktop->cursor.y; }
- if ((device = current->process->rawinput_mouse)) + if ((device = current->process->rawinput_mouse) && + !(req_flags & SEND_HWMSG_SKIP_RAW)) { if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; msg_data = msg->data; @@ -1670,6 +1671,9 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons queue_hardware_message( desktop, msg, 0 ); }
+ if (req_flags & SEND_HWMSG_ONLY_RAW) + return 0; + for (i = 0; i < ARRAY_SIZE( messages ); i++) { if (!messages[i]) continue; @@ -1701,7 +1705,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
/* queue a hardware message for a keyboard event */ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, - unsigned int origin, struct msg_queue *sender ) + unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; const struct rawinput_device *device; @@ -1777,7 +1781,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c break; }
- if ((device = current->process->rawinput_kbd)) + if ((device = current->process->rawinput_kbd) && + !(req_flags & SEND_HWMSG_SKIP_RAW)) { if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; msg_data = msg->data; @@ -1795,6 +1800,9 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c queue_hardware_message( desktop, msg, 0 ); }
+ if (req_flags & SEND_HWMSG_ONLY_RAW) + return 0; + if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; msg_data = msg->data;
@@ -2351,10 +2359,10 @@ DECL_HANDLER(send_hardware_message) switch (req->input.type) { case INPUT_MOUSE: - reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender ); + reply->wait = queue_mouse_message( desktop, req->win, &req->input, origin, sender, req->flags ); break; case INPUT_KEYBOARD: - reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender ); + reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, req->flags ); break; case INPUT_HARDWARE: queue_custom_hardware_message( desktop, req->win, origin, &req->input );
We now broadcast rawinput messages to all listening processes when a driver sends input with the SEND_HWMSG_BCAST_RAW flag, instead of looking for registered rawdevices in the current process.
For now, only the foreground window thread will receive the rawinput messages.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/protocol.def | 1 + server/queue.c | 95 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 75 insertions(+), 21 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index ab3af90545b..3b5da8dcaed 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2317,6 +2317,7 @@ enum message_type #define SEND_HWMSG_INJECTED 0x01 #define SEND_HWMSG_ONLY_RAW 0x02 #define SEND_HWMSG_SKIP_RAW 0x04 +#define SEND_HWMSG_BCAST_RAW 0x08
/* Get a message from the current queue */ diff --git a/server/queue.c b/server/queue.c index a18f3cdea00..d883811449e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1596,12 +1596,64 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa return 1; }
+struct rawinput_message +{ + struct desktop *desktop; + struct hw_msg_source source; + unsigned int time; + struct hardware_msg_data data; +}; + +static int queue_rawinput_message( struct process* process, void* user ) +{ + const struct rawinput_message* raw_msg = user; + const struct rawinput_device *device = NULL; + struct desktop *desktop = NULL; + struct thread *thread = NULL; + struct message *msg; + + if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) + device = process->rawinput_mouse; + else if (raw_msg->data.rawinput.type == RIM_TYPEKEYBOARD) + device = process->rawinput_kbd; + + if (!device) + return 0; + + if (!(desktop = get_desktop_obj( process, process->desktop, 0 )) || + (raw_msg->desktop && desktop != raw_msg->desktop)) + goto done; + + if (!(thread = get_window_thread( device->target ? device->target : desktop->foreground_input->active )) || + process != thread->process) + goto done; + + if (thread->queue->input != desktop->foreground_input) + goto done; + + if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time ))) + goto done; + + msg->win = device->target; + msg->msg = WM_INPUT; + msg->wparam = RIM_INPUT; + msg->lparam = 0; + memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) ); + + queue_hardware_message( desktop, msg, 0 ); + +done: + if (thread) release_object( thread ); + if (desktop) release_object( desktop ); + return 0; +} + /* queue a hardware message for a mouse event */ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) { - const struct rawinput_device *device; struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; struct message *msg; unsigned int i, time, flags; struct hw_msg_source source = { IMDT_MOUSE, origin }; @@ -1651,24 +1703,24 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons y = desktop->cursor.y; }
- if ((device = current->process->rawinput_mouse) && - !(req_flags & SEND_HWMSG_SKIP_RAW)) + if (!(req_flags & SEND_HWMSG_SKIP_RAW)) { - if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; - msg_data = msg->data; - - msg->win = device->target; - msg->msg = WM_INPUT; - msg->wparam = RIM_INPUT; - msg->lparam = 0; + raw_msg.desktop = desktop; + raw_msg.source = source; + raw_msg.time = time;
+ msg_data = &raw_msg.data; + msg_data->info = input->mouse.info; msg_data->flags = flags; msg_data->rawinput.type = RIM_TYPEMOUSE; msg_data->rawinput.mouse.x = x - desktop->cursor.x; msg_data->rawinput.mouse.y = y - desktop->cursor.y; msg_data->rawinput.mouse.data = input->mouse.data;
- queue_hardware_message( desktop, msg, 0 ); + if (req_flags & SEND_HWMSG_BCAST_RAW) + enum_processes( queue_rawinput_message, &raw_msg ); + else + queue_rawinput_message( current->process, &raw_msg ); }
if (req_flags & SEND_HWMSG_ONLY_RAW) @@ -1708,8 +1760,8 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c unsigned int origin, struct msg_queue *sender, unsigned int req_flags ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; - const struct rawinput_device *device; struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; struct message *msg; unsigned char vkey = input->kbd.vkey; unsigned int message_code, time; @@ -1781,23 +1833,24 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c break; }
- if ((device = current->process->rawinput_kbd) && - !(req_flags & SEND_HWMSG_SKIP_RAW)) + if (!(req_flags & SEND_HWMSG_SKIP_RAW)) { - if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; - msg_data = msg->data; - - msg->win = device->target; - msg->msg = WM_INPUT; - msg->wparam = RIM_INPUT; + raw_msg.desktop = desktop; + raw_msg.source = source; + raw_msg.time = time;
+ msg_data = &raw_msg.data; + msg_data->info = input->kbd.info; msg_data->flags = input->kbd.flags; msg_data->rawinput.type = RIM_TYPEKEYBOARD; msg_data->rawinput.kbd.message = message_code; msg_data->rawinput.kbd.vkey = vkey; msg_data->rawinput.kbd.scan = input->kbd.scan;
- queue_hardware_message( desktop, msg, 0 ); + if (req_flags & SEND_HWMSG_BCAST_RAW) + enum_processes( queue_rawinput_message, &raw_msg ); + else + queue_rawinput_message( current->process, &raw_msg ); }
if (req_flags & SEND_HWMSG_ONLY_RAW)
We need to be able to iterate all registered rawinput devices for foreign processes, not only the current one.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/server/queue.c b/server/queue.c index d883811449e..22abdaed34a 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1445,11 +1445,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; @@ -1462,7 +1462,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 ); @@ -3179,8 +3179,8 @@ 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.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 22abdaed34a..156a355c6d1 100644 --- a/server/queue.c +++ b/server/queue.c @@ -343,13 +343,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; @@ -358,9 +358,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; @@ -372,7 +372,7 @@ static void set_cursor_pos( struct desktop *desktop, int x, int y ) static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; 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->msg = WM_MOUSEMOVE; msg->x = x; @@ -1602,6 +1602,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; };
static int queue_rawinput_message( struct process* process, void* user ) @@ -1611,6 +1613,7 @@ static int queue_rawinput_message( struct process* process, void* user ) struct desktop *desktop = NULL; struct thread *thread = NULL; struct message *msg; + struct hardware_msg_data *msg_data;
if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) device = process->rawinput_mouse; @@ -1631,14 +1634,18 @@ static int queue_rawinput_message( struct process* process, void* user ) if (thread->queue->input != desktop->foreground_input) goto done;
- 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 = RIM_INPUT; 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( desktop, msg, 0 );
@@ -1705,9 +1712,11 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons
if (!(req_flags & SEND_HWMSG_SKIP_RAW)) { - raw_msg.desktop = desktop; - raw_msg.source = source; - raw_msg.time = time; + 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; @@ -1732,7 +1741,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 ); @@ -1835,9 +1844,11 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c
if (!(req_flags & SEND_HWMSG_SKIP_RAW)) { - raw_msg.desktop = desktop; - raw_msg.source = source; - raw_msg.time = time; + 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; @@ -1856,7 +1867,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (req_flags & SEND_HWMSG_ONLY_RAW) 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 ); @@ -1894,7 +1905,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;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/protocol.def | 28 +++++++++++++++++++++++---- server/queue.c | 47 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 3b5da8dcaed..4352044d795 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -309,6 +309,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; };
@@ -332,7 +339,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 */ @@ -341,7 +348,7 @@ typedef union } kbd; struct { - int type; /* INPUT_MOUSE */ + int type; /* HW_INPUT_MOUSE */ int x; /* coordinates */ int y; unsigned int data; /* mouse data */ @@ -351,11 +358,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_KEYBOARD INPUT_KEYBOARD +#define HW_INPUT_MOUSE INPUT_MOUSE +#define HW_INPUT_HARDWARE INPUT_HARDWARE +#define HW_INPUT_HID -1
typedef union { @@ -2304,8 +2323,9 @@ enum message_type /* Send a hardware message to a thread queue */ @REQ(send_hardware_message) user_handle_t win; /* window handle */ - hw_input_t input; /* input data */ + hw_input_t input; 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 156a355c6d1..188978495bf 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1557,7 +1557,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; @@ -1575,7 +1575,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; @@ -1601,6 +1601,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; @@ -1609,6 +1611,7 @@ struct rawinput_message static int queue_rawinput_message( struct process* process, void* user ) { const struct rawinput_message* raw_msg = user; + const struct rawinput_device_entry *entry; const struct rawinput_device *device = NULL; struct desktop *desktop = NULL; struct thread *thread = NULL; @@ -1619,6 +1622,8 @@ static int queue_rawinput_message( struct process* process, void* user ) 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; @@ -1917,6 +1922,35 @@ 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( struct desktop *desktop, user_handle_t win, const hw_input_t *input, + unsigned int origin, struct msg_queue *sender, unsigned int req_flags, + 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; + + raw_msg.desktop = NULL; /* send to all desktops */ + 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; + + if (req_flags & SEND_HWMSG_BCAST_RAW) + enum_processes( queue_rawinput_message, &raw_msg ); + else + queue_rawinput_message( current->process, &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 ) @@ -2422,15 +2456,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, req->flags ); break; - case INPUT_KEYBOARD: + case HW_INPUT_KEYBOARD: reply->wait = queue_keyboard_message( desktop, req->win, &req->input, origin, sender, req->flags ); 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( desktop, req->win, &req->input, origin, sender, req->flags, get_req_data(), get_req_data_size() ); + break; default: set_error( STATUS_INVALID_PARAMETER ); }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/message.c | 19 ++++++++++++++++++- dlls/user32/rawinput.c | 37 +++++++++++++++++++++++++++++++++++++ dlls/user32/user_private.h | 2 ++ 3 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index 43ce77c2dd6..ca2e01f45e5 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -2285,10 +2285,17 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * { struct user_thread_info *thread_info = get_user_thread_info(); RAWINPUT *rawinput = thread_info->rawinput; + SIZE_T data_len = 0; + + if (msg_data->rawinput.type == RIM_TYPEHID) + { + data_len = msg_data->rawinput.hid.length; + rawinput = thread_info->rawinput = HeapReAlloc( GetProcessHeap(), 0, rawinput, sizeof(*rawinput) + data_len ); + }
if (!rawinput) { - thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, sizeof(*rawinput) ); + thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, sizeof(*rawinput) + data_len ); if (!(rawinput = thread_info->rawinput)) return FALSE; }
@@ -2383,6 +2390,16 @@ static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data * rawinput->data.keyboard.Message = msg_data->rawinput.kbd.message; rawinput->data.keyboard.ExtraInformation = msg_data->info; } + else if (msg_data->rawinput.type == RIM_TYPEHID) + { + rawinput->header.dwSize = FIELD_OFFSET(RAWINPUT, data.hid.bRawData) + data_len; + rawinput->header.hDevice = rawinput_handle_from_device_handle(wine_server_ptr_handle(msg_data->rawinput.hid.device)); + rawinput->header.wParam = 0; + + rawinput->data.hid.dwSizeHid = data_len; + rawinput->data.hid.dwCount = 1; + memcpy(rawinput->data.hid.bRawData, msg_data + 1, data_len); + } else { FIXME("Unhandled rawinput type %#x.\n", msg_data->rawinput.type); diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index 94cf7a9a5d2..511f8ce1755 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -42,6 +42,7 @@ struct hid_device { WCHAR *path; HANDLE file; + HANDLE handle; RID_DEVICE_INFO_HID info; PHIDP_PREPARSED_DATA data; }; @@ -58,6 +59,8 @@ static CRITICAL_SECTION_DEBUG hid_devices_cs_debug = }; static CRITICAL_SECTION hid_devices_cs = { &hid_devices_cs_debug, -1, 0, 0, 0, 0 };
+extern DWORD WINAPI GetFinalPathNameByHandleW(HANDLE file, LPWSTR path, DWORD charcount, DWORD flags); + static BOOL array_reserve(void **elements, unsigned int *capacity, unsigned int count, unsigned int size) { unsigned int new_capacity, max_capacity; @@ -137,10 +140,43 @@ static struct hid_device *add_device(HDEVINFO set, SP_DEVICE_INTERFACE_DATA *ifa device = &hid_devices[hid_devices_count++]; device->path = path; device->file = file; + device->handle = INVALID_HANDLE_VALUE;
return device; }
+HANDLE rawinput_handle_from_device_handle(HANDLE device) +{ + WCHAR buffer[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH + 1]; + OBJECT_NAME_INFORMATION *info = (OBJECT_NAME_INFORMATION*)&buffer; + ULONG dummy; + unsigned int i; + + for (i = 0; i < hid_devices_count; ++i) + { + if (hid_devices[i].handle == device) + return &hid_devices[i]; + } + + if (NtQueryObject( device, ObjectNameInformation, &buffer, sizeof(buffer) - sizeof(WCHAR), &dummy ) || !info->Name.Buffer) + return NULL; + + /* replace ??\ with \?\ to match hid_devices paths */ + if (info->Name.Length > 1 && info->Name.Buffer[0] == '\' && info->Name.Buffer[1] == '?') + info->Name.Buffer[1] = '\'; + + for (i = 0; i < hid_devices_count; ++i) + { + if (strcmpW(hid_devices[i].path, info->Name.Buffer) == 0) + { + hid_devices[i].handle = device; + return &hid_devices[i]; + } + } + + return NULL; +} + static void find_hid_devices(void) { static ULONGLONG last_check; @@ -413,6 +449,7 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE device, UINT command, void *data, UINT device, command, data, data_size);
if (!data_size) return ~0U; + if (!device) return ~0U;
switch (command) { diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index c11aae707c9..60ceedf3a6a 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -371,4 +371,6 @@ static inline WCHAR *heap_strdupW(const WCHAR *src) return dst; }
+extern HANDLE rawinput_handle_from_device_handle(HANDLE device); + #endif /* __WINE_USER_PRIVATE_H */
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=56637
Your paranoid android.
=== debian10 (32 bit report) ===
user32: msg.c:5148: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (35221 bytes)
=== debian10 (32 bit Chinese:China report) ===
user32: msg.c:5148: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (35221 bytes)
=== debian10 (32 bit WoW report) ===
user32: msg.c:5148: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (35221 bytes)
=== debian10 (64 bit WoW report) ===
user32: msg.c:5148: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (35221 bytes)
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hidclass.sys/device.c | 30 ++++++++++++++++++++++++++++++ dlls/hidclass.sys/hid.h | 1 + dlls/hidclass.sys/pnp.c | 16 ++++++++++++++++ 3 files changed, 47 insertions(+)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index 0e905c8322f..ed1734ca81b 100644 --- a/dlls/hidclass.sys/device.c +++ b/dlls/hidclass.sys/device.c @@ -26,9 +26,11 @@ #include "winuser.h" #include "setupapi.h"
+#include "wine/server.h" #include "wine/debug.h" #include "ddk/hidsdi.h" #include "ddk/hidtypes.h" +#include "ddk/ntifs.h" #include "ddk/wdm.h"
#include "initguid.h" @@ -123,6 +125,8 @@ NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device) return status; }
+ ext->link_handle = INVALID_HANDLE_VALUE; + /* FIXME: This should probably be done in mouhid.sys. */ if (ext->preparseData->caps.UsagePage == HID_USAGE_PAGE_GENERIC && ext->preparseData->caps.Usage == HID_USAGE_GENERIC_MOUSE) @@ -207,6 +211,8 @@ void HID_DeleteDevice(DEVICE_OBJECT *device) IoCompleteRequest(irp, IO_NO_INCREMENT); }
+ CloseHandle(ext->link_handle); + TRACE("Delete device(%p) %s\n", device, debugstr_w(ext->device_name)); HeapFree(GetProcessHeap(), 0, ext->device_name); RtlFreeUnicodeString(&ext->link_name); @@ -241,6 +247,28 @@ 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; + + if (ext->link_handle == INVALID_HANDLE_VALUE) + return; + + SERVER_START_REQ(send_hardware_message) + { + req->win = 0; + req->flags = SEND_HWMSG_BCAST_RAW; + req->input.type = HW_INPUT_HID; + req->input.hid.device = wine_server_obj_handle(ext->link_handle); + 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; @@ -324,6 +352,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); }
@@ -370,6 +399,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); }
diff --git a/dlls/hidclass.sys/hid.h b/dlls/hidclass.sys/hid.h index 86d7bdf98f1..c3ff6a5065b 100644 --- a/dlls/hidclass.sys/hid.h +++ b/dlls/hidclass.sys/hid.h @@ -46,6 +46,7 @@ typedef struct _BASE_DEVICE_EXTENSION { ULONG poll_interval; WCHAR *device_name; UNICODE_STRING link_name; + HANDLE link_handle; WCHAR device_id[MAX_DEVICE_ID_LEN]; WCHAR instance_id[MAX_DEVICE_ID_LEN]; struct ReportRingBuffer *ring_buffer; diff --git a/dlls/hidclass.sys/pnp.c b/dlls/hidclass.sys/pnp.c index 1c130e8dd80..b84a358dba4 100644 --- a/dlls/hidclass.sys/pnp.c +++ b/dlls/hidclass.sys/pnp.c @@ -299,12 +299,28 @@ NTSTATUS WINAPI HID_PNP_Dispatch(DEVICE_OBJECT *device, IRP *irp) case IRP_MN_START_DEVICE: { BASE_DEVICE_EXTENSION *ext = device->DeviceExtension; + OBJECT_ATTRIBUTES attr;
rc = minidriver->PNPDispatch(device, irp);
IoSetDeviceInterfaceState(&ext->link_name, TRUE); if (ext->is_mouse) IoSetDeviceInterfaceState(&ext->mouse_link_name, TRUE); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.Attributes = OBJ_CASE_INSENSITIVE; + attr.ObjectName = &ext->link_name; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + NtOpenSymbolicLinkObject(&ext->link_handle, SYMBOLIC_LINK_QUERY, &attr); + ext->link_handle = ConvertToGlobalHandle(ext->link_handle); + + if (ext->link_handle == INVALID_HANDLE_VALUE) + ERR("Failed to open link %s, error %u.\n", debugstr_w(ext->link_name.Buffer), GetLastError()); + else + TRACE("Opened link handle: %p for %s\n", ext->link_handle, debugstr_w(ext->link_name.Buffer)); + return rc; } case IRP_MN_REMOVE_DEVICE:
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=56638
Your paranoid android.
=== debian10 (32 bit report) ===
user32: msg.c:5148: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (35221 bytes)
=== debian10 (32 bit Chinese:China report) ===
user32: msg.c:5148: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (35221 bytes)
=== debian10 (32 bit WoW report) ===
user32: msg.c:5148: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (35221 bytes)
=== debian10 (64 bit WoW report) ===
user32: msg.c:5148: Test succeeded inside todo block: ShowWindow(SW_SHOWMINIMIZED):overlapped: marked "todo_wine" but succeeds
Report errors: user32:msg prints too much data (35221 bytes)