server: Pass the original hardware input data to the server and set the message parameters on the server side.
diff --git a/server/queue.c b/server/queue.c
index 58be426..1353b00 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -1282,7 +1282,13 @@
     update_input_key_state( desktop, desktop->keystate, msg );
     last_input_time = get_tick_count();
 
-    if (!is_keyboard_msg( msg ))
+    if (is_keyboard_msg( msg ))
+    {
+        if (desktop->keystate[VK_MENU] & 0x80) msg->lparam |= KF_ALTDOWN << 16;
+        if (msg->wparam == VK_SHIFT || msg->wparam == VK_LSHIFT || msg->wparam == VK_RSHIFT)
+            msg->lparam &= ~(KF_EXTENDED << 16);
+    }
+    else
     {
         if (msg->msg == WM_MOUSEMOVE) set_cursor_pos( desktop, data->x, data->y );
         if (desktop->keystate[VK_LBUTTON] & 0x80)  msg->wparam |= MK_LBUTTON;
@@ -1322,6 +1328,128 @@
     release_object( thread );
 }
 
+/* queue a hardware message for a mouse event */
+static void queue_mouse_message( struct desktop *desktop, user_handle_t win, unsigned int message,
+                                 const hw_input_t *input )
+{
+    struct hardware_msg_data *msg_data;
+    struct message *msg;
+
+    if (!(msg = mem_alloc( sizeof(*msg) ))) return;
+    if (!(msg_data = mem_alloc( sizeof(*msg_data) )))
+    {
+        free( msg );
+        return;
+    }
+    memset( msg_data, 0, sizeof(*msg_data) );
+
+    msg->type      = MSG_HARDWARE;
+    msg->win       = get_user_full_handle( win );
+    msg->msg       = message;
+    msg->wparam    = input->mouse.data << 16;
+    msg->lparam    = 0;
+    msg->time      = input->mouse.time;
+    msg->result    = NULL;
+    msg->data      = msg_data;
+    msg->data_size = sizeof(*msg_data);
+    msg_data->x    = input->mouse.x;
+    msg_data->y    = input->mouse.y;
+    msg_data->info = input->mouse.info;
+    if (!msg->time) msg->time = get_tick_count();
+
+    queue_hardware_message( desktop, msg );
+}
+
+/* queue a hardware message for a keyboard event */
+static void queue_keyboard_message( struct desktop *desktop, user_handle_t win, unsigned int message,
+                                    const hw_input_t *input )
+{
+    struct hardware_msg_data *msg_data;
+    struct message *msg;
+    unsigned char vkey = input->kbd.vkey;
+
+    if (!(msg = mem_alloc( sizeof(*msg) ))) return;
+    if (!(msg_data = mem_alloc( sizeof(*msg_data) )))
+    {
+        free( msg );
+        return;
+    }
+    memset( msg_data, 0, sizeof(*msg_data) );
+
+    msg->type      = MSG_HARDWARE;
+    msg->win       = get_user_full_handle( win );
+    msg->msg       = message;
+    msg->lparam    = (input->kbd.scan << 16) | 1; /* repeat count */
+    msg->time      = input->kbd.time;
+    msg->result    = NULL;
+    msg->data      = msg_data;
+    msg->data_size = sizeof(*msg_data);
+    msg_data->info = input->kbd.info;
+    if (!msg->time) msg->time = get_tick_count();
+
+    if (input->kbd.flags & KEYEVENTF_UNICODE)
+    {
+        msg->wparam = VK_PACKET;
+    }
+    else
+    {
+        switch (vkey)
+        {
+        case VK_MENU:
+        case VK_LMENU:
+        case VK_RMENU:
+            vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU;
+            break;
+        case VK_CONTROL:
+        case VK_LCONTROL:
+        case VK_RCONTROL:
+            vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL;
+            break;
+        case VK_SHIFT:
+        case VK_LSHIFT:
+        case VK_RSHIFT:
+            vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT;
+            break;
+        }
+        if (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) msg->lparam |= KF_EXTENDED << 16;
+        /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
+        if (input->kbd.flags & KEYEVENTF_KEYUP) msg->lparam |= (KF_REPEAT | KF_UP) << 16;
+        else if (desktop->keystate[vkey] & 0x80) msg->lparam |= KF_REPEAT << 16;
+
+        msg->wparam = vkey;
+    }
+
+    queue_hardware_message( desktop, msg );
+}
+
+/* queue a hardware message for a custom type of event */
+static void queue_custom_hardware_message( struct desktop *desktop, user_handle_t win,
+                                           const hw_input_t *input )
+{
+    struct hardware_msg_data *msg_data;
+    struct message *msg;
+
+    if (!(msg = mem_alloc( sizeof(*msg) ))) return;
+    if (!(msg_data = mem_alloc( sizeof(*msg_data) )))
+    {
+        free( msg );
+        return;
+    }
+    memset( msg_data, 0, sizeof(*msg_data) );
+
+    msg->type      = MSG_HARDWARE;
+    msg->win       = get_user_full_handle( win );
+    msg->msg       = input->hw.msg;
+    msg->wparam    = 0;
+    msg->lparam    = input->hw.lparam;
+    msg->time      = get_tick_count();
+    msg->result    = NULL;
+    msg->data      = msg_data;
+    msg->data_size = sizeof(*msg_data);
+
+    queue_hardware_message( desktop, 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 )
@@ -1735,10 +1863,8 @@
 /* send a hardware message to a thread queue */
 DECL_HANDLER(send_hardware_message)
 {
-    struct message *msg;
     struct thread *thread = NULL;
     struct desktop *desktop;
-    struct hardware_msg_data *data;
 
     if (req->win)
     {
@@ -1747,29 +1873,20 @@
     }
     else if (!(desktop = get_thread_desktop( current, 0 ))) return;
 
-    if (!(data = mem_alloc( sizeof(*data) ))) goto done;
-
-    memset( data, 0, sizeof(*data) );
-    data->x    = req->x;
-    data->y    = req->y;
-    data->info = req->info;
-
-    if ((msg = mem_alloc( sizeof(*msg) )))
+    switch (req->input.type)
     {
-        msg->type      = MSG_HARDWARE;
-        msg->win       = get_user_full_handle( req->win );
-        msg->msg       = req->msg;
-        msg->wparam    = req->wparam;
-        msg->lparam    = req->lparam;
-        msg->time      = req->time;
-        msg->result    = NULL;
-        msg->data      = data;
-        msg->data_size = sizeof(*data);
-        queue_hardware_message( desktop, msg );
+    case INPUT_MOUSE:
+        queue_mouse_message( desktop, req->win, req->msg, &req->input );
+        break;
+    case INPUT_KEYBOARD:
+        queue_keyboard_message( desktop, req->win, req->msg, &req->input );
+        break;
+    case INPUT_HARDWARE:
+        queue_custom_hardware_message( desktop, req->win, &req->input );
+        break;
+    default:
+        set_error( STATUS_INVALID_PARAMETER );
     }
-    else free( data );
-
-done:
     if (thread) release_object( thread );
     release_object( desktop );
 }