Moved hardware message queue handling to the server.

diff --git a/dlls/user/user_main.c b/dlls/user/user_main.c
index cdd1ff2..196fbcc 100644
--- a/dlls/user/user_main.c
+++ b/dlls/user/user_main.c
@@ -197,7 +197,6 @@
 static BOOL process_attach(void)
 {
     HINSTANCE16 instance;
-    int queueSize;
 
     /* Create USER heap */
     if ((instance = LoadLibrary16( "USER.EXE" )) < 32) return FALSE;
@@ -232,10 +231,6 @@
     /* Initialize message spying */
     if (!SPY_Init()) return FALSE;
 
-    /* Create system message queue */
-    queueSize = GetProfileIntA( "windows", "TypeAhead", 120 );
-    if (!QUEUE_CreateSysMsgQueue( queueSize )) return FALSE;
-
     /* Set double click time */
     SetDoubleClickTime( GetProfileIntA("windows","DoubleClickSpeed",452) );
 
diff --git a/dlls/x11drv/window.c b/dlls/x11drv/window.c
index c40eb7d..6e58ba0 100644
--- a/dlls/x11drv/window.c
+++ b/dlls/x11drv/window.c
@@ -897,7 +897,8 @@
     if (!ret)
     {
         WIN_UnlinkWindow( hwnd );
-        goto failed;
+        X11DRV_DestroyWindow( hwnd );
+        return FALSE;
     }
 
     /* Send the size messages */
diff --git a/include/queue.h b/include/queue.h
index 20c14ca..86930df 100644
--- a/include/queue.h
+++ b/include/queue.h
@@ -17,6 +17,7 @@
   /* Message as stored in the queue (contains the extraInfo field) */
 typedef struct tagQMSG
 {
+    int   kind;   /* message kind (sent,posted,hardware) */
     int   type;
     MSG   msg;
     DWORD extraInfo;  /* Only in 3.1 */
@@ -98,22 +99,16 @@
 extern void QUEUE_DumpQueue( HQUEUE16 hQueue );
 extern BOOL QUEUE_IsExitingQueue( HQUEUE16 hQueue );
 extern void QUEUE_SetExitingQueue( HQUEUE16 hQueue );
-extern MESSAGEQUEUE *QUEUE_GetSysQueue(void);
 extern void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear );
 extern void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit );
-extern WORD QUEUE_TestWakeBit( MESSAGEQUEUE *queue, WORD bit );
 extern int QUEUE_WaitBits( WORD bits, DWORD timeout );
 extern void QUEUE_IncPaintCount( HQUEUE16 hQueue );
 extern void QUEUE_DecPaintCount( HQUEUE16 hQueue );
-extern BOOL QUEUE_CreateSysMsgQueue( int size );
 extern BOOL QUEUE_DeleteMsgQueue( HQUEUE16 hQueue );
 extern HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue );
-extern BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove,
-                           BOOL sent_only, QMSG *msg );
+extern BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, QMSG *msg );
 extern void QUEUE_RemoveMsg( MESSAGEQUEUE * msgQueue, QMSG *qmsg );
 extern void QUEUE_CleanupWindow( HWND hwnd );
-extern void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
-			    int xPos, int yPos, DWORD time, DWORD extraInfo );
 
 extern HQUEUE16 WINAPI InitThreadInput16( WORD unknown, WORD flags );
 
diff --git a/include/server.h b/include/server.h
index ef02a77..879dca4 100644
--- a/include/server.h
+++ b/include/server.h
@@ -1345,34 +1345,43 @@
 struct send_message_request
 {
     REQUEST_HEADER;                /* request header */
-    IN  int             posted;    /* posted instead of sent message? */
+    IN  int             kind;      /* message kind (see below) */
     IN  void*           id;        /* thread id */
     IN  int             type;      /* message type */
     IN  handle_t        win;       /* window handle */
     IN  unsigned int    msg;       /* message code */
     IN  unsigned int    wparam;    /* parameters */
     IN  unsigned int    lparam;    /* parameters */
+    IN  unsigned short  x;         /* x position */
+    IN  unsigned short  y;         /* y position */
+    IN  unsigned int    time;      /* message time */
     IN  unsigned int    info;      /* extra info */
 };
+enum message_kind { SEND_MESSAGE, POST_MESSAGE, COOKED_HW_MESSAGE, RAW_HW_MESSAGE };
+#define NB_MSG_KINDS (RAW_HW_MESSAGE+1)
 
 
 /* Get a message from the current queue */
 struct get_message_request
 {
     REQUEST_HEADER;                /* request header */
-    IN  int             remove;    /* remove it? */
-    IN  int             posted;    /* check posted messages too? */
+    IN  int             flags;     /* see below */
     IN  handle_t        get_win;   /* window handle to get */
     IN  unsigned int    get_first; /* first message code to get */
     IN  unsigned int    get_last;  /* last message code to get */
-    OUT int             sent;      /* it is a sent message */
+    OUT int             kind;      /* message kind */
     OUT int             type;      /* message type */
     OUT handle_t        win;       /* window handle */
     OUT unsigned int    msg;       /* message code */
     OUT unsigned int    wparam;    /* parameters */
     OUT unsigned int    lparam;    /* parameters */
+    OUT unsigned short  x;         /* x position */
+    OUT unsigned short  y;         /* y position */
+    OUT unsigned int    time;      /* message time */
     OUT unsigned int    info;      /* extra info */
 };
+#define GET_MSG_REMOVE 1     /* remove the message */
+#define GET_MSG_SENT_ONLY 2  /* only get sent messages */
 
 
 /* Reply to a sent message */
@@ -1734,7 +1743,7 @@
     struct create_async_request create_async;
 };
 
-#define SERVER_PROTOCOL_VERSION 45
+#define SERVER_PROTOCOL_VERSION 46
 
 /* ### make_requests end ### */
 /* Everything above this line is generated automatically by tools/make_requests */
diff --git a/server/queue.c b/server/queue.c
index 678506e..ccbd1ea 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -37,6 +37,9 @@
     unsigned int           msg;       /* message code */
     unsigned int           wparam;    /* parameters */
     unsigned int           lparam;    /* parameters */
+    unsigned short         x;         /* x position */
+    unsigned short         y;         /* y position */
+    unsigned int           time;      /* message time */
     unsigned int           info;      /* extra info */
     struct message_result *result;    /* result in sender queue */
 };
@@ -66,8 +69,7 @@
     unsigned int           wake_mask;     /* wakeup mask */
     unsigned int           changed_bits;  /* changed wakeup bits */
     unsigned int           changed_mask;  /* changed wakeup mask */
-    struct message_list    send_list;     /* list of sent messages */
-    struct message_list    post_list;     /* list of posted messages */
+    struct message_list    msg_list[NB_MSG_KINDS];  /* lists of messages */
     struct message_result *send_result;   /* stack of sent messages waiting for result */
     struct message_result *recv_result;   /* stack of received messages waiting for result */
     struct timer          *first_timer;   /* head of timer list */
@@ -104,6 +106,7 @@
 static struct msg_queue *create_msg_queue( struct thread *thread )
 {
     struct msg_queue *queue;
+    int i;
 
     if ((queue = alloc_object( &msg_queue_ops, -1 )))
     {
@@ -111,16 +114,15 @@
         queue->wake_mask       = 0;
         queue->changed_bits    = 0;
         queue->changed_mask    = 0;
-        queue->send_list.first = NULL;
-        queue->send_list.last  = NULL;
-        queue->post_list.first = NULL;
-        queue->post_list.last  = NULL;
         queue->send_result     = NULL;
         queue->recv_result     = NULL;
         queue->first_timer     = NULL;
         queue->last_timer      = NULL;
         queue->next_timer      = NULL;
         queue->timeout         = NULL;
+        for (i = 0; i < NB_MSG_KINDS; i++)
+            queue->msg_list[i].first = queue->msg_list[i].last = NULL;
+
         thread->queue = queue;
         if (!thread->process->queue)
             thread->process->queue = (struct msg_queue *)grab_object( queue );
@@ -142,6 +144,14 @@
     if (is_signaled( queue )) wake_up( &queue->obj, 0 );
 }
 
+/* get the QS_* bit corresponding to a given hardware message */
+inline static int get_hardware_msg_bit( struct message *msg )
+{
+    if (msg->msg == WM_MOUSEMOVE || msg->msg == WM_NCMOUSEMOVE) return QS_MOUSEMOVE;
+    if (msg->msg >= WM_KEYFIRST && msg->msg <= WM_KEYLAST) return QS_KEY;
+    return QS_MOUSEBUTTON;
+}
+
 /* get the current thread queue, creating it if needed */
 inline struct msg_queue *get_current_queue(void)
 {
@@ -189,20 +199,31 @@
     free( msg );
 }
 
-/* remove (and free) a message from the sent messages list */
-static void remove_sent_message( struct msg_queue *queue, struct message *msg )
+/* remove (and free) a message from a message list */
+static void remove_queue_message( struct msg_queue *queue, struct message *msg,
+                                  enum message_kind kind )
 {
-    unlink_message( &queue->send_list, msg );
-    free_message( msg );
-    if (!queue->send_list.first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
-}
+    int clr_bit;
+    struct message *other;
 
-/* remove (and free) a message from the posted messages list */
-static void remove_posted_message( struct msg_queue *queue, struct message *msg )
-{
-    unlink_message( &queue->post_list, msg );
+    unlink_message( &queue->msg_list[kind], msg );
+    switch(kind)
+    {
+    case SEND_MESSAGE:
+        if (!queue->msg_list[kind].first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
+        break;
+    case POST_MESSAGE:
+        if (!queue->msg_list[kind].first) change_queue_bits( queue, 0, QS_POSTMESSAGE );
+        break;
+    case COOKED_HW_MESSAGE:
+    case RAW_HW_MESSAGE:
+        clr_bit = get_hardware_msg_bit( msg );
+        for (other = queue->msg_list[kind].first; other; other = other->next)
+            if (get_hardware_msg_bit( other ) == clr_bit) break;
+        if (!other) change_queue_bits( queue, 0, clr_bit );
+        break;
+    }
     free_message( msg );
-    if (!queue->post_list.first) change_queue_bits( queue, 0, QS_POSTMESSAGE );
 }
 
 /* send a message from the sender queue to the receiver queue */
@@ -221,7 +242,7 @@
 
     /* and put the message on the receiver queue */
     msg->result = result;
-    append_message( &recv_queue->send_list, msg );
+    append_message( &recv_queue->msg_list[SEND_MESSAGE], msg );
     change_queue_bits( recv_queue, QS_SENDMESSAGE, 0 );
     return 1;
 }
@@ -231,12 +252,12 @@
 {
     struct message_result *result = msg->result;
 
-    unlink_message( &queue->send_list, msg );
+    unlink_message( &queue->msg_list[SEND_MESSAGE], msg );
     /* put the result on the receiver result stack */
     result->recv_next  = queue->recv_result;
     queue->recv_result = result;
     free( msg );
-    if (!queue->send_list.first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
+    if (!queue->msg_list[SEND_MESSAGE].first) change_queue_bits( queue, 0, QS_SENDMESSAGE );
 }
 
 /* set the result of the current received message */
@@ -380,10 +401,10 @@
 {
     struct msg_queue *queue = (struct msg_queue *)obj;
     struct timer *timer = queue->first_timer;
+    int i;
 
     cleanup_results( queue );
-    empty_msg_list( &queue->send_list );
-    empty_msg_list( &queue->post_list );
+    for (i = 0; i < NB_MSG_KINDS; i++) empty_msg_list( &queue->msg_list[i] );
 
     while (timer)
     {
@@ -457,6 +478,7 @@
     else queue->first_timer = timer->next;
     /* check if we removed the next timer */
     if (queue->next_timer == timer) set_next_timer( queue, timer->next );
+    else if (queue->next_timer == queue->first_timer) change_queue_bits( queue, 0, QS_TIMER );
 }
 
 /* restart an expired timer */
@@ -521,6 +543,7 @@
 {
     struct timer *timer;
     struct message *msg;
+    int i;
 
     /* remove timers */
     timer = queue->first_timer;
@@ -535,22 +558,16 @@
         timer = next;
     }
 
-    /* remove sent messages */
-    msg = queue->send_list.first;
-    while (msg)
+    /* remove messages */
+    for (i = 0; i < NB_MSG_KINDS; i++)
     {
-        struct message *next = msg->next;
-        if (msg->win == win) remove_sent_message( queue, msg );
-        msg = next;
-    }
-
-    /* remove posted messages */
-    msg = queue->post_list.first;
-    while (msg)
-    {
-        struct message *next = msg->next;
-        if (msg->win == win) remove_posted_message( queue, msg );
-        msg = next;
+        msg = queue->msg_list[i].first;
+        while (msg)
+        {
+            struct message *next = msg->next;
+            if (msg->win == win) remove_queue_message( queue, msg, i );
+            msg = next;
+        }
     }
 }
 
@@ -638,18 +655,65 @@
         msg->msg     = req->msg;
         msg->wparam  = req->wparam;
         msg->lparam  = req->lparam;
+        msg->x       = req->x;
+        msg->y       = req->y;
+        msg->time    = req->time;
         msg->info    = req->info;
         msg->result  = NULL;
-        if (!req->posted) send_message( send_queue, recv_queue, msg );
-        else
+        switch(req->kind)
         {
-            append_message( &recv_queue->post_list, msg );
+        case SEND_MESSAGE:
+            send_message( send_queue, recv_queue, msg );
+            break;
+        case POST_MESSAGE:
+            append_message( &recv_queue->msg_list[POST_MESSAGE], msg );
             change_queue_bits( recv_queue, QS_POSTMESSAGE, 0 );
+            break;
+        case COOKED_HW_MESSAGE:
+        case RAW_HW_MESSAGE:
+            append_message( &recv_queue->msg_list[req->kind], msg );
+            change_queue_bits( recv_queue, get_hardware_msg_bit(msg), 0 );
+            break;
+        default:
+            free( msg );
+            set_error( STATUS_INVALID_PARAMETER );
+            break;
         }
     }
     release_object( thread );
 }
 
+/* store a message contents into the request buffer; helper for get_message */
+inline static void put_req_message( struct get_message_request *req, const struct message *msg )
+{
+    req->type   = msg->type;
+    req->win    = msg->win;
+    req->msg    = msg->msg;
+    req->wparam = msg->wparam;
+    req->lparam = msg->lparam;
+    req->x      = msg->x;
+    req->y      = msg->y;
+    req->time   = msg->time;
+    req->info   = msg->info;
+}
+
+inline static struct message *find_matching_message( const struct message_list *list, handle_t win,
+                                                     unsigned int first, unsigned int last )
+{
+    struct message *msg;
+
+    for (msg = list->first; msg; msg = msg->next)
+    {
+        /* check against the filters */
+        if (win && msg->win && msg->win != win) continue;
+        if (msg->msg < first) continue;
+        if (msg->msg > last) continue;
+        break; /* found one */
+    }
+    return msg;
+}
+
+
 /* get a message from the current queue */
 DECL_HANDLER(get_message)
 {
@@ -660,62 +724,75 @@
     if (!queue) return;
 
     /* first check for sent messages */
-    if ((msg = queue->send_list.first))
+    if ((msg = queue->msg_list[SEND_MESSAGE].first))
     {
-        req->sent   = 1;
-        req->type   = msg->type;
-        req->win    = msg->win;
-        req->msg    = msg->msg;
-        req->wparam = msg->wparam;
-        req->lparam = msg->lparam;
-        req->info   = msg->info;
+        req->kind = SEND_MESSAGE;
+        put_req_message( req, msg );
         receive_message( queue, msg );
         return;
     }
-    if (!req->posted) goto done;  /* nothing else to check */
+    if (req->flags & GET_MSG_SENT_ONLY) goto done;  /* nothing else to check */
 
-    /* then try a posted message */
-    req->sent = 0;
-    for (msg = queue->post_list.first; msg; msg = msg->next)
+    /* then check for posted messages */
+    if ((msg = find_matching_message( &queue->msg_list[POST_MESSAGE], req->get_win,
+                                      req->get_first, req->get_last )))
     {
-        /* check against the filters */
-        if (req->get_win && msg->win != req->get_win) continue;
-        if (msg->msg >= req->get_first && msg->msg <= req->get_last)
-        {
-            /* found one */
-            req->type   = msg->type;
-            req->win    = msg->win;
-            req->msg    = msg->msg;
-            req->wparam = msg->wparam;
-            req->lparam = msg->lparam;
-            req->info   = msg->info;
-            if (req->remove) remove_posted_message( queue, msg );
-            return;
-        }
+        req->kind = POST_MESSAGE;
+        put_req_message( req, msg );
+        if (req->flags & GET_MSG_REMOVE) remove_queue_message( queue, msg, POST_MESSAGE );
+        return;
+    }
+
+    /* then check for cooked hardware messages */
+    if ((msg = find_matching_message( &queue->msg_list[COOKED_HW_MESSAGE], req->get_win,
+                                      req->get_first, req->get_last )))
+    {
+        req->kind = COOKED_HW_MESSAGE;
+        put_req_message( req, msg );
+        if (req->flags & GET_MSG_REMOVE) remove_queue_message( queue, msg, COOKED_HW_MESSAGE );
+        return;
+    }
+
+    /* then check for any raw hardware message */
+    if ((msg = queue->msg_list[RAW_HW_MESSAGE].first))
+    {
+        req->kind = RAW_HW_MESSAGE;
+        put_req_message( req, msg );
+        /* raw messages always get removed */
+        remove_queue_message( queue, msg, RAW_HW_MESSAGE );
+        return;
     }
 
     /* now check for WM_PAINT */
     if ((queue->wake_bits & QS_PAINT) &&
         (WM_PAINT >= req->get_first) && (WM_PAINT <= req->get_last))
     {
+        req->kind   = POST_MESSAGE;
         req->type   = 0;
         req->win    = 0;
         req->msg    = WM_PAINT;
         req->wparam = 0;
         req->lparam = 0;
+        req->x      = 0;
+        req->y      = 0;
+        req->time   = 0;
         req->info   = 0;
         return;
     }
 
     /* now check for timer */
     if ((timer = find_expired_timer( queue, req->get_win, req->get_first,
-                                     req->get_last, req->remove )))
+                                     req->get_last, (req->flags & GET_MSG_REMOVE) )))
     {
+        req->kind   = POST_MESSAGE;
         req->type   = 0;
         req->win    = timer->win;
         req->msg    = timer->msg;
         req->wparam = timer->id;
         req->lparam = timer->lparam;
+        req->x      = 0;
+        req->y      = 0;
+        req->time   = 0;
         req->info   = 0;
         return;
     }
diff --git a/server/trace.c b/server/trace.c
index a0f1fc2..2876fbd 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1464,20 +1464,22 @@
 
 static void dump_send_message_request( const struct send_message_request *req )
 {
-    fprintf( stderr, " posted=%d,", req->posted );
+    fprintf( stderr, " kind=%d,", req->kind );
     fprintf( stderr, " id=%p,", req->id );
     fprintf( stderr, " type=%d,", req->type );
     fprintf( stderr, " win=%d,", req->win );
     fprintf( stderr, " msg=%08x,", req->msg );
     fprintf( stderr, " wparam=%08x,", req->wparam );
     fprintf( stderr, " lparam=%08x,", req->lparam );
+    fprintf( stderr, " x=%04x,", req->x );
+    fprintf( stderr, " y=%04x,", req->y );
+    fprintf( stderr, " time=%08x,", req->time );
     fprintf( stderr, " info=%08x", req->info );
 }
 
 static void dump_get_message_request( const struct get_message_request *req )
 {
-    fprintf( stderr, " remove=%d,", req->remove );
-    fprintf( stderr, " posted=%d,", req->posted );
+    fprintf( stderr, " flags=%d,", req->flags );
     fprintf( stderr, " get_win=%d,", req->get_win );
     fprintf( stderr, " get_first=%08x,", req->get_first );
     fprintf( stderr, " get_last=%08x", req->get_last );
@@ -1485,12 +1487,15 @@
 
 static void dump_get_message_reply( const struct get_message_request *req )
 {
-    fprintf( stderr, " sent=%d,", req->sent );
+    fprintf( stderr, " kind=%d,", req->kind );
     fprintf( stderr, " type=%d,", req->type );
     fprintf( stderr, " win=%d,", req->win );
     fprintf( stderr, " msg=%08x,", req->msg );
     fprintf( stderr, " wparam=%08x,", req->wparam );
     fprintf( stderr, " lparam=%08x,", req->lparam );
+    fprintf( stderr, " x=%04x,", req->x );
+    fprintf( stderr, " y=%04x,", req->y );
+    fprintf( stderr, " time=%08x,", req->time );
     fprintf( stderr, " info=%08x", req->info );
 }
 
diff --git a/tools/make_requests b/tools/make_requests
index b0a77d7..b04e155 100755
--- a/tools/make_requests
+++ b/tools/make_requests
@@ -11,6 +11,7 @@
     "int"           => "%d",
     "char"          => "%c",
     "unsigned char" => "%02x",
+    "unsigned short"=> "%04x",
     "unsigned int"  => "%08x",
     "void*"         => "%p",
     "time_t"        => "%ld",
diff --git a/windows/input.c b/windows/input.c
index 9747d2b..a53ed3c 100644
--- a/windows/input.c
+++ b/windows/input.c
@@ -23,6 +23,7 @@
 #include "wine/winbase16.h"
 #include "wine/winuser16.h"
 #include "wine/keyboard16.h"
+#include "server.h"
 #include "win.h"
 #include "heap.h"
 #include "input.h"
@@ -33,10 +34,10 @@
 #include "debugtools.h"
 #include "winerror.h"
 
-DECLARE_DEBUG_CHANNEL(event);
 DECLARE_DEBUG_CHANNEL(key);
 DECLARE_DEBUG_CHANNEL(keyboard);
 DECLARE_DEBUG_CHANNEL(win);
+DEFAULT_DEBUG_CHANNEL(event);
 
 static BOOL InputEnabled = TRUE;
 static BOOL SwappedButtons;
@@ -73,6 +74,35 @@
     unsigned long lp2;
 } KEYLP;
 
+
+/***********************************************************************
+ *           queue_raw_hardware_message
+ *
+ * Add a message to the raw hardware queue.
+ * Note: the position is relative to the desktop window.
+ */
+static void queue_raw_hardware_message( UINT message, WPARAM wParam, LPARAM lParam,
+                                        int xPos, int yPos, DWORD time, DWORD extraInfo )
+{
+    SERVER_START_REQ( send_message )
+    {
+        req->kind   = RAW_HW_MESSAGE;
+        req->id     = (void *)GetCurrentThreadId();
+        req->type   = QMSG_HARDWARE;
+        req->win    = 0;
+        req->msg    = message;
+        req->wparam = wParam;
+        req->lparam = lParam;
+        req->x      = xPos;
+        req->y      = yPos;
+        req->time   = time;
+        req->info   = extraInfo;
+        SERVER_CALL();
+    }
+    SERVER_END_REQ;
+}
+
+
 /***********************************************************************
  *		keybd_event (USER32.@)
  */
@@ -147,7 +177,7 @@
     TRACE_(key)("            wParam=%04X, lParam=%08lX\n", bVk, keylp.lp2 );
     TRACE_(key)("            InputKeyState=%X\n", InputKeyStateTable[bVk] );
 
-    hardware_event( message, bVk, keylp.lp2, PosX, PosY, time, extra );
+    queue_raw_hardware_message( message, bVk, keylp.lp2, PosX, PosY, time, extra );
 }
 
 /***********************************************************************
@@ -242,49 +272,41 @@
 
     if ( dwFlags & MOUSEEVENTF_MOVE )
     {
-        hardware_event( WM_MOUSEMOVE,
-                        keyState, 0L, PosX, PosY, time, extra );
+        queue_raw_hardware_message( WM_MOUSEMOVE, keyState, 0, PosX, PosY, time, extra );
     }
     if ( dwFlags & (!SwappedButtons? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_RIGHTDOWN) )
     {
         MouseButtonsStates[0] = AsyncMouseButtonsStates[0] = TRUE;
-        hardware_event( WM_LBUTTONDOWN,
-                        keyState, 0L, PosX, PosY, time, extra );
+        queue_raw_hardware_message( WM_LBUTTONDOWN, keyState, 0, PosX, PosY, time, extra );
     }
     if ( dwFlags & (!SwappedButtons? MOUSEEVENTF_LEFTUP : MOUSEEVENTF_RIGHTUP) )
     {
         MouseButtonsStates[0] = FALSE;
-        hardware_event( WM_LBUTTONUP,
-                        keyState, 0L, PosX, PosY, time, extra );
+        queue_raw_hardware_message( WM_LBUTTONUP, keyState, 0, PosX, PosY, time, extra );
     }
     if ( dwFlags & (!SwappedButtons? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_LEFTDOWN) )
     {
         MouseButtonsStates[2] = AsyncMouseButtonsStates[2] = TRUE;
-        hardware_event( WM_RBUTTONDOWN,
-                        keyState, 0L, PosX, PosY, time, extra );
+        queue_raw_hardware_message( WM_RBUTTONDOWN, keyState, 0, PosX, PosY, time, extra );
     }
     if ( dwFlags & (!SwappedButtons? MOUSEEVENTF_RIGHTUP : MOUSEEVENTF_LEFTUP) )
     {
         MouseButtonsStates[2] = FALSE;
-        hardware_event( WM_RBUTTONUP,
-                        keyState, 0L, PosX, PosY, time, extra );
+        queue_raw_hardware_message( WM_RBUTTONUP, keyState, 0, PosX, PosY, time, extra );
     }
     if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN )
     {
         MouseButtonsStates[1] = AsyncMouseButtonsStates[1] = TRUE;
-        hardware_event( WM_MBUTTONDOWN,
-                        keyState, 0L, PosX, PosY, time, extra );
+        queue_raw_hardware_message( WM_MBUTTONDOWN, keyState, 0, PosX, PosY, time, extra );
     }
     if ( dwFlags & MOUSEEVENTF_MIDDLEUP )
     {
         MouseButtonsStates[1] = FALSE;
-        hardware_event( WM_MBUTTONUP,
-                        keyState, 0L, PosX, PosY, time, extra );
+        queue_raw_hardware_message( WM_MBUTTONUP, keyState, 0, PosX, PosY, time, extra );
     }
     if ( dwFlags & MOUSEEVENTF_WHEEL )
     {
-        hardware_event( WM_MOUSEWHEEL,
-                        keyState, 0L, PosX, PosY, time, extra );
+        queue_raw_hardware_message( WM_MOUSEWHEEL, keyState, 0, PosX, PosY, time, extra );
     }
 }
 
diff --git a/windows/message.c b/windows/message.c
index 213e089..18baf2f 100644
--- a/windows/message.c
+++ b/windows/message.c
@@ -32,44 +32,86 @@
 
 DEFAULT_DEBUG_CHANNEL(msg);
 DECLARE_DEBUG_CHANNEL(key);
-DECLARE_DEBUG_CHANNEL(sendmsg);
 
 #define WM_NCMOUSEFIRST         WM_NCMOUSEMOVE
 #define WM_NCMOUSELAST          WM_NCMBUTTONDBLCLK
 
-    
-typedef enum { SYSQ_MSG_ABANDON, SYSQ_MSG_SKIP, 
-               SYSQ_MSG_ACCEPT, SYSQ_MSG_CONTINUE } SYSQ_STATUS;
-
-extern HQUEUE16 hCursorQueue;			 /* queue.c */
-
 static UINT doubleClickSpeed = 452;
 
+
 /***********************************************************************
- *           MSG_CheckFilter
+ *           is_keyboard_message
  */
-static BOOL MSG_CheckFilter(DWORD uMsg, DWORD first, DWORD last)
+inline static BOOL is_keyboard_message( UINT message )
 {
-   if( first || last )
-       return (uMsg >= first && uMsg <= last);
-   return TRUE;
+    return (message >= WM_KEYFIRST && message <= WM_KEYLAST);
 }
 
+
+/***********************************************************************
+ *           is_mouse_message
+ */
+inline static BOOL is_mouse_message( UINT message )
+{
+    return ((message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST) ||
+            (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST));
+}
+
+
+/***********************************************************************
+ *           check_message_filter
+ */
+inline static BOOL check_message_filter( const MSG *msg, HWND hwnd, UINT first, UINT last )
+{
+    if (hwnd)
+    {
+        if (msg->hwnd != hwnd && !IsChild( hwnd, msg->hwnd )) return FALSE;
+    }
+    if (first || last)
+    {
+       return (msg->message >= first && msg->message <= last);
+    }
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *           queue_hardware_message
+ *
+ * store a hardware message in the thread queue
+ */
+static void queue_hardware_message( MSG *msg, ULONG_PTR extra_info, enum message_kind kind )
+{
+    SERVER_START_REQ( send_message )
+    {
+        req->kind   = kind;
+        req->id     = (void *)GetWindowThreadProcessId( msg->hwnd, NULL );
+        req->type   = QMSG_HARDWARE;
+        req->win    = msg->hwnd;
+        req->msg    = msg->message;
+        req->wparam = msg->wParam;
+        req->lparam = msg->lParam;
+        req->x      = msg->pt.x;
+        req->y      = msg->pt.y;
+        req->time   = msg->time;
+        req->info   = extra_info;
+        SERVER_CALL();
+    }
+    SERVER_END_REQ;
+}
+
+
 /***********************************************************************
  *           MSG_SendParentNotify
  *
  * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
  * the window has the WS_EX_NOPARENTNOTIFY style.
  */
-static void MSG_SendParentNotify(WND* wndPtr, WORD event, WORD idChild, LPARAM lValue)
+static void MSG_SendParentNotify( HWND hwnd, WORD event, WORD idChild, POINT pt )
 {
-    POINT pt;
+    WND *tmpWnd = WIN_FindWndPtr(hwnd);
 
     /* pt has to be in the client coordinates of the parent window */
-    WND *tmpWnd = WIN_LockWndPtr(wndPtr);
-
-    pt.x = SLOWORD(lValue);
-    pt.y = SHIWORD(lValue);
     MapWindowPoints( 0, tmpWnd->hwndSelf, &pt, 1 );
     while (tmpWnd)
     {
@@ -82,446 +124,58 @@
 	pt.y += tmpWnd->rectClient.top;
 	WIN_UpdateWndPtr(&tmpWnd,tmpWnd->parent);
 	SendMessageA( tmpWnd->hwndSelf, WM_PARENTNOTIFY,
-		      MAKEWPARAM( event, idChild ), 
-                      MAKELONG( pt.x, pt.y ) );
+                      MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
     }
 }
 
 
 /***********************************************************************
- *           MSG_TranslateMouseMsg
- *
- * Translate a mouse hardware event into a real mouse message.
- *
- * Returns:
- *
- *  SYSQ_MSG_ABANDON  - abandon the peek message loop
- *  SYSQ_MSG_CONTINUE - leave the message in the queue and
- *                      continue with the translation loop
- *  SYSQ_MSG_ACCEPT   - proceed to process the translated message
- */
-static DWORD MSG_TranslateMouseMsg( HWND hTopWnd, DWORD first, DWORD last,
-                                    MSG *msg, BOOL remove, WND* pWndScope,
-                                    INT *pHitTest, POINT *screen_pt, BOOL *pmouseClick )
-{
-    static DWORD   dblclk_time_limit = 0;
-    static UINT16     clk_message = 0;
-    static HWND16     clk_hwnd = 0;
-    static POINT clk_pos;
-
-    WND *pWnd;
-    HWND hWnd;
-    INT16 ht, hittest;
-    UINT message = msg->message;
-    POINT pt = msg->pt;
-    HANDLE16 hQ = GetFastQueue16();
-    MESSAGEQUEUE *queue = QUEUE_Lock(hQ);
-    int mouseClick = ((message == WM_LBUTTONDOWN) ||
-                      (message == WM_RBUTTONDOWN) ||
-                      (message == WM_MBUTTONDOWN));
-    DWORD retvalue;
-
-    /* Find the window to dispatch this mouse message to */
-
-    hWnd = GetCapture();
-
-    /* If no capture HWND, find window which contains the mouse position.
-     * Also find the position of the cursor hot spot (hittest) */
-    if( !hWnd )
-    {
-	ht = hittest = WINPOS_WindowFromPoint( pWndScope, pt, &pWnd );
-	if( !pWnd ) pWnd = WIN_GetDesktop();
-        else WIN_LockWndPtr(pWnd);
-	hWnd = pWnd->hwndSelf;
-    } 
-    else 
-    {
-        ht = hittest = HTCLIENT;
-	pWnd = WIN_FindWndPtr(hWnd);
-        if (queue)
-            ht = PERQDATA_GetCaptureInfo( queue->pQData );
-    }
-
-    /* Save hittest for return */
-    *pHitTest = hittest;
-        
-	/* stop if not the right queue */
-
-    if (pWnd->hmemTaskQ && pWnd->hmemTaskQ != hQ)
-    {
-        /* Not for the current task */
-        if (queue) QUEUE_ClearWakeBit( queue, QS_MOUSE );
-        /* Wake up the other task */
-        QUEUE_Unlock( queue );
-        queue = QUEUE_Lock( pWnd->hmemTaskQ );
-        if (queue) QUEUE_SetWakeBit( queue, QS_MOUSE, 0 );
-
-        QUEUE_Unlock( queue );
-        retvalue = SYSQ_MSG_ABANDON;
-        goto END;
-    }
-
-	/* check if hWnd is within hWndScope */
-
-    if( hTopWnd && hWnd != hTopWnd )
-        if( !IsChild(hTopWnd, hWnd) )
-        {
-            QUEUE_Unlock( queue );
-            retvalue = SYSQ_MSG_CONTINUE;
-            goto END;
-        }
-
-    /* Was it a mouse click message */
-    if( mouseClick )
-    {
-	/* translate double clicks -
-	 * note that ...MOUSEMOVEs can slip in between
-	 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
-
-	if(GetClassLongA(hWnd, GCL_STYLE) & CS_DBLCLKS || ht != HTCLIENT )
-	{
-           if ((message == clk_message) && (hWnd == clk_hwnd) &&
-               (msg->time - dblclk_time_limit < doubleClickSpeed) &&
-               (abs(msg->pt.x - clk_pos.x) < GetSystemMetrics(SM_CXDOUBLECLK)/2) &&
-               (abs(msg->pt.y - clk_pos.y) < GetSystemMetrics(SM_CYDOUBLECLK)/2))
-	   {
-	      message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
-	      mouseClick++;   /* == 2 */
-	   }
-	}
-    }
-    /* save mouse position */
-    *screen_pt = pt;
-
-    if (hittest != HTCLIENT)
-    {
-	message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
-	msg->wParam = hittest;
-    }
-    else
-        ScreenToClient( hWnd, &pt );
-
-	/* check message filter */
-
-    if (!MSG_CheckFilter(message, first, last))
-    {
-        QUEUE_Unlock(queue);
-        retvalue = SYSQ_MSG_CONTINUE;
-        goto END;
-    }
-
-    /* Update global hCursorQueue */
-    hCursorQueue = queue->self;
-    
-    /* Update static double click conditions */
-    if( remove && mouseClick )
-    {
-	if( mouseClick == 1 )
-	{
-	    /* set conditions */
-	    dblclk_time_limit = msg->time;
-            clk_message = msg->message;
-            clk_hwnd = hWnd;
-            clk_pos = *screen_pt;
-	} else 
-	    /* got double click - zero them out */
-	    dblclk_time_limit = clk_hwnd = 0;
-    }
-
-    QUEUE_Unlock(queue);
-
-    /* Update message params */
-    msg->hwnd    = hWnd;
-    msg->message = message;
-    msg->lParam  = MAKELONG( pt.x, pt.y );
-    retvalue = SYSQ_MSG_ACCEPT;
-
-END:
-    WIN_ReleaseWndPtr(pWnd);
-
-    /* Return mouseclick flag */
-    *pmouseClick = mouseClick;
-    
-    return retvalue;
-}
-
-
-/***********************************************************************
- *           MSG_ProcessMouseMsg
- *
- * Processes a translated mouse hardware event.
- * The passed in msg structure should contain the updated hWnd, 
- * lParam, wParam and message fields from MSG_TranslateMouseMsg.
- *
- * Returns:
- *
- *  SYSQ_MSG_SKIP     - Message should be skipped entirely (in this case
- *                      HIWORD contains hit test code). Continue translating..
- *  SYSQ_MSG_ACCEPT   - the translated message must be passed to the user
- *                      MSG_PeekHardwareMsg should return TRUE.
- */
-static DWORD MSG_ProcessMouseMsg( MSG *msg, BOOL remove, INT hittest,
-                                  POINT screen_pt, BOOL mouseClick )
-{
-    WND *pWnd;
-    HWND hWnd = msg->hwnd;
-    INT16 sendSC = (GetCapture() == 0);
-    UINT message = msg->message;
-    BOOL eatMsg = FALSE;
-    DWORD retvalue;
-
-    pWnd = WIN_FindWndPtr(hWnd);
-    
-	/* call WH_MOUSE */
-
-    if (HOOK_IsHooked( WH_MOUSE ))
-    { 
-        MOUSEHOOKSTRUCT hook;
-        hook.pt           = screen_pt;
-        hook.hwnd         = hWnd;
-        hook.wHitTestCode = hittest;
-        hook.dwExtraInfo  = 0;
-        if (HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
-                             message, (LPARAM)&hook ))
-        {
-            retvalue = MAKELONG((INT16)SYSQ_MSG_SKIP, hittest);
-            goto END;
-        }
-    }
-
-    if (message >= WM_NCMOUSEFIRST && message <= WM_NCMOUSELAST)
-        message += WM_MOUSEFIRST - WM_NCMOUSEFIRST;
-
-    if ((hittest == HTERROR) || (hittest == HTNOWHERE)) 
-	eatMsg = sendSC = 1;
-    else if( remove && mouseClick )
-    {
-        HWND hwndTop = WIN_GetTopParent( hWnd );
-
-	if( sendSC )
-	{
-            /* Send the WM_PARENTNOTIFY,
-	     * note that even for double/nonclient clicks
-	     * notification message is still WM_L/M/RBUTTONDOWN.
-	     */
-
-            MSG_SendParentNotify( pWnd, message, 0, MAKELPARAM(screen_pt.x, screen_pt.y) );
-
-            /* Activate the window if needed */
-
-            if (hWnd != GetActiveWindow() && hwndTop != GetDesktopWindow())
-            {
-                LONG ret = SendMessageA( hWnd, WM_MOUSEACTIVATE, hwndTop,
-                                          MAKELONG( hittest, message ) );
-
-                if ((ret == MA_ACTIVATEANDEAT) || (ret == MA_NOACTIVATEANDEAT))
-                         eatMsg = TRUE;
-
-                if (((ret == MA_ACTIVATE) || (ret == MA_ACTIVATEANDEAT))
-                        && hwndTop != GetForegroundWindow() )
-                {
-                      if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
-			 eatMsg = TRUE;
-                }
-            }
-	}
-    } else sendSC = (remove && sendSC);
-
-     /* Send the WM_SETCURSOR message */
-
-    if (sendSC)
-    {
-        /* Windows sends the normal mouse message as the message parameter
-           in the WM_SETCURSOR message even if it's non-client mouse message */
-        SendMessageA( hWnd, WM_SETCURSOR, hWnd,
-                       MAKELONG( hittest, message ));
-    }
-    if (eatMsg)
-    {
-        retvalue = MAKELONG( (UINT16)SYSQ_MSG_SKIP, hittest);
-        goto END;
-    }
-
-    retvalue = SYSQ_MSG_ACCEPT;
-END:
-    WIN_ReleaseWndPtr(pWnd);
-
-    return retvalue;
-}
-
-
-/***********************************************************************
- *           MSG_TranslateKbdMsg
- *
- * Translate a keyboard hardware event into a real message.
- */
-static DWORD MSG_TranslateKbdMsg( HWND hTopWnd, DWORD first, DWORD last,
-				  MSG *msg, BOOL remove )
-{
-    WORD message = msg->message;
-    HWND hWnd = GetFocus();
-    WND *pWnd;
-
-      /* Should check Ctrl-Esc and PrintScreen here */
-
-    if (!hWnd)
-    {
-	  /* Send the message to the active window instead,  */
-	  /* translating messages to their WM_SYS equivalent */
-
-	hWnd = GetActiveWindow();
-
-	if( message < WM_SYSKEYDOWN )
-	    message += WM_SYSKEYDOWN - WM_KEYDOWN;
-    }
-    if ( !hWnd ) return SYSQ_MSG_ABANDON;
-    pWnd = WIN_FindWndPtr( hWnd );
-
-    if (pWnd && pWnd->hmemTaskQ && (pWnd->hmemTaskQ != GetFastQueue16()))
-    {
-        /* Not for the current task */
-        MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
-        if (queue) QUEUE_ClearWakeBit( queue, QS_KEY );
-        QUEUE_Unlock( queue );
-        
-        /* Wake up the other task */
-        queue = QUEUE_Lock( pWnd->hmemTaskQ );
-        if (queue) QUEUE_SetWakeBit( queue, QS_KEY, 0 );
-        QUEUE_Unlock( queue );
-        WIN_ReleaseWndPtr(pWnd);
-        return SYSQ_MSG_ABANDON;
-    }
-    WIN_ReleaseWndPtr(pWnd);
-
-    if (hTopWnd && hWnd != hTopWnd)
-	if (!IsChild(hTopWnd, hWnd)) return SYSQ_MSG_CONTINUE;
-    if (!MSG_CheckFilter(message, first, last)) return SYSQ_MSG_CONTINUE;
-
-    msg->hwnd = hWnd;
-    msg->message = message;
-
-    return SYSQ_MSG_ACCEPT;
-}
-
-
-/***********************************************************************
- *           MSG_ProcessKbdMsg
- *
- *  Processes a translated keyboard message
- */
-static DWORD MSG_ProcessKbdMsg( MSG *msg, BOOL remove )
-{
-    /* Handle F1 key by sending out WM_HELP message */
-    if ((msg->message == WM_KEYUP) && 
-	(msg->wParam == VK_F1) &&
-	remove &&
-	(msg->hwnd != GetDesktopWindow()) &&
-	!MENU_IsMenuActive())
-    {   
-	HELPINFO hi;
-	WND *pWnd = WIN_FindWndPtr(msg->hwnd);
-
-	if (NULL != pWnd)
-	{
-	    hi.cbSize = sizeof(HELPINFO);
-	    hi.iContextType = HELPINFO_WINDOW;
-	    hi.iCtrlId = pWnd->wIDmenu; 
-	    hi.hItemHandle = msg->hwnd;
-	    hi.dwContextId = pWnd->helpContext;
-	    hi.MousePos = msg->pt;
-	    SendMessageA(msg->hwnd, WM_HELP, 0, (LPARAM)&hi);
-	}
-        WIN_ReleaseWndPtr(pWnd);
-    }
-
-    return (HOOK_CallHooksA( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
-                             LOWORD (msg->wParam), msg->lParam )
-            ? SYSQ_MSG_SKIP : SYSQ_MSG_ACCEPT);
-}
-
-
-/***********************************************************************
- *           MSG_JournalRecordMsg
- *
- * Build an EVENTMSG structure and call JOURNALRECORD hook
- */
-static void MSG_JournalRecordMsg( MSG *msg )
-{
-    EVENTMSG event;
-
-    event.message = msg->message;
-    event.time = msg->time;
-    if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
-    {
-        event.paramL = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
-        event.paramH = msg->lParam & 0x7FFF;
-        if (HIWORD(msg->lParam) & 0x0100)
-            event.paramH |= 0x8000;               /* special_key - bit */
-        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
-    }
-    else if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
-    {
-        POINT pt;
-        pt.x = SLOWORD(msg->lParam);
-        pt.y = SHIWORD(msg->lParam);
-        ClientToScreen( msg->hwnd, &pt );
-        event.paramL = pt.x;
-        event.paramH = pt.y;
-        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
-    }
-    else if ((msg->message >= WM_NCMOUSEFIRST) &&
-             (msg->message <= WM_NCMOUSELAST))
-    {
-        event.paramL = LOWORD(msg->lParam);       /* X pos */
-        event.paramH = HIWORD(msg->lParam);       /* Y pos */
-        event.message += WM_MOUSEMOVE-WM_NCMOUSEMOVE;/* give no info about NC area */
-        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
-    }
-}
-
-/***********************************************************************
  *          MSG_JournalPlayBackMsg
  *
  * Get an EVENTMSG struct via call JOURNALPLAYBACK hook function 
  */
-static int MSG_JournalPlayBackMsg(void)
+static void MSG_JournalPlayBackMsg(void)
 {
     EVENTMSG tmpMsg;
-    LPARAM lParam;
-    WPARAM wParam;
+    MSG msg;
     LRESULT wtime;
     int keyDown,i;
 
-    if (!HOOK_IsHooked( WH_JOURNALPLAYBACK )) return 0;
+    if (!HOOK_IsHooked( WH_JOURNALPLAYBACK )) return;
 
     wtime=HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_GETNEXT, 0, (LPARAM)&tmpMsg );
     /*  TRACE(msg,"Playback wait time =%ld\n",wtime); */
     if (wtime<=0)
     {
         wtime=0;
+        msg.message = tmpMsg.message;
+        msg.hwnd    = tmpMsg.hwnd;
+        msg.time    = tmpMsg.time;
         if ((tmpMsg.message >= WM_KEYFIRST) && (tmpMsg.message <= WM_KEYLAST))
         {
-            wParam=tmpMsg.paramL & 0xFF;
-            lParam=MAKELONG(tmpMsg.paramH&0x7ffff,tmpMsg.paramL>>8);
+            msg.wParam  = tmpMsg.paramL & 0xFF;
+            msg.lParam  = MAKELONG(tmpMsg.paramH&0x7ffff,tmpMsg.paramL>>8);
             if (tmpMsg.message == WM_KEYDOWN || tmpMsg.message == WM_SYSKEYDOWN)
             {
                 for (keyDown=i=0; i<256 && !keyDown; i++)
                     if (InputKeyStateTable[i] & 0x80)
                         keyDown++;
                 if (!keyDown)
-                    lParam |= 0x40000000;
-                AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] |= 0x80;
+                    msg.lParam |= 0x40000000;
+                AsyncKeyStateTable[msg.wParam]=InputKeyStateTable[msg.wParam] |= 0x80;
             }
             else                                       /* WM_KEYUP, WM_SYSKEYUP */
             {
-                lParam |= 0xC0000000;
-                AsyncKeyStateTable[wParam]=InputKeyStateTable[wParam] &= ~0x80;
+                msg.lParam |= 0xC0000000;
+                AsyncKeyStateTable[msg.wParam]=InputKeyStateTable[msg.wParam] &= ~0x80;
             }
             if (InputKeyStateTable[VK_MENU] & 0x80)
-                lParam |= 0x20000000;
+                msg.lParam |= 0x20000000;
             if (tmpMsg.paramH & 0x8000)              /*special_key bit*/
-                lParam |= 0x01000000;
-            hardware_event( tmpMsg.message, wParam, lParam, 0, 0, tmpMsg.time, 0 );
+                msg.lParam |= 0x01000000;
+
+            msg.pt.x = msg.pt.y = 0;
+            queue_hardware_message( &msg, 0, RAW_HW_MESSAGE );
         }
         else if ((tmpMsg.message>= WM_MOUSEFIRST) && (tmpMsg.message <= WM_MOUSELAST))
         {
@@ -544,180 +198,333 @@
             AsyncKeyStateTable[VK_MBUTTON]= InputKeyStateTable[VK_MBUTTON] = MouseButtonsStates[1] ? 0x80 : 0;
             AsyncKeyStateTable[VK_RBUTTON]= InputKeyStateTable[VK_RBUTTON] = MouseButtonsStates[2] ? 0x80 : 0;
             SetCursorPos(tmpMsg.paramL,tmpMsg.paramH);
-            lParam=MAKELONG(tmpMsg.paramL,tmpMsg.paramH);
-            wParam=0;
-            if (MouseButtonsStates[0]) wParam |= MK_LBUTTON;
-            if (MouseButtonsStates[1]) wParam |= MK_MBUTTON;
-            if (MouseButtonsStates[2]) wParam |= MK_RBUTTON;
-            hardware_event( tmpMsg.message, wParam, lParam,
-                            tmpMsg.paramL, tmpMsg.paramH, tmpMsg.time, 0 );
+            msg.lParam=MAKELONG(tmpMsg.paramL,tmpMsg.paramH);
+            msg.wParam=0;
+            if (MouseButtonsStates[0]) msg.wParam |= MK_LBUTTON;
+            if (MouseButtonsStates[1]) msg.wParam |= MK_MBUTTON;
+            if (MouseButtonsStates[2]) msg.wParam |= MK_RBUTTON;
+
+            msg.pt.x = tmpMsg.paramL;
+            msg.pt.y = tmpMsg.paramH;
+            queue_hardware_message( &msg, 0, RAW_HW_MESSAGE );
         }
         HOOK_CallHooksA( WH_JOURNALPLAYBACK, HC_SKIP, 0, (LPARAM)&tmpMsg);
-        return 0;
     }
     else
     {
         if( tmpMsg.message == WM_QUEUESYNC )
             if (HOOK_IsHooked( WH_CBT ))
                 HOOK_CallHooksA( WH_CBT, HCBT_QS, 0, 0L);
-
-        return QS_MOUSE | QS_KEY; /* ? */
     }
 }
 
+
 /***********************************************************************
- *           MSG_PeekHardwareMsg
+ *          process_raw_keyboard_message
  *
- * Peek for a hardware message matching the hwnd and message filters.
+ * returns TRUE if the contents of 'msg' should be passed to the application
  */
-static BOOL MSG_PeekHardwareMsg( MSG *msg, HWND hwnd, DWORD first, DWORD last,
-                                   BOOL remove )
+static BOOL process_raw_keyboard_message( MSG *msg, ULONG_PTR extra_info )
 {
-    DWORD status = SYSQ_MSG_ACCEPT;
-    MESSAGEQUEUE *sysMsgQueue = QUEUE_GetSysQueue();
-    enum { MOUSE_MSG = 0, KEYBOARD_MSG, HARDWARE_MSG } msgType;
-    QMSG *nextqmsg, *qmsg = 0;
-    BOOL bRet = FALSE;
-
-    EnterCriticalSection(&sysMsgQueue->cSection);
-
-    /* Loop through the Q and translate the message we wish to process
-     * while we own the lock. Based on the translation status (abandon/cont/accept)
-     * we then process the message accordingly
-     */
-
-    for ( qmsg = sysMsgQueue->firstMsg; qmsg; qmsg = nextqmsg )
+    if (!(msg->hwnd = GetFocus()))
     {
-        INT hittest;
-        POINT screen_pt;
-        BOOL mouseClick;
-
-        *msg = qmsg->msg;
-
-        nextqmsg = qmsg->nextMsg;
-
-          /* Translate message */
-
-        if ((msg->message >= WM_MOUSEFIRST) && (msg->message <= WM_MOUSELAST))
-        {
-            HWND hWndScope = (HWND)qmsg->extraInfo;
-            WND *tmpWnd = IsWindow(hWndScope) ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop();
-
-            status = MSG_TranslateMouseMsg(hwnd, first, last, msg, remove, tmpWnd,
-                                           &hittest, &screen_pt, &mouseClick );
-	    msgType = MOUSE_MSG;
-            
-            WIN_ReleaseWndPtr(tmpWnd);
-
-        }
-        else if ((msg->message >= WM_KEYFIRST) && (msg->message <= WM_KEYLAST))
-        {
-            status = MSG_TranslateKbdMsg(hwnd, first, last, msg, remove);
-	    msgType = KEYBOARD_MSG;
-        }
-        else /* Non-standard hardware event */
-        {
-            HARDWAREHOOKSTRUCT16 *hook;
-	    msgType = HARDWARE_MSG;
-            if ((hook = SEGPTR_NEW(HARDWAREHOOKSTRUCT16)))
-            {
-                BOOL ret;
-                hook->hWnd     = msg->hwnd;
-                hook->wMessage = msg->message & 0xffff;
-                hook->wParam   = LOWORD (msg->wParam);
-                hook->lParam   = msg->lParam;
-                ret = HOOK_CallHooks16( WH_HARDWARE,
-                                        remove ? HC_ACTION : HC_NOREMOVE,
-                                        0, (LPARAM)SEGPTR_GET(hook) );
-                SEGPTR_FREE(hook);
-                if (ret) 
-		{
-                    QUEUE_RemoveMsg( sysMsgQueue, qmsg );
-		    continue;
-		}
-		status = SYSQ_MSG_ACCEPT; 
-            }
-        }
-
-        
-	switch (LOWORD(status))
-	{
-	   case SYSQ_MSG_ACCEPT:
-           {
-               /* Remove the message from the system msg Q while it is still locked,
-                * before accepting it */
-               if (remove)
-               {
-                   if (HOOK_IsHooked( WH_JOURNALRECORD )) MSG_JournalRecordMsg( msg );
-                   QUEUE_RemoveMsg( sysMsgQueue, qmsg );
-               }
-               /* Now actually process the message, after we unlock the system msg Q.
-                * We should not hold on to the crst since SendMessage calls during processing 
-                * will potentially cause callbacks to PeekMessage from the application.
-                * If we're holding the crst and QUEUE_WaitBits is called with a
-                * QS_SENDMESSAGE mask we will deadlock in hardware_event() when a
-                * message is being posted to the Q.
-                */
-               LeaveCriticalSection(&sysMsgQueue->cSection);
-               if( msgType == KEYBOARD_MSG )
-                   status = MSG_ProcessKbdMsg( msg, remove );
-               else if ( msgType == MOUSE_MSG )
-                   status = MSG_ProcessMouseMsg( msg, remove, hittest, screen_pt, mouseClick );
-
-               /* Reclaim the sys msg Q crst */
-               EnterCriticalSection(&sysMsgQueue->cSection);
-               
-               /* Pass the translated message to the user if it was accepted */
-               if (status == SYSQ_MSG_ACCEPT)
-		break;
-
-               /* If not accepted, fall through into the SYSQ_MSG_SKIP case */
-           }
-                
-	   case SYSQ_MSG_SKIP:
-                if (HOOK_IsHooked( WH_CBT ))
-                {
-                   if( msgType == KEYBOARD_MSG )
-                       HOOK_CallHooksA( WH_CBT, HCBT_KEYSKIPPED,
-                                         LOWORD (msg->wParam), msg->lParam );
-		   else if ( msgType == MOUSE_MSG )
-		   {
-                       MOUSEHOOKSTRUCT hook;
-                       hook.pt           = msg->pt;
-                       hook.hwnd         = msg->hwnd;
-                       hook.wHitTestCode = HIWORD(status);
-                       hook.dwExtraInfo  = 0;
-                       HOOK_CallHooksA( WH_CBT, HCBT_CLICKSKIPPED, msg->message, (LPARAM)&hook );
-                   }
-                }
-
-                /* If the message was removed earlier set up nextqmsg so that we start 
-                 * at the top of the queue again.  We need to do this since our next pointer
-                 * could be invalid due to us unlocking the system message Q to process the message.
-                 * If not removed just refresh nextqmsg to point to the next msg.
-                 */
-		if (remove)
-                    nextqmsg = sysMsgQueue->firstMsg;
-                else
-                    nextqmsg = qmsg->nextMsg;
-
-		continue;
-                
-	   case SYSQ_MSG_CONTINUE:
-		continue;
-
-	   case SYSQ_MSG_ABANDON: 
-               bRet = FALSE;
-               goto END;
-	}
-
-        bRet = TRUE;
-        goto END;
+        /* Send the message to the active window instead,  */
+        /* translating messages to their WM_SYS equivalent */
+        msg->hwnd = GetActiveWindow();
+        if (msg->message < WM_SYSKEYDOWN) msg->message += WM_SYSKEYDOWN - WM_KEYDOWN;
     }
 
-END:
-    LeaveCriticalSection(&sysMsgQueue->cSection);
-    return bRet;
+    if (HOOK_IsHooked( WH_JOURNALRECORD ))
+    {
+        EVENTMSG event;
+
+        event.message = msg->message;
+        event.hwnd    = msg->hwnd;
+        event.time    = msg->time;
+        event.paramL  = (msg->wParam & 0xFF) | (HIWORD(msg->lParam) << 8);
+        event.paramH  = msg->lParam & 0x7FFF;
+        if (HIWORD(msg->lParam) & 0x0100) event.paramH |= 0x8000; /* special_key - bit */
+        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
+    }
+
+    return (msg->hwnd != 0);
+}
+
+
+/***********************************************************************
+ *          process_cooked_keyboard_message
+ *
+ * returns TRUE if the contents of 'msg' should be passed to the application
+ */
+static BOOL process_cooked_keyboard_message( MSG *msg, BOOL remove )
+{
+    if (remove)
+    {
+        /* Handle F1 key by sending out WM_HELP message */
+        if ((msg->message == WM_KEYUP) &&
+            (msg->wParam == VK_F1) &&
+            (msg->hwnd != GetDesktopWindow()) &&
+            !MENU_IsMenuActive())
+        {
+            HELPINFO hi;
+            hi.cbSize = sizeof(HELPINFO);
+            hi.iContextType = HELPINFO_WINDOW;
+            hi.iCtrlId = GetWindowLongA( msg->hwnd, GWL_ID );
+            hi.hItemHandle = msg->hwnd;
+            hi.dwContextId = GetWindowContextHelpId( msg->hwnd );
+            hi.MousePos = msg->pt;
+            SendMessageA(msg->hwnd, WM_HELP, 0, (LPARAM)&hi);
+        }
+    }
+
+    if (HOOK_CallHooksA( WH_KEYBOARD, remove ? HC_ACTION : HC_NOREMOVE,
+                         LOWORD(msg->wParam), msg->lParam ))
+    {
+        /* skip this message */
+        HOOK_CallHooksA( WH_CBT, HCBT_KEYSKIPPED, LOWORD(msg->wParam), msg->lParam );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *          process_raw_mouse_message
+ *
+ * returns TRUE if the contents of 'msg' should be passed to the application
+ */
+static BOOL process_raw_mouse_message( MSG *msg, ULONG_PTR extra_info )
+{
+    static MSG clk_msg;
+
+    POINT pt;
+    INT ht, hittest;
+
+    /* find the window to dispatch this mouse message to */
+
+    if (!(msg->hwnd = GetCapture()))
+    {
+        /* If no capture HWND, find window which contains the mouse position.
+         * Also find the position of the cursor hot spot (hittest) */
+        HWND hWndScope = (HWND)extra_info;
+        WND *pWndScope = IsWindow(hWndScope) ? WIN_FindWndPtr(hWndScope) : WIN_GetDesktop();
+        WND *pWnd;
+
+        ht = hittest = WINPOS_WindowFromPoint( pWndScope, msg->pt, &pWnd );
+        msg->hwnd = pWnd ? pWnd->hwndSelf : GetDesktopWindow();
+        WIN_ReleaseWndPtr( pWndScope );
+    }
+    else
+    {
+        MESSAGEQUEUE *queue = QUEUE_Lock( GetFastQueue16() );
+
+        ht = hittest = HTCLIENT;
+        if (queue)
+        {
+            ht = PERQDATA_GetCaptureInfo( queue->pQData );
+            QUEUE_Unlock(queue);
+        }
+    }
+
+    if (HOOK_IsHooked( WH_JOURNALRECORD ))
+    {
+        EVENTMSG event;
+        event.message = msg->message;
+        event.time    = msg->time;
+        event.hwnd    = msg->hwnd;
+        event.paramL  = msg->pt.x;
+        event.paramH  = msg->pt.y;
+        HOOK_CallHooksA( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
+    }
+
+    /* translate double clicks */
+
+    if ((msg->message == WM_LBUTTONDOWN) ||
+        (msg->message == WM_RBUTTONDOWN) ||
+        (msg->message == WM_MBUTTONDOWN))
+    {
+        BOOL update = TRUE;
+        /* translate double clicks -
+	 * note that ...MOUSEMOVEs can slip in between
+	 * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
+
+        if (GetClassLongA( msg->hwnd, GCL_STYLE ) & CS_DBLCLKS || ht != HTCLIENT )
+        {
+           if ((msg->message == clk_msg.message) &&
+               (msg->hwnd == clk_msg.hwnd) &&
+               (msg->time - clk_msg.time < doubleClickSpeed) &&
+               (abs(msg->pt.x - clk_msg.pt.x) < GetSystemMetrics(SM_CXDOUBLECLK)/2) &&
+               (abs(msg->pt.y - clk_msg.pt.y) < GetSystemMetrics(SM_CYDOUBLECLK)/2))
+           {
+               msg->message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
+               clk_msg.message = 0;
+               update = FALSE;
+           }
+        }
+        /* update static double click conditions */
+        if (update) clk_msg = *msg;
+    }
+
+    pt = msg->pt;
+    if (hittest != HTCLIENT)
+    {
+        msg->message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
+        msg->wParam = hittest;
+    }
+    else ScreenToClient( msg->hwnd, &pt );
+    msg->lParam = MAKELONG( pt.x, pt.y );
+    return TRUE;
+}
+
+
+/***********************************************************************
+ *          process_cooked_mouse_message
+ *
+ * returns TRUE if the contents of 'msg' should be passed to the application
+ */
+static BOOL process_cooked_mouse_message( MSG *msg, BOOL remove )
+{
+    INT hittest = HTCLIENT;
+    UINT raw_message = msg->message;
+    BOOL eatMsg;
+
+    if (msg->message >= WM_NCMOUSEFIRST && msg->message <= WM_NCMOUSELAST)
+    {
+        raw_message += WM_MOUSEFIRST - WM_NCMOUSEFIRST;
+        hittest = msg->wParam;
+    }
+    if (raw_message == WM_LBUTTONDBLCLK ||
+        raw_message == WM_RBUTTONDBLCLK ||
+        raw_message == WM_MBUTTONDBLCLK)
+    {
+        raw_message += WM_LBUTTONDOWN - WM_LBUTTONDBLCLK;
+    }
+
+    if (HOOK_IsHooked( WH_MOUSE ))
+    {
+        MOUSEHOOKSTRUCT hook;
+        hook.pt           = msg->pt;
+        hook.hwnd         = msg->hwnd;
+        hook.wHitTestCode = hittest;
+        hook.dwExtraInfo  = 0;
+        if (HOOK_CallHooksA( WH_MOUSE, remove ? HC_ACTION : HC_NOREMOVE,
+                             msg->message, (LPARAM)&hook ))
+        {
+            hook.pt           = msg->pt;
+            hook.hwnd         = msg->hwnd;
+            hook.wHitTestCode = hittest;
+            hook.dwExtraInfo  = 0;
+            HOOK_CallHooksA( WH_CBT, HCBT_CLICKSKIPPED, msg->message, (LPARAM)&hook );
+            return FALSE;
+        }
+    }
+
+    if ((hittest == HTERROR) || (hittest == HTNOWHERE))
+    {
+        SendMessageA( msg->hwnd, WM_SETCURSOR, msg->hwnd, MAKELONG( hittest, raw_message ));
+        return FALSE;
+    }
+
+    if (!remove || GetCapture()) return TRUE;
+
+    eatMsg = FALSE;
+
+    if ((raw_message == WM_LBUTTONDOWN) ||
+        (raw_message == WM_RBUTTONDOWN) ||
+        (raw_message == WM_MBUTTONDOWN))
+    {
+        HWND hwndTop = WIN_GetTopParent( msg->hwnd );
+
+        /* Send the WM_PARENTNOTIFY,
+         * note that even for double/nonclient clicks
+         * notification message is still WM_L/M/RBUTTONDOWN.
+         */
+        MSG_SendParentNotify( msg->hwnd, raw_message, 0, msg->pt );
+
+        /* Activate the window if needed */
+
+        if (msg->hwnd != GetActiveWindow() && hwndTop != GetDesktopWindow())
+        {
+            LONG ret = SendMessageA( msg->hwnd, WM_MOUSEACTIVATE, hwndTop,
+                                     MAKELONG( hittest, raw_message ) );
+
+            switch(ret)
+            {
+            case MA_NOACTIVATEANDEAT:
+                eatMsg = TRUE;
+                /* fall through */
+            case MA_NOACTIVATE:
+                break;
+            case MA_ACTIVATEANDEAT:
+                eatMsg = TRUE;
+                /* fall through */
+            case MA_ACTIVATE:
+                if (hwndTop != GetForegroundWindow() )
+                {
+                    if (!WINPOS_SetActiveWindow( hwndTop, TRUE , TRUE ))
+                        eatMsg = TRUE;
+                }
+                break;
+            default:
+                WARN( "unknown WM_MOUSEACTIVATE code %ld\n", ret );
+                break;
+            }
+        }
+    }
+
+    /* send the WM_SETCURSOR message */
+
+    /* Windows sends the normal mouse message as the message parameter
+       in the WM_SETCURSOR message even if it's non-client mouse message */
+    SendMessageA( msg->hwnd, WM_SETCURSOR, msg->hwnd, MAKELONG( hittest, raw_message ));
+
+    return !eatMsg;
+}
+
+
+/***********************************************************************
+ *          process_hardware_message
+ *
+ * returns TRUE if the contents of 'msg' should be passed to the application
+ */
+static BOOL process_hardware_message( QMSG *qmsg, HWND hwnd_filter,
+                                      UINT first, UINT last, BOOL remove )
+{
+    if (qmsg->kind == RAW_HW_MESSAGE)
+    {
+        /* if it is raw, try to cook it first */
+        if (is_keyboard_message( qmsg->msg.message ))
+        {
+            if (!process_raw_keyboard_message( &qmsg->msg, qmsg->extraInfo )) return FALSE;
+        }
+        else if (is_mouse_message( qmsg->msg.message ))
+        {
+            if (!process_raw_mouse_message( &qmsg->msg, qmsg->extraInfo )) return FALSE;
+        }
+        else goto invalid;
+
+        /* check destination thread and filters */
+        if (!check_message_filter( &qmsg->msg, hwnd_filter, first, last ) ||
+            GetWindowThreadProcessId( qmsg->msg.hwnd, NULL ) != GetCurrentThreadId())
+        {
+            /* queue it for later, or for another thread */
+            queue_hardware_message( &qmsg->msg, qmsg->extraInfo, COOKED_HW_MESSAGE );
+            return FALSE;
+        }
+
+        /* save the message in the cooked queue if we didn't want to remove it */
+        if (!remove) queue_hardware_message( &qmsg->msg, qmsg->extraInfo, COOKED_HW_MESSAGE );
+    }
+
+    if (is_keyboard_message( qmsg->msg.message ))
+        return process_cooked_keyboard_message( &qmsg->msg, remove );
+
+    if (is_mouse_message( qmsg->msg.message ))
+        return process_cooked_mouse_message( &qmsg->msg, remove );
+
+ invalid:
+    ERR( "unknown message type %x\n", qmsg->msg.message );
+    return FALSE;
 }
 
 
@@ -766,35 +573,33 @@
  *    0 if error or timeout
  *    1 if successful
  */
-static LRESULT MSG_SendMessageInterThread( HQUEUE16 hDestQueue,
-                                           HWND hwnd, UINT msg,
+static LRESULT MSG_SendMessageInterThread( DWORD dest_tid, HWND hwnd, UINT msg,
                                            WPARAM wParam, LPARAM lParam,
                                            DWORD timeout, WORD type,
                                            LRESULT *pRes)
 {
-    MESSAGEQUEUE *destQ;
     BOOL ret;
     int iWndsLocks;
     LRESULT result = 0;
 
     TRACE( "hwnd %x msg %x (%s) wp %x lp %lx\n", hwnd, msg, SPY_GetMsgName(msg), wParam, lParam );
 
-    if (!(destQ = QUEUE_Lock( hDestQueue ))) return 0;
-
     SERVER_START_REQ( send_message )
     {
-        req->posted = FALSE;
-        req->id     = destQ->teb->tid;
+        req->kind   = SEND_MESSAGE;
+        req->id     = (void *)dest_tid;
         req->type   = type;
         req->win    = hwnd;
         req->msg    = msg;
         req->wparam = wParam;
         req->lparam = lParam;
+        req->x      = 0;
+        req->y      = 0;
+        req->time   = GetCurrentTime();
         req->info   = 0;
         ret = !SERVER_CALL_ERR();
     }
     SERVER_END_REQ;
-    QUEUE_Unlock( destQ );
     if (!ret) return 0;
 
     iWndsLocks = WIN_SuspendWndsLock();
@@ -960,11 +765,11 @@
 static BOOL MSG_PeekMessage( int type, LPMSG msg_out, HWND hwnd, 
                              DWORD first, DWORD last, WORD flags, BOOL peek )
 {
-    int changeBits, mask;
+    int mask;
     MESSAGEQUEUE *msgQueue;
-    HQUEUE16 hQueue;
+    HQUEUE16 hQueue = GetFastQueue16();
     int iWndsLocks;
-    MSG msg;
+    QMSG qmsg;
 
     mask = QS_POSTMESSAGE | QS_SENDMESSAGE;  /* Always selected */
     if (first || last)
@@ -982,166 +787,110 @@
 
     iWndsLocks = WIN_SuspendWndsLock();
 
+    /* check for graphics events */
+    if (USER_Driver.pMsgWaitForMultipleObjectsEx)
+        USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
+
     while(1)
     {
+        /* FIXME: should remove this */
         WORD wakeBits = HIWORD(GetQueueStatus( mask ));
 
-	hQueue   = GetFastQueue16();
-        msgQueue = QUEUE_Lock( hQueue );
-        if (!msgQueue)
-        {
-            WIN_RestoreWndsLock(iWndsLocks);
-            return FALSE;
-        }
-
-#if 0
-        /* First handle a message put by SendMessage() */
-
-        while ( QUEUE_ReceiveMessage( msgQueue ) )
-            ;
-
-        /* Now handle a WM_QUIT message */
-
-        EnterCriticalSection( &msgQueue->cSection );
-        if (msgQueue->wPostQMsg &&
-	   (!first || WM_QUIT >= first) && 
-	   (!last || WM_QUIT <= last) )
-        {
-            msg.hwnd    = hwnd;
-            msg.message = WM_QUIT;
-            msg.wParam  = msgQueue->wExitCode;
-            msg.lParam  = 0;
-            if (flags & PM_REMOVE) msgQueue->wPostQMsg = 0;
-            LeaveCriticalSection( &msgQueue->cSection );
-            break;
-        }
-        LeaveCriticalSection( &msgQueue->cSection );
-#endif
-
-        /* Now find a normal message */
-
   retry:
-        if (wakeBits & (QS_SENDMESSAGE|QS_POSTMESSAGE|QS_TIMER|QS_PAINT))
+        if (QUEUE_FindMsg( hwnd, first, last, flags & PM_REMOVE, &qmsg ))
         {
-            QMSG qmsg;
-            if (QUEUE_FindMsg( hwnd, first, last, flags & PM_REMOVE, FALSE, &qmsg ))
+            if (qmsg.kind == RAW_HW_MESSAGE || qmsg.kind == COOKED_HW_MESSAGE)
+            {
+                if (!process_hardware_message( &qmsg, hwnd, first, last, flags & PM_REMOVE ))
+                    goto retry;
+            }
+            else
             {
                 /* Try to convert message to requested type */
-                MSG tmpMsg = qmsg.msg;
-                if ( !MSG_ConvertMsg( &tmpMsg, qmsg.type, type ) )
+                if ( !MSG_ConvertMsg( &qmsg.msg, qmsg.type, type ) )
                 {
                     ERR( "Message %s of wrong type contains pointer parameters. Skipped!\n",
-                         SPY_GetMsgName(tmpMsg.message));
+                         SPY_GetMsgName(qmsg.msg.message));
                     /* remove it (FIXME) */
-                    if (!(flags & PM_REMOVE)) QUEUE_FindMsg( hwnd, first, last, TRUE, FALSE, &qmsg );
+                    if (!(flags & PM_REMOVE)) QUEUE_FindMsg( hwnd, first, last, TRUE, &qmsg );
                     goto retry;
                 }
+            }
 
-                msg = tmpMsg;
-                msgQueue->GetMessageTimeVal      = msg.time;
-                msgQueue->GetMessagePosVal       = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y );
-                msgQueue->GetMessageExtraInfoVal = qmsg.extraInfo;
-
-                /* need to fill the window handle for WM_PAINT message */
-                if (msg.message == WM_PAINT)
+            /* need to fill the window handle for WM_PAINT message */
+            if (qmsg.msg.message == WM_PAINT)
+            {
+                if ((qmsg.msg.hwnd = WIN_FindWinToRepaint( hwnd, hQueue )))
                 {
-                    WND* wndPtr;
-                    msg.hwnd = WIN_FindWinToRepaint( hwnd , hQueue );
-                    if ((wndPtr = WIN_FindWndPtr(msg.hwnd)))
+                    if (IsIconic( qmsg.msg.hwnd ) && GetClassLongA( qmsg.msg.hwnd, GCL_HICON ))
                     {
-                        if( wndPtr->dwStyle & WS_MINIMIZE &&
-                            (HICON) GetClassLongA(wndPtr->hwndSelf, GCL_HICON) )
-                        {
-                            msg.message = WM_PAINTICON;
-                            msg.wParam = 1;
-                        }
-
-                        if( !hwnd || msg.hwnd == hwnd || IsChild16(hwnd,msg.hwnd) )
-                        {
-                            if( wndPtr->flags & WIN_INTERNAL_PAINT && !wndPtr->hrgnUpdate)
-                            {
-                                wndPtr->flags &= ~WIN_INTERNAL_PAINT;
-                                QUEUE_DecPaintCount( hQueue );
-                            }
-                            WIN_ReleaseWndPtr(wndPtr);
-                            break;
-                        }
-                        WIN_ReleaseWndPtr(wndPtr);
+                        qmsg.msg.message = WM_PAINTICON;
+                        qmsg.msg.wParam = 1;
+                    }
+                    if( !hwnd || qmsg.msg.hwnd == hwnd || IsChild(hwnd,qmsg.msg.hwnd) )
+                    {
+                        /* clear internal paint flag */
+                        RedrawWindow( qmsg.msg.hwnd, NULL, 0,
+                                      RDW_NOINTERNALPAINT | RDW_NOCHILDREN );
+                        break;
                     }
                 }
-                else break;
             }
+            else break;
         }
 
-        changeBits = MSG_JournalPlayBackMsg();
-#if 0  /* FIXME */
-        EnterCriticalSection( &msgQueue->cSection );
-        msgQueue->changeBits |= changeBits;
-        LeaveCriticalSection( &msgQueue->cSection );
-#endif
-
-        /* Now find a hardware event */
-
-        if (MSG_PeekHardwareMsg( &msg, hwnd, first, last, flags & PM_REMOVE ))
-        {
-            /* Got one */
-	    msgQueue->GetMessageTimeVal      = msg.time;
-            msgQueue->GetMessagePosVal       = MAKELONG( (INT16)msg.pt.x, (INT16)msg.pt.y );
-	    msgQueue->GetMessageExtraInfoVal = 0;  /* Always 0 for now */
-            break;
-        }
+        /* FIXME: should be done before checking for hw events */
+        MSG_JournalPlayBackMsg();
 
         if (peek)
         {
 #if 0  /* FIXME */
             if (!(flags & PM_NOYIELD)) UserYield16();
 #endif
-            /* check for graphics events */
-            if (USER_Driver.pMsgWaitForMultipleObjectsEx)
-                USER_Driver.pMsgWaitForMultipleObjectsEx( 0, NULL, 0, 0, 0 );
-
-            QUEUE_Unlock( msgQueue );
             WIN_RestoreWndsLock(iWndsLocks);
             return FALSE;
         }
 
         QUEUE_WaitBits( mask, INFINITE );
-        QUEUE_Unlock( msgQueue );
     }
 
     WIN_RestoreWndsLock(iWndsLocks);
-    
-    /* instead of unlocking queue for every break condition, all break
-       condition will fall here */
-    QUEUE_Unlock( msgQueue );
-    
+
+    if ((msgQueue = QUEUE_Lock( hQueue )))
+    {
+        msgQueue->GetMessageTimeVal      = qmsg.msg.time;
+        msgQueue->GetMessagePosVal       = MAKELONG( qmsg.msg.pt.x, qmsg.msg.pt.y );
+        msgQueue->GetMessageExtraInfoVal = qmsg.extraInfo;
+        QUEUE_Unlock( msgQueue );
+    }
+
       /* We got a message */
     if (flags & PM_REMOVE)
     {
-	WORD message = msg.message;
+	WORD message = qmsg.msg.message;
 
 	if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
 	{
-	    BYTE *p = &QueueKeyStateTable[msg.wParam & 0xff];
+	    BYTE *p = &QueueKeyStateTable[qmsg.msg.wParam & 0xff];
 
 	    if (!(*p & 0x80))
 		*p ^= 0x01;
 	    *p |= 0x80;
 	}
 	else if (message == WM_KEYUP || message == WM_SYSKEYUP)
-	    QueueKeyStateTable[msg.wParam & 0xff] &= ~0x80;
+	    QueueKeyStateTable[qmsg.msg.wParam & 0xff] &= ~0x80;
     }
 
     /* copy back our internal safe copy of message data to msg_out.
      * msg_out is a variable from the *program*, so it can't be used
      * internally as it can get "corrupted" by our use of SendMessage()
      * (back to the program) inside the message handling itself. */
-    *msg_out = msg;
+    *msg_out = qmsg.msg;
     if (peek)
         return TRUE;
 
     else
-        return (msg.message != WM_QUIT);
+        return (qmsg.msg.message != WM_QUIT);
 }
 
 /***********************************************************************
@@ -1408,13 +1157,16 @@
 
     SERVER_START_REQ( send_message )
     {
-        req->posted = TRUE;
+        req->kind   = POST_MESSAGE;
         req->id     = (void *)tid;
         req->type   = type;
         req->win    = hwnd;
         req->msg    = message;
         req->wparam = wParam;
         req->lparam = lParam;
+        req->x      = 0;
+        req->y      = 0;
+        req->time   = GetCurrentTime();
         req->info   = 0;
         res = SERVER_CALL();
     }
@@ -1643,6 +1395,8 @@
     WND * wndPtr = 0;
     WND **list, **ppWnd;
     LRESULT ret = 1;
+    DWORD dest_tid;
+    WNDPROC winproc;
 
     if (pRes) *pRes = 0;
 
@@ -1716,17 +1470,23 @@
     }
     if (QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))
     {
-        ret = 0;  /* Don't send anything if the task is dying */
-        goto END;
+        WIN_ReleaseWndPtr( wndPtr );
+        return 0;  /* Don't send anything if the task is dying */
     }
+    winproc = (WNDPROC)wndPtr->winproc;
+    WIN_ReleaseWndPtr( wndPtr );
+
     if (type != QMSG_WIN16)
         SPY_EnterMessage( SPY_SENDMESSAGE, hwnd, msg, wParam, lParam );
     else
         SPY_EnterMessage( SPY_SENDMESSAGE16, hwnd, msg, wParam, lParam );
 
-    if (wndPtr->hmemTaskQ && wndPtr->hmemTaskQ != GetFastQueue16())
-        ret = MSG_SendMessageInterThread( wndPtr->hmemTaskQ, hwnd, msg,
+    dest_tid = GetWindowThreadProcessId( hwnd, NULL );
+    if (dest_tid && dest_tid != GetCurrentThreadId())
+    {
+        ret = MSG_SendMessageInterThread( dest_tid, hwnd, msg,
                                           wParam, lParam, timeout, type, pRes );
+    }
     else
     {
         LRESULT res = 0;
@@ -1735,13 +1495,13 @@
         switch(type)
         {
         case QMSG_WIN16:
-            res = CallWindowProc16( (WNDPROC16)wndPtr->winproc, hwnd, msg, wParam, lParam );
+            res = CallWindowProc16( (WNDPROC16)winproc, hwnd, msg, wParam, lParam );
             break;
         case QMSG_WIN32A:
-            res = CallWindowProcA( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam );
+            res = CallWindowProcA( winproc, hwnd, msg, wParam, lParam );
             break;
         case QMSG_WIN32W:
-            res = CallWindowProcW( (WNDPROC)wndPtr->winproc, hwnd, msg, wParam, lParam );
+            res = CallWindowProcW( winproc, hwnd, msg, wParam, lParam );
             break;
         }
         if (pRes) *pRes = res;
@@ -1751,8 +1511,7 @@
         SPY_ExitMessage( SPY_RESULT_OK, hwnd, msg, pRes?*pRes:0, wParam, lParam );
     else
         SPY_ExitMessage( SPY_RESULT_OK16, hwnd, msg, pRes?*pRes:0, wParam, lParam );
-END:
-    WIN_ReleaseWndPtr(wndPtr);
+
     return ret;
 }
 
@@ -2471,7 +2230,7 @@
 	DWORD dwFlags,LPDWORD recipients,UINT uMessage,WPARAM wParam,
 	LPARAM lParam
 ) {
-	FIXME_(sendmsg)("(%08lx,%08lx,%08x,%08x,%08lx): stub!\n",
+	FIXME("(%08lx,%08lx,%08x,%08x,%08lx): stub!\n",
 	      dwFlags,*recipients,uMessage,wParam,lParam
 	);
 	return 0;
diff --git a/windows/queue.c b/windows/queue.c
index c2413c1..1a9b4af 100644
--- a/windows/queue.c
+++ b/windows/queue.c
@@ -21,20 +21,13 @@
 #include "server.h"
 #include "spy.h"
 
-DECLARE_DEBUG_CHANNEL(sendmsg);
 DEFAULT_DEBUG_CHANNEL(msg);
 
 #define MAX_QUEUE_SIZE   120  /* Max. size of a message queue */
 
 static HQUEUE16 hExitingQueue = 0;
-static HQUEUE16 hmemSysMsgQueue = 0;
-static MESSAGEQUEUE *sysMsgQueue = NULL;
 static PERQUEUEDATA *pQDataWin16 = NULL;  /* Global perQData for Win16 tasks */
 
-static MESSAGEQUEUE *pMouseQueue = NULL;  /* Queue for last mouse message */
-static MESSAGEQUEUE *pKbdQueue = NULL;    /* Queue for last kbd message */
-
-HQUEUE16 hCursorQueue = 0;
 HQUEUE16 hActiveQueue = 0;
 
 
@@ -470,8 +463,7 @@
     }
 
     msgQueue->magic = 0;
-    
-    if( hCursorQueue == hQueue ) hCursorQueue = 0;
+
     if( hActiveQueue == hQueue ) hActiveQueue = 0;
 
     HeapLock( GetProcessHeap() );  /* FIXME: a bit overkill */
@@ -496,142 +488,10 @@
 
 
 /***********************************************************************
- *           QUEUE_CreateSysMsgQueue
+ *           handle_sent_message
  *
- * Create the system message queue, and set the double-click speed.
- * Must be called only once.
+ * Handle the reception of a sent message by calling the corresponding window proc
  */
-BOOL QUEUE_CreateSysMsgQueue( int size )
-{
-    /* Note: We dont need perQ data for the system message queue */
-    if (!(hmemSysMsgQueue = QUEUE_CreateMsgQueue( FALSE )))
-        return FALSE;
-    FarSetOwner16( hmemSysMsgQueue, 0 );
-    sysMsgQueue = (MESSAGEQUEUE *) GlobalLock16( hmemSysMsgQueue );
-    return TRUE;
-}
-
-
-/***********************************************************************
- *           QUEUE_GetSysQueue
- */
-MESSAGEQUEUE *QUEUE_GetSysQueue(void)
-{
-    return sysMsgQueue;
-}
-
-
-/***********************************************************************
- *           QUEUE_SetWakeBit
- *
- * See "Windows Internals", p.449
- */
-static BOOL QUEUE_TrySetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear, BOOL always )
-{
-    BOOL wake = FALSE;
-
-    TRACE_(msg)("queue = %04x, set = %04x, clear = %04x, always = %d\n",
-                queue->self, set, clear, always );
-    if (!queue->server_queue) return FALSE;
-
-    SERVER_START_REQ( set_queue_bits )
-    {
-        req->handle    = queue->server_queue;
-        req->set       = set;
-        req->clear     = clear;
-        req->mask_cond = always ? 0 : set;
-        if (!SERVER_CALL()) wake = (req->changed_mask & set) != 0;
-    }
-    SERVER_END_REQ;
-
-    if (wake || always)
-    {
-        if (set & QS_MOUSE) pMouseQueue = queue;
-        if (set & QS_KEY) pKbdQueue = queue;
-    }
-    return wake;
-}
-void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear )
-{
-    QUEUE_TrySetWakeBit( queue, set, clear, TRUE );
-}
-
-
-/***********************************************************************
- *           QUEUE_ClearWakeBit
- */
-void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
-{
-    QUEUE_SetWakeBit( queue, 0, bit );
-}
-
-/***********************************************************************
- *           QUEUE_WaitBits
- *
- * See "Windows Internals", p.447
- *
- * return values:
- *    0 if exit with timeout
- *    1 otherwise
- */
-int QUEUE_WaitBits( WORD bits, DWORD timeout )
-{
-    MESSAGEQUEUE *queue;
-    HQUEUE16 hQueue;
-
-    TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
-
-    hQueue = GetFastQueue16();
-    if (!(queue = QUEUE_Lock( hQueue ))) return 0;
-    
-    for (;;)
-    {
-        unsigned int wake_bits = 0, changed_bits = 0;
-        DWORD dwlc;
-
-        SERVER_START_REQ( set_queue_mask )
-        {
-            req->wake_mask    = QS_SENDMESSAGE;
-            req->changed_mask = bits | QS_SENDMESSAGE;
-            req->skip_wait    = 1;
-            if (!SERVER_CALL())
-            {
-                wake_bits    = req->wake_bits;
-                changed_bits = req->changed_bits;
-            }
-        }
-        SERVER_END_REQ;
-
-        if (changed_bits & bits)
-        {
-            /* One of the bits is set; we can return */
-            QUEUE_Unlock( queue );
-            return 1;
-        }
-        if (wake_bits & QS_SENDMESSAGE)
-        {
-            /* Process the sent message immediately */
-            QMSG msg;
-            QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg );
-            continue;  /* nested sm crux */
-        }
-
-        TRACE_(msg)("(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
-                    queue->self, bits, wake_bits, changed_bits );
-
-        ReleaseThunkLock( &dwlc );
-        if (dwlc) TRACE_(msg)("had win16 lock\n");
-
-        if (USER_Driver.pMsgWaitForMultipleObjectsEx)
-            USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, timeout, 0, 0 );
-        else
-            WaitForSingleObject( queue->server_queue, timeout );
-        if (dwlc) RestoreThunkLock( dwlc );
-    }
-}
-
-
-/* handle the reception of a sent message by calling the corresponding window proc */
 static void handle_sent_message( QMSG *msg )
 {
     LRESULT result = 0;
@@ -680,13 +540,150 @@
 
 
 /***********************************************************************
+ *           process_sent_messages
+ *
+ * Process all pending sent messages
+ */
+static void process_sent_messages(void)
+{
+    QMSG msg;
+    unsigned int res;
+
+    for (;;)
+    {
+        SERVER_START_REQ( get_message )
+        {
+            req->flags = GET_MSG_REMOVE | GET_MSG_SENT_ONLY;
+            req->get_win   = 0;
+            req->get_first = 0;
+            req->get_last  = ~0;
+            if (!(res = SERVER_CALL()))
+            {
+                msg.type        = req->type;
+                msg.msg.hwnd    = req->win;
+                msg.msg.message = req->msg;
+                msg.msg.wParam  = req->wparam;
+                msg.msg.lParam  = req->lparam;
+                msg.msg.time    = req->time;
+                msg.msg.pt.x    = req->x;
+                msg.msg.pt.y    = req->y;
+                msg.extraInfo   = req->info;
+            }
+        }
+        SERVER_END_REQ;
+
+        if (res) break;
+        handle_sent_message( &msg );
+    }
+}
+
+
+
+/***********************************************************************
+ *           QUEUE_SetWakeBit
+ *
+ * See "Windows Internals", p.449
+ */
+void QUEUE_SetWakeBit( MESSAGEQUEUE *queue, WORD set, WORD clear )
+{
+    TRACE_(msg)("queue = %04x, set = %04x, clear = %04x\n",
+                queue->self, set, clear );
+    if (!queue->server_queue) return;
+
+    SERVER_START_REQ( set_queue_bits )
+    {
+        req->handle    = queue->server_queue;
+        req->set       = set;
+        req->clear     = clear;
+        req->mask_cond = 0;
+        SERVER_CALL();
+    }
+    SERVER_END_REQ;
+}
+
+
+/***********************************************************************
+ *           QUEUE_ClearWakeBit
+ */
+void QUEUE_ClearWakeBit( MESSAGEQUEUE *queue, WORD bit )
+{
+    QUEUE_SetWakeBit( queue, 0, bit );
+}
+
+
+/***********************************************************************
+ *           QUEUE_WaitBits
+ *
+ * See "Windows Internals", p.447
+ *
+ * return values:
+ *    0 if exit with timeout
+ *    1 otherwise
+ */
+int QUEUE_WaitBits( WORD bits, DWORD timeout )
+{
+    MESSAGEQUEUE *queue;
+    HQUEUE16 hQueue;
+
+    TRACE_(msg)("q %04x waiting for %04x\n", GetFastQueue16(), bits);
+
+    hQueue = GetFastQueue16();
+    if (!(queue = QUEUE_Lock( hQueue ))) return 0;
+    
+    for (;;)
+    {
+        unsigned int wake_bits = 0, changed_bits = 0;
+        DWORD dwlc;
+
+        SERVER_START_REQ( set_queue_mask )
+        {
+            req->wake_mask    = QS_SENDMESSAGE;
+            req->changed_mask = bits | QS_SENDMESSAGE;
+            req->skip_wait    = 1;
+            if (!SERVER_CALL())
+            {
+                wake_bits    = req->wake_bits;
+                changed_bits = req->changed_bits;
+            }
+        }
+        SERVER_END_REQ;
+
+        if (changed_bits & bits)
+        {
+            /* One of the bits is set; we can return */
+            QUEUE_Unlock( queue );
+            return 1;
+        }
+        if (wake_bits & QS_SENDMESSAGE)
+        {
+            /* Process the sent message immediately */
+            process_sent_messages();
+            continue;  /* nested sm crux */
+        }
+
+        TRACE_(msg)("(%04x) mask=%08x, bits=%08x, changed=%08x, waiting\n",
+                    queue->self, bits, wake_bits, changed_bits );
+
+        ReleaseThunkLock( &dwlc );
+        if (dwlc) TRACE_(msg)("had win16 lock\n");
+
+        if (USER_Driver.pMsgWaitForMultipleObjectsEx)
+            USER_Driver.pMsgWaitForMultipleObjectsEx( 1, &queue->server_queue, timeout, 0, 0 );
+        else
+            WaitForSingleObject( queue->server_queue, timeout );
+        if (dwlc) RestoreThunkLock( dwlc );
+    }
+}
+
+
+/***********************************************************************
  *           QUEUE_FindMsg
  *
- * Find a message matching the given parameters. Return -1 if none available.
+ * Find a message matching the given parameters. Return FALSE if none available.
  */
-BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, BOOL sent_only, QMSG *msg )
+BOOL QUEUE_FindMsg( HWND hwnd, UINT first, UINT last, BOOL remove, QMSG *msg )
 {
-    BOOL ret = FALSE, sent = FALSE;
+    BOOL ret = FALSE;
 
     if (!first && !last) last = ~0;
 
@@ -694,28 +691,27 @@
     {
         SERVER_START_REQ( get_message )
         {
-            req->remove    = remove;
-            req->posted    = !sent_only;
+            req->flags     = remove ? GET_MSG_REMOVE : 0;
             req->get_win   = hwnd;
             req->get_first = first;
             req->get_last  = last;
             if ((ret = !SERVER_CALL()))
             {
-                sent             = req->sent;
+                msg->kind        = req->kind;
                 msg->type        = req->type;
                 msg->msg.hwnd    = req->win;
                 msg->msg.message = req->msg;
                 msg->msg.wParam  = req->wparam;
                 msg->msg.lParam  = req->lparam;
-                msg->msg.time    = 0;  /* FIXME */
-                msg->msg.pt.x    = 0;  /* FIXME */
-                msg->msg.pt.y    = 0;  /* FIXME */
+                msg->msg.time    = req->time;
+                msg->msg.pt.x    = req->x;
+                msg->msg.pt.y    = req->y;
                 msg->extraInfo   = req->info;
             }
         }
         SERVER_END_REQ;
 
-        if (!ret || !sent) break;
+        if (!ret || (msg->kind != SEND_MESSAGE)) break;
         handle_sent_message( msg );
     }
 
@@ -773,92 +769,6 @@
 
 
 /***********************************************************************
- *           hardware_event
- *
- * Add an event to the system message queue.
- * Note: the position is relative to the desktop window.
- */
-void hardware_event( UINT message, WPARAM wParam, LPARAM lParam,
-		     int xPos, int yPos, DWORD time, DWORD extraInfo )
-{
-    MSG *msg;
-    QMSG  *qmsg;
-    MESSAGEQUEUE *queue;
-    int  mergeMsg = 0;
-
-    if (!sysMsgQueue) return;
-
-    EnterCriticalSection( &sysMsgQueue->cSection );
-
-    /* Merge with previous event if possible */
-    qmsg = sysMsgQueue->lastMsg;
-
-    if ((message == WM_MOUSEMOVE) && sysMsgQueue->lastMsg)
-    {
-        msg = &(sysMsgQueue->lastMsg->msg);
-        
-	if ((msg->message == message) && (msg->wParam == wParam))
-        {
-            /* Merge events */
-            qmsg = sysMsgQueue->lastMsg;
-            mergeMsg = 1;
-        }
-    }
-
-    if (!mergeMsg)
-    {
-        /* Should I limit the number of messages in
-          the system message queue??? */
-
-        /* Don't merge allocate a new msg in the global heap */
-        
-        if (!(qmsg = (QMSG *) HeapAlloc( GetProcessHeap(), 0, sizeof(QMSG) ) ))
-        {
-            LeaveCriticalSection( &sysMsgQueue->cSection );
-            return;
-        }
-        
-        /* put message at the end of the linked list */
-        qmsg->nextMsg = 0;
-        qmsg->prevMsg = sysMsgQueue->lastMsg;
-
-        if (sysMsgQueue->lastMsg)
-            sysMsgQueue->lastMsg->nextMsg = qmsg;
-
-        /* set last and first anchor index in system message queue */
-        sysMsgQueue->lastMsg = qmsg;
-        if (!sysMsgQueue->firstMsg)
-            sysMsgQueue->firstMsg = qmsg;
-    }
-
-      /* Store message */
-    msg = &(qmsg->msg);
-    msg->hwnd    = 0;
-    msg->message = message;
-    msg->wParam  = wParam;
-    msg->lParam  = lParam;
-    msg->time    = time;
-    msg->pt.x    = xPos;
-    msg->pt.y    = yPos;
-    qmsg->extraInfo = extraInfo;
-    qmsg->type      = QMSG_HARDWARE;
-
-    LeaveCriticalSection( &sysMsgQueue->cSection );
-
-    if ((queue = QUEUE_Lock( GetFastQueue16() )))
-    {
-        WORD wakeBit;
-
-        if ((message >= WM_KEYFIRST) && (message <= WM_KEYLAST)) wakeBit = QS_KEY;
-        else wakeBit = (message == WM_MOUSEMOVE) ? QS_MOUSEMOVE : QS_MOUSEBUTTON;
-
-        QUEUE_SetWakeBit( queue, wakeBit, 0 );
-        QUEUE_Unlock( queue );
-    }
-}
-
-
-/***********************************************************************
  *	     QUEUE_GetQueueTask
  */
 HTASK16 QUEUE_GetQueueTask( HQUEUE16 hQueue )
@@ -1116,9 +1026,8 @@
         ret = MsgWaitForMultipleObjects ( 1, &idle_event, FALSE, dwTimeOut, QS_SENDMESSAGE );
         if ( ret == ( WAIT_OBJECT_0 + 1 )) 
         {
-            QMSG msg;
-            QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg );
-            continue; 
+            process_sent_messages();
+            continue;
         }
         if ( ret == WAIT_TIMEOUT || ret == 0xFFFFFFFF ) 
         {
@@ -1141,18 +1050,14 @@
  */
 void WINAPI UserYield16(void)
 {
-    QMSG msg;
-
     /* Handle sent messages */
-    while (QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg ))
-        ;
+    process_sent_messages();
 
     /* Yield */
     OldYield16();
 
     /* Handle sent messages again */
-    while (QUEUE_FindMsg( 0, 0, 0, TRUE, TRUE, &msg ))
-        ;
+    process_sent_messages();
 }
 
 /***********************************************************************