[CMAKE]
[reactos.git] / subsystems / win32 / win32k / ntuser / input.c
index 316b930..604ede7 100644 (file)
@@ -2,7 +2,7 @@
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * PURPOSE:          Window classes
- * FILE:             subsys/win32k/ntuser/class.c
+ * FILE:             subsystems/win32/win32k/ntuser/input.c
  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
  * REVISION HISTORY:
  *       06-06-2001  CSH  Created
@@ -22,6 +22,8 @@ extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
 /* GLOBALS *******************************************************************/
 
 PTHREADINFO ptiRawInput;
+PTHREADINFO ptiKeyboard;
+PTHREADINFO ptiMouse;
 PKTIMER MasterTimer = NULL;
 PATTACHINFO gpai = NULL;
 
@@ -51,7 +53,7 @@ DWORD IntLastInputTick(BOOL LastInputTickSetGet);
   if(mi.dx != 0 || mi.dy != 0) \
     mi.dwFlags |= MOUSEEVENTF_MOVE; \
   if(mi.dwFlags) \
-    IntMouseInput(&mi); \
+    IntMouseInput(&mi,FALSE); \
   ClearMouseInput(mi);
 
 
@@ -79,7 +81,7 @@ NtUserGetLastInputInfo(PLASTINPUTINFO plii)
     {
         if (ProbeForReadUint(&plii->cbSize) != sizeof(LASTINPUTINFO))
         {
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);
+            EngSetLastError(ERROR_INVALID_PARAMETER);
             ret = FALSE;
             _SEH2_LEAVE;
         }
@@ -204,13 +206,6 @@ MouseThreadMain(PVOID StartContext)
    NTSTATUS Status;
    MOUSE_ATTRIBUTES MouseAttr;
 
-   Status = Win32kInitWin32Thread(PsGetCurrentThread());
-   if (!NT_SUCCESS(Status))
-   {
-      DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
-      return; //(Status);
-   }
-
    KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
                        LOW_REALTIME_PRIORITY + 3);
 
@@ -234,6 +229,18 @@ MouseThreadMain(PVOID StartContext)
                        FILE_SYNCHRONOUS_IO_ALERT);
    } while (!NT_SUCCESS(Status));
 
+ /* Need to setup basic win32k for this thread to process WH_MOUSE_LL messages. */
+   Status = Win32kInitWin32Thread(PsGetCurrentThread());
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("Win32K: Failed making mouse thread a win32 thread.\n");
+      return; //(Status);
+   }
+
+   ptiMouse = PsGetCurrentThreadWin32Thread();
+   ptiMouse->TIF_flags |= TIF_SYSTEMTHREAD;
+   DPRINT("Mouse Thread 0x%x \n", ptiMouse);
+
    KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
                        LOW_REALTIME_PRIORITY + 3);
 
@@ -369,7 +376,7 @@ IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
 
    Ret = ExAllocatePoolWithTag(PagedPool,
                                Size,
-                               TAG_KEYBOARD);
+                               USERTAG_KBDTABLE);
 
    while (Ret)
    {
@@ -385,13 +392,13 @@ IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
       if (Status != STATUS_BUFFER_TOO_SMALL)
          break;
 
-      ExFreePoolWithTag(Ret, TAG_KEYBOARD);
+      ExFreePoolWithTag(Ret, USERTAG_KBDTABLE);
 
       Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
 
       Ret = ExAllocatePoolWithTag(PagedPool,
                                   Size,
-                                  TAG_KEYBOARD);
+                                  USERTAG_KBDTABLE);
    }
 
    if (!Ret)
@@ -399,7 +406,7 @@ IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
 
    if (Status != STATUS_SUCCESS)
    {
-      ExFreePoolWithTag(Ret, TAG_KEYBOARD);
+      ExFreePoolWithTag(Ret, USERTAG_KBDTABLE);
       return Status;
    }
 
@@ -474,7 +481,8 @@ IntKeyboardSendWinKeyMsg()
 static VOID APIENTRY
 co_IntKeyboardSendAltKeyMsg()
 {
-   co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
+   DPRINT1("co_IntKeyboardSendAltKeyMsg\n");
+//   co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0); This sends everything into a msg loop!
 }
 
 static VOID APIENTRY
@@ -530,6 +538,10 @@ KeyboardThreadMain(PVOID StartContext)
       return; //(Status);
    }
 
+   ptiKeyboard = PsGetCurrentThreadWin32Thread();
+   ptiKeyboard->TIF_flags |= TIF_SYSTEMTHREAD;
+   DPRINT("Keyboard Thread 0x%x \n", ptiKeyboard);
+
    KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
                        LOW_REALTIME_PRIORITY + 3);
 
@@ -697,6 +709,7 @@ KeyboardThreadMain(PVOID StartContext)
 
                   if (ModifierState == 0)
                   {
+                     UserEnterExclusive();
                      if (fsModifiers == MOD_WIN)
                         IntKeyboardSendWinKeyMsg();
                      else if (fsModifiers == MOD_ALT)
@@ -712,6 +725,7 @@ KeyboardThreadMain(PVOID StartContext)
                         }
                         co_IntKeyboardSendAltKeyMsg();
                      }
+                     UserLeave();
                      continue;
                   }
 
@@ -720,6 +734,8 @@ KeyboardThreadMain(PVOID StartContext)
             }
          }
 
+         UserEnterExclusive();
+
          for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
                NumKeys--)
          {
@@ -778,7 +794,7 @@ KeyboardThreadMain(PVOID StartContext)
 
             if (ModifierState & MOD_ALT)
             {
-               lParam |= (1 << 29);
+               lParam |= (1 << 29); // wine -> (HIWORD(lParam) & KEYDATA_ALT) #define KEYDATA_ALT 0x2000
 
                if (!(KeyInput.Flags & KEY_BREAK))
                   msg.message = WM_SYSKEYDOWN;
@@ -849,6 +865,8 @@ KeyboardThreadMain(PVOID StartContext)
              */
             co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
          }
+
+         UserLeave();
       }
 
 KeyboardEscape:
@@ -890,8 +908,8 @@ RawInputThreadMain(PVOID StartContext)
   }
 
   ptiRawInput = PsGetCurrentThreadWin32Thread();
-  DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput);
-
+  ptiRawInput->TIF_flags |= TIF_SYSTEMTHREAD;
+  DPRINT("Raw Input Thread 0x%x \n", ptiRawInput);
 
   KeSetPriorityThread(&PsGetCurrentThread()->Tcb,
                        LOW_REALTIME_PRIORITY + 3);
@@ -922,14 +940,16 @@ RawInputThreadMain(PVOID StartContext)
   DPRINT1("Raw Input Thread Exit!\n");
 }
 
-NTSTATUS FASTCALL
+INIT_FUNCTION
+NTSTATUS
+NTAPI
 InitInputImpl(VOID)
 {
    NTSTATUS Status;
 
    KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
 
-   MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), TAG_INPUT);
+   MasterTimer = ExAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER), USERTAG_SYSTEM);
    if (!MasterTimer)
    {
       DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
@@ -992,16 +1012,6 @@ CleanupInputImp(VOID)
    return(STATUS_SUCCESS);
 }
 
-BOOL
-APIENTRY
-NtUserDragDetect(
-   HWND hWnd,
-   POINT pt) // Just like the User call.
-{
-   UNIMPLEMENTED
-   return 0;
-}
-
 BOOL FASTCALL
 IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
 {
@@ -1024,7 +1034,7 @@ IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
    if(!ThreadHasInputAccess(W32Thread) ||
          !IntIsActiveDesktop(W32Thread->rpdesk))
    {
-      SetLastWin32Error(ERROR_ACCESS_DENIED);
+      EngSetLastError(ERROR_ACCESS_DENIED);
       return FALSE;
    }
 
@@ -1034,7 +1044,7 @@ IntBlockInput(PTHREADINFO W32Thread, BOOL BlockIt)
    {
       if(OldBlock != W32Thread)
       {
-         SetLastWin32Error(ERROR_ACCESS_DENIED);
+         EngSetLastError(ERROR_ACCESS_DENIED);
          return FALSE;
       }
       W32Thread->rpdesk->BlockInputThread = (BlockIt ? W32Thread : NULL);
@@ -1064,7 +1074,7 @@ CLEANUP:
 }
 
 BOOL FASTCALL
-IntMouseInput(MOUSEINPUT *mi)
+IntMouseInput(MOUSEINPUT *mi, BOOL Injected)
 {
    const UINT SwapBtnMsg[2][2] =
       {
@@ -1128,7 +1138,7 @@ IntMouseInput(MOUSEINPUT *mi)
 
    if(mi->dwFlags & MOUSEEVENTF_MOVE)
    {
-      UserSetCursorPos(MousePos.x, MousePos.y, TRUE);
+      UserSetCursorPos(MousePos.x, MousePos.y, Injected, mi->dwExtraInfo, TRUE);
    }
    if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
    {
@@ -1136,7 +1146,7 @@ IntMouseInput(MOUSEINPUT *mi)
       Msg.message = SwapBtnMsg[0][SwapButtons];
       CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
       Msg.wParam |= CurInfo->ButtonsDown;
-      MsqInsertSystemMessage(&Msg);
+      co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
    }
    else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
    {
@@ -1144,7 +1154,7 @@ IntMouseInput(MOUSEINPUT *mi)
       Msg.message = SwapBtnMsg[1][SwapButtons];
       CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
       Msg.wParam |= CurInfo->ButtonsDown;
-      MsqInsertSystemMessage(&Msg);
+      co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
    }
    if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
    {
@@ -1152,7 +1162,7 @@ IntMouseInput(MOUSEINPUT *mi)
       Msg.message = WM_MBUTTONDOWN;
       CurInfo->ButtonsDown |= MK_MBUTTON;
       Msg.wParam |= CurInfo->ButtonsDown;
-      MsqInsertSystemMessage(&Msg);
+      co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
    }
    else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
    {
@@ -1160,7 +1170,7 @@ IntMouseInput(MOUSEINPUT *mi)
       Msg.message = WM_MBUTTONUP;
       CurInfo->ButtonsDown &= ~MK_MBUTTON;
       Msg.wParam |= CurInfo->ButtonsDown;
-      MsqInsertSystemMessage(&Msg);
+      co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
    }
    if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
    {
@@ -1168,7 +1178,7 @@ IntMouseInput(MOUSEINPUT *mi)
       Msg.message = SwapBtnMsg[0][!SwapButtons];
       CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
       Msg.wParam |= CurInfo->ButtonsDown;
-      MsqInsertSystemMessage(&Msg);
+      co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
    }
    else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
    {
@@ -1176,7 +1186,7 @@ IntMouseInput(MOUSEINPUT *mi)
       Msg.message = SwapBtnMsg[1][!SwapButtons];
       CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
       Msg.wParam |= CurInfo->ButtonsDown;
-      MsqInsertSystemMessage(&Msg);
+      co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
    }
 
    if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
@@ -1194,14 +1204,14 @@ IntMouseInput(MOUSEINPUT *mi)
          gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
          CurInfo->ButtonsDown |= MK_XBUTTON1;
          Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
-         MsqInsertSystemMessage(&Msg);
+         co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
       }
       if(mi->mouseData & XBUTTON2)
       {
          gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
          CurInfo->ButtonsDown |= MK_XBUTTON2;
          Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
-         MsqInsertSystemMessage(&Msg);
+         co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
       }
    }
    else if(mi->dwFlags & MOUSEEVENTF_XUP)
@@ -1212,45 +1222,39 @@ IntMouseInput(MOUSEINPUT *mi)
          gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
          CurInfo->ButtonsDown &= ~MK_XBUTTON1;
          Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
-         MsqInsertSystemMessage(&Msg);
+         co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
       }
       if(mi->mouseData & XBUTTON2)
       {
          gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
          CurInfo->ButtonsDown &= ~MK_XBUTTON2;
          Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
-         MsqInsertSystemMessage(&Msg);
+         co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
       }
    }
    if(mi->dwFlags & MOUSEEVENTF_WHEEL)
    {
       Msg.message = WM_MOUSEWHEEL;
       Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
-      MsqInsertSystemMessage(&Msg);
+      co_MsqInsertMouseMessage(&Msg, Injected, mi->dwExtraInfo, TRUE);
    }
 
    return TRUE;
 }
 
 BOOL FASTCALL
-IntKeyboardInput(KEYBDINPUT *ki)
+IntKeyboardInput(KEYBDINPUT *ki, BOOL Injected)
 {
    PUSER_MESSAGE_QUEUE FocusMessageQueue;
    MSG Msg;
    LARGE_INTEGER LargeTickCount;
    KBDLLHOOKSTRUCT KbdHookData;
    WORD flags, wVkStripped, wVkL, wVkR, wVk = ki->wVk, vk_hook = ki->wVk;
-   BOOLEAN Entered = FALSE;
 
    Msg.lParam = 0;
 
-  // 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;
-   }
+   // Condition may arise when calling MsqPostMessage and waiting for an event.
+   ASSERT (UserIsEntered());
 
    wVk = LOBYTE(wVk);
    Msg.wParam = wVk;
@@ -1293,9 +1297,10 @@ IntKeyboardInput(KEYBDINPUT *ki)
    if (ki->dwFlags & KEYEVENTF_KEYUP)
    {
       Msg.message = WM_KEYUP;
-      if ((gQueueKeyStateTable[VK_MENU] & 0x80) &&
+      if (((gQueueKeyStateTable[VK_MENU] & 0x80) &&
           ((wVkStripped == VK_MENU) || (wVkStripped == VK_CONTROL)
            || !(gQueueKeyStateTable[VK_CONTROL] & 0x80)))
+          || (wVkStripped == VK_F10))
       {
          if( TrackSysKey == VK_MENU || /* <ALT>-down/<ALT>-up sequence */
              (wVkStripped != VK_MENU)) /* <ALT>-down...<something else>-up */
@@ -1307,8 +1312,9 @@ IntKeyboardInput(KEYBDINPUT *ki)
    else
    {
       Msg.message = WM_KEYDOWN;
-      if ((gQueueKeyStateTable[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
+      if (((gQueueKeyStateTable[VK_MENU] & 0x80 || wVkStripped == VK_MENU) &&
           !(gQueueKeyStateTable[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL))
+          || (wVkStripped == VK_F10))
       {
          Msg.message = WM_SYSKEYDOWN;
          TrackSysKey = wVkStripped;
@@ -1339,17 +1345,18 @@ IntKeyboardInput(KEYBDINPUT *ki)
 
    /* All messages have to contain the cursor point. */
    Msg.pt = gpsi->ptCursor;
-   
+
    KbdHookData.vkCode = vk_hook;
    KbdHookData.scanCode = ki->wScan;
    KbdHookData.flags = flags >> 8;
+   if (Injected) KbdHookData.flags |= LLKHF_INJECTED;
    KbdHookData.time = Msg.time;
    KbdHookData.dwExtraInfo = ki->dwExtraInfo;
    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, vk_hook, Msg.lParam);
-      if (Entered) UserLeave();
+
       return FALSE;
    }
 
@@ -1377,7 +1384,7 @@ IntKeyboardInput(KEYBDINPUT *ki)
    if (FocusMessageQueue == NULL)
    {
          DPRINT("No focus message queue\n");
-         if (Entered) UserLeave();
+
          return FALSE;
    }
 
@@ -1389,16 +1396,15 @@ IntKeyboardInput(KEYBDINPUT *ki)
          FocusMessageQueue->Desktop->pDeskInfo->LastInputWasKbd = TRUE;
 
          Msg.pt = gpsi->ptCursor;
-
-         MsqPostMessage(FocusMessageQueue, &Msg, FALSE, QS_KEY);
+      // Post to hardware queue, based on the first part of wine "some GetMessage tests"
+      // in test_PeekMessage()
+         MsqPostMessage(FocusMessageQueue, &Msg, TRUE, QS_KEY);
    }
    else
    {
          DPRINT("Invalid focus window handle\n");
    }
 
-   if (Entered) UserLeave();
-
    return TRUE;
 }
 
@@ -1419,7 +1425,7 @@ UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
    /* If Attach set, allocate and link. */
    if ( fAttach )
    {
-      pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), TAG_ATTACHINFO);
+      pai = ExAllocatePoolWithTag(PagedPool, sizeof(ATTACHINFO), USERTAG_ATTACHINFO);
       if ( !pai ) return FALSE;
 
       pai->paiNext = gpai;
@@ -1447,7 +1453,7 @@ UserAttachThreadInput( PTHREADINFO pti, PTHREADINFO ptiTo, BOOL fAttach)
 
       if (paiprev) paiprev->paiNext = pai->paiNext;
 
-      ExFreePoolWithTag(pai, TAG_ATTACHINFO);
+      ExFreePoolWithTag(pai, USERTAG_ATTACHINFO);
   }
 
   return TRUE;
@@ -1477,7 +1483,7 @@ NtUserSendInput(
 
    if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
    {
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      EngSetLastError(ERROR_INVALID_PARAMETER);
       RETURN( 0);
    }
 
@@ -1488,7 +1494,7 @@ NtUserSendInput(
    if(!ThreadHasInputAccess(W32Thread) ||
          !IntIsActiveDesktop(W32Thread->rpdesk))
    {
-      SetLastWin32Error(ERROR_ACCESS_DENIED);
+      EngSetLastError(ERROR_ACCESS_DENIED);
       RETURN( 0);
    }
 
@@ -1508,13 +1514,13 @@ NtUserSendInput(
       switch(SafeInput.type)
       {
          case INPUT_MOUSE:
-            if(IntMouseInput(&SafeInput.mi))
+            if(IntMouseInput(&SafeInput.mi, TRUE))
             {
                cnt++;
             }
             break;
          case INPUT_KEYBOARD:
-            if(IntKeyboardInput(&SafeInput.ki))
+            if(IntKeyboardInput(&SafeInput.ki, TRUE))
             {
                cnt++;
             }
@@ -1539,4 +1545,280 @@ CLEANUP:
    END_CLEANUP;
 }
 
+BOOL
+FASTCALL
+IntQueryTrackMouseEvent(
+   LPTRACKMOUSEEVENT lpEventTrack)
+{
+   PDESKTOP pDesk;
+   PTHREADINFO pti;
+
+   pti = PsGetCurrentThreadWin32Thread();
+   pDesk = pti->rpdesk;
+
+   /* Always cleared with size set and return true. */
+   RtlZeroMemory(lpEventTrack ,sizeof(TRACKMOUSEEVENT));
+   lpEventTrack->cbSize = sizeof(TRACKMOUSEEVENT);
+
+   if ( pDesk->dwDTFlags & (DF_TME_LEAVE|DF_TME_HOVER) &&
+        pDesk->spwndTrack &&
+        pti->MessageQueue == pDesk->spwndTrack->head.pti->MessageQueue )
+   {
+      if ( pDesk->htEx != HTCLIENT )
+         lpEventTrack->dwFlags |= TME_NONCLIENT;
+
+      if ( pDesk->dwDTFlags & DF_TME_LEAVE )
+         lpEventTrack->dwFlags |= TME_LEAVE;
+
+      if ( pDesk->dwDTFlags & DF_TME_HOVER )
+      {
+         lpEventTrack->dwFlags |= TME_HOVER;
+         lpEventTrack->dwHoverTime = pDesk->dwMouseHoverTime;
+      }
+      lpEventTrack->hwndTrack = UserHMGetHandle(pDesk->spwndTrack);
+   }
+   return TRUE;
+}
+
+BOOL
+FASTCALL
+IntTrackMouseEvent(
+   LPTRACKMOUSEEVENT lpEventTrack)
+{
+   PDESKTOP pDesk;
+   PTHREADINFO pti;
+   PWND pWnd;
+   POINT point;
+
+   pti = PsGetCurrentThreadWin32Thread();
+   pDesk = pti->rpdesk;
+
+   if (!(pWnd = UserGetWindowObject(lpEventTrack->hwndTrack)))
+      return FALSE;
+
+   if ( pDesk->spwndTrack != pWnd ||
+       (pDesk->htEx != HTCLIENT) ^ !!(lpEventTrack->dwFlags & TME_NONCLIENT) )
+   {
+      if ( lpEventTrack->dwFlags & TME_LEAVE && !(lpEventTrack->dwFlags & TME_CANCEL) )
+      {
+         UserPostMessage( lpEventTrack->hwndTrack,
+                          lpEventTrack->dwFlags & TME_NONCLIENT ? WM_NCMOUSELEAVE : WM_MOUSELEAVE,
+                          0, 0);
+      }
+      DPRINT("IntTrackMouseEvent spwndTrack 0x%x pwnd 0x%x\n", pDesk->spwndTrack,pWnd);
+      return TRUE;
+   }
+
+   /* Tracking spwndTrack same as pWnd */
+   if ( lpEventTrack->dwFlags & TME_CANCEL ) // Canceled mode.
+   {
+      if ( lpEventTrack->dwFlags & TME_LEAVE )
+         pDesk->dwDTFlags &= ~DF_TME_LEAVE;
+
+      if ( lpEventTrack->dwFlags & TME_HOVER )
+      {
+         if ( pDesk->dwDTFlags & DF_TME_HOVER )
+         { // Kill hover timer.
+            IntKillTimer(pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, TRUE);
+            pDesk->dwDTFlags &= ~DF_TME_HOVER;
+         }
+      }
+   }
+   else // Not Canceled.
+   {
+      if ( lpEventTrack->dwFlags & TME_LEAVE )
+         pDesk->dwDTFlags |= DF_TME_LEAVE;
+
+      if ( lpEventTrack->dwFlags & TME_HOVER )
+      {
+         pDesk->dwDTFlags |= DF_TME_HOVER;
+
+         if ( !lpEventTrack->dwHoverTime || lpEventTrack->dwHoverTime == HOVER_DEFAULT )
+            pDesk->dwMouseHoverTime = gspv.iMouseHoverTime; // use the system default hover time-out.
+         else
+            pDesk->dwMouseHoverTime = lpEventTrack->dwHoverTime;
+         // Start timer for the hover period.
+         IntSetTimer( pWnd, ID_EVENT_SYSTIMER_MOUSEHOVER, pDesk->dwMouseHoverTime, SystemTimerProc, TMRF_SYSTEM);
+         // Get windows thread message points.
+         point = pWnd->head.pti->ptLast;
+         // Set desktop mouse hover from the system default hover rectangle.
+         RECTL_vSetRect(&pDesk->rcMouseHover,
+                         point.x - gspv.iMouseHoverWidth  / 2,
+                         point.y - gspv.iMouseHoverHeight / 2,
+                         point.x + gspv.iMouseHoverWidth  / 2,
+                         point.y + gspv.iMouseHoverHeight / 2);
+      }
+   }
+   return TRUE;
+}
+
+BOOL
+APIENTRY
+NtUserTrackMouseEvent(
+   LPTRACKMOUSEEVENT lpEventTrack)
+{
+   TRACKMOUSEEVENT saveTME;
+   BOOL Ret = FALSE;
+
+   DPRINT("Enter NtUserTrackMouseEvent\n");
+   UserEnterExclusive();
+
+   _SEH2_TRY
+   {
+      ProbeForRead(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
+      RtlCopyMemory(&saveTME, lpEventTrack, sizeof(TRACKMOUSEEVENT));
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      SetLastNtError(_SEH2_GetExceptionCode());
+      _SEH2_YIELD(goto Exit;)
+   }
+   _SEH2_END;
+
+   if ( saveTME.cbSize != sizeof(TRACKMOUSEEVENT) )
+   {
+      EngSetLastError(ERROR_INVALID_PARAMETER);
+      goto Exit;
+   }
+
+   if (saveTME.dwFlags & ~(TME_CANCEL|TME_QUERY|TME_NONCLIENT|TME_LEAVE|TME_HOVER) )
+   {
+      EngSetLastError(ERROR_INVALID_FLAGS);
+      goto Exit;
+   }
+
+   if ( saveTME.dwFlags & TME_QUERY )
+   {
+      Ret = IntQueryTrackMouseEvent(&saveTME);
+      _SEH2_TRY
+      {
+         ProbeForWrite(lpEventTrack, sizeof(TRACKMOUSEEVENT), 1);
+         RtlCopyMemory(lpEventTrack, &saveTME, sizeof(TRACKMOUSEEVENT));
+      }
+      _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+      {
+         SetLastNtError(_SEH2_GetExceptionCode());
+         Ret = FALSE;
+      }
+      _SEH2_END;
+   }
+   else
+   {
+      Ret = IntTrackMouseEvent(&saveTME);
+   }
+   
+Exit:
+   DPRINT("Leave NtUserTrackMouseEvent, ret=%i\n",Ret);
+   UserLeave();
+   return Ret;
+}
+
+extern MOUSEMOVEPOINT MouseHistoryOfMoves[];
+extern INT gcur_count; 
+
+DWORD
+APIENTRY
+NtUserGetMouseMovePointsEx(
+   UINT cbSize,
+   LPMOUSEMOVEPOINT lpptIn,
+   LPMOUSEMOVEPOINT lpptOut,
+   int nBufPoints,
+   DWORD resolution)
+{
+   MOUSEMOVEPOINT Safeppt;
+   BOOL Hit;
+   INT Count = -1;
+   DECLARE_RETURN(DWORD);
+
+   DPRINT("Enter NtUserGetMouseMovePointsEx\n");
+   UserEnterExclusive();
+
+   if ((cbSize != sizeof(MOUSEMOVEPOINT)) || (nBufPoints < 0) || (nBufPoints > 64))
+   {
+      EngSetLastError(ERROR_INVALID_PARAMETER);
+      RETURN( -1);
+   }
+
+   if (!lpptIn || (!lpptOut && nBufPoints))
+   {
+      EngSetLastError(ERROR_NOACCESS);
+      RETURN( -1);
+   }
+
+   _SEH2_TRY
+   {
+      ProbeForRead( lpptIn, cbSize, 1);
+      RtlCopyMemory(&Safeppt, lpptIn, cbSize);
+   }
+   _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+   {
+      SetLastNtError(_SEH2_GetExceptionCode());
+      _SEH2_YIELD(RETURN( -1))
+   }
+   _SEH2_END;
+
+   // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
+   // This explains the math issues in transforming points.
+   Count = gcur_count; // FIFO is forward so retrieve backward.
+   Hit = FALSE;
+   do
+   {
+       if (Safeppt.x == 0 && Safeppt.y == 0)
+          break; // No test.
+       // Finds the point, it returns the last nBufPoints prior to and including the supplied point. 
+       if (MouseHistoryOfMoves[Count].x == Safeppt.x && MouseHistoryOfMoves[Count].y == Safeppt.y)
+       {
+          if ( Safeppt.time ) // Now test time and it seems to be absolute.
+          {
+             if (Safeppt.time == MouseHistoryOfMoves[Count].time)
+             {
+                Hit = TRUE;
+                break;
+             }
+             else
+             {
+                if (--Count < 0) Count = 63;
+                continue;
+             }
+          }
+          Hit = TRUE;
+          break;
+       }
+       if (--Count < 0) Count = 63;
+   }
+   while ( Count != gcur_count);
+
+   switch(resolution)
+   {
+     case GMMP_USE_DISPLAY_POINTS:
+        if (nBufPoints)
+        {
+           _SEH2_TRY
+           {
+              ProbeForWrite(lpptOut, cbSize, 1);
+           }
+           _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+           {
+              SetLastNtError(_SEH2_GetExceptionCode());
+              _SEH2_YIELD(RETURN( -1))
+           }
+           _SEH2_END;
+        }
+        Count = nBufPoints;
+        break;
+     case GMMP_USE_HIGH_RESOLUTION_POINTS:
+        break;
+     default:
+        EngSetLastError(ERROR_POINT_NOT_FOUND);
+        RETURN( -1);
+   }
+
+   RETURN( Count);
+
+CLEANUP:
+   DPRINT("Leave NtUserGetMouseMovePointsEx, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
 /* EOF */