Create a new server request for accepting hardware messages instead of
abusing reply_message.
Allow passing the determined window for a hardware message back to the
server to have it redispatch the message to the correct thread.

diff --git a/server/protocol.def b/server/protocol.def
index c899ce9..b6553e2 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1552,13 +1552,19 @@
 
 /* Reply to a sent message */
 @REQ(reply_message)
-    int             type;      /* type of original message */
     unsigned int    result;    /* message result */
     int             remove;    /* should we remove the message? */
     VARARG(data,bytes);        /* message data for sent messages */
 @END
 
 
+/* Accept the current hardware message */
+@REQ(accept_hardware_message)
+    int             remove;    /* should we remove the message? */
+    user_handle_t   new_win;   /* new destination window for current message */
+@END
+
+
 /* Retrieve the reply for the last message sent */
 @REQ(get_message_reply)
     int             cancel;    /* cancel message if not ready? */
diff --git a/server/queue.c b/server/queue.c
index 05f4c7c..965c32a 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -1058,28 +1058,45 @@
 }
 
 /* release the hardware message currently being processed by the given thread */
-static void release_hardware_message( struct thread *thread, int remove )
+static void release_hardware_message( struct thread *thread, int remove, user_handle_t new_win )
 {
     struct thread_input *input = thread->queue->input;
 
     if (input->msg_thread != thread) return;
-    if (remove)
+
+    /* clear the queue bit for that message */
+    if (remove || new_win)
     {
         struct message *other;
         int clr_bit;
 
-        update_input_key_state( input, input->msg );
-        list_remove( &input->msg->entry );
         clr_bit = get_hardware_msg_bit( input->msg );
         LIST_FOR_EACH_ENTRY( other, &input->msg_list, struct message, entry )
         {
-            if (get_hardware_msg_bit( other ) == clr_bit)
+            if (other != input->msg && get_hardware_msg_bit( other ) == clr_bit)
             {
                 clr_bit = 0;
                 break;
             }
         }
         if (clr_bit) clear_queue_bits( thread->queue, clr_bit );
+    }
+
+    if (new_win)  /* set the new window */
+    {
+        struct thread *owner = get_window_thread( new_win );
+        if (owner)
+        {
+            input->msg->win = new_win;
+            set_queue_bits( owner->queue, get_hardware_msg_bit( input->msg ));
+            release_object( owner );
+        }
+        if (!remove) return;  /* don't release the message */
+    }
+    else if (remove)
+    {
+        update_input_key_state( input, input->msg );
+        list_remove( &input->msg->entry );
         free_message( input->msg );
     }
     release_object( input->msg_thread );
@@ -1513,7 +1530,7 @@
     if (queue->input->msg_thread == current && req->get_next_hw)
     {
         first_hw_msg = queue->input->msg;
-        release_hardware_message( current, 0 );
+        release_hardware_message( current, 0, 0 );
     }
 
     /* first check for sent messages */
@@ -1577,23 +1594,29 @@
 /* reply to a sent message */
 DECL_HANDLER(reply_message)
 {
-    if (!current->queue)
-    {
-        set_error( STATUS_ACCESS_DENIED );
-        return;
-    }
-    if (req->type == MSG_HARDWARE)
-    {
-        struct thread_input *input = current->queue->input;
-        if (input->msg_thread == current) release_hardware_message( current, req->remove );
-        else set_error( STATUS_ACCESS_DENIED );
-    }
+    if (!current->queue) set_error( STATUS_ACCESS_DENIED );
     else if (current->queue->recv_result)
         reply_message( current->queue, req->result, 0, req->remove,
                        get_req_data(), get_req_data_size() );
 }
 
 
+/* accept the current hardware message */
+DECL_HANDLER(accept_hardware_message)
+{
+    if (current->queue)
+    {
+        struct thread_input *input = current->queue->input;
+        if (input->msg_thread == current)
+        {
+            release_hardware_message( current, req->remove, req->new_win );
+            return;
+        }
+    }
+    set_error( STATUS_ACCESS_DENIED );
+}
+
+
 /* retrieve the reply for the last message sent */
 DECL_HANDLER(get_message_reply)
 {
diff --git a/server/request.h b/server/request.h
index dc57117..7ce7aa1 100644
--- a/server/request.h
+++ b/server/request.h
@@ -225,6 +225,7 @@
 DECL_HANDLER(send_message);
 DECL_HANDLER(get_message);
 DECL_HANDLER(reply_message);
+DECL_HANDLER(accept_hardware_message);
 DECL_HANDLER(get_message_reply);
 DECL_HANDLER(set_win_timer);
 DECL_HANDLER(kill_win_timer);
@@ -415,6 +416,7 @@
     (req_handler)req_send_message,
     (req_handler)req_get_message,
     (req_handler)req_reply_message,
+    (req_handler)req_accept_hardware_message,
     (req_handler)req_get_message_reply,
     (req_handler)req_set_win_timer,
     (req_handler)req_kill_win_timer,
diff --git a/server/trace.c b/server/trace.c
index a07a54c..738a1b8 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1895,13 +1895,18 @@
 
 static void dump_reply_message_request( const struct reply_message_request *req )
 {
-    fprintf( stderr, " type=%d,", req->type );
     fprintf( stderr, " result=%08x,", req->result );
     fprintf( stderr, " remove=%d,", req->remove );
     fprintf( stderr, " data=" );
     dump_varargs_bytes( cur_size );
 }
 
+static void dump_accept_hardware_message_request( const struct accept_hardware_message_request *req )
+{
+    fprintf( stderr, " remove=%d,", req->remove );
+    fprintf( stderr, " new_win=%p", req->new_win );
+}
+
 static void dump_get_message_reply_request( const struct get_message_reply_request *req )
 {
     fprintf( stderr, " cancel=%d", req->cancel );
@@ -2814,6 +2819,7 @@
     (dump_func)dump_send_message_request,
     (dump_func)dump_get_message_request,
     (dump_func)dump_reply_message_request,
+    (dump_func)dump_accept_hardware_message_request,
     (dump_func)dump_get_message_reply_request,
     (dump_func)dump_set_win_timer_request,
     (dump_func)dump_kill_win_timer_request,
@@ -3001,6 +3007,7 @@
     (dump_func)0,
     (dump_func)dump_get_message_reply,
     (dump_func)0,
+    (dump_func)0,
     (dump_func)dump_get_message_reply_reply,
     (dump_func)dump_set_win_timer_reply,
     (dump_func)0,
@@ -3188,6 +3195,7 @@
     "send_message",
     "get_message",
     "reply_message",
+    "accept_hardware_message",
     "get_message_reply",
     "set_win_timer",
     "kill_win_timer",