2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
33 #include <ddk/ntddkbd.h>
38 extern BYTE QueueKeyStateTable
[];
40 /* GLOBALS *******************************************************************/
42 static HANDLE MouseDeviceHandle
;
43 static HANDLE MouseThreadHandle
;
44 static CLIENT_ID MouseThreadId
;
45 static HANDLE KeyboardThreadHandle
;
46 static CLIENT_ID KeyboardThreadId
;
47 static HANDLE KeyboardDeviceHandle
;
48 static KEVENT InputThreadsStart
;
49 static BOOLEAN InputThreadsRunning
= FALSE
;
50 PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue
= 0;
52 /* FUNCTIONS *****************************************************************/
54 #define ClearMouseInput(mi) \
60 #define SendMouseEvent(mi) \
61 if(mi.dx != 0 || mi.dy != 0) \
62 mi.dwFlags |= MOUSEEVENTF_MOVE; \
68 ProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
70 PMOUSE_INPUT_DATA mid
;
77 for(i
= 0; i
< InputCount
; i
++)
85 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
87 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
90 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
92 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
95 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
97 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
100 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
102 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
105 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
107 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
110 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
112 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
115 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
117 mi
.mouseData
|= XBUTTON1
;
118 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
121 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
123 mi
.mouseData
|= XBUTTON1
;
124 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
127 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
129 mi
.mouseData
|= XBUTTON2
;
130 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
133 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
135 mi
.mouseData
|= XBUTTON2
;
136 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
139 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
141 mi
.mouseData
= mid
->ButtonData
;
142 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
152 MouseThreadMain(PVOID StartContext
)
154 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\??\\Mouse");
155 OBJECT_ATTRIBUTES MouseObjectAttributes
;
156 IO_STATUS_BLOCK Iosb
;
159 InitializeObjectAttributes(&MouseObjectAttributes
,
164 Status
= NtOpenFile(&MouseDeviceHandle
,
166 &MouseObjectAttributes
,
169 FILE_SYNCHRONOUS_IO_ALERT
);
170 if(!NT_SUCCESS(Status
))
172 DPRINT1("Win32K: Failed to open mouse.\n");
179 * Wait to start input.
181 DPRINT("Mouse Input Thread Waiting for start event\n");
182 Status
= KeWaitForSingleObject(&InputThreadsStart
,
187 DPRINT("Mouse Input Thread Starting...\n");
190 * Receive and process mouse input.
192 while(InputThreadsRunning
)
194 MOUSE_INPUT_DATA MouseInput
;
195 Status
= NtReadFile(MouseDeviceHandle
,
201 sizeof(MOUSE_INPUT_DATA
),
204 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
208 if(Status
== STATUS_PENDING
)
210 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
211 Status
= Iosb
.Status
;
213 if(!NT_SUCCESS(Status
))
215 DPRINT1("Win32K: Failed to read from mouse.\n");
218 DPRINT("MouseEvent\n");
220 UserEnterExclusive();
222 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
226 DPRINT("Mouse Input Thread Stopped...\n");
230 /* Returns a value that indicates if the key is a modifier key, and
234 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
236 if (InputData
->Flags
& KEY_E1
)
239 if (!(InputData
->Flags
& KEY_E0
))
241 switch (InputData
->MakeCode
)
243 case 0x2a: /* left shift */
244 case 0x36: /* right shift */
247 case 0x1d: /* left control */
250 case 0x38: /* left alt */
259 switch (InputData
->MakeCode
)
261 case 0x1d: /* right control */
264 case 0x38: /* right alt */
267 case 0x5b: /* left gui (windows) */
268 case 0x5c: /* right gui (windows) */
277 /* Asks the keyboard driver to send a small table that shows which
278 * lights should connect with which scancodes
280 STATIC NTSTATUS STDCALL
281 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
282 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
286 IO_STATUS_BLOCK Block
;
287 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
289 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
291 Ret
= ExAllocatePoolWithTag(PagedPool
,
297 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
302 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
306 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
311 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
313 Ret
= ExAllocatePoolWithTag(PagedPool
,
319 return STATUS_INSUFFICIENT_RESOURCES
;
321 if (Status
!= STATUS_SUCCESS
)
327 *IndicatorTrans
= Ret
;
331 /* Sends the keyboard commands to turn on/off the lights.
333 STATIC NTSTATUS STDCALL
334 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
335 PKEYBOARD_INPUT_DATA KeyInput
,
336 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
340 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
341 IO_STATUS_BLOCK Block
;
344 return STATUS_NOT_SUPPORTED
;
346 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
347 return STATUS_SUCCESS
;
349 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
351 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
353 Indicators
.LedFlags
^=
354 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
356 /* Update the lights on the hardware */
358 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
363 IOCTL_KEYBOARD_SET_INDICATORS
,
364 &Indicators
, sizeof(Indicators
),
371 return STATUS_SUCCESS
;
375 IntKeyboardSendWinKeyMsg()
377 PWINDOW_OBJECT Window
;
381 Status
= ObmReferenceObjectByHandle(InputWindowStation
->HandleTable
,
382 InputWindowStation
->ShellWindow
,
386 if (!NT_SUCCESS(Status
))
388 DPRINT1("Couldn't find window to send Windows key message!\n");
392 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
393 Mesg
.message
= WM_SYSCOMMAND
;
394 Mesg
.wParam
= SC_TASKLIST
;
397 /* The QS_HOTKEY is just a guess */
398 MsqPostMessage(Window
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
400 ObmDereferenceObject(Window
);
404 co_IntKeyboardSendAltKeyMsg()
406 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
410 KeyboardThreadMain(PVOID StartContext
)
412 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\??\\Keyboard");
413 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
414 IO_STATUS_BLOCK Iosb
;
417 PUSER_MESSAGE_QUEUE FocusQueue
;
418 struct _ETHREAD
*FocusThread
;
419 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
422 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
423 UINT ModifierState
= 0;
424 USHORT LastMakeCode
= 0;
425 USHORT LastFlags
= 0;
426 UINT RepeatCount
= 0;
428 InitializeObjectAttributes(&KeyboardObjectAttributes
,
433 Status
= NtOpenFile(&KeyboardDeviceHandle
,
435 &KeyboardObjectAttributes
,
438 FILE_SYNCHRONOUS_IO_ALERT
);
439 if (!NT_SUCCESS(Status
))
441 DPRINT1("Win32K: Failed to open keyboard.\n");
445 /* Not sure if converting this thread to a win32 thread is such
446 a great idea. Since we're posting keyboard messages to the focus
447 window message queue, we'll be (indirectly) doing sendmessage
448 stuff from this thread (for WH_KEYBOARD_LL processing), which
449 means we need our own message queue. If keyboard messages were
450 instead queued to the system message queue, the thread removing
451 the message from the system message queue would be responsible
452 for WH_KEYBOARD_LL processing and we wouldn't need this thread
453 to be a win32 thread. */
454 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
455 if (!NT_SUCCESS(Status
))
457 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
461 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
467 * Wait to start input.
469 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
470 Status
= KeWaitForSingleObject(&InputThreadsStart
,
475 DPRINT( "Keyboard Input Thread Starting...\n" );
478 * Receive and process keyboard input.
480 while (InputThreadsRunning
)
483 KEYBOARD_INPUT_DATA KeyInput
;
484 KEYBOARD_INPUT_DATA NextKeyInput
;
486 UINT fsModifiers
, fsNextModifiers
;
487 struct _ETHREAD
*Thread
;
491 Status
= NtReadFile (KeyboardDeviceHandle
,
497 sizeof(KEYBOARD_INPUT_DATA
),
500 DPRINT("KeyRaw: %s %04x\n",
501 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
504 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
507 if (!NT_SUCCESS(Status
))
509 DPRINT1("Win32K: Failed to read from keyboard.\n");
513 /* Update modifier state */
514 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
518 if (KeyInput
.Flags
& KEY_BREAK
)
520 ModifierState
&= ~fsModifiers
;
524 ModifierState
|= fsModifiers
;
526 if (ModifierState
== fsModifiers
&&
527 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
529 /* First send out special notifications
530 * (For alt, the message that turns on accelerator
531 * display, not sure what for win. Both TODO though.)
534 /* Read the next key before sending this one */
537 Status
= NtReadFile (KeyboardDeviceHandle
,
543 sizeof(KEYBOARD_INPUT_DATA
),
546 DPRINT("KeyRaw: %s %04x\n",
547 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
548 NextKeyInput
.MakeCode
);
550 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
553 } while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
554 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
555 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
556 * code. I'm not caring about the counting, not sure
557 * if that matters. I think not.
560 /* If the ModifierState is now empty again, send a
561 * special notification and eat both keypresses
564 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
567 ModifierState
^= fsNextModifiers
;
569 if (ModifierState
== 0)
571 if (fsModifiers
== MOD_WIN
)
572 IntKeyboardSendWinKeyMsg();
573 else if (fsModifiers
== MOD_ALT
)
574 co_IntKeyboardSendAltKeyMsg();
583 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
588 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
592 /* While we are working, we set up lParam. The format is:
593 * 0-15: The number of times this key has autorepeated
594 * 16-23: The keyboard scancode
595 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
596 * Note that E1 is only used for PAUSE (E1-1D-45) and
597 * E0-45 happens not to be anything.
598 * 29: Alt is pressed ('Context code')
599 * 30: Previous state, if the key was down before this message
600 * This is a cheap way to ignore autorepeat keys
601 * 31: 1 if the key is being pressed
604 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
605 * and it's the same key as the last one, increase the repeat
609 if (!(KeyInput
.Flags
& KEY_BREAK
))
611 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
612 (KeyInput
.MakeCode
== LastMakeCode
))
620 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
621 LastMakeCode
= KeyInput
.MakeCode
;
627 LastMakeCode
= 0; /* Should never match */
628 lParam
|= (1 << 30) | (1 << 31);
631 lParam
|= RepeatCount
;
633 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
635 if (KeyInput
.Flags
& KEY_E0
)
638 if (ModifierState
& MOD_ALT
)
642 if (!(KeyInput
.Flags
& KEY_BREAK
))
643 msg
.message
= WM_SYSKEYDOWN
;
645 msg
.message
= WM_SYSKEYUP
;
649 if (!(KeyInput
.Flags
& KEY_BREAK
))
650 msg
.message
= WM_KEYDOWN
;
652 msg
.message
= WM_KEYUP
;
655 /* Find the target thread whose locale is in effect */
656 if (!IntGetScreenDC())
657 FocusQueue
= W32kGetPrimitiveMessageQueue();
659 FocusQueue
= IntGetFocusMessageQueue();
661 /* This might cause us to lose hot keys, which are important
662 * (ctrl-alt-del secure attention sequence). Not sure if it
665 if (!FocusQueue
) continue;
668 msg
.hwnd
= FocusQueue
->FocusWindow
;
670 FocusThread
= FocusQueue
->Thread
;
672 if (!(FocusThread
&& FocusThread
->Tcb
.Win32Thread
&&
673 FocusThread
->Tcb
.Win32Thread
->KeyboardLayout
))
676 /* This function uses lParam to fill wParam according to the
677 * keyboard layout in use.
679 W32kKeyProcessMessage(&msg
,
680 FocusThread
->Tcb
.Win32Thread
->KeyboardLayout
,
681 KeyInput
.Flags
& KEY_E0
? 0xE0 :
682 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
684 if (GetHotKey(InputWindowStation
,
691 if (!(KeyInput
.Flags
& KEY_BREAK
))
693 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
694 MsqPostHotKeyMessage (Thread
,
697 MAKELPARAM((WORD
)ModifierState
,
700 continue; /* Eat key up motion too */
704 * Post a keyboard message.
706 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
711 DPRINT( "KeyboardInput Thread Stopped...\n" );
717 UserAcquireOrReleaseInputOwnership(BOOLEAN Release
)
719 if (Release
&& InputThreadsRunning
&& !pmPrimitiveMessageQueue
)
721 DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue
);
722 KeClearEvent(&InputThreadsStart
);
723 InputThreadsRunning
= FALSE
;
725 NtAlertThread(KeyboardThreadHandle
);
727 else if (!Release
&& !InputThreadsRunning
)
729 InputThreadsRunning
= TRUE
;
730 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
733 return(STATUS_SUCCESS
);
738 NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release
)
740 DECLARE_RETURN(NTSTATUS
);
742 DPRINT("Enter NtUserAcquireOrReleaseInputOwnership\n");
743 UserEnterExclusive();
745 RETURN(UserAcquireOrReleaseInputOwnership(Release
));
748 DPRINT("Leave NtUserAcquireOrReleaseInputOwnership, ret=%i\n",_ret_
);
759 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
761 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
768 if (!NT_SUCCESS(Status
))
770 DPRINT1("Win32K: Failed to create keyboard thread.\n");
773 /* Initialize the default keyboard layout */
774 (VOID
)W32kGetDefaultKeyLayout();
777 Status
= PsCreateSystemThread(&MouseThreadHandle
,
784 if (!NT_SUCCESS(Status
))
786 DPRINT1("Win32K: Failed to create mouse thread.\n");
789 return STATUS_SUCCESS
;
793 CleanupInputImp(VOID
)
795 return(STATUS_SUCCESS
);
810 IntBlockInput(PW32THREAD W32Thread
, BOOL BlockIt
)
815 if(!W32Thread
->Desktop
|| (W32Thread
->IsExiting
&& BlockIt
))
818 * fail blocking if exiting the thread
825 * FIXME - check access rights of the window station
826 * e.g. services running in the service window station cannot block input
828 if(!ThreadHasInputAccess(W32Thread
) ||
829 !IntIsActiveDesktop(W32Thread
->Desktop
))
831 SetLastWin32Error(ERROR_ACCESS_DENIED
);
835 ASSERT(W32Thread
->Desktop
);
836 OldBlock
= W32Thread
->Desktop
->BlockInputThread
;
839 if(OldBlock
!= W32Thread
)
841 SetLastWin32Error(ERROR_ACCESS_DENIED
);
844 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
845 return OldBlock
== NULL
;
848 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
849 return OldBlock
== NULL
;
857 DECLARE_RETURN(BOOLEAN
);
859 DPRINT("Enter NtUserBlockInput\n");
860 UserEnterExclusive();
862 RETURN( IntBlockInput(PsGetWin32Thread(), BlockIt
));
865 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
871 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject
, BOOL Swap
)
873 PSYSTEM_CURSORINFO CurInfo
;
876 CurInfo
= IntGetSysCursorInfo(WinStaObject
);
877 res
= CurInfo
->SwapButtons
;
878 CurInfo
->SwapButtons
= Swap
;
883 IntMouseInput(MOUSEINPUT
*mi
)
885 const UINT SwapBtnMsg
[2][2] = {{WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
886 {WM_LBUTTONUP
, WM_RBUTTONUP
}};
887 const WPARAM SwapBtn
[2] = {MK_LBUTTON
, MK_RBUTTON
};
888 POINT MousePos
, OrgPos
;
889 PSYSTEM_CURSORINFO CurInfo
;
890 PWINSTATION_OBJECT WinSta
;
891 BOOL DoMove
, SwapButtons
;
894 BITMAPOBJ
*BitmapObj
;
897 PWINDOW_OBJECT DesktopWindow
;
903 /* FIXME - get the screen dc from the window station or desktop */
904 if(!(hDC
= IntGetScreenDC()))
912 WinSta
= PsGetWin32Process()->WindowStation
;
914 /* FIXME - ugly hack but as long as we're using this dumb callback from the
915 mouse class driver, we can't access the window station from the calling
917 WinSta
= InputWindowStation
;
921 CurInfo
= IntGetSysCursorInfo(WinSta
);
925 LARGE_INTEGER LargeTickCount
;
926 KeQueryTickCount(&LargeTickCount
);
927 mi
->time
= LargeTickCount
.u
.LowPart
;
930 SwapButtons
= CurInfo
->SwapButtons
;
933 IntGetCursorLocation(WinSta
, &MousePos
);
934 OrgPos
.x
= MousePos
.x
;
935 OrgPos
.y
= MousePos
.y
;
937 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
939 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
946 MousePos
.x
+= mi
->dx
;
947 MousePos
.y
+= mi
->dy
;
950 Status
= ObmReferenceObjectByHandle(WinSta
->HandleTable
,
951 WinSta
->ActiveDesktop
->DesktopWindow
, otWindow
, (PVOID
*)&DesktopWindow
);
952 if (NT_SUCCESS(Status
))
954 if(MousePos
.x
>= DesktopWindow
->ClientRect
.right
)
955 MousePos
.x
= DesktopWindow
->ClientRect
.right
- 1;
956 if(MousePos
.y
>= DesktopWindow
->ClientRect
.bottom
)
957 MousePos
.y
= DesktopWindow
->ClientRect
.bottom
- 1;
958 ObmDereferenceObject(DesktopWindow
);
966 if(CurInfo
->CursorClipInfo
.IsClipped
)
968 /* The mouse cursor needs to be clipped */
970 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
971 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
972 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
973 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
974 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
975 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
976 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
977 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
980 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
988 hBitmap
= dc
->w
.hBitmap
;
991 BitmapObj
= BITMAPOBJ_LockBitmap(hBitmap
);
994 SurfObj
= &BitmapObj
->SurfObj
;
996 IntEngMovePointer(SurfObj
, MousePos
.x
, MousePos
.y
, &(GDIDEV(SurfObj
)->Pointer
.Exclude
));
997 /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
998 * use the old values to move the pointer image */
999 GDIDEV(SurfObj
)->Pointer
.Pos
.x
= MousePos
.x
;
1000 GDIDEV(SurfObj
)->Pointer
.Pos
.y
= MousePos
.y
;
1002 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1008 * Insert the messages into the system queue
1011 Msg
.wParam
= CurInfo
->ButtonsDown
;
1012 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1016 Msg
.message
= WM_MOUSEMOVE
;
1017 MsqInsertSystemMessage(&Msg
);
1021 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1023 QueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1024 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1025 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1026 MsqInsertSystemMessage(&Msg
);
1028 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1030 QueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1031 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1032 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1033 MsqInsertSystemMessage(&Msg
);
1035 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1037 QueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1038 Msg
.message
= WM_MBUTTONDOWN
;
1039 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1040 MsqInsertSystemMessage(&Msg
);
1042 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1044 QueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1045 Msg
.message
= WM_MBUTTONUP
;
1046 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1047 MsqInsertSystemMessage(&Msg
);
1049 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1051 QueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1052 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1053 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1054 MsqInsertSystemMessage(&Msg
);
1056 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1058 QueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1059 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1060 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1061 MsqInsertSystemMessage(&Msg
);
1064 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1065 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1067 /* fail because both types of events use the mouseData field */
1071 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1073 Msg
.message
= WM_XBUTTONDOWN
;
1074 if(mi
->mouseData
& XBUTTON1
)
1076 QueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1077 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1078 CurInfo
->ButtonsDown
|= XBUTTON1
;
1079 MsqInsertSystemMessage(&Msg
);
1081 if(mi
->mouseData
& XBUTTON2
)
1083 QueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1084 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1085 CurInfo
->ButtonsDown
|= XBUTTON2
;
1086 MsqInsertSystemMessage(&Msg
);
1089 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1091 Msg
.message
= WM_XBUTTONUP
;
1092 if(mi
->mouseData
& XBUTTON1
)
1094 QueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1095 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1096 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1097 MsqInsertSystemMessage(&Msg
);
1099 if(mi
->mouseData
& XBUTTON2
)
1101 QueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1102 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1103 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1104 MsqInsertSystemMessage(&Msg
);
1107 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1109 Msg
.message
= WM_MOUSEWHEEL
;
1110 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1111 MsqInsertSystemMessage(&Msg
);
1118 IntKeyboardInput(KEYBDINPUT
*ki
)
1130 PW32THREAD W32Thread
;
1132 DECLARE_RETURN(UINT
);
1134 DPRINT("Enter NtUserSendInput\n");
1135 UserEnterExclusive();
1137 W32Thread
= PsGetWin32Thread();
1140 if(!W32Thread
->Desktop
)
1145 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1147 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1152 * FIXME - check access rights of the window station
1153 * e.g. services running in the service window station cannot block input
1155 if(!ThreadHasInputAccess(W32Thread
) ||
1156 !IntIsActiveDesktop(W32Thread
->Desktop
))
1158 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1168 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1169 if(!NT_SUCCESS(Status
))
1171 SetLastNtError(Status
);
1175 switch(SafeInput
.type
)
1178 if(IntMouseInput(&SafeInput
.mi
))
1183 case INPUT_KEYBOARD
:
1184 if(IntKeyboardInput(&SafeInput
.ki
))
1189 case INPUT_HARDWARE
:
1193 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1202 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);