server: Pass the original hardware input data to the server and set the message parameters on the server side.
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 8a8f482..190436b 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -1156,7 +1156,6 @@
     UINT message;
     KBDLLHOOKSTRUCT hook;
     WORD flags, wVkStripped, wVkL, wVkR, vk_hook = wVk;
-    LPARAM lParam = 0;
 
     if (!time) time = GetTickCount();
 
@@ -1225,13 +1224,7 @@
         if (!(event_flags & KEYEVENTF_UNICODE) && key_state_table[wVk] & 0x80) flags |= KF_REPEAT;
     }
 
-    if (event_flags & KEYEVENTF_UNICODE)
-    {
-        vk_hook = wVk = VK_PACKET;
-        lParam = MAKELPARAM(1 /* repeat count */, wScan);
-        TRACE_(key)("message=0x%04x wParam=0x%04X lParam=0x%08lx\n",
-                    message, wVk, lParam);
-    }
+    if (event_flags & KEYEVENTF_UNICODE) vk_hook = wVk = VK_PACKET;
 
     /* Hook gets whatever key was sent. */
     hook.vkCode      = vk_hook;
@@ -1254,25 +1247,22 @@
             key_state_table[wVk] |= 0xc0;
             key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR];
         }
-
-        if (key_state_table[VK_MENU] & 0x80) flags |= KF_ALTDOWN;
-
-        if (wVkStripped == VK_SHIFT) flags &= ~KF_EXTENDED;
-
-        lParam = MAKELPARAM(1 /* repeat count */, flags);
-
-        TRACE_(key)(" message=0x%04x wParam=0x%04X, lParam=0x%08lx, InputKeyState=0x%x\n",
-                    message, wVk, lParam, key_state_table[wVk]);
     }
 
+    TRACE_(key)("message=0x%04x wParam=0x%04x InputKeyState=0x%x\n",
+                message, wVk, key_state_table[wVk]);
+
     SERVER_START_REQ( send_hardware_message )
     {
-        req->win      = wine_server_user_handle( hwnd );
-        req->msg      = message;
-        req->wparam   = wVk;
-        req->lparam   = lParam;
-        req->time     = time;
-        req->info     = dwExtraInfo;
+        req->win             = wine_server_user_handle( hwnd );
+        req->msg             = message;
+        req->input.type      = INPUT_KEYBOARD;
+        req->input.kbd.vkey  = vk_hook;
+        req->input.kbd.scan  = wScan;
+        req->input.kbd.flags = event_flags;
+        req->input.kbd.time  = time;
+        req->input.kbd.info  = dwExtraInfo;
+        if (injected_flags & LLKHF_INJECTED) req->flags = SEND_HWMSG_INJECTED;
         wine_server_call( req );
     }
     SERVER_END_REQ;
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index 811695a..bbdccd7 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -306,14 +306,16 @@
 
     SERVER_START_REQ( send_hardware_message )
     {
-        req->win      = wine_server_user_handle( hwnd );
-        req->msg      = message;
-        req->wparam   = MAKEWPARAM( 0, data );
-        req->lparam   = 0;
-        req->x        = x;
-        req->y        = y;
-        req->time     = time;
-        req->info     = extra_info;
+        req->win               = wine_server_user_handle( hwnd );
+        req->msg               = message;
+        req->input.type        = INPUT_MOUSE;
+        req->input.mouse.x     = x;
+        req->input.mouse.y     = y;
+        req->input.mouse.data  = data;
+        req->input.mouse.flags = 0; /* FIXME */
+        req->input.mouse.time  = time;
+        req->input.mouse.info  = extra_info;
+        if (injected_flags & LLMHF_INJECTED) req->flags = SEND_HWMSG_INJECTED;
         wine_server_call( req );
     }
     SERVER_END_REQ;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 4a25433..327acc4 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -303,6 +303,36 @@
 
 typedef union
 {
+    int type;
+    struct
+    {
+        int            type;
+        unsigned short vkey;
+        unsigned short scan;
+        unsigned int   flags;
+        unsigned int   time;
+        lparam_t       info;
+    } kbd;
+    struct
+    {
+        int            type;
+        int            x;
+        int            y;
+        unsigned int   data;
+        unsigned int   flags;
+        unsigned int   time;
+        lparam_t       info;
+    } mouse;
+    struct
+    {
+        int            type;
+        unsigned int   msg;
+        lparam_t       lparam;
+    } hw;
+} hw_input_t;
+
+typedef union
+{
     unsigned char            bytes[1];
     struct hardware_msg_data hardware;
     struct callback_msg_data callback;
@@ -2762,18 +2792,15 @@
 {
     struct request_header __header;
     user_handle_t   win;
+    hw_input_t      input;
+    unsigned int    flags;
     unsigned int    msg;
-    unsigned int    time;
-    lparam_t        wparam;
-    lparam_t        lparam;
-    lparam_t        info;
-    int             x;
-    int             y;
 };
 struct send_hardware_message_reply
 {
     struct reply_header __header;
 };
+#define SEND_HWMSG_INJECTED    0x01
 
 
 
@@ -5529,6 +5556,6 @@
     struct set_cursor_reply set_cursor_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 415
+#define SERVER_PROTOCOL_VERSION 416
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index c1e4fdb..593ce4e 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -319,6 +319,36 @@
 
 typedef union
 {
+    int type;
+    struct
+    {
+        int            type;    /* INPUT_KEYBOARD */
+        unsigned short vkey;    /* virtual key code */
+        unsigned short scan;    /* scan code */
+        unsigned int   flags;   /* event flags */
+        unsigned int   time;    /* event time */
+        lparam_t       info;    /* extra info */
+    } kbd;
+    struct
+    {
+        int            type;    /* INPUT_MOUSE */
+        int            x;       /* coordinates */
+        int            y;
+        unsigned int   data;    /* mouse data */
+        unsigned int   flags;   /* event flags */
+        unsigned int   time;    /* event time */
+        lparam_t       info;    /* extra info */
+    } mouse;
+    struct
+    {
+        int            type;    /* INPUT_HARDWARE */
+        unsigned int   msg;     /* message code */
+        lparam_t       lparam;  /* message param */
+    } hw;
+} hw_input_t;
+
+typedef union
+{
     unsigned char            bytes[1];   /* raw data for sent messages */
     struct hardware_msg_data hardware;
     struct callback_msg_data callback;
@@ -2002,14 +2032,11 @@
 /* Send a hardware message to a thread queue */
 @REQ(send_hardware_message)
     user_handle_t   win;       /* window handle */
+    hw_input_t      input;     /* input data */
+    unsigned int    flags;     /* flags (see below) */
     unsigned int    msg;       /* message code */
-    unsigned int    time;      /* message time */
-    lparam_t        wparam;    /* parameters */
-    lparam_t        lparam;    /* parameters */
-    lparam_t        info;      /* extra info */
-    int             x;         /* x position */
-    int             y;         /* y position */
 @END
+#define SEND_HWMSG_INJECTED    0x01
 
 
 /* Get a message from the current queue */
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 );
 }
diff --git a/server/request.h b/server/request.h
index d757987..780c2eb 100644
--- a/server/request.h
+++ b/server/request.h
@@ -617,6 +617,7 @@
 C_ASSERT( sizeof(cpu_type_t) == 4 );
 C_ASSERT( sizeof(data_size_t) == 4 );
 C_ASSERT( sizeof(file_pos_t) == 8 );
+C_ASSERT( sizeof(hw_input_t) == 32 );
 C_ASSERT( sizeof(int) == 4 );
 C_ASSERT( sizeof(ioctl_code_t) == 4 );
 C_ASSERT( sizeof(lparam_t) == 8 );
@@ -1378,13 +1379,9 @@
 C_ASSERT( FIELD_OFFSET(struct post_quit_message_request, exit_code) == 12 );
 C_ASSERT( sizeof(struct post_quit_message_request) == 16 );
 C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, win) == 12 );
-C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, msg) == 16 );
-C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, time) == 20 );
-C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, wparam) == 24 );
-C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, lparam) == 32 );
-C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, info) == 40 );
-C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, x) == 48 );
-C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, y) == 52 );
+C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, input) == 16 );
+C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, flags) == 48 );
+C_ASSERT( FIELD_OFFSET(struct send_hardware_message_request, msg) == 52 );
 C_ASSERT( sizeof(struct send_hardware_message_request) == 56 );
 C_ASSERT( FIELD_OFFSET(struct get_message_request, flags) == 12 );
 C_ASSERT( FIELD_OFFSET(struct get_message_request, get_win) == 16 );
diff --git a/server/trace.c b/server/trace.c
index 0539fcc..e39780e 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -36,6 +36,7 @@
 #include "winbase.h"
 #include "wincon.h"
 #include "winternl.h"
+#include "winuser.h"
 #include "winioctl.h"
 #include "file.h"
 #include "request.h"
@@ -293,6 +294,34 @@
     fputc( '}', stderr );
 }
 
+static void dump_hw_input( const char *prefix, const hw_input_t *input )
+{
+    switch (input->type)
+    {
+    case 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:
+        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:
+        fprintf( stderr, "%s{type=HARDWARE,msg=%04x", prefix, input->hw.msg );
+        dump_uint64( ",lparam=", &input->hw.lparam );
+        fputc( '}', stderr );
+        break;
+    default:
+        fprintf( stderr, "%s{type=%04x}", prefix, input->type );
+        break;
+    }
+}
+
 static void dump_luid( const char *prefix, const luid_t *luid )
 {
     fprintf( stderr, "%s%d.%u", prefix, luid->high_part, luid->low_part );
@@ -2465,13 +2494,9 @@
 static void dump_send_hardware_message_request( const struct send_hardware_message_request *req )
 {
     fprintf( stderr, " win=%08x", req->win );
+    dump_hw_input( ", input=", &req->input );
+    fprintf( stderr, ", flags=%08x", req->flags );
     fprintf( stderr, ", msg=%08x", req->msg );
-    fprintf( stderr, ", time=%08x", req->time );
-    dump_uint64( ", wparam=", &req->wparam );
-    dump_uint64( ", lparam=", &req->lparam );
-    dump_uint64( ", info=", &req->info );
-    fprintf( stderr, ", x=%d", req->x );
-    fprintf( stderr, ", y=%d", req->y );
 }
 
 static void dump_get_message_request( const struct get_message_request *req )
diff --git a/tools/make_requests b/tools/make_requests
index 22be2f7..445ad06 100755
--- a/tools/make_requests
+++ b/tools/make_requests
@@ -51,6 +51,7 @@
     "luid_t"        => [  8,   4,  "&dump_luid" ],
     "ioctl_code_t"  => [  4,   4,  "&dump_ioctl_code" ],
     "cpu_type_t"    => [  4,   4,  "&dump_cpu_type" ],
+    "hw_input_t"    => [  32,  8,  "&dump_hw_input" ],
 );
 
 my @requests = ();