[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / msgqueue.c
index 1bba2a1..e0210da 100644 (file)
@@ -1,27 +1,11 @@
-/*
- *  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
  * PURPOSE:          Message queues
  * FILE:             subsystems/win32/win32k/ntuser/msgqueue.c
  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
+                     Alexandre Julliard
+                     Maarten Lankhorst
  * REVISION HISTORY:
  *       06-06-2001  CSH  Created
  */
 
 /* GLOBALS *******************************************************************/
 
-#define SYSTEM_MESSAGE_QUEUE_SIZE           (256)
-
-static MSG SystemMessageQueue[SYSTEM_MESSAGE_QUEUE_SIZE];
-static ULONG SystemMessageQueueHead = 0;
-static ULONG SystemMessageQueueTail = 0;
-static ULONG SystemMessageQueueCount = 0;
-static KSPIN_LOCK SystemMessageQueueLock;
-
-static ULONG volatile HardwareMessageQueueStamp = 0;
-static LIST_ENTRY HardwareMessageQueueHead;
-static KMUTANT HardwareMessageQueueLock;
-
-static KEVENT HardwareMessageEvent;
-
 static PAGED_LOOKASIDE_LIST MessageLookasideList;
-static PAGED_LOOKASIDE_LIST TimerLookasideList;
-
-#define IntLockSystemMessageQueue(OldIrql) \
-  KeAcquireSpinLock(&SystemMessageQueueLock, &OldIrql)
+MOUSEMOVEPOINT MouseHistoryOfMoves[64];
+INT gcur_count = 0;
 
-#define IntUnLockSystemMessageQueue(OldIrql) \
-  KeReleaseSpinLock(&SystemMessageQueueLock, OldIrql)
+/* FUNCTIONS *****************************************************************/
 
-#define IntUnLockSystemHardwareMessageQueueLock(Wait) \
-  KeReleaseMutant(&HardwareMessageQueueLock, IO_NO_INCREMENT, FALSE, Wait)
+INIT_FUNCTION
+NTSTATUS
+NTAPI
+MsqInitializeImpl(VOID)
+{
+   ExInitializePagedLookasideList(&MessageLookasideList,
+                                  NULL,
+                                  NULL,
+                                  0,
+                                  sizeof(USER_MESSAGE),
+                                  TAG_USRMSG,
+                                  256);
 
-/* FUNCTIONS *****************************************************************/
+   return(STATUS_SUCCESS);
+}
 
-//
-// Wakeup any thread/process waiting on idle input.
-//
-static VOID FASTCALL
-IdlePing(VOID)
+DWORD FASTCALL UserGetKeyState(DWORD key)
 {
-  HWND hWnd;
-  PWINDOW_OBJECT Window;
-  PPROCESSINFO W32d = PsGetCurrentProcessWin32Process();
+   DWORD ret = 0;
+   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE MessageQueue;
 
-  hWnd = UserGetForegroundWindow();
+   pti = PsGetCurrentThreadWin32Thread();
+   MessageQueue = pti->MessageQueue;
 
-  Window = UserGetWindowObject(hWnd);
+   if( key < 0x100 )
+   {
+       ret = (DWORD)MessageQueue->KeyState[key];
+   }
 
-  if (Window && Window->pti)
-  {
-     if (Window->pti->fsHooks & HOOKID_TO_FLAG(WH_FOREGROUNDIDLE))
-     {
-        co_HOOK_CallHooks(WH_FOREGROUNDIDLE,HC_ACTION,0,0);
-     }
-  }
+   return ret;
+}
 
-  if (W32d && W32d->InputIdleEvent)
-     KePulseEvent( W32d->InputIdleEvent, EVENT_INCREMENT, TRUE);
+/* 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
@@ -95,15 +150,29 @@ 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)
+   {
+      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();
+
    return MessageEventHandle;
 }
 
@@ -111,602 +180,228 @@ BOOL FASTCALL
 IntMsqClearWakeMask(VOID)
 {
    PTHREADINFO Win32Thread;
-   PUSER_MESSAGE_QUEUE MessageQueue;
 
    Win32Thread = PsGetCurrentThreadWin32Thread();
    if (Win32Thread == NULL || Win32Thread->MessageQueue == NULL)
       return FALSE;
+   // Very hacky, but that is what they do.
+   Win32Thread->pcti->fsWakeBits = 0;
 
-   MessageQueue = Win32Thread->MessageQueue;
-// HACK!!!!!!! Newbies that wrote this should hold your head down in shame! (jt)
-   MessageQueue->WakeMask = ~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
-MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
-{
-   Queue->PaintCount++;
-   Queue->QueueBits |= QS_PAINT;
-   Queue->ChangedBits |= QS_PAINT;
-   if (Queue->WakeMask & QS_PAINT)
-      KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
-}
-
-VOID FASTCALL
-MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
+MsqWakeQueue(PUSER_MESSAGE_QUEUE Queue, DWORD MessageBits, BOOL KeyEvent)
 {
-   Queue->PaintCount--;
-}
+   PTHREADINFO pti;
 
+   pti = Queue->Thread->Tcb.Win32Thread;
+   pti->pcti->fsWakeBits |= MessageBits;
+   pti->pcti->fsChangeBits |= MessageBits;
 
-NTSTATUS FASTCALL
-MsqInitializeImpl(VOID)
-{
-   /*CurrentFocusMessageQueue = NULL;*/
-   InitializeListHead(&HardwareMessageQueueHead);
-   KeInitializeEvent(&HardwareMessageEvent, NotificationEvent, 0);
-   KeInitializeSpinLock(&SystemMessageQueueLock);
-   KeInitializeMutant(&HardwareMessageQueueLock, 0);
+   // 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]++;
 
-   ExInitializePagedLookasideList(&MessageLookasideList,
-                                  NULL,
-                                  NULL,
-                                  0,
-                                  sizeof(USER_MESSAGE),
-                                  TAG_USRMSG,
-                                  256);
-   ExInitializePagedLookasideList(&TimerLookasideList,
-                                  NULL,
-                                  NULL,
-                                  0,
-                                  sizeof(TIMER_ENTRY),
-                                  TAG_TIMER,
-                                  64);
-
-   return(STATUS_SUCCESS);
+   if (KeyEvent)
+      KeSetEvent(Queue->NewMessages, IO_NO_INCREMENT, FALSE);
 }
 
 VOID FASTCALL
-MsqInsertSystemMessage(MSG* Msg)
-{
-   KIRQL OldIrql;
-   ULONG Prev;
-
-   /*
-    * If we got WM_MOUSEMOVE and there are already messages in the
-    * system message queue, check if the last message is mouse move
-    * and if it is then just overwrite it.
-    */
-   IntLockSystemMessageQueue(OldIrql);
-
-   /*
-    * Bail out if the queue is full. FIXME: We should handle this case
-    * more gracefully.
-    */
-
-   if (SystemMessageQueueCount == SYSTEM_MESSAGE_QUEUE_SIZE)
-   {
-      IntUnLockSystemMessageQueue(OldIrql);
-      return;
-   }
-
-   if (Msg->message == WM_MOUSEMOVE && SystemMessageQueueCount)
-   {
-      if (SystemMessageQueueTail == 0)
-         Prev = SYSTEM_MESSAGE_QUEUE_SIZE - 1;
-      else
-         Prev = SystemMessageQueueTail - 1;
-      if (SystemMessageQueue[Prev].message == WM_MOUSEMOVE)
-      {
-         SystemMessageQueueTail = Prev;
-         SystemMessageQueueCount--;
-      }
-   }
-
-   /*
-    * Actually insert the message into the system message queue.
-    */
-
-   SystemMessageQueue[SystemMessageQueueTail] = *Msg;
-   SystemMessageQueueTail =
-      (SystemMessageQueueTail + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
-   SystemMessageQueueCount++;
-
-   IntUnLockSystemMessageQueue(OldIrql);
-
-   KeSetEvent(&HardwareMessageEvent, IO_NO_INCREMENT, FALSE);
-}
-
-BOOL FASTCALL
-MsqIsClkLck(LPMSG Msg, BOOL Remove)
+ClearMsgBitsMask(PUSER_MESSAGE_QUEUE Queue, UINT MessageBits)
 {
    PTHREADINFO pti;
-   PSYSTEM_CURSORINFO CurInfo;
-   BOOL Res = FALSE;
-
-   pti = PsGetCurrentThreadWin32Thread();
-   if (pti->rpdesk == NULL)
-   {
-      return FALSE;
-   }
+   UINT ClrMask = 0;
 
-   CurInfo = IntGetSysCursorInfo();
+   pti = Queue->Thread->Tcb.Win32Thread;
 
-   switch (Msg->message)
+   if (MessageBits & QS_KEY)
    {
-     case WM_LBUTTONUP:
-       Res = ((Msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
-       if (Res && (!CurInfo->ClickLockActive))
-       {
-         CurInfo->ClickLockActive = TRUE;
-       }
-       break;
-     case WM_LBUTTONDOWN:
-       if (CurInfo->ClickLockActive)
-       {
-         Res = TRUE;
-         CurInfo->ClickLockActive = FALSE;
-         CurInfo->ClickLockTime = 0;
-       }
-       else
-       {
-         CurInfo->ClickLockTime = Msg->time;
-       }
-       break;
+      if (--Queue->nCntsQBits[QSRosKey] == 0) ClrMask |= QS_KEY;
    }
-   return Res;
-}
-
-BOOL FASTCALL
-MsqIsDblClk(LPMSG Msg, BOOL Remove)
-{
-   PTHREADINFO pti;
-   PSYSTEM_CURSORINFO CurInfo;
-   LONG dX, dY;
-   BOOL Res;
-
-   pti = PsGetCurrentThreadWin32Thread();
-   if (pti->rpdesk == NULL)
-   {
-      return FALSE;
+   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;
    }
-
-   CurInfo = IntGetSysCursorInfo();
-   Res = (Msg->hwnd == (HWND)CurInfo->LastClkWnd) &&
-         ((Msg->time - CurInfo->LastBtnDown) < gspv.iDblClickTime);
-   if(Res)
+   if (MessageBits & QS_MOUSEBUTTON)
    {
-
-      dX = CurInfo->LastBtnDownX - Msg->pt.x;
-      dY = CurInfo->LastBtnDownY - Msg->pt.y;
-      if(dX < 0)
-         dX = -dX;
-      if(dY < 0)
-         dY = -dY;
-
-      Res = (dX <= gspv.iDblClickWidth) &&
-            (dY <= gspv.iDblClickHeight);
-
-      if(Res)
-      {
-         if(CurInfo->ButtonsDown)
-           Res = (CurInfo->ButtonsDown == Msg->message);
-      }
+      if (--Queue->nCntsQBits[QSRosMouseButton] == 0) ClrMask |= QS_MOUSEBUTTON;
    }
-
-   if(Remove)
+   if (MessageBits & QS_POSTMESSAGE)
    {
-      CurInfo->LastBtnDownX = Msg->pt.x;
-      CurInfo->LastBtnDownY = Msg->pt.y;
-      CurInfo->ButtonsDown = Msg->message;
-      if (Res)
-      {
-         CurInfo->LastBtnDown = 0;
-         CurInfo->LastClkWnd = NULL;
-      }
-      else
-      {
-         CurInfo->LastClkWnd = (HANDLE)Msg->hwnd;
-         CurInfo->LastBtnDown = Msg->time;
-      }
+      if (--Queue->nCntsQBits[QSRosPostMessage] == 0) ClrMask |= QS_POSTMESSAGE;
    }
-
-   return Res;
-}
-
-static BOOL APIENTRY
-co_MsqTranslateMouseMessage(PUSER_MESSAGE_QUEUE MessageQueue, PWINDOW_OBJECT Window, UINT FilterLow, UINT FilterHigh,
-                            PUSER_MESSAGE Message, BOOL Remove, PBOOL Freed,
-                            PWINDOW_OBJECT ScopeWin, PPOINT ScreenPoint, BOOL FromGlobalQueue, PLIST_ENTRY *Next)
-{
-   USHORT Msg = Message->Msg.message;
-   PWINDOW_OBJECT CaptureWindow = NULL;
-   HWND hCaptureWin;
-
-   ASSERT_REFS_CO(ScopeWin);
-
-   /*
-   co_WinPosWindowFromPoint can return a Window, and in that case
-   that window has a ref that we need to deref. Thats why we add "dummy"
-   refs in all other cases.
-   */
-
-   hCaptureWin = IntGetCaptureWindow();
-   if (hCaptureWin == NULL)
-   {
-      if (Msg == WM_MOUSEWHEEL)
+   if (MessageBits & QS_TIMER) // ReactOS hard coded.
+   {  // Handle timer bits here.
+      if ( pti->cTimersReady )
       {
-         CaptureWindow = UserGetWindowObject(IntGetFocusWindow());
-         if (CaptureWindow) UserReferenceObject(CaptureWindow);
-      }
-      else
-      {
-         co_WinPosWindowFromPoint(ScopeWin, NULL, &Message->Msg.pt, &CaptureWindow);
-         if(CaptureWindow == NULL)
-         {
-            CaptureWindow = ScopeWin;
-            if (CaptureWindow) UserReferenceObject(CaptureWindow);
-         }
-         else
-         {
-            /* this is the one case where we dont add a ref, since the returned
-            window is already referenced */
-         }
+         if (--pti->cTimersReady == 0) ClrMask |= QS_TIMER;
       }
    }
-   else
-   {
-      /* FIXME - window messages should go to the right window if no buttons are
-                 pressed */
-      CaptureWindow = UserGetWindowObject(hCaptureWin);
-      if (CaptureWindow) UserReferenceObject(CaptureWindow);
-   }
-
-
-
-   if (CaptureWindow == NULL)
-   {
-      if(!FromGlobalQueue)
+   if (MessageBits & QS_PAINT) // ReactOS hard coded.
+   {  // Handle paint bits here.
+      if ( pti->cPaintsReady )
       {
-         RemoveEntryList(&Message->ListEntry);
-         if(MessageQueue->MouseMoveMsg == Message)
-         {
-            MessageQueue->MouseMoveMsg = NULL;
-         }
+         if (--pti->cPaintsReady == 0) ClrMask |= QS_PAINT;
       }
-      // when FromGlobalQueue is true, the caller has already removed the Message
-      ExFreePool(Message);
-      *Freed = TRUE;
-      return(FALSE);
    }
-
-   if (CaptureWindow->pti->MessageQueue != MessageQueue)
+   if (MessageBits & QS_SENDMESSAGE)
    {
-      if (! FromGlobalQueue)
-      {
-         DPRINT("Moving msg between private queues\n");
-         /* This message is already queued in a private queue, but we need
-          * to move it to a different queue, perhaps because a new window
-          * was created which now covers the screen area previously taken
-          * by another window. To move it, we need to take it out of the
-          * old queue. Note that we're already holding the lock mutexes of the
-          * old queue */
-         RemoveEntryList(&Message->ListEntry);
-
-         /* remove the pointer for the current WM_MOUSEMOVE message in case we
-            just removed it */
-         if(MessageQueue->MouseMoveMsg == Message)
-         {
-            MessageQueue->MouseMoveMsg = NULL;
-         }
-      }
-
-      /* lock the destination message queue, so we don't get in trouble with other
-         threads, messing with it at the same time */
-      IntLockHardwareMessageQueue(CaptureWindow->pti->MessageQueue);
-      InsertTailList(&CaptureWindow->pti->MessageQueue->HardwareMessagesListHead,
-                     &Message->ListEntry);
-      if(Message->Msg.message == WM_MOUSEMOVE)
-      {
-         if(CaptureWindow->pti->MessageQueue->MouseMoveMsg)
-         {
-            /* remove the old WM_MOUSEMOVE message, we're processing a more recent
-               one */
-            RemoveEntryList(&CaptureWindow->pti->MessageQueue->MouseMoveMsg->ListEntry);
-            ExFreePool(CaptureWindow->pti->MessageQueue->MouseMoveMsg);
-         }
-         /* save the pointer to the WM_MOUSEMOVE message in the new queue */
-         CaptureWindow->pti->MessageQueue->MouseMoveMsg = Message;
-
-         CaptureWindow->pti->MessageQueue->QueueBits |= QS_MOUSEMOVE;
-         CaptureWindow->pti->MessageQueue->ChangedBits |= QS_MOUSEMOVE;
-         if (CaptureWindow->pti->MessageQueue->WakeMask & QS_MOUSEMOVE)
-            KeSetEvent(CaptureWindow->pti->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
-      }
-      else
-      {
-         CaptureWindow->pti->MessageQueue->QueueBits |= QS_MOUSEBUTTON;
-         CaptureWindow->pti->MessageQueue->ChangedBits |= QS_MOUSEBUTTON;
-         if (CaptureWindow->pti->MessageQueue->WakeMask & QS_MOUSEBUTTON)
-            KeSetEvent(CaptureWindow->pti->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
-      }
-      IntUnLockHardwareMessageQueue(CaptureWindow->pti->MessageQueue);
-
-      *Freed = FALSE;
-      UserDereferenceObject(CaptureWindow);
-      return(FALSE);
+      if (--Queue->nCntsQBits[QSRosSendMessage] == 0) ClrMask |= QS_SENDMESSAGE;
    }
-
-   /* From here on, we're in the same message queue as the caller! */
-
-   *ScreenPoint = Message->Msg.pt;
-
-   if((Window != NULL && PtrToInt(Window) != 1 && CaptureWindow->hSelf != Window->hSelf) ||
-         ((FilterLow != 0 || FilterHigh != 0) && (Msg < FilterLow || Msg > FilterHigh)))
+   if (MessageBits & QS_HOTKEY)
    {
-      /* Reject the message because it doesn't match the filter */
-
-      if(FromGlobalQueue)
-      {
-         /* Lock the message queue so no other thread can mess with it.
-            Our own message queue is not locked while fetching from the global
-            queue, so we have to make sure nothing interferes! */
-         IntLockHardwareMessageQueue(CaptureWindow->pti->MessageQueue);
-         /* if we're from the global queue, we need to add our message to our
-            private queue so we don't loose it! */
-         InsertTailList(&CaptureWindow->pti->MessageQueue->HardwareMessagesListHead,
-                        &Message->ListEntry);
-      }
-
-      if (Message->Msg.message == WM_MOUSEMOVE)
-      {
-         if(CaptureWindow->pti->MessageQueue->MouseMoveMsg &&
-               (CaptureWindow->pti->MessageQueue->MouseMoveMsg != Message))
-         {
-            /* delete the old message */
-            RemoveEntryList(&CaptureWindow->pti->MessageQueue->MouseMoveMsg->ListEntry);
-            ExFreePool(CaptureWindow->pti->MessageQueue->MouseMoveMsg);
-            if (!FromGlobalQueue)
-            {
-               // We might have deleted the next one in our queue, so fix next
-               *Next = Message->ListEntry.Flink;
-            }
-         }
-         /* always save a pointer to this WM_MOUSEMOVE message here because we're
-            sure that the message is in the private queue */
-         CaptureWindow->pti->MessageQueue->MouseMoveMsg = Message;
-      }
-      if(FromGlobalQueue)
-      {
-         IntUnLockHardwareMessageQueue(CaptureWindow->pti->MessageQueue);
-      }
-
-      UserDereferenceObject(CaptureWindow);
-      *Freed = FALSE;
-      return(FALSE);
+      if (--Queue->nCntsQBits[QSRosHotKey] == 0) ClrMask |= QS_HOTKEY;
    }
 
-   /* FIXME - only assign if removing? */
-   Message->Msg.hwnd = CaptureWindow->hSelf;
-   Message->Msg.message = Msg;
-   Message->Msg.lParam = MAKELONG(Message->Msg.pt.x, Message->Msg.pt.y);
-
-   /* remove the reference to the current WM_(NC)MOUSEMOVE message, if this message
-      is it */
-   if (Message->Msg.message == WM_MOUSEMOVE ||
-         Message->Msg.message == WM_NCMOUSEMOVE)
-   {
-      if(FromGlobalQueue)
-      {
-         /* Lock the message queue so no other thread can mess with it.
-            Our own message queue is not locked while fetching from the global
-            queue, so we have to make sure nothing interferes! */
-         IntLockHardwareMessageQueue(CaptureWindow->pti->MessageQueue);
-         if(CaptureWindow->pti->MessageQueue->MouseMoveMsg)
-         {
-            /* delete the WM_(NC)MOUSEMOVE message in the private queue, we're dealing
-               with one that's been sent later */
-            RemoveEntryList(&CaptureWindow->pti->MessageQueue->MouseMoveMsg->ListEntry);
-            ExFreePool(CaptureWindow->pti->MessageQueue->MouseMoveMsg);
-            /* our message is not in the private queue so we can remove the pointer
-               instead of setting it to the current message we're processing */
-            CaptureWindow->pti->MessageQueue->MouseMoveMsg = NULL;
-         }
-         IntUnLockHardwareMessageQueue(CaptureWindow->pti->MessageQueue);
-      }
-      else if (CaptureWindow->pti->MessageQueue->MouseMoveMsg == Message)
-      {
-         CaptureWindow->pti->MessageQueue->MouseMoveMsg = NULL;
-      }
-   }
+   pti->pcti->fsWakeBits &= ~ClrMask;
+   pti->pcti->fsChangeBits &= ~ClrMask;
+}
 
-   UserDereferenceObject(CaptureWindow);
-   *Freed = FALSE;
-   return(TRUE);
+VOID FASTCALL
+MsqIncPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
+{
+   PTHREADINFO pti;
+   pti = Queue->Thread->Tcb.Win32Thread;
+   pti->cPaintsReady++;
+   MsqWakeQueue(Queue, QS_PAINT, TRUE);
 }
 
-BOOL APIENTRY
-co_MsqPeekHardwareMessage(PUSER_MESSAGE_QUEUE MessageQueue, PWINDOW_OBJECT Window,
-                          UINT FilterLow, UINT FilterHigh, BOOL Remove,
-                          PUSER_MESSAGE* Message)
+VOID FASTCALL
+MsqDecPaintCountQueue(PUSER_MESSAGE_QUEUE Queue)
 {
-   KIRQL OldIrql;
-   POINT ScreenPoint;
-   BOOL Accept, Freed;
-   PLIST_ENTRY CurrentEntry;
-   PWINDOW_OBJECT DesktopWindow = NULL;
-   PVOID WaitObjects[2];
-   NTSTATUS WaitStatus;
-   DECLARE_RETURN(BOOL);
-   USER_REFERENCE_ENTRY Ref;
-   PDESKTOPINFO Desk = NULL;
+   ClearMsgBitsMask(Queue, QS_PAINT);
+}
 
-   WaitObjects[1] = MessageQueue->NewMessages;
-   WaitObjects[0] = &HardwareMessageQueueLock;
-   do
-   {
-      IdlePing();
+VOID FASTCALL
+MsqPostMouseMove(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg)
+{
+    MessageQueue->MouseMoveMsg = *Msg;
+    MessageQueue->MouseMoved = TRUE;
+    MsqWakeQueue(MessageQueue, QS_MOUSEMOVE, TRUE);
+}
 
-      UserLeaveCo();
+VOID FASTCALL
+co_MsqInsertMouseMessage(MSG* Msg, DWORD flags, ULONG_PTR dwExtraInfo, BOOL Hook)
+{
+   LARGE_INTEGER LargeTickCount;
+   MSLLHOOKSTRUCT MouseHookData;
+   PDESKTOP pDesk;
+   PWND pwnd, pwndDesktop;
 
-      WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
-                                            UserMode, FALSE, NULL, NULL);
+   KeQueryTickCount(&LargeTickCount);
+   Msg->time = MsqCalculateMessageTime(&LargeTickCount);
 
-      UserEnterCo();
+   MouseHookData.pt.x = LOWORD(Msg->lParam);
+   MouseHookData.pt.y = HIWORD(Msg->lParam);
+   switch(Msg->message)
+   {
+      case WM_MOUSEWHEEL:
+         MouseHookData.mouseData = MAKELONG(0, GET_WHEEL_DELTA_WPARAM(Msg->wParam));
+         break;
+      case WM_XBUTTONDOWN:
+      case WM_XBUTTONUP:
+      case WM_XBUTTONDBLCLK:
+      case WM_NCXBUTTONDOWN:
+      case WM_NCXBUTTONUP:
+      case WM_NCXBUTTONDBLCLK:
+         MouseHookData.mouseData = MAKELONG(0, HIWORD(Msg->wParam));
+         break;
+      default:
+         MouseHookData.mouseData = 0;
+         break;
    }
-   while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus);
 
-   DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
+   MouseHookData.flags = flags; // LLMHF_INJECTED
+   MouseHookData.time = Msg->time;
+   MouseHookData.dwExtraInfo = dwExtraInfo;
 
-   if (DesktopWindow)
+   /* If the hook procedure returned non zero, dont send the message */
+   if (Hook)
    {
-       UserRefObjectCo(DesktopWindow, &Ref);//can DesktopWindow be NULL?
-       Desk = DesktopWindow->pti->pDeskInfo;
+      if (co_HOOK_CallHooks(WH_MOUSE_LL, HC_ACTION, Msg->message, (LPARAM) &MouseHookData))
+         return;
    }
 
-   /* Process messages in the message queue itself. */
-   IntLockHardwareMessageQueue(MessageQueue);
-   CurrentEntry = MessageQueue->HardwareMessagesListHead.Flink;
-   while (CurrentEntry != &MessageQueue->HardwareMessagesListHead)
-   {
-      PUSER_MESSAGE Current =
-         CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
-      CurrentEntry = CurrentEntry->Flink;
-      if (Current->Msg.message >= WM_MOUSEFIRST &&
-            Current->Msg.message <= WM_MOUSELAST)
-      {
+   /* 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;
 
-         Accept = co_MsqTranslateMouseMessage(MessageQueue, Window, FilterLow, FilterHigh,
-                                              Current, Remove, &Freed,
-                                              DesktopWindow, &ScreenPoint, FALSE, &CurrentEntry);
-         if (Accept)
-         {
-            if (Remove)
-            {
-               RemoveEntryList(&Current->ListEntry);
-            }
-            IntUnLockHardwareMessageQueue(MessageQueue);
-            IntUnLockSystemHardwareMessageQueueLock(FALSE);
-            *Message = Current;
-
-            if (Desk)
-                Desk->LastInputWasKbd = FALSE;
-
-            RETURN(TRUE);
-         }
-
-      }
-   }
-   IntUnLockHardwareMessageQueue(MessageQueue);
-
-   /* Now try the global queue. */
-
-   /* Transfer all messages from the DPC accessible queue to the main queue. */
-   IntLockSystemMessageQueue(OldIrql);
-   while (SystemMessageQueueCount > 0)
+   /* Check if the mouse is captured */
+   Msg->hwnd = IntGetCaptureWindow();
+   if(Msg->hwnd != NULL)
    {
-      PUSER_MESSAGE UserMsg;
-      MSG Msg;
-
-      ASSERT(SystemMessageQueueHead < SYSTEM_MESSAGE_QUEUE_SIZE);
-      Msg = SystemMessageQueue[SystemMessageQueueHead];
-      SystemMessageQueueHead =
-         (SystemMessageQueueHead + 1) % SYSTEM_MESSAGE_QUEUE_SIZE;
-      SystemMessageQueueCount--;
-      IntUnLockSystemMessageQueue(OldIrql);
-
-      UserMsg = ExAllocateFromPagedLookasideList(&MessageLookasideList);
-      /* What to do if out of memory? For now we just panic a bit in debug */
-      ASSERT(UserMsg);
-      UserMsg->FreeLParam = FALSE;
-      UserMsg->Msg = Msg;
-      InsertTailList(&HardwareMessageQueueHead, &UserMsg->ListEntry);
-
-      IntLockSystemMessageQueue(OldIrql);
+       pwnd = UserGetWindowObject(Msg->hwnd);
+       if ((pwnd->style & WS_VISIBLE) &&
+            IntPtInWindow(pwnd, Msg->pt.x, Msg->pt.y))
+       {
+          pDesk->htEx = HTCLIENT;
+          pDesk->spwndTrack = pwnd;
+       }
    }
-   HardwareMessageQueueStamp++;
-   IntUnLockSystemMessageQueue(OldIrql);
-
-   /* Process messages in the queue until we find one to return. */
-   CurrentEntry = HardwareMessageQueueHead.Flink;
-   while (CurrentEntry != &HardwareMessageQueueHead)
+   else
    {
-      PUSER_MESSAGE Current =
-         CONTAINING_RECORD(CurrentEntry, USER_MESSAGE, ListEntry);
-      CurrentEntry = CurrentEntry->Flink;
-      RemoveEntryList(&Current->ListEntry);
-      HardwareMessageQueueStamp++;
-      if (Current->Msg.message >= WM_MOUSEFIRST &&
-            Current->Msg.message <= WM_MOUSELAST)
-      {
-         const ULONG ActiveStamp = HardwareMessageQueueStamp;
-         /* Translate the message. */
-         Accept = co_MsqTranslateMouseMessage(MessageQueue, Window, FilterLow, FilterHigh,
-                                              Current, Remove, &Freed,
-                                              DesktopWindow, &ScreenPoint, TRUE, NULL);
-         if (Accept)
-         {
-            /* Check for no more messages in the system queue. */
-            IntLockSystemMessageQueue(OldIrql);
-            if (SystemMessageQueueCount == 0 &&
-                  IsListEmpty(&HardwareMessageQueueHead))
-            {
-               KeClearEvent(&HardwareMessageEvent);
-            }
-            IntUnLockSystemMessageQueue(OldIrql);
-
-            /*
-            If we aren't removing the message then add it to the private
-            queue.
-            */
-            if (!Remove)
-            {
-               IntLockHardwareMessageQueue(MessageQueue);
-               if(Current->Msg.message == WM_MOUSEMOVE)
-               {
-                  if(MessageQueue->MouseMoveMsg)
-                  {
-                     RemoveEntryList(&MessageQueue->MouseMoveMsg->ListEntry);
-                     ExFreePool(MessageQueue->MouseMoveMsg);
-                  }
-                  MessageQueue->MouseMoveMsg = Current;
-               }
-               InsertTailList(&MessageQueue->HardwareMessagesListHead,
-                              &Current->ListEntry);
-               IntUnLockHardwareMessageQueue(MessageQueue);
-            }
-            IntUnLockSystemHardwareMessageQueueLock(FALSE);
-            *Message = Current;
-
-            RETURN(TRUE);
-         }
-         /* If the contents of the queue changed then restart processing. */
-         if (HardwareMessageQueueStamp != ActiveStamp)
-         {
-            CurrentEntry = HardwareMessageQueueHead.Flink;
-            continue;
-         }
-      }
+       /* Loop all top level windows to find which one should receive input */
+       for( pwnd = pwndDesktop->spwndChild;
+            pwnd != NULL;
+            pwnd = pwnd->spwndNext )
+       {
+           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;
+           }
+       }
    }
 
-   /* Check if the system message queue is now empty. */
-   IntLockSystemMessageQueue(OldIrql);
-   if (SystemMessageQueueCount == 0 && IsListEmpty(&HardwareMessageQueueHead))
+   /* Check if we found a window */
+   if(Msg->hwnd != NULL && pwnd != NULL)
    {
-      KeClearEvent(&HardwareMessageEvent);
+       if(Msg->message == WM_MOUSEMOVE)
+       {
+           /* Mouse move is a special case*/
+           MsqPostMouseMove(pwnd->head.pti->MessageQueue, Msg);
+       }
+       else
+       {
+           DPRINT("Posting mouse message to hwnd=0x%x!\n", UserHMGetHandle(pwnd));
+           MsqPostMessage(pwnd->head.pti->MessageQueue, Msg, TRUE, QS_MOUSEBUTTON);
+       }
    }
-   IntUnLockSystemMessageQueue(OldIrql);
-   IntUnLockSystemHardwareMessageQueueLock(FALSE);
-
-   RETURN(FALSE);
-
-CLEANUP:
-   if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
 
-   END_CLEANUP;
+   /* 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.
 }
 
 //
@@ -719,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();
 
@@ -758,16 +447,14 @@ co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    KbdHookData.dwExtraInfo = 0;
    if (co_HOOK_CallHooks(WH_KEYBOARD_LL, HC_ACTION, Msg.message, (LPARAM) &KbdHookData))
    {
-      DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
+      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;
    }
 
@@ -779,25 +466,27 @@ co_MsqPostKeyboardMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
          FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
 
          Msg.pt = gpsi->ptCursor;
-         MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
+         update_input_key_state(FocusMessageQueue, &Msg);
+         MsqPostMessage(FocusMessageQueue, &Msg, TRUE, QS_KEY);
    }
    else
    {
          DPRINT("Invalid focus window handle\n");
    }
 
-   if (Entered) UserLeave();
    return;
 }
 
 VOID FASTCALL
 MsqPostHotKeyMessage(PVOID Thread, HWND hWnd, WPARAM wParam, LPARAM lParam)
 {
-   PWINDOW_OBJECT Window;
+   PWND Window;
    PTHREADINFO Win32Thread;
    MSG Mesg;
    LARGE_INTEGER LargeTickCount;
    NTSTATUS Status;
+   INT id;
+   DWORD Type;
 
    Status = ObReferenceObjectByPointer (Thread,
                                         THREAD_ALL_ACCESS,
@@ -820,24 +509,24 @@ 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->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);
 
-   //  InsertHeadList(&pThread->MessageQueue->PostedMessagesListHead,
-   //   &Message->ListEntry);
-   //  KeSetEvent(pThread->MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
 }
 
 PUSER_MESSAGE FASTCALL
-MsqCreateMessage(LPMSG Msg, BOOLEAN FreeLParam)
+MsqCreateMessage(LPMSG Msg)
 {
    PUSER_MESSAGE Message;
 
@@ -847,7 +536,6 @@ MsqCreateMessage(LPMSG Msg, BOOLEAN FreeLParam)
       return NULL;
    }
 
-   Message->FreeLParam = FreeLParam;
    RtlMoveMemory(&Message->Msg, Msg, sizeof(MSG));
 
    return Message;
@@ -859,41 +547,13 @@ MsqDestroyMessage(PUSER_MESSAGE Message)
    ExFreeToPagedLookasideList(&MessageLookasideList, Message);
 }
 
-VOID FASTCALL
-co_MsqDispatchSentNotifyMessages(PUSER_MESSAGE_QUEUE MessageQueue)
-{
-   PLIST_ENTRY ListEntry;
-   PUSER_SENT_MESSAGE_NOTIFY Message;
-
-   while (!IsListEmpty(&MessageQueue->SentMessagesListHead))
-   {
-      ListEntry = RemoveHeadList(&MessageQueue->SentMessagesListHead);
-      Message = CONTAINING_RECORD(ListEntry, USER_SENT_MESSAGE_NOTIFY,
-                                  ListEntry);
-
-      co_IntCallSentMessageCallback(Message->CompletionCallback,
-                                    Message->hWnd,
-                                    Message->Msg,
-                                    Message->CompletionCallbackContext,
-                                    Message->Result);
-
-   }
-
-}
-
-BOOLEAN FASTCALL
-MsqPeekSentMessages(PUSER_MESSAGE_QUEUE MessageQueue)
-{
-   return(!IsListEmpty(&MessageQueue->SentMessagesListHead));
-}
-
 BOOLEAN FASTCALL
 co_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue)
 {
-   PUSER_SENT_MESSAGE Message;
+   PUSER_SENT_MESSAGE SaveMsg, Message;
    PLIST_ENTRY Entry;
-   LRESULT Result;
-   BOOL SenderReturned;
+   PTHREADINFO pti;
+   LRESULT Result = 0;
 
    if (IsListEmpty(&MessageQueue->SentMessagesListHead))
    {
@@ -904,43 +564,93 @@ 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)
-   {
-      Result = co_HOOK_CallHooks(Message->Msg.message,
-                                 (INT)(INT_PTR)Message->Msg.hwnd,
-                                 Message->Msg.wParam,
-                                 Message->Msg.lParam);
+   {  // Direct Hook Call processor
+      Result = co_CallHook( Message->Msg.message,     // HookId
+                           (INT)(INT_PTR)Message->Msg.hwnd, // Code
+                            Message->Msg.wParam,
+                            Message->Msg.lParam);
    }
    else if (Message->HookMessage == MSQ_ISEVENT)
-   {
+   {  // Direct Event Call processor
       Result = co_EVENT_CallEvents( Message->Msg.message,
                                     Message->Msg.hwnd,
                                     Message->Msg.wParam,
-                                    Message->Msg.lParam);                                  
+                                    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,
-                                 Message->Msg.message,
-                                 Message->Msg.wParam,
-                                 Message->Msg.lParam);
+   {  /* Call the window procedure. */
+      Result = co_IntSendMessage( Message->Msg.hwnd,
+                                  Message->Msg.message,
+                                  Message->Msg.wParam,
+                                  Message->Msg.lParam);
    }
 
    /* remove the message from the local dispatching list, because it doesn't need
       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)
    {
-      SenderReturned = (Message->DispatchingListEntry.Flink == NULL);
-      if (!SenderReturned)
+      if (Message->DispatchingListEntry.Flink != NULL)
       {
          /* only remove it from the dispatching list if not already removed by a timeout */
          RemoveEntryList(&Message->DispatchingListEntry);
@@ -949,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)
    {
@@ -967,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 (!SenderReturned && 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);
 }
 
@@ -996,11 +707,11 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
    PUSER_MESSAGE PostedMessage;
    PUSER_MESSAGE_QUEUE MessageQueue;
    PLIST_ENTRY CurrentEntry, ListHead;
-   PWINDOW_OBJECT Window = pWindow;
+   PWND Window = pWindow;
 
    ASSERT(Window);
 
-   MessageQueue = Window->pti->MessageQueue;
+   MessageQueue = Window->head.pti->MessageQueue;
    ASSERT(MessageQueue);
 
    /* remove the posted messages for this window */
@@ -1010,9 +721,10 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
    {
       PostedMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
                                         ListEntry);
-      if (PostedMessage->Msg.hwnd == Window->hSelf)
+      if (PostedMessage->Msg.hwnd == Window->head.h)
       {
          RemoveEntryList(&PostedMessage->ListEntry);
+         ClearMsgBitsMask(MessageQueue, PostedMessage->QS_Flags);
          MsqDestroyMessage(PostedMessage);
          CurrentEntry = MessageQueue->PostedMessagesListHead.Flink;
       }
@@ -1029,14 +741,20 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
    {
       SentMessage = CONTAINING_RECORD(CurrentEntry, USER_SENT_MESSAGE,
                                       ListEntry);
-      if(SentMessage->Msg.hwnd == Window->hSelf)
+      if(SentMessage->Msg.hwnd == Window->head.h)
       {
          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);
@@ -1054,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);
@@ -1074,32 +792,20 @@ MsqRemoveWindowMessagesFromQueue(PVOID pWindow)
    }
 }
 
-VOID FASTCALL
-MsqSendNotifyMessage(PUSER_MESSAGE_QUEUE MessageQueue,
-                     PUSER_SENT_MESSAGE_NOTIFY NotifyMessage)
-{
-   InsertTailList(&MessageQueue->NotifyMessagesListHead,
-                  &NotifyMessage->ListEntry);
-   MessageQueue->QueueBits |= QS_SENDMESSAGE;
-   MessageQueue->ChangedBits |= QS_SENDMESSAGE;
-   if (MessageQueue->WakeMask & QS_SENDMESSAGE)
-      KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
-}
-
 NTSTATUS FASTCALL
 co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
                   HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam,
                   UINT uTimeout, BOOL Block, INT HookMessage,
                   ULONG_PTR *uResult)
 {
-   PTHREADINFO pti;
+   PTHREADINFO pti, ptirec;
    PUSER_SENT_MESSAGE Message;
    KEVENT CompletionEvent;
    NTSTATUS WaitStatus;
-   LRESULT Result;
    PUSER_MESSAGE_QUEUE ThreadQueue;
    LARGE_INTEGER Timeout;
    PLIST_ENTRY Entry;
+   LRESULT Result = 0;   //// Result could be trashed. ////
 
    if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))
    {
@@ -1111,22 +817,34 @@ 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;
 
    /* FIXME - increase reference counter of sender's message queue here */
 
-   Result = 0;
    Message->Msg.hwnd = Wnd;
    Message->Msg.message = Msg;
    Message->Msg.wParam = wParam;
    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;
    Message->HookMessage = HookMessage;
    Message->HasPackedLParam = FALSE;
 
@@ -1138,17 +856,13 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
    /* queue it in the destination's message queue */
    InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry);
 
-   MessageQueue->QueueBits |= QS_SENDMESSAGE;
-   MessageQueue->ChangedBits |= QS_SENDMESSAGE;
-   if (MessageQueue->WakeMask & QS_SENDMESSAGE)
-      KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
+   Message->QS_Flags = QS_SENDMESSAGE;
+   MsqWakeQueue(MessageQueue, QS_SENDMESSAGE, TRUE);
 
    /* we can't access the Message anymore since it could have already been deleted! */
 
    if(Block)
    {
-      IdlePing();
-
       UserLeaveCo();
 
       /* don't process messages sent to the thread */
@@ -1197,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))
          ;
@@ -1210,8 +924,6 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
       WaitObjects[1] = ThreadQueue->NewMessages;
       do
       {
-         IdlePing();
-
          UserLeaveCo();
 
          WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,
@@ -1259,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))
@@ -1275,21 +987,29 @@ co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,
 }
 
 VOID FASTCALL
-MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN FreeLParam,
+MsqPostMessage(PUSER_MESSAGE_QUEUE MessageQueue, MSG* Msg, BOOLEAN HardwareMessage,
                DWORD MessageBits)
 {
    PUSER_MESSAGE Message;
 
-   if(!(Message = MsqCreateMessage(Msg, FreeLParam)))
+   if(!(Message = MsqCreateMessage(Msg)))
    {
       return;
    }
-   InsertTailList(&MessageQueue->PostedMessagesListHead,
-                  &Message->ListEntry);
-   MessageQueue->QueueBits |= MessageBits;
-   MessageQueue->ChangedBits |= MessageBits;
-   if (MessageQueue->WakeMask & MessageBits)
-      KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
+
+   if(!HardwareMessage)
+   {
+       InsertTailList(&MessageQueue->PostedMessagesListHead,
+                      &Message->ListEntry);
+   }
+   else
+   {
+       InsertTailList(&MessageQueue->HardwareMessagesListHead,
+                      &Message->ListEntry);
+   }
+
+   Message->QS_Flags = MessageBits;
+   MsqWakeQueue(MessageQueue, MessageBits, (MessageBits & QS_TIMER ? FALSE : TRUE));
 }
 
 VOID FASTCALL
@@ -1297,81 +1017,543 @@ MsqPostQuitMessage(PUSER_MESSAGE_QUEUE MessageQueue, ULONG ExitCode)
 {
    MessageQueue->QuitPosted = TRUE;
    MessageQueue->QuitExitCode = ExitCode;
-   MessageQueue->QueueBits |= QS_POSTMESSAGE;
-   MessageQueue->ChangedBits |= QS_POSTMESSAGE;
-   if (MessageQueue->WakeMask & QS_POSTMESSAGE)
-      KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);
+   MsqWakeQueue(MessageQueue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE, TRUE);
+}
+
+/***********************************************************************
+ *           MsqSendParentNotify
+ *
+ * Send a WM_PARENTNOTIFY to all ancestors of the given window, unless
+ * the window has the WS_EX_NOPARENTNOTIFY style.
+ */
+static void MsqSendParentNotify( PWND pwnd, WORD event, WORD idChild, POINT pt )
+{
+    PWND pwndDesktop = UserGetWindowObject(IntGetDesktopWindow());
+
+    /* pt has to be in the client coordinates of the parent window */
+    pt.x += pwndDesktop->rcClient.left - pwnd->rcClient.left;
+    pt.y += pwndDesktop->rcClient.top - pwnd->rcClient.top;
+
+    for (;;)
+    {
+        PWND pwndParent;
+
+        if (!(pwnd->style & WS_CHILD)) break;
+        if (pwnd->ExStyle & WS_EX_NOPARENTNOTIFY) break;
+        if (!(pwndParent = IntGetParent(pwnd))) break;
+        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 ) );
+    }
+}
+
+BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT last)
+{
+    MSG clk_msg;
+    POINT pt;
+    UINT message;
+    USHORT hittest;
+    EVENTMSG event;
+    MOUSEHOOKSTRUCT hook;
+    BOOL eatMsg;
+
+    PWND pwndMsg, pwndDesktop;
+    PUSER_MESSAGE_QUEUE MessageQueue;
+    PTHREADINFO pti;
+    PSYSTEM_CURSORINFO CurInfo;
+    DECLARE_RETURN(BOOL);
+
+    pti = PsGetCurrentThreadWin32Thread();
+    pwndDesktop = UserGetDesktopWindow();
+    MessageQueue = pti->MessageQueue;
+    CurInfo = IntGetSysCursorInfo();
+    pwndMsg = UserGetWindowObject(msg->hwnd);
+    clk_msg = MessageQueue->msgDblClk;
+
+    /* find the window to dispatch this mouse message to */
+    if (MessageQueue->CaptureWindow)
+    {
+        hittest = HTCLIENT;
+        pwndMsg = IntGetWindowObject(MessageQueue->CaptureWindow);
+    }
+    else
+    {
+        pwndMsg = co_WinPosWindowFromPoint(pwndMsg, &msg->pt, &hittest);
+    }
+
+    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 */
+        *RemoveMessages = TRUE;
+        RETURN(FALSE);
+    }
+
+    msg->hwnd = UserHMGetHandle(pwndMsg);
+
+#if 0
+    if (!check_hwnd_filter( msg, hwnd_filter )) RETURN(FALSE);
+#endif
+
+    pt = msg->pt;
+    message = msg->message;
+    /* Note: windows has no concept of a non-client wheel message */
+    if (message != WM_MOUSEWHEEL)
+    {
+        if (hittest != HTCLIENT)
+        {
+            message += WM_NCMOUSEMOVE - WM_MOUSEMOVE;
+            msg->wParam = hittest;
+        }
+        else
+        {
+            /* coordinates don't get translated while tracking a menu */
+            /* FIXME: should differentiate popups and top-level menus */
+            if (!(MessageQueue->MenuOwner))
+            {
+                pt.x += pwndDesktop->rcClient.left - pwndMsg->rcClient.left;
+                pt.y += pwndDesktop->rcClient.top - pwndMsg->rcClient.top;
+            }
+        }
+    }
+    msg->lParam = MAKELONG( pt.x, pt.y );
+
+    /* translate double clicks */
+
+    if ((msg->message == WM_LBUTTONDOWN) ||
+        (msg->message == WM_RBUTTONDOWN) ||
+        (msg->message == WM_MBUTTONDOWN) ||
+        (msg->message == WM_XBUTTONDOWN))
+    {
+        BOOL update = *RemoveMessages;
+
+        /* translate double clicks -
+         * note that ...MOUSEMOVEs can slip in between
+         * ...BUTTONDOWN and ...BUTTONDBLCLK messages */
+
+        if ((MessageQueue->MenuOwner || MessageQueue->MoveSize) ||
+            hittest != HTCLIENT ||
+            (pwndMsg->pcls->style & CS_DBLCLKS))
+        {
+           if ((msg->message == clk_msg.message) &&
+               (msg->hwnd == clk_msg.hwnd) &&
+               (msg->wParam == clk_msg.wParam) &&
+               (msg->time - clk_msg.time < gspv.iDblClickTime) &&
+               (abs(msg->pt.x - clk_msg.pt.x) < UserGetSystemMetrics(SM_CXDOUBLECLK)/2) &&
+               (abs(msg->pt.y - clk_msg.pt.y) < UserGetSystemMetrics(SM_CYDOUBLECLK)/2))
+           {
+               message += (WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
+               if (update)
+               {
+                   MessageQueue->msgDblClk.message = 0;  /* clear the double click conditions */
+                   update = FALSE;
+               }
+           }
+        }
+
+        if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
+        {
+            DPRINT("Message out of range!!!\n");
+            RETURN(FALSE);
+        }
+
+        /* update static double click conditions */
+        if (update) MessageQueue->msgDblClk = *msg;
+    }
+    else
+    {
+        if (!((first ==  0 && last == 0) || (message >= first || message <= last)))
+        {
+            DPRINT("Message out of range!!!\n");
+            RETURN(FALSE);
+        }
+    }
+
+    if(gspv.bMouseClickLock)
+    {
+        BOOL IsClkLck = FALSE;
+
+        if(msg->message == WM_LBUTTONUP)
+        {
+            IsClkLck = ((msg->time - CurInfo->ClickLockTime) >= gspv.dwMouseClickLockTime);
+            if (IsClkLck && (!CurInfo->ClickLockActive))
+            {
+                CurInfo->ClickLockActive = TRUE;
+            }
+        }
+        else if (msg->message == WM_LBUTTONDOWN)
+        {
+            if (CurInfo->ClickLockActive)
+            {
+                IsClkLck = TRUE;
+                CurInfo->ClickLockActive = FALSE;
+            }
+
+            CurInfo->ClickLockTime = msg->time;
+        }
+
+        if(IsClkLck)
+        {
+            /* Remove and ignore the message */
+            *RemoveMessages = TRUE;
+            RETURN(FALSE);
+        }
+    }
+
+    /* message is accepted now (but may still get dropped) */
+
+    event.message = msg->message;
+    event.time    = msg->time;
+    event.hwnd    = msg->hwnd;
+    event.paramL  = msg->pt.x;
+    event.paramH  = msg->pt.y;
+    co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&event );
+
+    hook.pt           = msg->pt;
+    hook.hwnd         = msg->hwnd;
+    hook.wHitTestCode = hittest;
+    hook.dwExtraInfo  = 0/*extra_info*/;
+    if (co_HOOK_CallHooks( WH_MOUSE, *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
+                        message, (LPARAM)&hook ))
+    {
+        hook.pt           = msg->pt;
+        hook.hwnd         = msg->hwnd;
+        hook.wHitTestCode = hittest;
+        hook.dwExtraInfo  = 0/*extra_info*/;
+        co_HOOK_CallHooks( WH_CBT, HCBT_CLICKSKIPPED, message, (LPARAM)&hook );
+
+        DPRINT1("WH_MOUSE dorpped mouse message!\n");
+
+        /* Remove and skip message */
+        *RemoveMessages = TRUE;
+        RETURN(FALSE);
+    }
+
+    if ((hittest == HTERROR) || (hittest == HTNOWHERE))
+    {
+        co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd,
+                      MAKELONG( hittest, msg->message ));
+
+        /* Remove and skip message */
+        *RemoveMessages = TRUE;
+        RETURN(FALSE);
+    }
+
+    if ((*RemoveMessages == FALSE) || MessageQueue->CaptureWindow)
+    {
+        /* Accept the message */
+        msg->message = message;
+        RETURN(TRUE);
+    }
+
+    eatMsg = FALSE;
+
+    if ((msg->message == WM_LBUTTONDOWN) ||
+        (msg->message == WM_RBUTTONDOWN) ||
+        (msg->message == WM_MBUTTONDOWN) ||
+        (msg->message == WM_XBUTTONDOWN))
+    {
+        /* Send the WM_PARENTNOTIFY,
+         * note that even for double/nonclient clicks
+         * notification message is still WM_L/M/RBUTTONDOWN.
+         */
+        MsqSendParentNotify(pwndMsg, msg->message, 0, msg->pt );
+
+        /* Activate the window if needed */
+
+        if (msg->hwnd != UserGetForegroundWindow())
+        {
+            PWND pwndTop = pwndMsg;
+            while (pwndTop)
+            {
+                if ((pwndTop->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) break;
+                pwndTop = IntGetParent( pwndTop );
+            }
+
+            if (pwndTop && pwndTop != pwndDesktop)
+            {
+                LONG ret = co_IntSendMessage( msg->hwnd,
+                                              WM_MOUSEACTIVATE,
+                                              (WPARAM)UserHMGetHandle(pwndTop),
+                                              MAKELONG( hittest, msg->message));
+                switch(ret)
+                {
+                case MA_NOACTIVATEANDEAT:
+                    eatMsg = TRUE;
+                    /* fall through */
+                case MA_NOACTIVATE:
+                    break;
+                case MA_ACTIVATEANDEAT:
+                    eatMsg = TRUE;
+                    /* fall through */
+                case MA_ACTIVATE:
+                case 0:
+                    if(!co_IntMouseActivateWindow(pwndMsg)) eatMsg = TRUE;
+                    break;
+                default:
+                    DPRINT1( "unknown WM_MOUSEACTIVATE code %d\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 */
+    co_IntSendMessage( msg->hwnd, WM_SETCURSOR, (WPARAM)msg->hwnd, MAKELONG( hittest, msg->message ));
+
+    msg->message = message;
+    RETURN(!eatMsg);
+
+CLEANUP:
+    if(pwndMsg)
+        UserDereferenceObject(pwndMsg);
+
+    END_CLEANUP;
+}
+
+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;
+    Event.paramL  = (Msg->wParam & 0xFF) | (HIWORD(Msg->lParam) << 8);
+    Event.paramH  = Msg->lParam & 0x7FFF;
+    if (HIWORD(Msg->lParam) & 0x0100) Event.paramH |= 0x8000;
+    co_HOOK_CallHooks( WH_JOURNALRECORD, HC_ACTION, 0, (LPARAM)&Event);
+
+    if (co_HOOK_CallHooks( WH_KEYBOARD,
+                           *RemoveMessages ? HC_ACTION : HC_NOREMOVE,
+                           LOWORD(Msg->wParam),
+                           Msg->lParam))
+    {
+        /* skip this message */
+        co_HOOK_CallHooks( WH_CBT,
+                           HCBT_KEYSKIPPED,
+                           LOWORD(Msg->wParam),
+                           Msg->lParam );
+        DPRINT1("KeyboardMessage WH_CBT Call Hook return!\n");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+BOOL co_IntProcessHardwareMessage(MSG* Msg, BOOL* RemoveMessages, UINT first, UINT last)
+{
+    if ( IS_MOUSE_MESSAGE(Msg->message))
+    {
+        return co_IntProcessMouseMessage(Msg, RemoveMessages, first, last);
+    }
+    else if ( IS_KBD_MESSAGE(Msg->message))
+    {
+        return co_IntProcessKeyboardMessage(Msg, RemoveMessages);
+    }
+
+    return TRUE;
+}
+
+BOOL APIENTRY
+co_MsqPeekMouseMove(IN PUSER_MESSAGE_QUEUE MessageQueue,
+                   IN BOOL Remove,
+                   IN PWND Window,
+                   IN UINT MsgFilterLow,
+                   IN UINT MsgFilterHigh,
+                   OUT MSG* pMsg)
+{
+    BOOL AcceptMessage;
+    MSG msg;
+
+    if(!(MessageQueue->MouseMoved))
+        return FALSE;
+
+    msg = MessageQueue->MouseMoveMsg;
+
+    AcceptMessage = co_IntProcessMouseMessage(&msg, &Remove, MsgFilterLow, MsgFilterHigh);
+
+    if(AcceptMessage)
+        *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)
+{
+
+    BOOL AcceptMessage;
+    PUSER_MESSAGE CurrentMessage;
+    PLIST_ENTRY ListHead, CurrentEntry = NULL;
+    MSG msg;
+
+    if (!filter_contains_hw_range( MsgFilterLow, MsgFilterHigh )) return FALSE;
+
+    ListHead = &MessageQueue->HardwareMessagesListHead;
+    CurrentEntry = ListHead->Flink;
+
+    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 ( (( MsgFilterLow == 0 && MsgFilterHigh == 0 ) && (CurrentMessage->QS_Flags & QSflags)) ||
+             ( MsgFilterLow <= CurrentMessage->Msg.message && MsgFilterHigh >= CurrentMessage->Msg.message ) )
+        {
+           msg = CurrentMessage->Msg;
+
+           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;
 }
 
 BOOLEAN APIENTRY
-co_MsqFindMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
-                  IN BOOLEAN Hardware,
+MsqPeekMessage(IN PUSER_MESSAGE_QUEUE MessageQueue,
                   IN BOOLEAN Remove,
-                  IN PWINDOW_OBJECT Window,
+                  IN PWND Window,
                   IN UINT MsgFilterLow,
                   IN UINT MsgFilterHigh,
-                  OUT PUSER_MESSAGE* Message)
+                  IN UINT QSflags,
+                  OUT PMSG Message)
 {
    PLIST_ENTRY CurrentEntry;
    PUSER_MESSAGE CurrentMessage;
    PLIST_ENTRY ListHead;
 
-   if (Hardware)
-   {
-      return(co_MsqPeekHardwareMessage( MessageQueue,
-                                        Window,
-                                        MsgFilterLow,
-                                        MsgFilterHigh,
-                                        Remove,
-                                        Message));
-   }
-
    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->hSelf == 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;
+
          if (Remove)
          {
-            RemoveEntryList(&CurrentMessage->ListEntry);
+             RemoveEntryList(&CurrentMessage->ListEntry);
+             ClearMsgBitsMask(MessageQueue, CurrentMessage->QS_Flags);
+             MsqDestroyMessage(CurrentMessage);
          }
-
-         *Message = CurrentMessage;
          return(TRUE);
       }
-      CurrentEntry = CurrentEntry->Flink;
+      CurrentMessage = CONTAINING_RECORD(CurrentEntry, USER_MESSAGE,
+                                         ListEntry);
    }
+   while (CurrentEntry != ListHead);
 
    return(FALSE);
 }
 
 NTSTATUS FASTCALL
-co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWINDOW_OBJECT WndFilter,
+co_MsqWaitForNewMessages(PUSER_MESSAGE_QUEUE MessageQueue, PWND WndFilter,
                          UINT MsgFilterMin, UINT MsgFilterMax)
 {
-   PVOID WaitObjects[2] = {MessageQueue->NewMessages, &HardwareMessageEvent};
    NTSTATUS ret;
-
-   IdlePing(); // Going to wait so send Idle ping.
-
    UserLeaveCo();
-
-   ret = KeWaitForMultipleObjects(2,
-                                  WaitObjects,
-                                  WaitAny,
-                                  Executive,
-                                  UserMode,
-                                  FALSE,
-                                  NULL,
-                                  NULL);
+   ret = KeWaitForSingleObject( MessageQueue->NewMessages,
+                                UserRequest,
+                                UserMode,
+                                FALSE,
+                                NULL );
    UserEnterCo();
    return ret;
 }
@@ -1385,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)
 {
@@ -1396,7 +1587,6 @@ MsqInitializeMessageQueue(struct _ETHREAD *Thread, PUSER_MESSAGE_QUEUE MessageQu
    InitializeListHead(&MessageQueue->PostedMessagesListHead);
    InitializeListHead(&MessageQueue->SentMessagesListHead);
    InitializeListHead(&MessageQueue->HardwareMessagesListHead);
-   InitializeListHead(&MessageQueue->TimerListHead);
    InitializeListHead(&MessageQueue->DispatchingMessagesHead);
    InitializeListHead(&MessageQueue->LocalDispatchingMessagesHead);
    KeInitializeMutex(&MessageQueue->HardwareLock, 0);
@@ -1405,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,
@@ -1435,8 +1622,11 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
 {
    PLIST_ENTRY CurrentEntry;
    PUSER_MESSAGE CurrentMessage;
-   PTIMER_ENTRY CurrentTimer;
    PUSER_SENT_MESSAGE CurrentSentMessage;
+   PTHREADINFO pti;
+
+   pti = MessageQueue->Thread->Tcb.Win32Thread;
+
 
    /* cleanup posted messages */
    while (!IsListEmpty(&MessageQueue->PostedMessagesListHead))
@@ -1454,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);
@@ -1475,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);
@@ -1487,14 +1682,6 @@ MsqCleanupMessageQueue(PUSER_MESSAGE_QUEUE MessageQueue)
       ExFreePool(CurrentSentMessage);
    }
 
-   /* cleanup timers */
-   while (! IsListEmpty(&MessageQueue->TimerListHead))
-   {
-      CurrentEntry = RemoveHeadList(&MessageQueue->TimerListHead);
-      CurrentTimer = CONTAINING_RECORD(CurrentEntry, TIMER_ENTRY, ListEntry);
-      ExFreeToPagedLookasideList(&TimerLookasideList, CurrentTimer);
-   }
-
    /* notify senders of dispatching messages. This needs to be cleaned up if e.g.
       ExitThread() was called in a SendMessage() umode callback */
    while (!IsListEmpty(&MessageQueue->LocalDispatchingMessagesHead))
@@ -1503,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)
       {
@@ -1523,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);
@@ -1548,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
@@ -1557,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)
    {
@@ -1582,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)))
    {
@@ -1592,22 +1797,13 @@ 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);
 }
 
-PHOOKTABLE FASTCALL
-MsqGetHooks(PUSER_MESSAGE_QUEUE Queue)
-{
-   return Queue->Hooks;
-}
-
-VOID FASTCALL
-MsqSetHooks(PUSER_MESSAGE_QUEUE Queue, PHOOKTABLE Hooks)
-{
-   Queue->Hooks = Hooks;
-}
-
 LPARAM FASTCALL
 MsqSetMessageExtraInfo(LPARAM lParam)
 {
@@ -1644,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)
 {
@@ -1681,290 +1901,81 @@ MsqSetStateWindow(PUSER_MESSAGE_QUEUE MessageQueue, ULONG Type, HWND hWnd)
    return NULL;
 }
 
-#ifndef NDEBUG
-static VOID FASTCALL
-DumpTimerList(PUSER_MESSAGE_QUEUE MessageQueue)
-{
-   PLIST_ENTRY Current;
-   PTIMER_ENTRY Timer;
-
-   Current = MessageQueue->TimerListHead.Flink;
-   if (Current == &MessageQueue->TimerListHead)
-   {
-      DPRINT("timer list is empty for queue %p\n", MessageQueue);
-   }
-   while (Current != &MessageQueue->TimerListHead)
-   {
-      Timer = CONTAINING_RECORD(Current, TIMER_ENTRY, ListEntry);
-      DPRINT("queue %p timer %p expiry %I64d wnd %x id %p period %u timerproc %p msg %u\n",
-             MessageQueue, Timer, Timer->ExpiryTime.QuadPart, Timer->Wnd, Timer->IDEvent,
-             Timer->Period, Timer->TimerFunc, Timer->Msg);
-      Current = Current->Flink;
-   }
-}
-#endif /* ! defined(NDEBUG) */
-
-/* Must have the message queue locked while calling this */
-static VOID FASTCALL
-InsertTimer(PUSER_MESSAGE_QUEUE MessageQueue, PTIMER_ENTRY NewTimer)
+SHORT
+APIENTRY
+NtUserGetKeyState(INT key)
 {
-   PLIST_ENTRY Current;
-
-   Current = MessageQueue->TimerListHead.Flink;
-   while (Current != &MessageQueue->TimerListHead)
-   {
-      if (NewTimer->ExpiryTime.QuadPart <
-            CONTAINING_RECORD(Current, TIMER_ENTRY, ListEntry)->ExpiryTime.QuadPart)
-      {
-         break;
-      }
-      Current = Current->Flink;
-   }
-
-   InsertTailList(Current, &NewTimer->ListEntry);
-}
+   DWORD Ret;
 
-/* Must have the message queue locked while calling this */
-static PTIMER_ENTRY FASTCALL
-RemoveTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd, UINT_PTR IDEvent, UINT Msg)
-{
-   PTIMER_ENTRY Timer;
-   PLIST_ENTRY EnumEntry;
+   UserEnterExclusive();
 
-   /* Remove timer if already in the queue */
-   EnumEntry = MessageQueue->TimerListHead.Flink;
-   while (EnumEntry != &MessageQueue->TimerListHead)
-   {
-      Timer = CONTAINING_RECORD(EnumEntry, TIMER_ENTRY, ListEntry);
-      EnumEntry = EnumEntry->Flink;
+   Ret = UserGetKeyState(key);
 
-      if (Timer->Wnd == Wnd &&
-            Timer->IDEvent == IDEvent &&
-            Timer->Msg == Msg)
-      {
-         RemoveEntryList(&Timer->ListEntry);
-         return Timer;
-      }
-   }
+   UserLeave();
 
-   return NULL;
+   return Ret;
 }
 
-BOOLEAN FASTCALL
-MsqSetTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
-            UINT_PTR IDEvent, UINT Period, TIMERPROC TimerFunc,
-            UINT Msg)
-{
-   PTIMER_ENTRY Timer;
-   LARGE_INTEGER CurrentTime;
-
-   DPRINT("MsqSetTimer queue %p wnd %x id %p period %u timerproc %p msg %d\n",
-          MessageQueue, Wnd, IDEvent, Period, TimerFunc, Msg);
-
-   Timer = RemoveTimer(MessageQueue, Wnd, IDEvent, Msg);
-   if (NULL == Timer)
-   {
-      Timer = ExAllocateFromPagedLookasideList(&TimerLookasideList);
-      if (NULL == Timer)
-      {
-         DPRINT1("Failed to allocate timer entry\n");
-         return FALSE;
-      }
-      DPRINT("Allocated new timer entry %p\n", Timer);
-      Timer->Wnd = Wnd;
-      Timer->IDEvent = IDEvent;
-      Timer->Msg = Msg;
-   }
-   else
-   {
-      DPRINT("Updating existing timer entry %p\n", Timer);
-   }
-
-   KeQuerySystemTime(&CurrentTime);
-   Timer->ExpiryTime.QuadPart = CurrentTime.QuadPart +
-                                (ULONGLONG) Period * (ULONGLONG) 10000;
-   Timer->Period = Period;
-   Timer->TimerFunc = TimerFunc;
-   DPRINT("Insert timer now %I64d expiry %I64d\n", CurrentTime.QuadPart,
-          Timer->ExpiryTime.QuadPart);
 
-   InsertTimer(MessageQueue, Timer);
-
-#ifndef NDEBUG
-
-   DumpTimerList(MessageQueue);
-#endif /* ! defined(NDEBUG) */
-
-   return TRUE;
-}
-
-BOOLEAN FASTCALL
-MsqKillTimer(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd,
-             UINT_PTR IDEvent, UINT Msg)
+DWORD
+APIENTRY
+NtUserGetKeyboardState(LPBYTE lpKeyState)
 {
-   PTIMER_ENTRY Timer;
+   DWORD ret = TRUE;
+   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE MessageQueue;
 
-   DPRINT("MsqKillTimer queue %p wnd %x id %p msg %d\n",
-          MessageQueue, Wnd, IDEvent, Msg);
+   UserEnterShared();
 
-   Timer = RemoveTimer(MessageQueue, Wnd, IDEvent, Msg);
+   pti = PsGetCurrentThreadWin32Thread();
+   MessageQueue = pti->MessageQueue;
 
-   if (NULL == Timer)
+   _SEH2_TRY
    {
-      DPRINT("Failed to remove timer from list, not found\n");
+       ProbeForWrite(lpKeyState,sizeof(MessageQueue->KeyState) ,1);
+       RtlCopyMemory(lpKeyState,MessageQueue->KeyState,sizeof(MessageQueue->KeyState));
    }
-   else
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
-      ExFreeToPagedLookasideList(&TimerLookasideList, Timer);
+       SetLastNtError(_SEH2_GetExceptionCode());
+       ret = FALSE;
    }
+   _SEH2_END;
 
-#ifndef NDEBUG
-   DumpTimerList(MessageQueue);
-#endif /* ! defined(NDEBUG) */
+   UserLeave();
 
-   return NULL != Timer;
+   return ret;
 }
 
-BOOLEAN FASTCALL
-MsqGetTimerMessage(PUSER_MESSAGE_QUEUE MessageQueue,
-                   PWINDOW_OBJECT WindowFilter, UINT MsgFilterMin, UINT MsgFilterMax,
-                   MSG *Msg, BOOLEAN Restart)
+BOOL
+APIENTRY
+NtUserSetKeyboardState(LPBYTE lpKeyState)
 {
-   PTIMER_ENTRY Timer;
-   LARGE_INTEGER CurrentTime;
-   LARGE_INTEGER LargeTickCount;
-   PLIST_ENTRY EnumEntry;
-   BOOLEAN GotMessage;
-
-   DPRINT("MsqGetTimerMessage queue %p msg %p restart %s\n",
-          MessageQueue, Msg, Restart ? "TRUE" : "FALSE");
-
-   KeQuerySystemTime(&CurrentTime);
-   DPRINT("Current time %I64d\n", CurrentTime.QuadPart);
-   EnumEntry = MessageQueue->TimerListHead.Flink;
-   GotMessage = FALSE;
-   while (EnumEntry != &MessageQueue->TimerListHead)
-   {
-      Timer = CONTAINING_RECORD(MessageQueue->TimerListHead.Flink,
-                                TIMER_ENTRY, ListEntry);
-      DPRINT("Checking timer %p wnd %x expiry %I64d\n", Timer, Timer->Wnd,
-             Timer->ExpiryTime.QuadPart);
-      EnumEntry = EnumEntry->Flink;
-      if ((NULL == WindowFilter || Timer->Wnd == WindowFilter->hSelf) &&
-            ((MsgFilterMin == 0 && MsgFilterMax == 0) ||
-             (MsgFilterMin <= Timer->Msg &&
-              Timer->Msg <= MsgFilterMax)))
-      {
-         if (Timer->ExpiryTime.QuadPart <= CurrentTime.QuadPart)
-         {
-            DPRINT("Timer is expired\n");
-            GotMessage = TRUE;
-            break;
-         }
-         else
-         {
-            DPRINT("No need to check later timers\n");
-            break;
-         }
-      }
-      else
-      {
-         DPRINT("timer %p (wnd %x msg %d) failed filter wnd %x msgmin %d msgmax %d\n",
-                Timer, Timer->Wnd, Timer->Msg, WindowFilter->hSelf, MsgFilterMin, MsgFilterMax);
-      }
-   }
+   DWORD ret = TRUE;
+   PTHREADINFO pti;
+   PUSER_MESSAGE_QUEUE MessageQueue;
 
-   if (! GotMessage)
-   {
-      DPRINT("No timer pending\n");
-      return FALSE;
-   }
+   UserEnterExclusive();
 
-   Msg->hwnd = Timer->Wnd;
-   Msg->message = Timer->Msg;
-   Msg->wParam = (WPARAM) Timer->IDEvent;
-   Msg->lParam = (LPARAM) Timer->TimerFunc;
-   KeQueryTickCount(&LargeTickCount);
-   Msg->time = MsqCalculateMessageTime(&LargeTickCount);
-   Msg->pt = gpsi->ptCursor;
+   pti = PsGetCurrentThreadWin32Thread();
+   MessageQueue = pti->MessageQueue;
 
-   if (Restart)
+   _SEH2_TRY
    {
-      RemoveEntryList(&Timer->ListEntry);
-      Timer->ExpiryTime.QuadPart = CurrentTime.QuadPart +
-                                   (ULONGLONG) Timer->Period * (ULONGLONG) 10000;
-      DPRINT("Restarting timer %p expires %I64d\n", Timer, Timer->ExpiryTime.QuadPart);
-      InsertTimer(MessageQueue, Timer);
-
-#ifndef NDEBUG
-
-      DumpTimerList(MessageQueue);
-#endif /* ! defined(NDEBUG) */
-
+       ProbeForRead(lpKeyState,sizeof(MessageQueue->KeyState) ,1);
+       RtlCopyMemory(MessageQueue->KeyState,lpKeyState,sizeof(MessageQueue->KeyState));
    }
-
-   DPRINT("Created message wnd %x msg %d wParam %u lParam %u\n", Msg->hwnd, Msg->message,
-          Msg->wParam, Msg->lParam);
-
-   return TRUE;
-}
-
-VOID FASTCALL
-MsqRemoveTimersWindow(PUSER_MESSAGE_QUEUE MessageQueue, HWND Wnd)
-{
-   PTIMER_ENTRY Timer;
-   PLIST_ENTRY EnumEntry;
-
-   DPRINT("MsqRemoveTimersWindow queue %p wnd %x\n", MessageQueue, Wnd);
-
-   EnumEntry = MessageQueue->TimerListHead.Flink;
-   while (EnumEntry != &MessageQueue->TimerListHead)
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
-      Timer = CONTAINING_RECORD(EnumEntry, TIMER_ENTRY, ListEntry);
-      EnumEntry = EnumEntry->Flink;
-      if (Timer->Wnd == Wnd)
-      {
-         DPRINT("Removing timer %p because its window is going away\n", Timer);
-         RemoveEntryList(&Timer->ListEntry);
-         ExFreeToPagedLookasideList(&TimerLookasideList, Timer);
-      }
+       SetLastNtError(_SEH2_GetExceptionCode());
+       ret = FALSE;
    }
+   _SEH2_END;
 
-#ifndef NDEBUG
-   DumpTimerList(MessageQueue);
-#endif /* ! defined(NDEBUG) */
+   UserLeave();
 
+   return ret;
 }
 
-BOOLEAN FASTCALL
-MsqGetFirstTimerExpiry(PUSER_MESSAGE_QUEUE MessageQueue,
-                       PWINDOW_OBJECT WndFilter, UINT MsgFilterMin, UINT MsgFilterMax,
-                       PLARGE_INTEGER FirstTimerExpiry)
-{
-   PTIMER_ENTRY Timer;
-   PLIST_ENTRY EnumEntry;
-
-   DPRINT("MsqGetFirstTimerExpiry queue %p wndfilter %x msgfiltermin %d msgfiltermax %d expiry %p\n",
-          MessageQueue, WndFilter, MsgFilterMin, MsgFilterMax, FirstTimerExpiry);
-
-   EnumEntry = MessageQueue->TimerListHead.Flink;
-   while (EnumEntry != &MessageQueue->TimerListHead)
-   {
-      Timer = CONTAINING_RECORD(MessageQueue->TimerListHead.Flink,
-                                TIMER_ENTRY, ListEntry);
-      EnumEntry = EnumEntry->Flink;
-      if ((NULL == WndFilter || PtrToInt(WndFilter) == 1 || Timer->Wnd == WndFilter->hSelf) &&
-            ((MsgFilterMin == 0 && MsgFilterMax == 0) ||
-             (MsgFilterMin <= Timer->Msg &&
-              Timer->Msg <= MsgFilterMax)))
-      {
-         *FirstTimerExpiry = Timer->ExpiryTime;
-         DPRINT("First timer expires %I64d\n", Timer->ExpiryTime);
-         return TRUE;
-      }
-   }
-
-   return FALSE;
-}
 
 /* EOF */