[PATCH v2 5/6] server: Implement WM_INPUT / RIM_TYPEHID messages.

Rémi Bernon rbernon at codeweavers.com
Fri Mar 5 04:49:24 CST 2021


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 at 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 );
 
-- 
2.30.0




More information about the wine-devel mailing list