[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / msgqueue.c
index b03ba84..e0210da 100644 (file)
@@ -1,21 +1,3 @@
-/*
- *  ReactOS W32 Subsystem
- *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
 /*
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
 /* GLOBALS *******************************************************************/
 
 static PAGED_LOOKASIDE_LIST MessageLookasideList;
+MOUSEMOVEPOINT MouseHistoryOfMoves[64];
+INT gcur_count = 0;
 
 /* FUNCTIONS *****************************************************************/
 
+INIT_FUNCTION
+NTSTATUS
+NTAPI
+MsqInitializeImpl(VOID)
+{
+   ExInitializePagedLookasideList(&MessageLookasideList,
+                                  NULL,
+                                  NULL,
+                                  0,
+                                  sizeof(USER_MESSAGE),
+                                  TAG_USRMSG,
+                                  256);
+
+   return(STATUS_SUCCESS);
+}
+
+DWORD FASTCALL UserGetKeyState(DWORD key)
+{
+   DWORD ret = 0;
+   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE MessageQueue;
+
+   pti = PsGetCurrentThreadWin32Thread();
+   MessageQueue = pti->MessageQueue;
+
+   if( key < 0x100 )
+   {
+       ret = (DWORD)MessageQueue->KeyState[key];
+   }
+
+   return ret;
+}
+
+/* change the input key state for a given key */
+static void set_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue, UCHAR key, BOOL down )
+{
+    DPRINT("set_input_key_state key:%d, down:%d\n", key, down);
+
+    if (down)
+    {
+        if (!(MessageQueue->KeyState[key] & KS_DOWN_BIT))
+        {
+            MessageQueue->KeyState[key] ^= KS_LOCK_BIT;
+        }
+        MessageQueue->KeyState[key] |= KS_DOWN_BIT;
+    }
+    else
+    {
+        MessageQueue->KeyState[key] &= ~KS_DOWN_BIT;
+    }
+}
+
+/* update the input key state for a keyboard message */
+static void update_input_key_state( PUSER_MESSAGE_QUEUE MessageQueue, MSG* msg )
+{
+    UCHAR key;
+    BOOL down = 0;
+
+    DPRINT("update_input_key_state message:%d\n", msg->message);
+
+    switch (msg->message)
+    {
+    case WM_LBUTTONDOWN:
+        down = 1;
+        /* fall through */
+    case WM_LBUTTONUP:
+        set_input_key_state( MessageQueue, VK_LBUTTON, down );
+        break;
+    case WM_MBUTTONDOWN:
+        down = 1;
+        /* fall through */
+    case WM_MBUTTONUP:
+        set_input_key_state( MessageQueue, VK_MBUTTON, down );
+        break;
+    case WM_RBUTTONDOWN:
+        down = 1;
+        /* fall through */
+    case WM_RBUTTONUP:
+        set_input_key_state( MessageQueue, VK_RBUTTON, down );
+        break;
+    case WM_XBUTTONDOWN:
+        down = 1;
+        /* fall through */
+    case WM_XBUTTONUP:
+        if (msg->wParam == XBUTTON1)
+            set_input_key_state( MessageQueue, VK_XBUTTON1, down );
+        else if (msg->wParam == XBUTTON2)
+            set_input_key_state( MessageQueue, VK_XBUTTON2, down );
+        break;
+    case WM_KEYDOWN:
+    case WM_SYSKEYDOWN:
+        down = 1;
+        /* fall through */
+    case WM_KEYUP:
+    case WM_SYSKEYUP:
+        key = (UCHAR)msg->wParam;
+        set_input_key_state( MessageQueue, key, down );
+        switch(key)
+        {
+        case VK_LCONTROL:
+        case VK_RCONTROL:
+            down = (MessageQueue->KeyState[VK_LCONTROL] | MessageQueue->KeyState[VK_RCONTROL]) & KS_DOWN_BIT;
+            set_input_key_state( MessageQueue, VK_CONTROL, down );
+            break;
+        case VK_LMENU:
+        case VK_RMENU:
+            down = (MessageQueue->KeyState[VK_LMENU] | MessageQueue->KeyState[VK_RMENU]) & KS_DOWN_BIT;
+            set_input_key_state( MessageQueue, VK_MENU, down );
+            break;
+        case VK_LSHIFT:
+        case VK_RSHIFT:
+            down = (MessageQueue->KeyState[VK_LSHIFT] | MessageQueue->KeyState[VK_RSHIFT]) & KS_DOWN_BIT;
+            set_input_key_state( MessageQueue, VK_SHIFT, down );
+            break;
+        }
+        break;
+    }
+}
+
 HANDLE FASTCALL
 IntMsqSetWakeMask(DWORD WakeMask)
 {
    PTHREADINFO Win32Thread;
    PUSER_MESSAGE_QUEUE MessageQueue;
    HANDLE MessageEventHandle;
+   DWORD dwFlags = HIWORD(WakeMask);
 
    Win32Thread = PsGetCurrentThreadWin32Thread();
    if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
       return 0;
 
    MessageQueue = Win32Thread->MessageQueue;
-   MessageQueue->WakeMask = WakeMask;
+// Win32Thread->pEventQueueServer; IntMsqSetWakeMask returns Win32Thread->hEventQueueClient
    MessageEventHandle = MessageQueue->NewMessagesHandle;
 
    if (Win32Thread->pcti)
-      Win32Thread->pcti->fsWakeMask = WakeMask;
+   {
+      if ( (Win32Thread->pcti->fsChangeBits & LOWORD(WakeMask)) ||
+           ( (dwFlags & MWMO_INPUTAVAILABLE) && (Win32Thread->pcti->fsWakeBits & LOWORD(WakeMask)) ) )
+      {
+         DPRINT1("Chg 0x%x Wake 0x%x Mask 0x%x\n",Win32Thread->pcti->fsChangeBits, Win32Thread->pcti->fsWakeBits, WakeMask);
+         KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); // Wake it up!
+         return MessageEventHandle;
+      }
+   }
 
    IdlePing();
 
@@ -68,61 +180,109 @@ BOOL FASTCALL
 IntMsqClearWakeMask(VOID)
 {
    PTHREADINFO Win32Thread;
-   PUSER_MESSAGE_QUEUE MessageQueue;
 
    Win32Thread = PsGetCurrentThreadWin32Thread();
    if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
       return FALSE;
-
-   MessageQueue = Win32Thread->MessageQueue;
-// HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
-   MessageQueue->WakeMask = ~0;
-
-   if (Win32Thread->pcti)
-      Win32Thread->pcti->fsWakeMask = 0;
+   // Very hacky, but that is what they do.
+   Win32Thread->pcti->fsWakeBits = 0;
 
    IdlePong();
 
    return TRUE;
 }
 
+/*
+   Due to the uncertainty of knowing what was set in our multilevel message queue,
+   and even if the bits are all cleared. The same as cTimers/cPaintsReady.
+   I think this is the best solution... (jt) */
 VOID FASTCALL
-MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits)
+MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits, BOOL KeyEvent)
 {
-   Queue->QueueBits |= MessageBits;
-   Queue->ChangedBits |= MessageBits;
-   if (Queue->WakeMask & MessageBits)
+   PTHREADINFO pti;
+
+   pti = Queue->Thread->Tcb.Win32Thread;
+   pti->pcti->fsWakeBits |= MessageBits;
+   pti->pcti->fsChangeBits |= MessageBits;
+
+   // Start bit accounting to help clear the main set of bits.
+   if (MessageBits & QS_KEY)         Queue->nCntsQBits[QSRosKey]++;
+   if (MessageBits & QS_MOUSEMOVE)   Queue->nCntsQBits[QSRosMouseMove]++;
+   if (MessageBits & QS_MOUSEBUTTON) Queue->nCntsQBits[QSRosMouseButton]++;
+   if (MessageBits & QS_POSTMESSAGE) Queue->nCntsQBits[QSRosPostMessage]++;
+   if (MessageBits & QS_SENDMESSAGE) Queue->nCntsQBits[QSRosSendMessage]++;
+   if (MessageBits & QS_HOTKEY)      Queue->nCntsQBits[QSRosHotKey]++;
+
+   if (KeyEvent)
       KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
 }
 
 VOID FASTCALL
-MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
+ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits)
 {
-   Queue->PaintCount++;
-   MsqWakeQueue(Queue, QS_PAINT);
+   PTHREADINFO pti;
+   UINT ClrMask = 0;
+
+   pti = Queue->Thread->Tcb.Win32Thread;
+
+   if (MessageBits & QS_KEY)
+   {
+      if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
+   }
+   if (MessageBits & QS_MOUSEMOVE) // ReactOS hard coded.
+   {  // Account for tracking mouse moves..
+      if (--Queue->nCntsQBits[QSRosMouseMove] == 0) ClrMask |= QS_MOUSEMOVE;
+      // Handle mouse move bits here.
+      if (Queue->MouseMoved) ClrMask |= QS_MOUSEMOVE;
+   }
+   if (MessageBits & QS_MOUSEBUTTON)
+   {
+      if (--Queue->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
+   }
+   if (MessageBits & QS_POSTMESSAGE)
+   {
+      if (--Queue->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
+   }
+   if (MessageBits & QS_TIMER) // ReactOS hard coded.
+   {  // Handle timer bits here.
+      if ( pti->cTimersReady )
+      {
+         if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER;
+      }
+   }
+   if (MessageBits & QS_PAINT) // ReactOS hard coded.
+   {  // Handle paint bits here.
+      if ( pti->cPaintsReady )
+      {
+         if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT;
+      }
+   }
+   if (MessageBits & QS_SENDMESSAGE)
+   {
+      if (--Queue->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
+   }
+   if (MessageBits & QS_HOTKEY)
+   {
+      if (--Queue->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
+   }
+
+   pti->pcti->fsWakeBits &= ~ClrMask;
+   pti->pcti->fsChangeBits &= ~ClrMask;
 }
 
 VOID FASTCALL
-MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
+MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
 {
-   Queue->PaintCount--;
+   PTHREADINFO pti;
+   pti = Queue->Thread->Tcb.Win32Thread;
+   pti->cPaintsReady++;
+   MsqWakeQueue(Queue, QS_PAINT, TRUE);
 }
 
-
-INIT_FUNCTION
-NTSTATUS
-NTAPI
-MsqInitializeImpl(VOID)
+VOID FASTCALL
+MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
 {
-   ExInitializePagedLookasideList(&MessageLookasideList,
-                                  NULL,
-                                  NULL,
-                                  0,
-                                  sizeof(USER_MESSAGE),
-                                  TAG_USRMSG,
-                                  256);
-
-   return(STATUS_SUCCESS);
+   ClearMsgBitsMask(Queue, QS_PAINT);
 }
 
 VOID FASTCALL
@@ -130,14 +290,15 @@ MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg)
 {
     MessageQueue->MouseMoveMsg = *Msg;
     MessageQueue->MouseMoved = TRUE;
-    MsqWakeQueue(MessageQueue, QS_MOUSEMOVE);
+    MsqWakeQueue(MessageQueue, QS_MOUSEMOVE, TRUE);
 }
 
 VOID FASTCALL
-co_MsqInsertMouseMessage(MSG* Msg)
+co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
 {
    LARGE_INTEGER LargeTickCount;
    MSLLHOOKSTRUCT MouseHookData;
+   PDESKTOP pDesk;
    PWND pwnd, pwndDesktop;
 
    KeQueryTickCount(&LargeTickCount);
@@ -163,24 +324,38 @@ co_MsqInsertMouseMessage(MSG* Msg)
          break;
    }
 
-   MouseHookData.flags = 0;
+   MouseHookData.flags = flags; // LLMHF_INJECTED
    MouseHookData.time = Msg->time;
-   MouseHookData.dwExtraInfo = 0;
+   MouseHookData.dwExtraInfo = dwExtraInfo;
 
    /* If the hook procedure returned non zero, dont send the message */
-   if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
-      return;
+   if (Hook)
+   {
+      if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
+         return;
+   }
 
    /* Get the desktop window */
    pwndDesktop = UserGetDesktopWindow();
    if(!pwndDesktop)
        return;
 
+   /* Set hit somewhere on the desktop */
+   pDesk = pwndDesktop->head.rpdesk;
+   pDesk->htEx = HTNOWHERE;
+   pDesk->spwndTrack = pwndDesktop;
+
    /* Check if the mouse is captured */
    Msg->hwnd = IntGetCaptureWindow();
    if(Msg->hwnd != NULL)
    {
        pwnd = UserGetWindowObject(Msg->hwnd);
+       if ((pwnd->style & WS_VISIBLE) &&
+            IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y))
+       {
+          pDesk->htEx = HTCLIENT;
+          pDesk->spwndTrack = pwnd;
+       }
    }
    else
    {
@@ -189,10 +364,18 @@ co_MsqInsertMouseMessage(MSG* Msg)
             pwnd != NULL;
             pwnd = pwnd->spwndNext )
        {
-           if((pwnd->style & WS_VISIBLE) && 
+           if ( pwnd->state2 & WNDS2_INDESTROY || pwnd->state & WNDS_DESTROYED )
+           {
+              DPRINT("The Window is in DESTROY!\n");
+              continue;
+           }
+
+           if((pwnd->style & WS_VISIBLE) &&
               IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y))
            {
                Msg->hwnd = pwnd->head.h;
+               pDesk->htEx = HTCLIENT;
+               pDesk->spwndTrack = pwnd;
                break;
            }
        }
@@ -212,6 +395,13 @@ co_MsqInsertMouseMessage(MSG* Msg)
            MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSEBUTTON);
        }
    }
+
+   /* Do GetMouseMovePointsEx FIFO. */
+   MouseHistoryOfMoves[gcur_count].x = Msg->pt.x;
+   MouseHistoryOfMoves[gcur_count].y = Msg->pt.y;
+   MouseHistoryOfMoves[gcur_count].time = Msg->time;
+   MouseHistoryOfMoves[gcur_count].dwExtraInfo = dwExtraInfo;
+   if (gcur_count++ == 64) gcur_count = 0; // 0 - 63 is 64, FIFO forwards.
 }
 
 //
@@ -224,18 +414,12 @@ co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    MSG Msg;
    LARGE_INTEGER LargeTickCount;
    KBDLLHOOKSTRUCT KbdHookData;
-   BOOLEAN Entered = FALSE;
 
    DPRINT("MsqPostKeyboardMessage(uMsg 0x%x, wParam 0x%x, lParam 0x%x)\n",
           uMsg, wParam, lParam);
 
    // Condition may arise when calling MsqPostMessage and waiting for an event.
-   if (!UserIsEntered())
-   {
-         // Fixme: Not sure ATM if this thread is locked.
-         UserEnterExclusive();
-         Entered = TRUE;
-   }
+   ASSERT(UserIsEntered());
 
    FocusMessageQueue = IntGetFocusMessageQueue();
 
@@ -265,14 +449,12 @@ co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
       DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
              Msg.message, Msg.wParam, Msg.lParam);
-      if (Entered) UserLeave();
       return;
    }
 
    if (FocusMessageQueue == NULL)
    {
          DPRINT("No focus message queue\n");
-         if (Entered) UserLeave();
          return;
    }
 
@@ -284,6 +466,7 @@ co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
          FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
 
          Msg.pt = gpsi->ptCursor;
+         update_input_key_state(FocusMessageQueue, &Msg);
          MsqPostMessage(FocusMessageQueue, &Msg, TRUE, QS_KEY);
    }
    else
@@ -291,7 +474,6 @@ co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
          DPRINT("Invalid focus window handle\n");
    }
 
-   if (Entered) UserLeave();
    return;
 }
 
@@ -303,6 +485,8 @@ MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
    MSG Mesg;
    LARGE_INTEGER LargeTickCount;
    NTSTATUS Status;
+   INT id;
+   DWORD Type;
 
    Status = ObReferenceObjectByPointer (Thread,
                                         THREAD_ALL_ACCESS,
@@ -325,14 +509,17 @@ MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
       return;
    }
 
-   Mesg.hwnd = hWnd;
-   Mesg.message = WM_HOTKEY;
-   Mesg.wParam = wParam;
-   Mesg.lParam = lParam;
+   id = wParam; // Check for hot keys unrelated to the hot keys set by RegisterHotKey.
+
+   Mesg.hwnd    = hWnd;
+   Mesg.message = id != IDHOT_REACTOS ? WM_HOTKEY : WM_SYSCOMMAND;
+   Mesg.wParam  = id != IDHOT_REACTOS ? wParam    : SC_HOTKEY;
+   Mesg.lParam  = id != IDHOT_REACTOS ? lParam    : (LPARAM)hWnd;
+   Type         = id != IDHOT_REACTOS ? QS_HOTKEY : QS_POSTMESSAGE;
    KeQueryTickCount(&LargeTickCount);
-   Mesg.time = MsqCalculateMessageTime(&LargeTickCount);
-   Mesg.pt = gpsi->ptCursor;
-   MsqPostMessage(Window->head.pti->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
+   Mesg.time    = MsqCalculateMessageTime(&LargeTickCount);
+   Mesg.pt      = gpsi->ptCursor;
+   MsqPostMessage(Window->head.pti->MessageQueue, &Mesg, FALSE, Type);
    UserDereferenceObject(Window);
    ObDereferenceObject (Thread);
 
@@ -363,9 +550,10 @@ MsqDestroyMessage(PUSER_MESSAGE Message)
 BOOLEAN FASTCALL
 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
 {
-   PUSER_SENT_MESSAGE Message;
+   PUSER_SENT_MESSAGE SaveMsg, Message;
    PLIST_ENTRY Entry;
-   LRESULT Result;
+   PTHREADINFO pti;
+   LRESULT Result = 0;
 
    if (IsListEmpty(&MessageQueue->SentMessagesListHead))
    {
@@ -376,11 +564,25 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
    Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
    Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry);
 
+   pti = MessageQueue->Thread->Tcb.Win32Thread;
+
+   SaveMsg = pti->pusmCurrent;
+   pti->pusmCurrent = Message;
+
+   // Processing a message sent to it from another thread.
+   if ( ( Message->SenderQueue && MessageQueue != Message->SenderQueue) ||
+        ( Message->CallBackSenderQueue && MessageQueue != Message->CallBackSenderQueue ))
+   {  // most likely, but, to be sure.
+      pti->pcti->CTI_flags |= CTI_INSENDMESSAGE; // Let the user know...
+   }
+
    /* insert it to the list of messages that are currently dispatched by this
       message queue */
    InsertTailList(&MessageQueue->LocalDispatchingMessagesHead,
                   &Message->ListEntry);
 
+   ClearMsgBitsMask(MessageQueue, Message->QS_Flags);
+
    if (Message->HookMessage == MSQ_ISHOOK)
    {  // Direct Hook Call processor
       Result = co_CallHook( Message->Msg.message,     // HookId
@@ -395,6 +597,28 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
                                     Message->Msg.wParam,
                                     Message->Msg.lParam);
    }
+   else if ((Message->CompletionCallback)
+       && (Message->CallBackSenderQueue == MessageQueue))
+   {   /* Call the callback routine */
+      if (Message->QS_Flags & QS_SMRESULT)
+      {
+         co_IntCallSentMessageCallback(Message->CompletionCallback,
+                                       Message->Msg.hwnd,
+                                       Message->Msg.message,
+                                       Message->CompletionCallbackContext,
+                                       Message->lResult);
+         /* Set callback to NULL to prevent reentry */
+         Message->CompletionCallback = NULL;
+      }
+      else
+      {
+         /* The message has not been processed yet, reinsert it. */
+         RemoveEntryList(&Message->ListEntry);
+         InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
+         DPRINT("Callback Message not processed yet. Requeuing the message\n");
+         return (FALSE);
+      }
+   }
    else
    {  /* Call the window procedure. */
       Result = co_IntSendMessage( Message->Msg.hwnd,
@@ -407,8 +631,24 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
       to be cleaned up on thread termination anymore */
    RemoveEntryList(&Message->ListEntry);
 
+   /* If the message is a callback, insert it in the callback senders MessageQueue */
+   if (Message->CompletionCallback)
+   {
+      if (Message->CallBackSenderQueue)
+      {
+         Message->lResult = Result;
+         Message->QS_Flags |= QS_SMRESULT;
+
+         /* insert it in the callers message queue */
+         InsertTailList(&Message->CallBackSenderQueue->SentMessagesListHead, &Message->ListEntry);
+         MsqWakeQueue(Message->CallBackSenderQueue, QS_SENDMESSAGE, TRUE);
+         IntDereferenceMessageQueue(Message->CallBackSenderQueue);
+      }
+      return (TRUE);
+   }
+
    /* remove the message from the dispatching list if needed, so lock the sender's message queue */
-   if (!(Message->HookMessage & MSQ_SENTNOWAIT))
+   if (Message->SenderQueue)
    {
       if (Message->DispatchingListEntry.Flink != NULL)
       {
@@ -419,6 +659,11 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
    /* still keep the sender's message queue locked, so the sender can't exit the
       MsqSendMessage() function (if timed out) */
 
+   if (Message->QS_Flags & QS_SMRESULT)
+   {
+      Result = Message->lResult;
+   }
+
    /* Let the sender know the result. */
    if (Message->Result != NULL)
    {
@@ -437,25 +682,21 @@ co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
       KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE);
    }
 
-   /* Call the callback if the message was sent with SendMessageCallback */
-   if (Message->CompletionCallback != NULL)
-   {
-      co_IntCallSentMessageCallback(Message->CompletionCallback,
-                                    Message->Msg.hwnd,
-                                    Message->Msg.message,
-                                    Message->CompletionCallbackContext,
-                                    Result);
-   }
-
-   /* Only if it is not a no wait message */
-   if (!(Message->HookMessage & MSQ_SENTNOWAIT))
+   /* if the message has a sender */
+   if (Message->SenderQueue)
    {
+       /* dereference our and the sender's message queue */
       IntDereferenceMessageQueue(Message->SenderQueue);
       IntDereferenceMessageQueue(MessageQueue);
    }
 
    /* free the message */
    ExFreePoolWithTag(Message, TAG_USRMSG);
+
+   /* do not hangup on the user if this is reentering */
+   if (!SaveMsg) pti->pcti->CTI_flags &= ~CTI_INSENDMESSAGE;
+   pti->pusmCurrent = SaveMsg;
+
    return(TRUE);
 }
 
@@ -483,6 +724,7 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
       if (PostedMessage->Msg.hwnd == Window->head.h)
       {
          RemoveEntryList(&PostedMessage->ListEntry);
+         ClearMsgBitsMask(MessageQueue, PostedMessage->QS_Flags);
          MsqDestroyMessage(PostedMessage);
          CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
       }
@@ -504,9 +746,15 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
          DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
 
          RemoveEntryList(&SentMessage->ListEntry);
+         ClearMsgBitsMask(MessageQueue, SentMessage->QS_Flags);
 
-         /* remove the message from the dispatching list if neede */
-         if ((!(SentMessage->HookMessage & MSQ_SENTNOWAIT))
+         /* if it is a callback and this queue is not the sender queue, dereference queue */
+         if ((SentMessage->CompletionCallback) && (SentMessage->CallBackSenderQueue != MessageQueue))
+         {
+            IntDereferenceMessageQueue(SentMessage->CallBackSenderQueue);
+         }
+         /* Only if the message has a sender was the queue referenced */
+         if ((SentMessage->SenderQueue)
             && (SentMessage->DispatchingListEntry.Flink != NULL))
          {
             RemoveEntryList(&SentMessage->DispatchingListEntry);
@@ -524,8 +772,8 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
                ExFreePool((PVOID)SentMessage->Msg.lParam);
          }
 
-         /* Only if it is not a no wait message */
-         if (!(SentMessage->HookMessage & MSQ_SENTNOWAIT))
+         /* if the message has a sender */
+         if (SentMessage->SenderQueue)
          {
             /* dereference our and the sender's message queue */
             IntDereferenceMessageQueue(MessageQueue);
@@ -550,7 +798,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
                   UINT uTimeout, BOOL Block, INT HookMessage,
                   ULONG_PTR *uResult)
 {
-   PTHREADINFO pti;
+   PTHREADINFO pti, ptirec;
    PUSER_SENT_MESSAGE Message;
    KEVENT CompletionEvent;
    NTSTATUS WaitStatus;
@@ -569,7 +817,16 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
 
    pti = PsGetCurrentThreadWin32Thread();
    ThreadQueue = pti->MessageQueue;
+   ptirec = MessageQueue->Thread->Tcb.Win32Thread;
    ASSERT(ThreadQueue != MessageQueue);
+   ASSERT(ptirec->pcti); // Send must have a client side to receive it!!!!
+
+   /* Don't send from or to a dying thread */
+    if (pti->TIF_flags & TIF_INCLEANUP || ptirec->TIF_flags & TIF_INCLEANUP)
+    {
+        *uResult = -1;
+        return STATUS_TIMEOUT;
+    }
 
    Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000;
 
@@ -581,7 +838,10 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
    Message->Msg.lParam = lParam;
    Message->CompletionEvent = &CompletionEvent;
    Message->Result = &Result;
+   Message->lResult = 0;
+   Message->QS_Flags = 0;
    Message->SenderQueue = ThreadQueue;
+   Message->CallBackSenderQueue = NULL;
    IntReferenceMessageQueue(ThreadQueue);
    Message->CompletionCallback = NULL;
    Message->CompletionCallbackContext = 0;
@@ -596,7 +856,8 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
    /* queue it in the destination's message queue */
    InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
 
-   MsqWakeQueue(MessageQueue, QS_SENDMESSAGE);
+   Message->QS_Flags = QS_SENDMESSAGE;
+   MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE);
 
    /* we can't access the Message anymore since it could have already been deleted! */
 
@@ -650,7 +911,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
             Entry = Entry->Flink;
          }
 
-         DPRINT("MsqSendMessage (blocked) timed out\n");
+         DPRINT("MsqSendMessage (blocked) timed out 1\n");
       }
       while (co_MsqDispatchOneSentMessage(ThreadQueue))
          ;
@@ -710,7 +971,7 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
                Entry = Entry->Flink;
             }
 
-            DPRINT("MsqSendMessage timed out\n");
+            DPRINT("MsqSendMessage timed out 2\n");
             break;
          }
          while (co_MsqDispatchOneSentMessage(ThreadQueue))
@@ -746,7 +1007,9 @@ MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN HardwareMessa
        InsertTailList(&MessageQueue->HardwareMessagesListHead,
                       &Message->ListEntry);
    }
-   MsqWakeQueue(MessageQueue, MessageBits);
+
+   Message->QS_Flags = MessageBits;
+   MsqWakeQueue(MessageQueue, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE));
 }
 
 VOID FASTCALL
@@ -754,7 +1017,7 @@ MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
 {
    MessageQueue->QuitPosted = TRUE;
    MessageQueue->QuitExitCode = ExitCode;
-   MsqWakeQueue(MessageQueue, QS_POSTMESSAGE);
+   MsqWakeQueue(MessageQueue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
 }
 
 /***********************************************************************
@@ -781,7 +1044,7 @@ static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
         if (pwndParent == pwndDesktop) break;
         pt.x += pwnd->rcClient.left - pwndParent->rcClient.left;
         pt.y += pwnd->rcClient.top - pwndParent->rcClient.top;
-        
+
         pwnd = pwndParent;
         co_IntSendMessage( UserHMGetHandle(pwnd), WM_PARENTNOTIFY,
                       MAKEWPARAM( event, idChild ), MAKELPARAM( pt.x, pt.y ) );
@@ -823,7 +1086,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
     }
 
     DPRINT("Got mouse message for 0x%x, hittest: 0x%x\n", msg->hwnd, hittest );
-    
+
     if (pwndMsg == NULL || pwndMsg->head.pti != pti)
     {
         /* Remove and ignore the message */
@@ -893,7 +1156,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
            }
         }
 
-        if (!((first ==  0 && last == 0) || (message >= first || message <= last))) 
+        if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
         {
             DPRINT("Message out of range!!!\n");
             RETURN(FALSE);
@@ -944,8 +1207,6 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
 
     /* message is accepted now (but may still get dropped) */
 
-    pti->rpdesk->htEx = hittest; /* Now set the capture hit. */
-
     event.message = msg->message;
     event.time    = msg->time;
     event.hwnd    = msg->hwnd;
@@ -1005,7 +1266,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
 
         /* Activate the window if needed */
 
-        if (msg->hwnd != MessageQueue->ActiveWindow)
+        if (msg->hwnd != UserGetForegroundWindow())
         {
             PWND pwndTop = pwndMsg;
             while (pwndTop)
@@ -1016,8 +1277,8 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
 
             if (pwndTop && pwndTop != pwndDesktop)
             {
-                LONG ret = co_IntSendMessage( msg->hwnd, 
-                                              WM_MOUSEACTIVATE, 
+                LONG ret = co_IntSendMessage( msg->hwnd,
+                                              WM_MOUSEACTIVATE,
                                               (WPARAM)UserHMGetHandle(pwndTop),
                                               MAKELONG( hittest, msg->message));
                 switch(ret)
@@ -1062,6 +1323,27 @@ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
 {
     EVENTMSG Event;
 
+    if (Msg->message == WM_KEYDOWN || Msg->message == WM_SYSKEYDOWN ||
+        Msg->message == WM_KEYUP || Msg->message == WM_SYSKEYUP)
+    {
+        switch (Msg->wParam)
+        {
+            case VK_LSHIFT: case VK_RSHIFT:
+                Msg->wParam = VK_SHIFT;
+                break;
+            case VK_LCONTROL: case VK_RCONTROL:
+                Msg->wParam = VK_CONTROL;
+                break;
+            case VK_LMENU: case VK_RMENU:
+                Msg->wParam = VK_MENU;
+                break;
+            case VK_F10:
+                if (Msg->message == WM_KEYUP) Msg->message = WM_SYSKEYUP;
+                if (Msg->message == WM_KEYDOWN) Msg->message = WM_SYSKEYDOWN;
+                break;
+        }
+    }
+
     Event.message = Msg->message;
     Event.hwnd    = Msg->hwnd;
     Event.time    = Msg->time;
@@ -1122,17 +1404,38 @@ co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
         *pMsg = msg;
 
     if(Remove)
+    {
+        ClearMsgBitsMask(MessageQueue, QS_MOUSEMOVE);
         MessageQueue->MouseMoved = FALSE;
+    }
 
    return AcceptMessage;
 }
 
+/* check whether a message filter contains at least one potential hardware message */
+static INT FASTCALL
+filter_contains_hw_range( UINT first, UINT last )
+{
+   /* hardware message ranges are (in numerical order):
+    *   WM_NCMOUSEFIRST .. WM_NCMOUSELAST
+    *   WM_KEYFIRST .. WM_KEYLAST
+    *   WM_MOUSEFIRST .. WM_MOUSELAST
+    */
+    if (!last) --last;
+    if (last < WM_NCMOUSEFIRST) return 0;
+    if (first > WM_NCMOUSELAST && last < WM_KEYFIRST) return 0;
+    if (first > WM_KEYLAST && last < WM_MOUSEFIRST) return 0;
+    if (first > WM_MOUSELAST) return 0;
+    return 1;
+}
+
 BOOL APIENTRY
 co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
                          IN BOOL Remove,
                          IN PWND Window,
                          IN UINT MsgFilterLow,
                          IN UINT MsgFilterHigh,
+                         IN UINT QSflags,
                          OUT MSG* pMsg)
 {
 
@@ -1141,33 +1444,46 @@ co_MsqPeekHardwareMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
     PLIST_ENTRY ListHead, CurrentEntry = NULL;
     MSG msg;
 
+    if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
+
     ListHead = &MessageQueue->HardwareMessagesListHead;
     CurrentEntry = ListHead->Flink;
 
-    while(CurrentEntry != ListHead)
-    {
-        CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
-                                          ListEntry);
-
-        msg = CurrentMessage->Msg;
-
-        AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
+    if (IsListEmpty(CurrentEntry)) return FALSE;
 
+    CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+                                          ListEntry);
+    do
+    {
+        if (IsListEmpty(CurrentEntry)) break;
+        if (!CurrentMessage) break;
         CurrentEntry = CurrentMessage->ListEntry.Flink;
 
-        if (Remove)
+        if ( (( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && (CurrentMessage->QS_Flags & QSflags)) ||
+             ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) )
         {
-            RemoveEntryList(&CurrentMessage->ListEntry);
-            MsqDestroyMessage(CurrentMessage);
-        }
+           msg = CurrentMessage->Msg;
 
-        if(AcceptMessage)
-        {
-            *pMsg = msg;
-            return TRUE;
-        }
+           AcceptMessage = co_IntProcessHardwareMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
+
+           if (Remove)
+           {
+               update_input_key_state(MessageQueue, &msg);
+               RemoveEntryList(&CurrentMessage->ListEntry);
+               ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
+               MsqDestroyMessage(CurrentMessage);
+           }
 
+           if (AcceptMessage)
+           {
+              *pMsg = msg;
+              return TRUE;
+           }
+        }
+        CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+                                          ListEntry);
     }
+    while(CurrentEntry != ListHead);
 
     return FALSE;
 }
@@ -1178,37 +1494,51 @@ MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
                   IN PWND Window,
                   IN UINT MsgFilterLow,
                   IN UINT MsgFilterHigh,
+                  IN UINT QSflags,
                   OUT PMSG Message)
 {
    PLIST_ENTRY CurrentEntry;
    PUSER_MESSAGE CurrentMessage;
    PLIST_ENTRY ListHead;
-   
+
    CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
    ListHead = &MessageQueue->PostedMessagesListHead;
-   while (CurrentEntry != ListHead)
-   {
-      CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+
+   if (IsListEmpty(CurrentEntry)) return FALSE;
+
+   CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
                                          ListEntry);
-      if ( ( !Window ||
-            PtrToInt(Window) == 1 ||
-            Window->head.h == CurrentMessage->Msg.hwnd ) &&
-            ( (MsgFilterLow == 0 && MsgFilterHigh == 0) ||
-              ( MsgFilterLow <= CurrentMessage->Msg.message &&
-                MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
+   do
+   {
+      if (IsListEmpty(CurrentEntry)) break;
+      if (!CurrentMessage) break;
+      CurrentEntry = CurrentEntry->Flink;
+/*
+ MSDN:
+ 1: any window that belongs to the current thread, and any messages on the current thread's message queue whose hwnd value is NULL.
+ 2: retrieves only messages on the current thread's message queue whose hwnd value is NULL.
+ 3: handle to the window whose messages are to be retrieved.
+ */
+      if ( ( !Window || // 1
+            ( Window == HWND_BOTTOM && CurrentMessage->Msg.hwnd == NULL ) || // 2
+            ( Window != HWND_BOTTOM && Window->head.h == CurrentMessage->Msg.hwnd ) ) && // 3
+            ( ( ( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && CurrentMessage->QS_Flags & QSflags ) ||
+              ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) ) )
       {
-         *Message= CurrentMessage->Msg;
+         *Message = CurrentMessage->Msg;
 
          if (Remove)
          {
              RemoveEntryList(&CurrentMessage->ListEntry);
+             ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
              MsqDestroyMessage(CurrentMessage);
          }
-
          return(TRUE);
       }
-      CurrentEntry = CurrentEntry->Flink;
+      CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+                                         ListEntry);
    }
+   while (CurrentEntry != ListHead);
 
    return(FALSE);
 }
@@ -1218,13 +1548,12 @@ co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
                          UINT MsgFilterMin, UINT MsgFilterMax)
 {
    NTSTATUS ret;
-
    UserLeaveCo();
-   ret = KeWaitForSingleObject(MessageQueue->NewMessages,
-                              Executive,
-                              UserMode,
-                              FALSE, 
-                              NULL);
+   ret = KeWaitForSingleObject( MessageQueue->NewMessages,
+                                UserRequest,
+                                UserMode,
+                                FALSE,
+                                NULL );
    UserEnterCo();
    return ret;
 }
@@ -1238,6 +1567,15 @@ MsqIsHung(PUSER_MESSAGE_QUEUE MessageQueue)
    return ((LargeTickCount.u.LowPart - MessageQueue->LastMsgRead) > MSQ_HUNG);
 }
 
+VOID
+CALLBACK
+HungAppSysTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+   //DoTheScreenSaver();
+   DPRINT("HungAppSysTimerProc\n");
+   // Process list of windows that are hung and waiting.
+}
+
 BOOLEAN FASTCALL
 MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQueue)
 {
@@ -1257,9 +1595,6 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu
    KeQueryTickCount(&LargeTickCount);
    MessageQueue->LastMsgRead = LargeTickCount.u.LowPart;
    MessageQueue->FocusWindow = NULL;
-   MessageQueue->PaintCount = 0;
-// HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
-   MessageQueue->WakeMask = ~0;
    MessageQueue->NewMessagesHandle = NULL;
 
    Status = ZwCreateEvent(&MessageQueue->NewMessagesHandle, EVENT_ALL_ACCESS,
@@ -1288,6 +1623,10 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
    PLIST_ENTRY CurrentEntry;
    PUSER_MESSAGE CurrentMessage;
    PUSER_SENT_MESSAGE CurrentSentMessage;
+   PTHREADINFO pti;
+
+   pti = MessageQueue->Thread->Tcb.Win32Thread;
+
 
    /* cleanup posted messages */
    while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
@@ -1305,10 +1644,15 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
                                              ListEntry);
 
-      DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
+      /* if it is a callback and this queue is not the sender queue, dereference queue */
+      if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
+      {
+         IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
+      }
 
-      /* remove the message from the dispatching list if needed */
-      if ((!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT)) 
+      DPRINT("Notify the sender and remove a message from the queue that had not been dispatched\n");
+      /* Only if the message has a sender was the message in the DispatchingList */
+      if ((CurrentSentMessage->SenderQueue)
          && (CurrentSentMessage->DispatchingListEntry.Flink != NULL))
       {
          RemoveEntryList(&CurrentSentMessage->DispatchingListEntry);
@@ -1326,8 +1670,8 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
             ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
       }
 
-      /* Only if it is not a no wait message */
-      if (!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT))
+      /* if the message has a sender */
+      if (CurrentSentMessage->SenderQueue)
       {
          /* dereference our and the sender's message queue */
          IntDereferenceMessageQueue(MessageQueue);
@@ -1346,6 +1690,12 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
       CurrentSentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
                                              ListEntry);
 
+      /* if it is a callback and this queue is not the sender queue, dereference queue */
+      if ((CurrentSentMessage->CompletionCallback) && (CurrentSentMessage->CallBackSenderQueue != MessageQueue))
+      {
+         IntDereferenceMessageQueue(CurrentSentMessage->CallBackSenderQueue);
+      }
+
       /* remove the message from the dispatching list */
       if(CurrentSentMessage->DispatchingListEntry.Flink != NULL)
       {
@@ -1366,8 +1716,8 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
             ExFreePool((PVOID)CurrentSentMessage->Msg.lParam);
       }
 
-      /* Only if it is not a no wait message */
-      if (!(CurrentSentMessage->HookMessage & MSQ_SENTNOWAIT))
+      /* if the message has a sender */
+      if (CurrentSentMessage->SenderQueue)
       {
          /* dereference our and the sender's message queue */
          IntDereferenceMessageQueue(MessageQueue);
@@ -1391,6 +1741,16 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
          locked later */
    }
 
+   // Clear it all out.
+   pti->pcti->fsWakeBits = 0;
+   pti->pcti->fsChangeBits = 0;
+
+   MessageQueue->nCntsQBits[QSRosKey] = 0;
+   MessageQueue->nCntsQBits[QSRosMouseMove] = 0;
+   MessageQueue->nCntsQBits[QSRosMouseButton] = 0;
+   MessageQueue->nCntsQBits[QSRosPostMessage] = 0;
+   MessageQueue->nCntsQBits[QSRosSendMessage] = 0;
+   MessageQueue->nCntsQBits[QSRosHotKey] = 0;
 }
 
 PUSER_MESSAGE_QUEUE FASTCALL
@@ -1400,7 +1760,7 @@ MsqCreateMessageQueue(struct _ETHREAD *Thread)
 
    MessageQueue = (PUSER_MESSAGE_QUEUE)ExAllocatePoolWithTag(NonPagedPool,
                   sizeof(USER_MESSAGE_QUEUE) + sizeof(THRDCARETINFO),
-                  TAG_MSGQ);
+                  USERTAG_Q);
 
    if (!MessageQueue)
    {
@@ -1425,6 +1785,8 @@ MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
 {
    PDESKTOP desk;
 
+   MessageQueue->QF_flags |= QF_INDESTROY;
+
    /* remove the message queue from any desktops */
    if ((desk = InterlockedExchangePointer((PVOID*)&MessageQueue->Desktop, 0)))
    {
@@ -1435,6 +1797,9 @@ MsqDestroyMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
    /* clean it up */
    MsqCleanupMessageQueue(MessageQueue);
 
+   if (MessageQueue->NewMessagesHandle != NULL)
+      ZwClose(MessageQueue->NewMessagesHandle);
+   MessageQueue->NewMessagesHandle = NULL;
    /* decrease the reference counter, if it hits zero, the queue will be freed */
    IntDereferenceMessageQueue(MessageQueue);
 }
@@ -1475,6 +1840,30 @@ MsqGetMessageExtraInfo(VOID)
    return MessageQueue->ExtraInfo;
 }
 
+// ReplyMessage is called by the thread receiving the window message.
+BOOL FASTCALL
+co_MsqReplyMessage( LRESULT lResult )
+{
+   PUSER_SENT_MESSAGE Message;
+   PTHREADINFO pti;
+
+   pti = PsGetCurrentThreadWin32Thread();
+   Message = pti->pusmCurrent;
+
+   if (!Message) return FALSE;
+
+   if (Message->QS_Flags & QS_SMRESULT) return FALSE;
+
+   //     SendMessageXxx    || Callback msg and not a notify msg
+   if (Message->SenderQueue || Message->CompletionCallback)
+   {
+      Message->lResult = lResult;
+      Message->QS_Flags |= QS_SMRESULT;
+   // See co_MsqDispatchOneSentMessage, change bits already accounted for and cleared and this msg is going away..
+   }
+   return TRUE;
+}
+
 HWND FASTCALL
 MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
 {
@@ -1512,4 +1901,81 @@ MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
    return NULL;
 }
 
+SHORT
+APIENTRY
+NtUserGetKeyState(INT key)
+{
+   DWORD Ret;
+
+   UserEnterExclusive();
+
+   Ret = UserGetKeyState(key);
+
+   UserLeave();
+
+   return Ret;
+}
+
+
+DWORD
+APIENTRY
+NtUserGetKeyboardState(LPBYTE lpKeyState)
+{
+   DWORD ret = TRUE;
+   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE MessageQueue;
+
+   UserEnterShared();
+
+   pti = PsGetCurrentThreadWin32Thread();
+   MessageQueue = pti->MessageQueue;
+
+   _SEH2_TRY
+   {
+       ProbeForWrite(lpKeyState,sizeof(MessageQueue->KeyState) ,1);
+       RtlCopyMemory(lpKeyState,MessageQueue->KeyState,sizeof(MessageQueue->KeyState));
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+       SetLastNtError(_SEH2_GetExceptionCode());
+       ret = FALSE;
+   }
+   _SEH2_END;
+
+   UserLeave();
+
+   return ret;
+}
+
+BOOL
+APIENTRY
+NtUserSetKeyboardState(LPBYTE lpKeyState)
+{
+   DWORD ret = TRUE;
+   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE MessageQueue;
+
+   UserEnterExclusive();
+
+   pti = PsGetCurrentThreadWin32Thread();
+   MessageQueue = pti->MessageQueue;
+
+   _SEH2_TRY
+   {
+       ProbeForRead(lpKeyState,sizeof(MessageQueue->KeyState) ,1);
+       RtlCopyMemory(MessageQueue->KeyState,lpKeyState,sizeof(MessageQueue->KeyState));
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+       SetLastNtError(_SEH2_GetExceptionCode());
+       ret = FALSE;
+   }
+   _SEH2_END;
+
+   UserLeave();
+
+   return ret;
+}
+
+
 /* EOF */