Fixed skipped events from keyboard:
[reactos.git] / reactos / subsys / win32k / ntuser / input.c
index f2ff2a0..f9e77ff 100644 (file)
@@ -16,7 +16,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: input.c,v 1.33 2004/05/14 23:57:32 weiden Exp $
+/* $Id$
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
 /* INCLUDES ******************************************************************/
 
 #include <w32k.h>
-
-#include <rosrtl/string.h>
+#include <ddk/ntddkbd.h>
 
 #define NDEBUG
 #include <debug.h>
 
-/* GLOBALS *******************************************************************/
+extern BYTE gQueueKeyStateTable[];
 
-#define ENABLEMOUSEGDICALLBACK 1
+/* GLOBALS *******************************************************************/
 
 static HANDLE MouseDeviceHandle;
-#if !ENABLEMOUSEGDICALLBACK
 static HANDLE MouseThreadHandle;
 static CLIENT_ID MouseThreadId;
-#endif
 static HANDLE KeyboardThreadHandle;
 static CLIENT_ID KeyboardThreadId;
 static HANDLE KeyboardDeviceHandle;
@@ -54,771 +51,1186 @@ PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue = 0;
 
 /* FUNCTIONS *****************************************************************/
 
-#if !ENABLEMOUSEGDICALLBACK
-VOID STDCALL_FUNC STATIC
+#define ClearMouseInput(mi) \
+  mi.dx = 0; \
+  mi.dy = 0; \
+  mi.mouseData = 0; \
+  mi.dwFlags = 0;
+
+#define SendMouseEvent(mi) \
+  if(mi.dx != 0 || mi.dy != 0) \
+    mi.dwFlags |= MOUSEEVENTF_MOVE; \
+  if(mi.dwFlags) \
+    IntMouseInput(&mi); \
+  ClearMouseInput(mi);
+
+VOID FASTCALL
+ProcessMouseInputData(PMOUSE_INPUT_DATA Data, ULONG InputCount)
+{
+   PMOUSE_INPUT_DATA mid;
+   MOUSEINPUT mi;
+   ULONG i;
+
+   ClearMouseInput(mi);
+   mi.time = 0;
+   mi.dwExtraInfo = 0;
+   for(i = 0; i < InputCount; i++)
+   {
+      mid = (Data + i);
+      mi.dx += mid->LastX;
+      mi.dy += mid->LastY;
+
+      if(mid->ButtonFlags)
+      {
+         if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN)
+         {
+            mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP)
+         {
+            mi.dwFlags |= MOUSEEVENTF_LEFTUP;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
+         {
+            mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
+         {
+            mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN)
+         {
+            mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP)
+         {
+            mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_BUTTON_4_DOWN)
+         {
+            mi.mouseData |= XBUTTON1;
+            mi.dwFlags |= MOUSEEVENTF_XDOWN;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_BUTTON_4_UP)
+         {
+            mi.mouseData |= XBUTTON1;
+            mi.dwFlags |= MOUSEEVENTF_XUP;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_BUTTON_5_DOWN)
+         {
+            mi.mouseData |= XBUTTON2;
+            mi.dwFlags |= MOUSEEVENTF_XDOWN;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_BUTTON_5_UP)
+         {
+            mi.mouseData |= XBUTTON2;
+            mi.dwFlags |= MOUSEEVENTF_XUP;
+            SendMouseEvent(mi);
+         }
+         if(mid->ButtonFlags & MOUSE_WHEEL)
+         {
+            mi.mouseData = mid->ButtonData;
+            mi.dwFlags |= MOUSEEVENTF_WHEEL;
+            SendMouseEvent(mi);
+         }
+      }
+   }
+
+   SendMouseEvent(mi);
+}
+
+VOID STDCALL
 MouseThreadMain(PVOID StartContext)
 {
-  UNICODE_STRING MouseDeviceName;
-  OBJECT_ATTRIBUTES MouseObjectAttributes;
-  IO_STATUS_BLOCK Iosb;
-  NTSTATUS Status;
-  
-  RtlRosInitUnicodeStringFromLiteral(&MouseDeviceName, L"\\??\\Mouse"); /* FIXME - does win use the same? */
-  InitializeObjectAttributes(&MouseObjectAttributes,
-                             &MouseDeviceName,
-                             0,
+   UNICODE_STRING MouseDeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerClass0");
+   OBJECT_ATTRIBUTES MouseObjectAttributes;
+   IO_STATUS_BLOCK Iosb;
+   NTSTATUS Status;
+
+   InitializeObjectAttributes(&MouseObjectAttributes,
+                              &MouseDeviceName,
+                              0,
+                              NULL,
+                              NULL);
+   do
+   {
+      LARGE_INTEGER DueTime;
+      KEVENT Event;
+      DueTime.QuadPart = (LONGLONG)(-10000000);
+      KeInitializeEvent(&Event, NotificationEvent, FALSE);
+      Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime); 
+      Status = NtOpenFile(&MouseDeviceHandle,
+                       FILE_ALL_ACCESS,
+                       &MouseObjectAttributes,
+                       &Iosb,
+                       0,
+                       FILE_SYNCHRONOUS_IO_ALERT);
+   } while (!NT_SUCCESS(Status));
+
+   for(;;)
+   {
+      /*
+       * Wait to start input.
+       */
+      DPRINT("Mouse Input Thread Waiting for start event\n");
+      Status = KeWaitForSingleObject(&InputThreadsStart,
+                                     0,
+                                     KernelMode,
+                                     TRUE,
+                                     NULL);
+      DPRINT("Mouse Input Thread Starting...\n");
+
+      /*
+       * Receive and process mouse input.
+       */
+      while(InputThreadsRunning)
+      {
+         MOUSE_INPUT_DATA MouseInput;
+         Status = NtReadFile(MouseDeviceHandle,
+                             NULL,
+                             NULL,
+                             NULL,
+                             &Iosb,
+                             &MouseInput,
+                             sizeof(MOUSE_INPUT_DATA),
                              NULL,
                              NULL);
-  Status = NtOpenFile(&MouseDeviceHandle,
-                      FILE_ALL_ACCESS,
-                      &MouseObjectAttributes,
-                      &Iosb,
-                      0,
-                      FILE_SYNCHRONOUS_IO_ALERT);
-  if(!NT_SUCCESS(Status))
-  {
-    DPRINT1("Win32K: Failed to open mouse.\n");
-    return; //(Status);
-  }
-  
-  for(;;)
-  {
-    /*
-     * Wait to start input.
-     */
-    DPRINT("Mouse Input Thread Waiting for start event\n");
-    Status = KeWaitForSingleObject(&InputThreadsStart,
-                                   0,
-                                   KernelMode,
-                                   TRUE,
-                                   NULL);
-    DPRINT("Mouse Input Thread Starting...\n");
-    
-    /*
-     * Receive and process keyboard input.
-     */
-    while(InputThreadsRunning)
-    {
-      MOUSE_INPUT_DATA MouseInput;
-      Status = NtReadFile(MouseDeviceHandle,
-                          NULL,
-                          NULL,
-                          NULL,
-                          &Iosb,
-                          &MouseInput,
-                          sizeof(MOUSE_INPUT_DATA),
-                          NULL,
-                          NULL);
-      if(Status == STATUS_ALERTED && !InputThreadsRunning)
+         if(Status == STATUS_ALERTED && !InputThreadsRunning)
+         {
+            break;
+         }
+         if(Status == STATUS_PENDING)
+         {
+            NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
+            Status = Iosb.Status;
+         }
+         if(!NT_SUCCESS(Status))
+         {
+            DPRINT1("Win32K: Failed to read from mouse.\n");
+            return; //(Status);
+         }
+         DPRINT("MouseEvent\n");
+
+         UserEnterExclusive();
+
+         ProcessMouseInputData(&MouseInput, Iosb.Information / sizeof(MOUSE_INPUT_DATA));
+
+         UserLeave();
+      }
+      DPRINT("Mouse Input Thread Stopped...\n");
+   }
+}
+
+/* Returns a value that indicates if the key is a modifier key, and
+ * which one.
+ */
+STATIC UINT STDCALL
+IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
+{
+   if (InputData->Flags & KEY_E1)
+      return 0;
+
+   if (!(InputData->Flags & KEY_E0))
+   {
+      switch (InputData->MakeCode)
       {
-        break;
+         case 0x2a: /* left shift */
+         case 0x36: /* right shift */
+            return MOD_SHIFT;
+
+         case 0x1d: /* left control */
+            return MOD_CONTROL;
+
+         case 0x38: /* left alt */
+            return MOD_ALT;
+
+         default:
+            return 0;
       }
-      if(Status == STATUS_PENDING)
+   }
+   else
+   {
+      switch (InputData->MakeCode)
       {
-        NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
-        Status = Iosb.Status;
+         case 0x1d: /* right control */
+            return MOD_CONTROL;
+
+         case 0x38: /* right alt */
+            return MOD_ALT;
+
+         case 0x5b: /* left gui (windows) */
+         case 0x5c: /* right gui (windows) */
+            return MOD_WIN;
+
+         default:
+            return 0;
       }
-      if(!NT_SUCCESS(Status))
+   }
+}
+
+/* Asks the keyboard driver to send a small table that shows which
+ * lights should connect with which scancodes
+ */
+STATIC NTSTATUS STDCALL
+IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
+                             PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
+{
+   NTSTATUS Status;
+   DWORD Size = 0;
+   IO_STATUS_BLOCK Block;
+   PKEYBOARD_INDICATOR_TRANSLATION Ret;
+
+   Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
+
+   Ret = ExAllocatePoolWithTag(PagedPool,
+                               Size,
+                               TAG_KEYBOARD);
+
+   while (Ret)
+   {
+      Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
+                                     NULL,
+                                     NULL,
+                                     NULL,
+                                     &Block,
+                                     IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
+                                     NULL, 0,
+                                     Ret, Size);
+
+      if (Status != STATUS_BUFFER_TOO_SMALL)
+         break;
+
+      ExFreePool(Ret);
+
+      Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
+
+      Ret = ExAllocatePoolWithTag(PagedPool,
+                                  Size,
+                                  TAG_KEYBOARD);
+   }
+
+   if (!Ret)
+      return STATUS_INSUFFICIENT_RESOURCES;
+
+   if (Status != STATUS_SUCCESS)
+   {
+      ExFreePool(Ret);
+      return Status;
+   }
+
+   *IndicatorTrans = Ret;
+   return Status;
+}
+
+/* Sends the keyboard commands to turn on/off the lights.
+ */
+STATIC NTSTATUS STDCALL
+IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
+                      PKEYBOARD_INPUT_DATA KeyInput,
+                      PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
+{
+   NTSTATUS Status;
+   UINT Count;
+   static KEYBOARD_INDICATOR_PARAMETERS Indicators;
+   IO_STATUS_BLOCK Block;
+
+   if (!IndicatorTrans)
+      return STATUS_NOT_SUPPORTED;
+
+   if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
+      return STATUS_SUCCESS;
+
+   for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
+   {
+      if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
       {
-        DPRINT1("Win32K: Failed to read from mouse.\n");
-        return; //(Status);
+         Indicators.LedFlags ^=
+            IndicatorTrans->IndicatorList[Count].IndicatorFlags;
+
+         /* Update the lights on the hardware */
+
+         Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
+                                        NULL,
+                                        NULL,
+                                        NULL,
+                                        &Block,
+                                        IOCTL_KEYBOARD_SET_INDICATORS,
+                                        &Indicators, sizeof(Indicators),
+                                        NULL, 0);
+
+         return Status;
       }
-      DPRINT("MouseEvent\n");
-      
-      MouseGDICallBack(&MouseInput, sizeof(MOUSE_INPUT_DATA));
-    }
-    DPRINT("Mouse Input Thread Stopped...\n");
-  }
+   }
+
+   return STATUS_SUCCESS;
+}
+
+STATIC VOID STDCALL
+IntKeyboardSendWinKeyMsg()
+{
+   PWINDOW_OBJECT Window;
+   MSG Mesg;
+
+   if (!(Window = UserGetWindowObject(InputWindowStation->ShellWindow)))
+   {
+      DPRINT1("Couldn't find window to send Windows key message!\n");
+      return;
+   }
+
+   Mesg.hwnd = InputWindowStation->ShellWindow;
+   Mesg.message = WM_SYSCOMMAND;
+   Mesg.wParam = SC_TASKLIST;
+   Mesg.lParam = 0;
+
+   /* The QS_HOTKEY is just a guess */
+   MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
+}
+
+STATIC VOID STDCALL
+co_IntKeyboardSendAltKeyMsg()
+{
+   co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
 }
-#endif
 
 STATIC VOID STDCALL
 KeyboardThreadMain(PVOID StartContext)
 {
-  UNICODE_STRING KeyboardDeviceName;
-  OBJECT_ATTRIBUTES KeyboardObjectAttributes;
-  IO_STATUS_BLOCK Iosb;
-  NTSTATUS Status;
-  MSG msg;
-  PUSER_MESSAGE_QUEUE FocusQueue;
-  struct _ETHREAD *FocusThread;
-  
-  RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
-  InitializeObjectAttributes(&KeyboardObjectAttributes,
-                            &KeyboardDeviceName,
-                            0,
-                            NULL,
-                            NULL);
-  Status = NtOpenFile(&KeyboardDeviceHandle,
-                     FILE_ALL_ACCESS,
-                     &KeyboardObjectAttributes,
-                     &Iosb,
-                     0,
-                     FILE_SYNCHRONOUS_IO_ALERT);
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT1("Win32K: Failed to open keyboard.\n");
+   UNICODE_STRING KeyboardDeviceName = RTL_CONSTANT_STRING(L"\\Device\\KeyboardClass0");
+   OBJECT_ATTRIBUTES KeyboardObjectAttributes;
+   IO_STATUS_BLOCK Iosb;
+   NTSTATUS Status;
+   MSG msg;
+   PUSER_MESSAGE_QUEUE FocusQueue;
+   struct _ETHREAD *FocusThread;
+   extern NTSTATUS Win32kInitWin32Thread(PETHREAD Thread);
+
+   PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
+   UINT ModifierState = 0;
+   USHORT LastMakeCode = 0;
+   USHORT LastFlags = 0;
+   UINT RepeatCount = 0;
+
+   InitializeObjectAttributes(&KeyboardObjectAttributes,
+                              &KeyboardDeviceName,
+                              0,
+                              NULL,
+                              NULL);
+   do
+   {
+      LARGE_INTEGER DueTime;
+      KEVENT Event;
+      DueTime.QuadPart = (LONGLONG)(-10000000);
+      KeInitializeEvent(&Event, NotificationEvent, FALSE);
+      Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &DueTime); 
+      Status = NtOpenFile(&KeyboardDeviceHandle,
+                       FILE_ALL_ACCESS,
+                       &KeyboardObjectAttributes,
+                       &Iosb,
+                       0,
+                       FILE_SYNCHRONOUS_IO_ALERT);
+   } while (!NT_SUCCESS(Status));
+
+   /* Not sure if converting this thread to a win32 thread is such
+      a great idea. Since we're posting keyboard messages to the focus
+      window message queue, we'll be (indirectly) doing sendmessage
+      stuff from this thread (for WH_KEYBOARD_LL processing), which
+      means we need our own message queue. If keyboard messages were
+      instead queued to the system message queue, the thread removing
+      the message from the system message queue would be responsible
+      for WH_KEYBOARD_LL processing and we wouldn't need this thread
+      to be a win32 thread. */
+   Status = Win32kInitWin32Thread(PsGetCurrentThread());
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
       return; //(Status);
-    }
+   }
+
+   IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
+                                &IndicatorTrans);
 
-  for (;;)
-    {
+   for (;;)
+   {
       /*
        * Wait to start input.
        */
       DPRINT( "Keyboard Input Thread Waiting for start event\n" );
       Status = KeWaitForSingleObject(&InputThreadsStart,
-                                    0,
-                                    KernelMode,
-                                    TRUE,
-                                    NULL);
+                                     0,
+                                     KernelMode,
+                                     TRUE,
+                                     NULL);
       DPRINT( "Keyboard Input Thread Starting...\n" );
 
       /*
        * Receive and process keyboard input.
        */
       while (InputThreadsRunning)
-       {
-         KEY_EVENT_RECORD KeyEvent;
-         LPARAM lParam = 0;
-         UINT fsModifiers;
-         struct _ETHREAD *Thread;
-         HWND hWnd;
-         int id;
-
-         Status = NtReadFile (KeyboardDeviceHandle,
-                              NULL,
-                              NULL,
-                              NULL,
-                              &Iosb,
-                              &KeyEvent,
-                              sizeof(KEY_EVENT_RECORD),
-                              NULL,
-                              NULL);
-         DPRINT( "KeyRaw: %s %04x\n",
-                KeyEvent.bKeyDown ? "down" : "up",
-                KeyEvent.wVirtualScanCode );
-
-         if (Status == STATUS_ALERTED && !InputThreadsRunning)
-           {
-             break;
-           }
-         if (!NT_SUCCESS(Status))
-           {
-             DPRINT1("Win32K: Failed to read from keyboard.\n");
-             return; //(Status);
-           }
-
-         DPRINT( "Key: %s\n", KeyEvent.bKeyDown ? "down" : "up" );
-
-         fsModifiers = 0;
-         if (KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
-           fsModifiers |= MOD_ALT;
-
-         if (KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
-           fsModifiers |= MOD_CONTROL;
-
-         if (KeyEvent.dwControlKeyState & SHIFT_PRESSED)
-           fsModifiers |= MOD_SHIFT;
-
-         /* FIXME: Support MOD_WIN */
-
-         lParam = KeyEvent.wRepeatCount | 
-           ((KeyEvent.wVirtualScanCode << 16) & 0x00FF0000) | 0x40000000;
-         
-         /* Bit 24 indicates if this is an extended key */
-         if (KeyEvent.dwControlKeyState & ENHANCED_KEY)
-           {
-             lParam |= (1 << 24);
-           }
-         
-         if (fsModifiers & MOD_ALT)
-           {
-             /* Context mode. 1 if ALT if pressed while the key is pressed */
-             lParam |= (1 << 29);
-           }
-         
-         if(KeyEvent.bKeyDown && (fsModifiers & MOD_ALT)) 
-           msg.message = WM_SYSKEYDOWN;
-         else if(KeyEvent.bKeyDown)
-           msg.message = WM_KEYDOWN;
-         else if(fsModifiers & MOD_ALT)
-           msg.message = WM_SYSKEYUP;
-         else
-           msg.message = WM_KEYUP;
-
-         /* Find the target thread whose locale is in effect */
-         if (!IntGetScreenDC())
-           {
-             FocusQueue = W32kGetPrimitiveMessageQueue();
-           }
-         else
-           {
-             FocusQueue = IntGetFocusMessageQueue();
-           }
-
-         if (!FocusQueue) continue;
-
-         msg.wParam = KeyEvent.wVirtualKeyCode;
-         msg.lParam = lParam;
-         msg.hwnd = FocusQueue->FocusWindow;
-
-         FocusThread = FocusQueue->Thread;
-
-         if (FocusThread && FocusThread->Win32Thread && 
-             FocusThread->Win32Thread->KeyboardLayout) 
-           {
-             W32kKeyProcessMessage(&msg,
-                                   FocusThread->Win32Thread->KeyboardLayout);
-           } 
-         else
-           continue;
-         
-         if (GetHotKey(InputWindowStation,
-                       fsModifiers,
-                       msg.wParam,
-                       &Thread,
-                       &hWnd,
-                       &id))
-           {
-             if (KeyEvent.bKeyDown)
-               {
-                 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
-                 MsqPostHotKeyMessage (Thread,
-                                       hWnd,
-                                       (WPARAM)id,
-                                       MAKELPARAM((WORD)fsModifiers, 
-                                                  (WORD)msg.wParam));
-               }
-           }
-         else 
-           {
-             /*
-              * Post a keyboard message.
-              */
-             MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
-           }
-       }
+      {
+         BOOLEAN NumKeys = 1;
+         KEYBOARD_INPUT_DATA KeyInput;
+         KEYBOARD_INPUT_DATA NextKeyInput;
+         LPARAM lParam = 0;
+         UINT fsModifiers, fsNextModifiers;
+         struct _ETHREAD *Thread;
+         HWND hWnd;
+         int id;
+
+        DPRINT("KeyInput @ %08x\n", &KeyInput);
+
+         Status = NtReadFile (KeyboardDeviceHandle,
+                             NULL,
+                              NULL,
+                              NULL,
+                              &Iosb,
+                              &KeyInput,
+                              sizeof(KEYBOARD_INPUT_DATA),
+                              NULL,
+                              NULL);
+
+         if(Status == STATUS_ALERTED && !InputThreadsRunning)
+         {
+            break;
+         }
+         if(Status == STATUS_PENDING)
+         {
+            NtWaitForSingleObject(KeyboardDeviceHandle, FALSE, NULL);
+            Status = Iosb.Status;
+         }
+         if(!NT_SUCCESS(Status))
+         {
+            DPRINT1("Win32K: Failed to read from mouse.\n");
+            return; //(Status);
+         }
+
+         DPRINT("KeyRaw: %s %04x\n",
+                (KeyInput.Flags & KEY_BREAK) ? "up" : "down",
+                KeyInput.MakeCode );
+
+         if (Status == STATUS_ALERTED && !InputThreadsRunning)
+            break;
+
+         if (!NT_SUCCESS(Status))
+         {
+            DPRINT1("Win32K: Failed to read from keyboard.\n");
+            return; //(Status);
+         }
+
+         /* Update modifier state */
+         fsModifiers = IntKeyboardGetModifiers(&KeyInput);
+
+         if (fsModifiers)
+         {
+            if (KeyInput.Flags & KEY_BREAK)
+            {
+               ModifierState &= ~fsModifiers;
+            }
+            else
+            {
+               ModifierState |= fsModifiers;
+
+               if (ModifierState == fsModifiers &&
+                     (fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
+               {
+                  /* First send out special notifications
+                   * (For alt, the message that turns on accelerator
+                   * display, not sure what for win. Both TODO though.)
+                   */
+
+                  /* Read the next key before sending this one */
+                  do
+                  {
+                     Status = NtReadFile (KeyboardDeviceHandle,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          &Iosb,
+                                          &NextKeyInput,
+                                          sizeof(KEYBOARD_INPUT_DATA),
+                                          NULL,
+                                          NULL);
+                     DPRINT("KeyRaw: %s %04x\n",
+                            (NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
+                            NextKeyInput.MakeCode );
+
+                     if (Status == STATUS_ALERTED && !InputThreadsRunning)
+                        goto KeyboardEscape;
+
+                  }
+                  while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
+                         NextKeyInput.MakeCode == KeyInput.MakeCode);
+                  /* ^ Ignore repeats, they'll be KEY_MAKE and the same
+                   *   code. I'm not caring about the counting, not sure
+                   *   if that matters. I think not.
+                   */
+
+                  /* If the ModifierState is now empty again, send a
+                   * special notification and eat both keypresses
+                   */
+
+                  fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
+
+                  if (fsNextModifiers)
+                     ModifierState ^= fsNextModifiers;
+
+                  if (ModifierState == 0)
+                  {
+                     if (fsModifiers == MOD_WIN)
+                        IntKeyboardSendWinKeyMsg();
+                     else if (fsModifiers == MOD_ALT)
+                        co_IntKeyboardSendAltKeyMsg();
+                     continue;
+                  }
+
+                  NumKeys = 2;
+               }
+            }
+         }
+
+         for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
+               NumKeys--)
+         {
+            lParam = 0;
+
+            IntKeyboardUpdateLeds(KeyboardDeviceHandle,
+                                  &KeyInput,
+                                  IndicatorTrans);
+
+            /* While we are working, we set up lParam. The format is:
+             *  0-15: The number of times this key has autorepeated
+             * 16-23: The keyboard scancode
+             *    24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
+             *        Note that E1 is only used for PAUSE (E1-1D-45) and
+             *        E0-45 happens not to be anything.
+             *    29: Alt is pressed ('Context code')
+             *    30: Previous state, if the key was down before this message
+             *        This is a cheap way to ignore autorepeat keys
+             *    31: 1 if the key is being pressed
+             */
+
+            /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
+             * and it's the same key as the last one, increase the repeat
+             * count.
+             */
+
+            if (!(KeyInput.Flags & KEY_BREAK))
+            {
+               if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
+                     (KeyInput.MakeCode == LastMakeCode))
+               {
+                  RepeatCount++;
+                  lParam |= (1 << 30);
+               }
+               else
+               {
+                  RepeatCount = 0;
+                  LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
+                  LastMakeCode = KeyInput.MakeCode;
+               }
+            }
+            else
+            {
+               LastFlags = 0;
+               LastMakeCode = 0; /* Should never match */
+               lParam |= (1 << 30) | (1 << 31);
+            }
+
+            lParam |= RepeatCount;
+
+            lParam |= (KeyInput.MakeCode & 0xff) << 16;
+
+            if (KeyInput.Flags & KEY_E0)
+               lParam |= (1 << 24);
+
+            if (ModifierState & MOD_ALT)
+            {
+               lParam |= (1 << 29);
+
+               if (!(KeyInput.Flags & KEY_BREAK))
+                  msg.message = WM_SYSKEYDOWN;
+               else
+                  msg.message = WM_SYSKEYUP;
+            }
+            else
+            {
+               if (!(KeyInput.Flags & KEY_BREAK))
+                  msg.message = WM_KEYDOWN;
+               else
+                  msg.message = WM_KEYUP;
+            }
+
+            /* Find the target thread whose locale is in effect */
+            if (!IntGetScreenDC())
+               FocusQueue = W32kGetPrimitiveMessageQueue();
+            else
+               FocusQueue = IntGetFocusMessageQueue();
+
+            /* This might cause us to lose hot keys, which are important
+             * (ctrl-alt-del secure attention sequence). Not sure if it
+             * can happen though.
+             */
+            if (!FocusQueue)
+               continue;
+
+            msg.lParam = lParam;
+            msg.hwnd = FocusQueue->FocusWindow;
+
+            FocusThread = FocusQueue->Thread;
+
+            if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
+                  ((PW32THREAD)FocusThread->Tcb.Win32Thread)->KeyboardLayout))
+               continue;
+
+            /* This function uses lParam to fill wParam according to the
+             * keyboard layout in use.
+             */
+            W32kKeyProcessMessage(&msg,
+                                  ((PW32THREAD)FocusThread->Tcb.Win32Thread)->KeyboardLayout,
+                                  KeyInput.Flags & KEY_E0 ? 0xE0 :
+                                  (KeyInput.Flags & KEY_E1 ? 0xE1 : 0));
+
+            if (GetHotKey(ModifierState,
+                          msg.wParam,
+                          &Thread,
+                          &hWnd,
+                          &id))
+            {
+               if (!(KeyInput.Flags & KEY_BREAK))
+               {
+                  DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
+                  MsqPostHotKeyMessage (Thread,
+                                        hWnd,
+                                        (WPARAM)id,
+                                        MAKELPARAM((WORD)ModifierState,
+                                                   (WORD)msg.wParam));
+               }
+               continue; /* Eat key up motion too */
+            }
+
+            /*
+             * Post a keyboard message.
+             */
+            co_MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
+         }
+      }
+
+KeyboardEscape:
       DPRINT( "KeyboardInput Thread Stopped...\n" );
-    }
+   }
 }
 
 
-NTSTATUS STDCALL
-NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
+NTSTATUS FASTCALL
+UserAcquireOrReleaseInputOwnership(BOOLEAN Release)
 {
-  if (Release && InputThreadsRunning && !pmPrimitiveMessageQueue)
-    {
+   if (Release && InputThreadsRunning && !pmPrimitiveMessageQueue)
+   {
       DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue );
       KeClearEvent(&InputThreadsStart);
       InputThreadsRunning = FALSE;
-      
+
       NtAlertThread(KeyboardThreadHandle);
-    }
-  else if (!Release && !InputThreadsRunning)
-    {
+      NtAlertThread(MouseThreadHandle);
+   }
+   else if (!Release && !InputThreadsRunning)
+   {
       InputThreadsRunning = TRUE;
       KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
-    }
+   }
 
-  return(STATUS_SUCCESS);
+   return(STATUS_SUCCESS);
 }
 
+
+NTSTATUS STDCALL
+NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
+{
+   DECLARE_RETURN(NTSTATUS);
+
+   DPRINT("Enter NtUserAcquireOrReleaseInputOwnership\n");
+   UserEnterExclusive();
+
+   RETURN(UserAcquireOrReleaseInputOwnership(Release));
+
+CLEANUP:
+   DPRINT("Leave NtUserAcquireOrReleaseInputOwnership, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+
 NTSTATUS FASTCALL
 InitInputImpl(VOID)
 {
-  NTSTATUS Status;
-#if ENABLEMOUSEGDICALLBACK
-  UNICODE_STRING MouseDeviceName;
-  OBJECT_ATTRIBUTES MouseObjectAttributes;
-  IO_STATUS_BLOCK Iosb;
-  PIRP Irp;
-  PFILE_OBJECT FileObject;
-  GDI_INFORMATION GdiInfo;
-  KEVENT IoEvent;
-  PIO_STACK_LOCATION StackPtr;
-#endif
+   NTSTATUS Status;
 
-  KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
-
-  Status = PsCreateSystemThread(&KeyboardThreadHandle,
-                               THREAD_ALL_ACCESS,
-                               NULL,
-                               NULL,
-                               &KeyboardThreadId,
-                               KeyboardThreadMain,
-                               NULL);
-  if (!NT_SUCCESS(Status))
-  {
-    DPRINT1("Win32K: Failed to create keyboard thread.\n");
-  }
-
-  /* Initialize the default keyboard layout */
-  (VOID)W32kGetDefaultKeyLayout();
-  
-#if ENABLEMOUSEGDICALLBACK
-  /*
-   * Connect to the mouse class driver.
-   * Failures here don't result in a failure return, the system must be
-   * able to operate without mouse
-   */  
-  RtlRosInitUnicodeStringFromLiteral(&MouseDeviceName, L"\\??\\MouseClass");
-  InitializeObjectAttributes(&MouseObjectAttributes,
-                            &MouseDeviceName,
-                            0,
-                            NULL,
-                            NULL);
-  Status = ZwOpenFile(&MouseDeviceHandle,
-                     FILE_ALL_ACCESS,
-                     &MouseObjectAttributes,
-                     &Iosb,
-                     0,
-                     FILE_SYNCHRONOUS_IO_ALERT);
-  if (!NT_SUCCESS(Status))
-    {
-      DPRINT1("Win32K: Failed to open mouse.\n");
-      return STATUS_SUCCESS;
-    }
-  Status = ObReferenceObjectByHandle(MouseDeviceHandle,
-                                    FILE_READ_DATA | FILE_WRITE_DATA,
-                                    IoFileObjectType,
-                                    KernelMode,
-                                    (PVOID *) &FileObject,
-                                    NULL);
-   
+   KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
+
+   Status = PsCreateSystemThread(&KeyboardThreadHandle,
+                                 THREAD_ALL_ACCESS,
+                                 NULL,
+                                 NULL,
+                                 &KeyboardThreadId,
+                                 KeyboardThreadMain,
+                                 NULL);
    if (!NT_SUCCESS(Status))
-     {
-       DPRINT1("Win32K: Failed to reference mouse file object. (0x%X)\n", Status);
-       ZwClose(MouseDeviceHandle);
-       return STATUS_SUCCESS;
-     }
-   KeInitializeEvent(&IoEvent, FALSE, NotificationEvent);
-   GdiInfo.CallBack = MouseGDICallBack;
-   Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
-                                      FileObject->DeviceObject,
-                                      &GdiInfo,
-                                      sizeof(GdiInfo),
-                                      NULL,
-                                      0,
-                                      TRUE,
-                                      &FileObject->Event,
-                                      &Iosb);
-
-   //trigger FileObject/Event dereferencing
-   Irp->Tail.Overlay.OriginalFileObject = FileObject;
-
-   StackPtr = IoGetNextIrpStackLocation(Irp);
-   StackPtr->FileObject = FileObject;
-   StackPtr->DeviceObject = FileObject->DeviceObject;
-   StackPtr->Parameters.DeviceIoControl.InputBufferLength = sizeof(GdiInfo);
-   StackPtr->Parameters.DeviceIoControl.OutputBufferLength = 0;
-
-   Status = IoCallDriver(FileObject->DeviceObject, Irp);
-   if (Status == STATUS_PENDING)
-     {
-       KeWaitForSingleObject(&FileObject->Event, Executive, KernelMode, FALSE,
-                            NULL);
-       Status = Iosb.Status;
-     }
+   {
+      DPRINT1("Win32K: Failed to create keyboard thread.\n");
+   }
+
+   /* Initialize the default keyboard layout */
+   (VOID)W32kGetDefaultKeyLayout();
+
+
+   Status = PsCreateSystemThread(&MouseThreadHandle,
+                                 THREAD_ALL_ACCESS,
+                                 NULL,
+                                 NULL,
+                                 &MouseThreadId,
+                                 MouseThreadMain,
+                                 NULL);
    if (!NT_SUCCESS(Status))
-     {
-       DPRINT1("Win32K: Failed to connect to mouse driver.\n");
-       ObDereferenceObject(&FileObject);
-       NtClose(MouseDeviceHandle);
-       return STATUS_SUCCESS;
-     }
-#else
-  Status = PsCreateSystemThread(&MouseThreadHandle,
-                               THREAD_ALL_ACCESS,
-                               NULL,
-                               NULL,
-                               &MouseThreadId,
-                               MouseThreadMain,
-                               NULL);
-  if (!NT_SUCCESS(Status))
-  {
-    DPRINT1("Win32K: Failed to create mouse thread.\n");
-  }
-#endif
-  
-  return STATUS_SUCCESS;
+   {
+      DPRINT1("Win32K: Failed to create mouse thread.\n");
+   }
+
+   return STATUS_SUCCESS;
 }
 
 NTSTATUS FASTCALL
 CleanupInputImp(VOID)
 {
-  return(STATUS_SUCCESS);
+   return(STATUS_SUCCESS);
 }
 
 BOOL
 STDCALL
 NtUserDragDetect(
-  HWND hWnd,
-  LONG x,
-  LONG y)
+   HWND hWnd,
+   LONG x,
+   LONG y)
 {
-  UNIMPLEMENTED
-  return 0;
+   UNIMPLEMENTED
+   return 0;
 }
 
 BOOL FASTCALL
 IntBlockInput(PW32THREAD W32Thread, BOOL BlockIt)
 {
-  PW32THREAD OldBlock;
-  ASSERT(W32Thread);
-  
-  if(!W32Thread->Desktop || (W32Thread->IsExiting && BlockIt))
-  {
-    /*
-     * fail blocking if exiting the thread
-     */
-    
-    return FALSE;
-  }
-  
-  /*
-   * FIXME - check access rights of the window station
-   *         e.g. services running in the service window station cannot block input
-   */
-  if(!ThreadHasInputAccess(W32Thread) ||
-     !IntIsActiveDesktop(W32Thread->Desktop))
-  {
-    SetLastWin32Error(ERROR_ACCESS_DENIED);
-    return FALSE;
-  }
-  
-  ASSERT(W32Thread->Desktop);
-  OldBlock = W32Thread->Desktop->BlockInputThread;
-  if(OldBlock)
-  {
-    if(OldBlock != W32Thread)
-    {
+   PW32THREAD OldBlock;
+   ASSERT(W32Thread);
+
+   if(!W32Thread->Desktop || (W32Thread->IsExiting && BlockIt))
+   {
+      /*
+       * fail blocking if exiting the thread
+       */
+
+      return FALSE;
+   }
+
+   /*
+    * FIXME - check access rights of the window station
+    *         e.g. services running in the service window station cannot block input
+    */
+   if(!ThreadHasInputAccess(W32Thread) ||
+         !IntIsActiveDesktop(W32Thread->Desktop))
+   {
       SetLastWin32Error(ERROR_ACCESS_DENIED);
       return FALSE;
-    }
-    W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
-    return OldBlock == NULL;
-  }
-  
-  W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
-  return OldBlock == NULL;
+   }
+
+   ASSERT(W32Thread->Desktop);
+   OldBlock = W32Thread->Desktop->BlockInputThread;
+   if(OldBlock)
+   {
+      if(OldBlock != W32Thread)
+      {
+         SetLastWin32Error(ERROR_ACCESS_DENIED);
+         return FALSE;
+      }
+      W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
+      return OldBlock == NULL;
+   }
+
+   W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
+   return OldBlock == NULL;
 }
 
 BOOL
 STDCALL
 NtUserBlockInput(
-  BOOL BlockIt)
+   BOOL BlockIt)
 {
-  return IntBlockInput(PsGetWin32Thread(), BlockIt);
+   DECLARE_RETURN(BOOLEAN);
+
+   DPRINT("Enter NtUserBlockInput\n");
+   UserEnterExclusive();
+
+   RETURN( IntBlockInput(PsGetWin32Thread(), BlockIt));
+
+CLEANUP:
+   DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 BOOL FASTCALL
 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
 {
-  PSYSTEM_CURSORINFO CurInfo;
-  BOOL res;
-  
-  CurInfo = IntGetSysCursorInfo(WinStaObject);
-  res = CurInfo->SwapButtons;
-  CurInfo->SwapButtons = Swap;
-  return res;
+   PSYSTEM_CURSORINFO CurInfo;
+   BOOL res;
+
+   CurInfo = IntGetSysCursorInfo(WinStaObject);
+   res = CurInfo->SwapButtons;
+   CurInfo->SwapButtons = Swap;
+   return res;
 }
 
 BOOL FASTCALL
 IntMouseInput(MOUSEINPUT *mi)
 {
-  const UINT SwapBtnMsg[2][2] = {{WM_LBUTTONDOWN, WM_RBUTTONDOWN},
-                                 {WM_LBUTTONUP, WM_RBUTTONUP}};
-  const WPARAM SwapBtn[2] = {MK_LBUTTON, MK_RBUTTON};
-  POINT MousePos;
-  PSYSTEM_CURSORINFO CurInfo;
-  PWINSTATION_OBJECT WinSta;
-  BOOL DoMove, SwapButtons;
-  MSG Msg;
-  SURFOBJ *SurfObj;
-  PSURFGDI SurfGDI;
-  PDC dc;
-  RECTL PointerRect;
-  
+   const UINT SwapBtnMsg[2][2] =
+      {
+         {
+            WM_LBUTTONDOWN, WM_RBUTTONDOWN
+         },
+         {WM_LBUTTONUP, WM_RBUTTONUP}
+      };
+   const WPARAM SwapBtn[2] =
+      {
+         MK_LBUTTON, MK_RBUTTON
+      };
+   POINT MousePos, OrgPos;
+   PSYSTEM_CURSORINFO CurInfo;
+   PWINSTATION_OBJECT WinSta;
+   BOOL DoMove, SwapButtons;
+   MSG Msg;
+   HBITMAP hBitmap;
+   BITMAPOBJ *BitmapObj;
+   SURFOBJ *SurfObj;
+   PDC dc;
+   PWINDOW_OBJECT DesktopWindow;
+
 #if 1
-  HDC hDC;
-  
-  /* FIXME - get the screen dc from the window station or desktop */
-  if(!(hDC = IntGetScreenDC()))
-  {
-    return FALSE;
-  }
+
+   HDC hDC;
+
+   /* FIXME - get the screen dc from the window station or desktop */
+   if(!(hDC = IntGetScreenDC()))
+   {
+      return FALSE;
+   }
 #endif
-  
-  ASSERT(mi);
+
+   ASSERT(mi);
 #if 0
-  WinSta = PsGetWin32Process()->WindowStation;
+
+   WinSta = PsGetWin32Process()->WindowStation;
 #else
-  /* FIXME - ugly hack but as long as we're using this dumb callback from the
-             mouse class driver, we can't access the window station from the calling
-             process */
-  WinSta = InputWindowStation;
+   /* FIXME - ugly hack but as long as we're using this dumb callback from the
+   mouse class driver, we can't access the window station from the calling
+   process */
+   WinSta = InputWindowStation;
 #endif
-  ASSERT(WinSta);
-  
-  CurInfo = IntGetSysCursorInfo(WinSta);
-  
-  dc = DC_LockDc(hDC);
-  SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
-  SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
-  DC_UnlockDc(hDC);
-  ASSERT(SurfObj);
-  ASSERT(SurfGDI);
-  
-  if(!mi->time)
-  {
-    LARGE_INTEGER LargeTickCount;
-    KeQueryTickCount(&LargeTickCount);
-    mi->time = LargeTickCount.u.LowPart;
-  }
-  
-  SwapButtons = CurInfo->SwapButtons;
-  DoMove = FALSE;
-  ExAcquireFastMutex(&CurInfo->CursorMutex);
-  MousePos.x = CurInfo->x;
-  MousePos.y = CurInfo->y;
-  if(mi->dwFlags & MOUSEEVENTF_MOVE)
-  {
-    if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
-    {
-      MousePos.x = mi->dx;
-      MousePos.y = mi->dy;
-    }
-    else
-    {
-      MousePos.x += mi->dx;
-      MousePos.y += mi->dy;
-    }
-    
-    if(MousePos.x < 0)
-      MousePos.x = 0;
-    if(MousePos.y < 0)
-      MousePos.y = 0;
-    if(MousePos.x >= SurfObj->sizlBitmap.cx)
-      MousePos.x = SurfObj->sizlBitmap.cx - 1;
-    if(MousePos.y >= SurfObj->sizlBitmap.cy)
-      MousePos.y = SurfObj->sizlBitmap.cy - 1;
-    
-    if(CurInfo->CursorClipInfo.IsClipped)
-    {
-      /* The mouse cursor needs to be clipped */
-      
-      if(MousePos.x >= (LONG)CurInfo->CursorClipInfo.Right)
-        MousePos.x = (LONG)CurInfo->CursorClipInfo.Right;
-      if(MousePos.x < (LONG)CurInfo->CursorClipInfo.Left)
-        MousePos.x = (LONG)CurInfo->CursorClipInfo.Left;
-      if(MousePos.y >= (LONG)CurInfo->CursorClipInfo.Bottom)
-        MousePos.y = (LONG)CurInfo->CursorClipInfo.Bottom;
-      if(MousePos.y < (LONG)CurInfo->CursorClipInfo.Top)
-        MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
-    }
-    
-    if((DoMove = (MousePos.x != CurInfo->x || MousePos.y != CurInfo->y)))
-    {
-      CurInfo->x = MousePos.x;
-      CurInfo->y = MousePos.y;
-      if(SurfGDI->MovePointer)
+
+   ASSERT(WinSta);
+
+   CurInfo = IntGetSysCursorInfo(WinSta);
+
+   if(!mi->time)
+   {
+      LARGE_INTEGER LargeTickCount;
+      KeQueryTickCount(&LargeTickCount);
+      mi->time = LargeTickCount.u.LowPart;
+   }
+
+   SwapButtons = CurInfo->SwapButtons;
+   DoMove = FALSE;
+
+   IntGetCursorLocation(WinSta, &MousePos);
+   OrgPos.x = MousePos.x;
+   OrgPos.y = MousePos.y;
+
+   if(mi->dwFlags & MOUSEEVENTF_MOVE)
+   {
+      if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
       {
-        IntLockGDIDriver(SurfGDI);
-        SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
-        IntUnLockGDIDriver(SurfGDI);
+         MousePos.x = mi->dx;
+         MousePos.y = mi->dy;
       }
       else
       {
-        IntLockGDIDriver(SurfGDI);
-        EngMovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
-        IntUnLockGDIDriver(SurfGDI);
+         MousePos.x += mi->dx;
+         MousePos.y += mi->dy;
+      }
+
+      DesktopWindow = IntGetWindowObject(WinSta->ActiveDesktop->DesktopWindow);
+
+      if (DesktopWindow)
+      {
+         if(MousePos.x >= DesktopWindow->ClientRect.right)
+            MousePos.x = DesktopWindow->ClientRect.right - 1;
+         if(MousePos.y >= DesktopWindow->ClientRect.bottom)
+            MousePos.y = DesktopWindow->ClientRect.bottom - 1;
+         ObmDereferenceObject(DesktopWindow);
       }
-      SetPointerRect(CurInfo, &PointerRect);
-    }
-  }
-
-  ExReleaseFastMutex(&CurInfo->CursorMutex);
-  
-  /*
-   * Insert the messages into the system queue
-   */
-  
-  Msg.wParam = CurInfo->ButtonsDown;
-  Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
-  Msg.pt = MousePos;
-  if(DoMove)
-  {
-    Msg.message = WM_MOUSEMOVE;
-    MsqInsertSystemMessage(&Msg);
-  }
-  
-  Msg.message = 0;
-  if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
-  {
-    Msg.message = SwapBtnMsg[0][SwapButtons];
-    CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
-    MsqInsertSystemMessage(&Msg);
-  }
-  else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
-  {
-    Msg.message = SwapBtnMsg[1][SwapButtons];
-    CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
-    MsqInsertSystemMessage(&Msg);
-  }
-  if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
-  {
-    Msg.message = WM_MBUTTONDOWN;
-    CurInfo->ButtonsDown |= MK_MBUTTON;
-    MsqInsertSystemMessage(&Msg);
-  }
-  else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
-  {
-    Msg.message = WM_MBUTTONUP;
-    CurInfo->ButtonsDown &= ~MK_MBUTTON;
-    MsqInsertSystemMessage(&Msg);
-  }
-  if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
-  {
-    Msg.message = SwapBtnMsg[0][!SwapButtons];
-    CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
-    MsqInsertSystemMessage(&Msg);
-  }
-  else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
-  {
-    Msg.message = SwapBtnMsg[1][!SwapButtons];
-    CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
-    MsqInsertSystemMessage(&Msg);
-  }
-  
-  if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
-     (mi->dwFlags & MOUSEEVENTF_WHEEL))
-  {
-    /* fail because both types of events use the mouseData field */
-    return FALSE;
-  }
-  
-  if(mi->dwFlags & MOUSEEVENTF_XDOWN)
-  {
-    Msg.message = WM_XBUTTONDOWN;
-    if(mi->mouseData & XBUTTON1)
-    {
-      Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
-      CurInfo->ButtonsDown |= XBUTTON1;
+
+      if(MousePos.x < 0)
+         MousePos.x = 0;
+      if(MousePos.y < 0)
+         MousePos.y = 0;
+
+      if(CurInfo->CursorClipInfo.IsClipped)
+      {
+         /* The mouse cursor needs to be clipped */
+
+         if(MousePos.x >= (LONG)CurInfo->CursorClipInfo.Right)
+            MousePos.x = (LONG)CurInfo->CursorClipInfo.Right;
+         if(MousePos.x < (LONG)CurInfo->CursorClipInfo.Left)
+            MousePos.x = (LONG)CurInfo->CursorClipInfo.Left;
+         if(MousePos.y >= (LONG)CurInfo->CursorClipInfo.Bottom)
+            MousePos.y = (LONG)CurInfo->CursorClipInfo.Bottom;
+         if(MousePos.y < (LONG)CurInfo->CursorClipInfo.Top)
+            MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
+      }
+
+      DoMove = (MousePos.x != OrgPos.x || MousePos.y != OrgPos.y);
+   }
+
+   if (DoMove)
+   {
+      dc = DC_LockDc(hDC);
+      if (dc)
+      {
+         hBitmap = dc->w.hBitmap;
+         DC_UnlockDc(dc);
+
+         BitmapObj = BITMAPOBJ_LockBitmap(hBitmap);
+         if (BitmapObj)
+         {
+            SurfObj = &BitmapObj->SurfObj;
+
+            IntEngMovePointer(SurfObj, MousePos.x, MousePos.y, &(GDIDEV(SurfObj)->Pointer.Exclude));
+            /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
+            * use the old values to move the pointer image */
+            GDIDEV(SurfObj)->Pointer.Pos.x = MousePos.x;
+            GDIDEV(SurfObj)->Pointer.Pos.y = MousePos.y;
+
+            BITMAPOBJ_UnlockBitmap(BitmapObj);
+         }
+      }
+   }
+
+   /*
+    * Insert the messages into the system queue
+    */
+
+   Msg.wParam = CurInfo->ButtonsDown;
+   Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
+   Msg.pt = MousePos;
+   if(DoMove)
+   {
+      Msg.message = WM_MOUSEMOVE;
       MsqInsertSystemMessage(&Msg);
-    }
-    if(mi->mouseData & XBUTTON2)
-    {
-      Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
-      CurInfo->ButtonsDown |= XBUTTON2;
+   }
+
+   Msg.message = 0;
+   if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
+   {
+      gQueueKeyStateTable[VK_LBUTTON] |= 0xc0;
+      Msg.message = SwapBtnMsg[0][SwapButtons];
+      CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
+      MsqInsertSystemMessage(&Msg);
+   }
+   else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
+   {
+      gQueueKeyStateTable[VK_LBUTTON] &= ~0x80;
+      Msg.message = SwapBtnMsg[1][SwapButtons];
+      CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
+      MsqInsertSystemMessage(&Msg);
+   }
+   if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
+   {
+      gQueueKeyStateTable[VK_MBUTTON] |= 0xc0;
+      Msg.message = WM_MBUTTONDOWN;
+      CurInfo->ButtonsDown |= MK_MBUTTON;
+      MsqInsertSystemMessage(&Msg);
+   }
+   else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
+   {
+      gQueueKeyStateTable[VK_MBUTTON] &= ~0x80;
+      Msg.message = WM_MBUTTONUP;
+      CurInfo->ButtonsDown &= ~MK_MBUTTON;
       MsqInsertSystemMessage(&Msg);
-    }
-  }
-  else if(mi->dwFlags & MOUSEEVENTF_XUP)
-  {
-    Msg.message = WM_XBUTTONUP;
-    if(mi->mouseData & XBUTTON1)
-    {
-      Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
-      CurInfo->ButtonsDown &= ~XBUTTON1;
+   }
+   if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
+   {
+      gQueueKeyStateTable[VK_RBUTTON] |= 0xc0;
+      Msg.message = SwapBtnMsg[0][!SwapButtons];
+      CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
       MsqInsertSystemMessage(&Msg);
-    }
-    if(mi->mouseData & XBUTTON2)
-    {
-      Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
-      CurInfo->ButtonsDown &= ~XBUTTON2;
+   }
+   else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
+   {
+      gQueueKeyStateTable[VK_RBUTTON] &= ~0x80;
+      Msg.message = SwapBtnMsg[1][!SwapButtons];
+      CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
       MsqInsertSystemMessage(&Msg);
-    }
-  }
-  if(mi->dwFlags & MOUSEEVENTF_WHEEL)
-  {
-    Msg.message = WM_MOUSEWHEEL;
-    Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
-    MsqInsertSystemMessage(&Msg);
-  }
-  
-  return TRUE;
+   }
+
+   if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
+         (mi->dwFlags & MOUSEEVENTF_WHEEL))
+   {
+      /* fail because both types of events use the mouseData field */
+      return FALSE;
+   }
+
+   if(mi->dwFlags & MOUSEEVENTF_XDOWN)
+   {
+      Msg.message = WM_XBUTTONDOWN;
+      if(mi->mouseData & XBUTTON1)
+      {
+         gQueueKeyStateTable[VK_XBUTTON1] |= 0xc0;
+         Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
+         CurInfo->ButtonsDown |= XBUTTON1;
+         MsqInsertSystemMessage(&Msg);
+      }
+      if(mi->mouseData & XBUTTON2)
+      {
+         gQueueKeyStateTable[VK_XBUTTON2] |= 0xc0;
+         Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
+         CurInfo->ButtonsDown |= XBUTTON2;
+         MsqInsertSystemMessage(&Msg);
+      }
+   }
+   else if(mi->dwFlags & MOUSEEVENTF_XUP)
+   {
+      Msg.message = WM_XBUTTONUP;
+      if(mi->mouseData & XBUTTON1)
+      {
+         gQueueKeyStateTable[VK_XBUTTON1] &= ~0x80;
+         Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
+         CurInfo->ButtonsDown &= ~XBUTTON1;
+         MsqInsertSystemMessage(&Msg);
+      }
+      if(mi->mouseData & XBUTTON2)
+      {
+         gQueueKeyStateTable[VK_XBUTTON2] &= ~0x80;
+         Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
+         CurInfo->ButtonsDown &= ~XBUTTON2;
+         MsqInsertSystemMessage(&Msg);
+      }
+   }
+   if(mi->dwFlags & MOUSEEVENTF_WHEEL)
+   {
+      Msg.message = WM_MOUSEWHEEL;
+      Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
+      MsqInsertSystemMessage(&Msg);
+   }
+
+   return TRUE;
 }
 
 BOOL FASTCALL
 IntKeyboardInput(KEYBDINPUT *ki)
 {
-  return FALSE;
+   return FALSE;
 }
 
 UINT
 STDCALL
 NtUserSendInput(
-  UINT nInputs,
-  LPINPUT pInput,
-  INT cbSize)
+   UINT nInputs,
+   LPINPUT pInput,
+   INT cbSize)
 {
-  PW32THREAD W32Thread;
-  UINT cnt;
-  
-  W32Thread = PsGetWin32Thread();
-  ASSERT(W32Thread);
-  
-  if(!W32Thread->Desktop)
-  {
-    return 0;
-  }
-  
-  if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
-  {
-    SetLastWin32Error(ERROR_INVALID_PARAMETER);
-    return 0;
-  }
-  
-  /*
-   * FIXME - check access rights of the window station
-   *         e.g. services running in the service window station cannot block input
-   */
-  if(!ThreadHasInputAccess(W32Thread) ||
-     !IntIsActiveDesktop(W32Thread->Desktop))
-  {
-    SetLastWin32Error(ERROR_ACCESS_DENIED);
-    return 0;
-  }
-  
-  cnt = 0;
-  while(nInputs--)
-  {
-    INPUT SafeInput;
-    NTSTATUS Status;
-    
-    Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
-    if(!NT_SUCCESS(Status))
-    {
-      SetLastNtError(Status);
-      return cnt;
-    }
-    
-    switch(SafeInput.type)
-    {
-      case INPUT_MOUSE:
-        if(IntMouseInput(&SafeInput.mi))
-        {
-          cnt++;
-        }
-        break;
-      case INPUT_KEYBOARD:
-        if(IntKeyboardInput(&SafeInput.ki))
-        {
-          cnt++;
-        }
-        break;
-      case INPUT_HARDWARE:
-        break;
+   PW32THREAD W32Thread;
+   UINT cnt;
+   DECLARE_RETURN(UINT);
+
+   DPRINT("Enter NtUserSendInput\n");
+   UserEnterExclusive();
+
+   W32Thread = PsGetWin32Thread();
+   ASSERT(W32Thread);
+
+   if(!W32Thread->Desktop)
+   {
+      RETURN( 0);
+   }
+
+   if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      RETURN( 0);
+   }
+
+   /*
+    * FIXME - check access rights of the window station
+    *         e.g. services running in the service window station cannot block input
+    */
+   if(!ThreadHasInputAccess(W32Thread) ||
+         !IntIsActiveDesktop(W32Thread->Desktop))
+   {
+      SetLastWin32Error(ERROR_ACCESS_DENIED);
+      RETURN( 0);
+   }
+
+   cnt = 0;
+   while(nInputs--)
+   {
+      INPUT SafeInput;
+      NTSTATUS Status;
+
+      Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
+      if(!NT_SUCCESS(Status))
+      {
+         SetLastNtError(Status);
+         RETURN( cnt);
+      }
+
+      switch(SafeInput.type)
+      {
+         case INPUT_MOUSE:
+            if(IntMouseInput(&SafeInput.mi))
+            {
+               cnt++;
+            }
+            break;
+         case INPUT_KEYBOARD:
+            if(IntKeyboardInput(&SafeInput.ki))
+            {
+               cnt++;
+            }
+            break;
+         case INPUT_HARDWARE:
+            break;
 #ifndef NDEBUG
-      default:
-        DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
-        break;
+
+         default:
+            DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
+            break;
 #endif
-    }
-  }
-  
-  return cnt;
+
+      }
+   }
+
+   RETURN( cnt);
+
+CLEANUP:
+   DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 /* EOF */