diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index ab239f3604d391a0398210bd3f6bae295777bb78..5880b47f765268aed97a5252715dcf025ec322e8 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2796,6 +2796,7 @@ struct send_hardware_message_reply
 {
     struct reply_header __header;
     int             wait;
+    /* VARARG(keystate,bytes); */
     char __pad_12[4];
 };
 #define SEND_HWMSG_INJECTED    0x01
@@ -5639,6 +5640,6 @@ union generic_reply
     struct set_suspend_context_reply set_suspend_context_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 428
+#define SERVER_PROTOCOL_VERSION 429
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index a59bb6ec9127cafd7b7d3b8e905da5ae9ae0198a..91a59b2875ab8f0a859e97ab8bd03a828b0f8c37 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2032,6 +2032,7 @@ enum message_type
     unsigned int    flags;     /* flags (see below) */
 @REPLY
     int             wait;      /* do we need to wait for a reply? */
+    VARARG(keystate,bytes);    /* global state array for all the keys */
 @END
 #define SEND_HWMSG_INJECTED    0x01
 
diff --git a/server/queue.c b/server/queue.c
index 7de6d88368ea0fcea75678e12a34d687672c5367..20d3e41c562d12cd5880fd909faf63dd8ff421b1 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -2189,13 +2189,20 @@ DECL_HANDLER(send_hardware_message)
     struct thread *thread = NULL;
     struct desktop *desktop;
     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 (!(thread = get_window_thread( req->win ))) return;
-        desktop = (struct desktop *)grab_object( thread->queue->input->desktop );
+        if (desktop != thread->queue->input->desktop)
+        {
+            /* don't allow queuing events to a different desktop */
+            release_object( desktop );
+            return;
+        }
     }
-    else if (!(desktop = get_thread_desktop( current, 0 ))) return;
 
     switch (req->input.type)
     {
@@ -2212,6 +2219,7 @@ DECL_HANDLER(send_hardware_message)
         set_error( STATUS_INVALID_PARAMETER );
     }
     if (thread) release_object( thread );
+    set_reply_data( desktop->keystate, size );
     release_object( desktop );
 }
 
diff --git a/server/trace.c b/server/trace.c
index e463229237645ef97e4d0fc20233840a4b3683ab..4a5023240cf7f2a0796840d1593f720d9c588238 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2452,6 +2452,7 @@ static void dump_send_hardware_message_request( const struct send_hardware_messa
 static void dump_send_hardware_message_reply( const struct send_hardware_message_reply *req )
 {
     fprintf( stderr, " wait=%d", req->wait );
+    dump_varargs_bytes( ", keystate=", cur_size );
 }
 
 static void dump_get_message_request( const struct get_message_request *req )