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 ---
v2: Remove the dubious device handle, it will have to be implemented somehow but that can be done later.
Also did a bit of splitting and reordering to have refactor patches first and start sending hardware messages earlier, they won't be dispatched to the applications until the last patch though, but they can be monitored on +server.
Supersedes: 199658-199662
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;
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 | 9 ++++++--- server/queue.c | 10 +++++----- server/trace.c | 6 +++--- 4 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/dlls/user32/message.c b/dlls/user32/message.c index def59998a52..bc90d96f56a 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -3246,10 +3246,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; @@ -3258,6 +3258,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; @@ -3265,6 +3266,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/server/protocol.def b/server/protocol.def index 7f3b785df51..dbe65c67881 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -335,7 +335,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 +344,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 +354,14 @@ typedef union } mouse; struct { - int type; /* INPUT_HARDWARE */ + int type; /* HW_INPUT_HARDWARE */ unsigned int msg; /* message code */ lparam_t lparam; /* message param */ } hw; } hw_input_t; +#define HW_INPUT_MOUSE 0 +#define HW_INPUT_KEYBOARD 1 +#define HW_INPUT_HARDWARE 2
typedef union { diff --git a/server/queue.c b/server/queue.c index ca71f9ee3b4..6019086251d 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; @@ -2489,13 +2489,13 @@ 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; default: diff --git a/server/trace.c b/server/trace.c index b07935cc54b..faaf0c78481 100644 --- a/server/trace.c +++ b/server/trace.c @@ -404,20 +404,20 @@ 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 );
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=86475
Your paranoid android.
=== debiant2 (32 bit report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit Chinese:China report) ===
user32: msg.c:14833: Test failed: bad time bd4690 win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (64 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
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 | 31 +++++++++++++++++++++++++++++++ server/protocol.def | 10 ++++++++++ server/trace.c | 4 ++++ 3 files changed, 45 insertions(+)
diff --git a/dlls/hidclass.sys/device.c b/dlls/hidclass.sys/device.c index fc1dfd07db1..7da7ac43a62 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,34 @@ 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; + UCHAR report_id; + + SERVER_START_REQ(send_hardware_message) + { + req->win = 0; + req->flags = 0; + req->input.type = HW_INPUT_HID; + req->input.hid.usage_page = ext->preparseData->caps.UsagePage; + req->input.hid.usage = ext->preparseData->caps.Usage; + req->input.hid.length = 0; + + if (!(report_id = ext->preparseData->reports[0].reportID)) + { + wine_server_add_data(req, &report_id, sizeof(report_id)); + req->input.hid.length++; + } + + wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen); + req->input.hid.length += packet->reportBufferLen; + + wine_server_call(req); + } + SERVER_END_REQ; +} + static void HID_Device_processQueue(DEVICE_OBJECT *device) { IRP *irp; @@ -320,6 +349,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 +396,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/server/protocol.def b/server/protocol.def index dbe65c67881..ac23a8ce716 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -358,10 +358,19 @@ typedef union unsigned int msg; /* message code */ lparam_t lparam; /* message param */ } hw; + struct + { + int type; /* HW_INPUT_HID */ + unsigned char usage_page; /* HID usage page */ + unsigned char usage; /* HID usage */ + unsigned int length; /* HID report length */ + /* followed by length bytes of HID report data */ + } 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 { @@ -2027,6 +2036,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/trace.c b/server/trace.c index faaf0c78481..9c0c90f379f 100644 --- a/server/trace.c +++ b/server/trace.c @@ -422,6 +422,10 @@ static void dump_hw_input( const char *prefix, const hw_input_t *input ) dump_uint64( ",lparam=", &input->hw.lparam ); fputc( '}', stderr ); break; + case HW_INPUT_HID: + fprintf( stderr, "%s{type=HID,usage_page=%02x,usage=%02x,length=%04x}", + prefix, 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=86476
Your paranoid android.
=== debiant2 (32 bit report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit Chinese:China report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (64 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
Rémi Bernon rbernon@codeweavers.com writes:
@@ -237,6 +238,34 @@ 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;
- UCHAR report_id;
- SERVER_START_REQ(send_hardware_message)
- {
req->win = 0;
req->flags = 0;
req->input.type = HW_INPUT_HID;
req->input.hid.usage_page = ext->preparseData->caps.UsagePage;
req->input.hid.usage = ext->preparseData->caps.Usage;
req->input.hid.length = 0;
if (!(report_id = ext->preparseData->reports[0].reportID))
{
wine_server_add_data(req, &report_id, sizeof(report_id));
req->input.hid.length++;
}
wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen);
req->input.hid.length += packet->reportBufferLen;
wine_server_call(req);
- }
- SERVER_END_REQ;
+}
It would be better to find a way to do this using exported APIs. I don't think we want to have even more modules make direct server calls (the goal is for all server calls to be done on the Unix side of the syscall interface).
On 3/5/21 6:03 PM, Alexandre Julliard wrote:
Rémi Bernon rbernon@codeweavers.com writes:
@@ -237,6 +238,34 @@ 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;
- UCHAR report_id;
- SERVER_START_REQ(send_hardware_message)
- {
req->win = 0;
req->flags = 0;
req->input.type = HW_INPUT_HID;
req->input.hid.usage_page = ext->preparseData->caps.UsagePage;
req->input.hid.usage = ext->preparseData->caps.Usage;
req->input.hid.length = 0;
if (!(report_id = ext->preparseData->reports[0].reportID))
{
wine_server_add_data(req, &report_id, sizeof(report_id));
req->input.hid.length++;
}
wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen);
req->input.hid.length += packet->reportBufferLen;
wine_server_call(req);
- }
- SERVER_END_REQ;
+}
It would be better to find a way to do this using exported APIs. I don't think we want to have even more modules make direct server calls (the goal is for all server calls to be done on the Unix side of the syscall interface).
Alright, does it include __wine_send_input?
Rémi Bernon rbernon@codeweavers.com writes:
On 3/5/21 6:03 PM, Alexandre Julliard wrote:
Rémi Bernon rbernon@codeweavers.com writes:
@@ -237,6 +238,34 @@ 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;
- UCHAR report_id;
- SERVER_START_REQ(send_hardware_message)
- {
req->win = 0;
req->flags = 0;
req->input.type = HW_INPUT_HID;
req->input.hid.usage_page = ext->preparseData->caps.UsagePage;
req->input.hid.usage = ext->preparseData->caps.Usage;
req->input.hid.length = 0;
if (!(report_id = ext->preparseData->reports[0].reportID))
{
wine_server_add_data(req, &report_id, sizeof(report_id));
req->input.hid.length++;
}
wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen);
req->input.hid.length += packet->reportBufferLen;
wine_server_call(req);
- }
- SERVER_END_REQ;
+}
It would be better to find a way to do this using exported APIs. I don't think we want to have even more modules make direct server calls (the goal is for all server calls to be done on the Unix side of the syscall interface).
Alright, does it include __wine_send_input?
At least for now that would be better, yes.
On 3/5/21 6:10 PM, Alexandre Julliard wrote:
Rémi Bernon rbernon@codeweavers.com writes:
On 3/5/21 6:03 PM, Alexandre Julliard wrote:
Rémi Bernon rbernon@codeweavers.com writes:
@@ -237,6 +238,34 @@ 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;
- UCHAR report_id;
- SERVER_START_REQ(send_hardware_message)
- {
req->win = 0;
req->flags = 0;
req->input.type = HW_INPUT_HID;
req->input.hid.usage_page = ext->preparseData->caps.UsagePage;
req->input.hid.usage = ext->preparseData->caps.Usage;
req->input.hid.length = 0;
if (!(report_id = ext->preparseData->reports[0].reportID))
{
wine_server_add_data(req, &report_id, sizeof(report_id));
req->input.hid.length++;
}
wine_server_add_data(req, packet->reportBuffer, packet->reportBufferLen);
req->input.hid.length += packet->reportBufferLen;
wine_server_call(req);
- }
- SERVER_END_REQ;
+}
It would be better to find a way to do this using exported APIs. I don't think we want to have even more modules make direct server calls (the goal is for all server calls to be done on the Unix side of the syscall interface).
Alright, does it include __wine_send_input?
At least for now that would be better, yes.
About that, is there any known use of INPUT_HARDWARE / HARDWAREINPUT type? I tried a few SendInput combination on Windows and it doesn't seem to have any effect.
On Wine it looks like it's plugged and able send fake Wine hardware messages, but it doesn't seem to be tested anywhere, or really used anywhere.
Would it be appropriate to use this structure to send HID rawinput message then? Maybe disable its support from SendInput and only allow it from __wine_send_input?
The INPUT structure doesn't have any explicit variable size member, but SendInput has a size parameter, so I guess we can keep any additional data internally.
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/rawinput.c | 24 +++++++++++++++++++-- server/protocol.def | 6 ++++++ server/queue.c | 47 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 70 insertions(+), 7 deletions(-)
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 ac23a8ce716..17db365640f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -312,6 +312,12 @@ struct hardware_msg_data int y; /* y coordinate */ unsigned int data; /* mouse data */ } mouse; + struct + { + int type; /* RIM_TYPEHID */ + unsigned int length; /* HID report length */ + /* followed by length bytes of HID report data */ + } hid; } rawinput; };
diff --git a/server/queue.c b/server/queue.c index 6019086251d..8b8bb41baf2 100644 --- a/server/queue.c +++ b/server/queue.c @@ -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,33 @@ 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.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 ) @@ -2498,6 +2530,9 @@ DECL_HANDLER(send_hardware_message) 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 +3314,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 +3335,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 );
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=86477
Your paranoid android.
=== debiant2 (32 bit report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit Chinese:China report) ===
user32: msg.c:14833: Test failed: bad time bd4b4a win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (64 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
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 | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 8b8bb41baf2..e8b6211ec1a 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; }
@@ -2498,15 +2506,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) { @@ -2516,21 +2523,28 @@ 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: + if (!desktop) set_error( STATUS_SUCCESS ); queue_hid_message( req->win, &req->input, origin, sender, get_req_data(), get_req_data_size() ); break; default: @@ -2538,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 */
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=86478
Your paranoid android.
=== debiant2 (32 bit report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (32 bit Chinese:China report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE win.c:10097: Test failed: Expected foreground window 0, got 00E10102 win.c:10103: Test failed: Expected foreground window 000E013E, got 00E10102
=== debiant2 (32 bit WoW report) ===
user32: menu.c:2337: Test failed: test 25 win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE
=== debiant2 (64 bit WoW report) ===
user32: win.c:3079: Test succeeded inside todo block: Focus should be on child 000800FE, not 000800FE