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 gQueueKeyStateTable
[];
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
"\\Device\\PointerClassPnp0");
155 OBJECT_ATTRIBUTES MouseObjectAttributes
;
156 IO_STATUS_BLOCK Iosb
;
159 InitializeObjectAttributes(&MouseObjectAttributes
,
166 LARGE_INTEGER DueTime
;
168 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
169 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
170 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
171 Status
= NtOpenFile(&MouseDeviceHandle
,
173 &MouseObjectAttributes
,
176 FILE_SYNCHRONOUS_IO_ALERT
);
177 } while (!NT_SUCCESS(Status
));
182 * Wait to start input.
184 DPRINT("Mouse Input Thread Waiting for start event\n");
185 Status
= KeWaitForSingleObject(&InputThreadsStart
,
190 DPRINT("Mouse Input Thread Starting...\n");
193 * Receive and process mouse input.
195 while(InputThreadsRunning
)
197 MOUSE_INPUT_DATA MouseInput
;
198 Status
= NtReadFile(MouseDeviceHandle
,
204 sizeof(MOUSE_INPUT_DATA
),
207 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
211 if(Status
== STATUS_PENDING
)
213 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
214 Status
= Iosb
.Status
;
216 if(!NT_SUCCESS(Status
))
218 DPRINT1("Win32K: Failed to read from mouse.\n");
221 DPRINT("MouseEvent\n");
223 UserEnterExclusive();
225 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
229 DPRINT("Mouse Input Thread Stopped...\n");
233 /* Returns a value that indicates if the key is a modifier key, and
237 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
239 if (InputData
->Flags
& KEY_E1
)
242 if (!(InputData
->Flags
& KEY_E0
))
244 switch (InputData
->MakeCode
)
246 case 0x2a: /* left shift */
247 case 0x36: /* right shift */
250 case 0x1d: /* left control */
253 case 0x38: /* left alt */
262 switch (InputData
->MakeCode
)
264 case 0x1d: /* right control */
267 case 0x38: /* right alt */
270 case 0x5b: /* left gui (windows) */
271 case 0x5c: /* right gui (windows) */
280 /* Asks the keyboard driver to send a small table that shows which
281 * lights should connect with which scancodes
283 STATIC NTSTATUS STDCALL
284 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
285 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
289 IO_STATUS_BLOCK Block
;
290 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
292 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
294 Ret
= ExAllocatePoolWithTag(PagedPool
,
300 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
305 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
309 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
314 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
316 Ret
= ExAllocatePoolWithTag(PagedPool
,
322 return STATUS_INSUFFICIENT_RESOURCES
;
324 if (Status
!= STATUS_SUCCESS
)
330 *IndicatorTrans
= Ret
;
334 /* Sends the keyboard commands to turn on/off the lights.
336 STATIC NTSTATUS STDCALL
337 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
338 PKEYBOARD_INPUT_DATA KeyInput
,
339 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
343 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
344 IO_STATUS_BLOCK Block
;
347 return STATUS_NOT_SUPPORTED
;
349 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
350 return STATUS_SUCCESS
;
352 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
354 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
356 Indicators
.LedFlags
^=
357 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
359 /* Update the lights on the hardware */
361 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
366 IOCTL_KEYBOARD_SET_INDICATORS
,
367 &Indicators
, sizeof(Indicators
),
374 return STATUS_SUCCESS
;
378 IntKeyboardSendWinKeyMsg()
380 PWINDOW_OBJECT Window
;
383 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
385 DPRINT1("Couldn't find window to send Windows key message!\n");
389 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
390 Mesg
.message
= WM_SYSCOMMAND
;
391 Mesg
.wParam
= SC_TASKLIST
;
394 /* The QS_HOTKEY is just a guess */
395 MsqPostMessage(Window
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
399 co_IntKeyboardSendAltKeyMsg()
401 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
405 KeyboardThreadMain(PVOID StartContext
)
407 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\??\\Keyboard");
408 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
409 IO_STATUS_BLOCK Iosb
;
412 PUSER_MESSAGE_QUEUE FocusQueue
;
413 struct _ETHREAD
*FocusThread
;
414 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
417 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
418 UINT ModifierState
= 0;
419 USHORT LastMakeCode
= 0;
420 USHORT LastFlags
= 0;
421 UINT RepeatCount
= 0;
423 InitializeObjectAttributes(&KeyboardObjectAttributes
,
430 LARGE_INTEGER DueTime
;
432 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
433 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
434 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
435 Status
= NtOpenFile(&KeyboardDeviceHandle
,
437 &KeyboardObjectAttributes
,
440 FILE_SYNCHRONOUS_IO_ALERT
);
441 } while (!NT_SUCCESS(Status
));
443 /* Not sure if converting this thread to a win32 thread is such
444 a great idea. Since we're posting keyboard messages to the focus
445 window message queue, we'll be (indirectly) doing sendmessage
446 stuff from this thread (for WH_KEYBOARD_LL processing), which
447 means we need our own message queue. If keyboard messages were
448 instead queued to the system message queue, the thread removing
449 the message from the system message queue would be responsible
450 for WH_KEYBOARD_LL processing and we wouldn't need this thread
451 to be a win32 thread. */
452 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
453 if (!NT_SUCCESS(Status
))
455 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
459 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
465 * Wait to start input.
467 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
468 Status
= KeWaitForSingleObject(&InputThreadsStart
,
473 DPRINT( "Keyboard Input Thread Starting...\n" );
476 * Receive and process keyboard input.
478 while (InputThreadsRunning
)
481 KEYBOARD_INPUT_DATA KeyInput
;
482 KEYBOARD_INPUT_DATA NextKeyInput
;
484 UINT fsModifiers
, fsNextModifiers
;
485 struct _ETHREAD
*Thread
;
489 Status
= NtReadFile (KeyboardDeviceHandle
,
495 sizeof(KEYBOARD_INPUT_DATA
),
498 DPRINT("KeyRaw: %s %04x\n",
499 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
502 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
505 if (!NT_SUCCESS(Status
))
507 DPRINT1("Win32K: Failed to read from keyboard.\n");
511 /* Update modifier state */
512 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
516 if (KeyInput
.Flags
& KEY_BREAK
)
518 ModifierState
&= ~fsModifiers
;
522 ModifierState
|= fsModifiers
;
524 if (ModifierState
== fsModifiers
&&
525 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
527 /* First send out special notifications
528 * (For alt, the message that turns on accelerator
529 * display, not sure what for win. Both TODO though.)
532 /* Read the next key before sending this one */
535 Status
= NtReadFile (KeyboardDeviceHandle
,
541 sizeof(KEYBOARD_INPUT_DATA
),
544 DPRINT("KeyRaw: %s %04x\n",
545 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
546 NextKeyInput
.MakeCode
);
548 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
552 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
553 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
554 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
555 * code. I'm not caring about the counting, not sure
556 * if that matters. I think not.
559 /* If the ModifierState is now empty again, send a
560 * special notification and eat both keypresses
563 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
566 ModifierState
^= fsNextModifiers
;
568 if (ModifierState
== 0)
570 if (fsModifiers
== MOD_WIN
)
571 IntKeyboardSendWinKeyMsg();
572 else if (fsModifiers
== MOD_ALT
)
573 co_IntKeyboardSendAltKeyMsg();
582 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
587 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
591 /* While we are working, we set up lParam. The format is:
592 * 0-15: The number of times this key has autorepeated
593 * 16-23: The keyboard scancode
594 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
595 * Note that E1 is only used for PAUSE (E1-1D-45) and
596 * E0-45 happens not to be anything.
597 * 29: Alt is pressed ('Context code')
598 * 30: Previous state, if the key was down before this message
599 * This is a cheap way to ignore autorepeat keys
600 * 31: 1 if the key is being pressed
603 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
604 * and it's the same key as the last one, increase the repeat
608 if (!(KeyInput
.Flags
& KEY_BREAK
))
610 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
611 (KeyInput
.MakeCode
== LastMakeCode
))
619 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
620 LastMakeCode
= KeyInput
.MakeCode
;
626 LastMakeCode
= 0; /* Should never match */
627 lParam
|= (1 << 30) | (1 << 31);
630 lParam
|= RepeatCount
;
632 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
634 if (KeyInput
.Flags
& KEY_E0
)
637 if (ModifierState
& MOD_ALT
)
641 if (!(KeyInput
.Flags
& KEY_BREAK
))
642 msg
.message
= WM_SYSKEYDOWN
;
644 msg
.message
= WM_SYSKEYUP
;
648 if (!(KeyInput
.Flags
& KEY_BREAK
))
649 msg
.message
= WM_KEYDOWN
;
651 msg
.message
= WM_KEYUP
;
654 /* Find the target thread whose locale is in effect */
655 if (!IntGetScreenDC())
656 FocusQueue
= W32kGetPrimitiveMessageQueue();
658 FocusQueue
= IntGetFocusMessageQueue();
660 /* This might cause us to lose hot keys, which are important
661 * (ctrl-alt-del secure attention sequence). Not sure if it
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(ModifierState
,
690 if (!(KeyInput
.Flags
& KEY_BREAK
))
692 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
693 MsqPostHotKeyMessage (Thread
,
696 MAKELPARAM((WORD
)ModifierState
,
699 continue; /* Eat key up motion too */
703 * Post a keyboard message.
705 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
710 DPRINT( "KeyboardInput Thread Stopped...\n" );
716 UserAcquireOrReleaseInputOwnership(BOOLEAN Release
)
718 if (Release
&& InputThreadsRunning
&& !pmPrimitiveMessageQueue
)
720 DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue
);
721 KeClearEvent(&InputThreadsStart
);
722 InputThreadsRunning
= FALSE
;
724 NtAlertThread(KeyboardThreadHandle
);
725 NtAlertThread(MouseThreadHandle
);
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] =
888 WM_LBUTTONDOWN
, WM_RBUTTONDOWN
890 {WM_LBUTTONUP
, WM_RBUTTONUP
}
892 const WPARAM SwapBtn
[2] =
894 MK_LBUTTON
, MK_RBUTTON
896 POINT MousePos
, OrgPos
;
897 PSYSTEM_CURSORINFO CurInfo
;
898 PWINSTATION_OBJECT WinSta
;
899 BOOL DoMove
, SwapButtons
;
902 BITMAPOBJ
*BitmapObj
;
905 PWINDOW_OBJECT DesktopWindow
;
911 /* FIXME - get the screen dc from the window station or desktop */
912 if(!(hDC
= IntGetScreenDC()))
921 WinSta
= PsGetWin32Process()->WindowStation
;
923 /* FIXME - ugly hack but as long as we're using this dumb callback from the
924 mouse class driver, we can't access the window station from the calling
926 WinSta
= InputWindowStation
;
931 CurInfo
= IntGetSysCursorInfo(WinSta
);
935 LARGE_INTEGER LargeTickCount
;
936 KeQueryTickCount(&LargeTickCount
);
937 mi
->time
= LargeTickCount
.u
.LowPart
;
940 SwapButtons
= CurInfo
->SwapButtons
;
943 IntGetCursorLocation(WinSta
, &MousePos
);
944 OrgPos
.x
= MousePos
.x
;
945 OrgPos
.y
= MousePos
.y
;
947 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
949 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
956 MousePos
.x
+= mi
->dx
;
957 MousePos
.y
+= mi
->dy
;
960 DesktopWindow
= IntGetWindowObject(WinSta
->ActiveDesktop
->DesktopWindow
);
964 if(MousePos
.x
>= DesktopWindow
->ClientRect
.right
)
965 MousePos
.x
= DesktopWindow
->ClientRect
.right
- 1;
966 if(MousePos
.y
>= DesktopWindow
->ClientRect
.bottom
)
967 MousePos
.y
= DesktopWindow
->ClientRect
.bottom
- 1;
968 ObmDereferenceObject(DesktopWindow
);
976 if(CurInfo
->CursorClipInfo
.IsClipped
)
978 /* The mouse cursor needs to be clipped */
980 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
981 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
982 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
983 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
984 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
985 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
986 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
987 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
990 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
998 hBitmap
= dc
->w
.hBitmap
;
1001 BitmapObj
= BITMAPOBJ_LockBitmap(hBitmap
);
1004 SurfObj
= &BitmapObj
->SurfObj
;
1006 IntEngMovePointer(SurfObj
, MousePos
.x
, MousePos
.y
, &(GDIDEV(SurfObj
)->Pointer
.Exclude
));
1007 /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
1008 * use the old values to move the pointer image */
1009 GDIDEV(SurfObj
)->Pointer
.Pos
.x
= MousePos
.x
;
1010 GDIDEV(SurfObj
)->Pointer
.Pos
.y
= MousePos
.y
;
1012 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1018 * Insert the messages into the system queue
1021 Msg
.wParam
= CurInfo
->ButtonsDown
;
1022 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1026 Msg
.message
= WM_MOUSEMOVE
;
1027 MsqInsertSystemMessage(&Msg
);
1031 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1033 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1034 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1035 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1036 MsqInsertSystemMessage(&Msg
);
1038 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1040 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1041 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1042 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1043 MsqInsertSystemMessage(&Msg
);
1045 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1047 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1048 Msg
.message
= WM_MBUTTONDOWN
;
1049 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1050 MsqInsertSystemMessage(&Msg
);
1052 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1054 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1055 Msg
.message
= WM_MBUTTONUP
;
1056 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1057 MsqInsertSystemMessage(&Msg
);
1059 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1061 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1062 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1063 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1064 MsqInsertSystemMessage(&Msg
);
1066 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1068 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1069 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1070 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1071 MsqInsertSystemMessage(&Msg
);
1074 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1075 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1077 /* fail because both types of events use the mouseData field */
1081 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1083 Msg
.message
= WM_XBUTTONDOWN
;
1084 if(mi
->mouseData
& XBUTTON1
)
1086 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1087 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1088 CurInfo
->ButtonsDown
|= XBUTTON1
;
1089 MsqInsertSystemMessage(&Msg
);
1091 if(mi
->mouseData
& XBUTTON2
)
1093 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1094 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1095 CurInfo
->ButtonsDown
|= XBUTTON2
;
1096 MsqInsertSystemMessage(&Msg
);
1099 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1101 Msg
.message
= WM_XBUTTONUP
;
1102 if(mi
->mouseData
& XBUTTON1
)
1104 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1105 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1106 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1107 MsqInsertSystemMessage(&Msg
);
1109 if(mi
->mouseData
& XBUTTON2
)
1111 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1112 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1113 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1114 MsqInsertSystemMessage(&Msg
);
1117 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1119 Msg
.message
= WM_MOUSEWHEEL
;
1120 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1121 MsqInsertSystemMessage(&Msg
);
1128 IntKeyboardInput(KEYBDINPUT
*ki
)
1140 PW32THREAD W32Thread
;
1142 DECLARE_RETURN(UINT
);
1144 DPRINT("Enter NtUserSendInput\n");
1145 UserEnterExclusive();
1147 W32Thread
= PsGetWin32Thread();
1150 if(!W32Thread
->Desktop
)
1155 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1157 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1162 * FIXME - check access rights of the window station
1163 * e.g. services running in the service window station cannot block input
1165 if(!ThreadHasInputAccess(W32Thread
) ||
1166 !IntIsActiveDesktop(W32Thread
->Desktop
))
1168 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1178 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1179 if(!NT_SUCCESS(Status
))
1181 SetLastNtError(Status
);
1185 switch(SafeInput
.type
)
1188 if(IntMouseInput(&SafeInput
.mi
))
1193 case INPUT_KEYBOARD
:
1194 if(IntKeyboardInput(&SafeInput
.ki
))
1199 case INPUT_HARDWARE
:
1204 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1214 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);