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 ExAcquireFastMutex(&CurInfo
->CursorMutex
);
934 IntGetCursorLocation(WinSta
, &MousePos
);
935 OrgPos
.x
= MousePos
.x
;
936 OrgPos
.y
= MousePos
.y
;
938 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
940 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
947 MousePos
.x
+= mi
->dx
;
948 MousePos
.y
+= mi
->dy
;
951 Status
= ObmReferenceObjectByHandle(WinSta
->HandleTable
,
952 WinSta
->ActiveDesktop
->DesktopWindow
, otWindow
, (PVOID
*)&DesktopWindow
);
953 if (NT_SUCCESS(Status
))
955 if(MousePos
.x
>= DesktopWindow
->ClientRect
.right
)
956 MousePos
.x
= DesktopWindow
->ClientRect
.right
- 1;
957 if(MousePos
.y
>= DesktopWindow
->ClientRect
.bottom
)
958 MousePos
.y
= DesktopWindow
->ClientRect
.bottom
- 1;
959 ObmDereferenceObject(DesktopWindow
);
967 if(CurInfo
->CursorClipInfo
.IsClipped
)
969 /* The mouse cursor needs to be clipped */
971 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
972 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
973 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
974 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
975 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
976 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
977 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
978 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
981 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
984 ExReleaseFastMutex(&CurInfo
->CursorMutex
);
991 hBitmap
= dc
->w
.hBitmap
;
994 BitmapObj
= BITMAPOBJ_LockBitmap(hBitmap
);
997 SurfObj
= &BitmapObj
->SurfObj
;
999 IntEngMovePointer(SurfObj
, MousePos
.x
, MousePos
.y
, &(GDIDEV(SurfObj
)->Pointer
.Exclude
));
1000 /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
1001 * use the old values to move the pointer image */
1002 GDIDEV(SurfObj
)->Pointer
.Pos
.x
= MousePos
.x
;
1003 GDIDEV(SurfObj
)->Pointer
.Pos
.y
= MousePos
.y
;
1005 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1011 * Insert the messages into the system queue
1014 Msg
.wParam
= CurInfo
->ButtonsDown
;
1015 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1019 Msg
.message
= WM_MOUSEMOVE
;
1020 MsqInsertSystemMessage(&Msg
);
1024 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1026 QueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1027 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1028 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1029 MsqInsertSystemMessage(&Msg
);
1031 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1033 QueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1034 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1035 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1036 MsqInsertSystemMessage(&Msg
);
1038 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1040 QueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1041 Msg
.message
= WM_MBUTTONDOWN
;
1042 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1043 MsqInsertSystemMessage(&Msg
);
1045 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1047 QueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1048 Msg
.message
= WM_MBUTTONUP
;
1049 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1050 MsqInsertSystemMessage(&Msg
);
1052 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1054 QueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1055 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1056 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1057 MsqInsertSystemMessage(&Msg
);
1059 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1061 QueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1062 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1063 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1064 MsqInsertSystemMessage(&Msg
);
1067 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1068 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1070 /* fail because both types of events use the mouseData field */
1074 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1076 Msg
.message
= WM_XBUTTONDOWN
;
1077 if(mi
->mouseData
& XBUTTON1
)
1079 QueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1080 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1081 CurInfo
->ButtonsDown
|= XBUTTON1
;
1082 MsqInsertSystemMessage(&Msg
);
1084 if(mi
->mouseData
& XBUTTON2
)
1086 QueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1087 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1088 CurInfo
->ButtonsDown
|= XBUTTON2
;
1089 MsqInsertSystemMessage(&Msg
);
1092 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1094 Msg
.message
= WM_XBUTTONUP
;
1095 if(mi
->mouseData
& XBUTTON1
)
1097 QueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1098 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1099 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1100 MsqInsertSystemMessage(&Msg
);
1102 if(mi
->mouseData
& XBUTTON2
)
1104 QueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1105 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1106 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1107 MsqInsertSystemMessage(&Msg
);
1110 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1112 Msg
.message
= WM_MOUSEWHEEL
;
1113 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1114 MsqInsertSystemMessage(&Msg
);
1121 IntKeyboardInput(KEYBDINPUT
*ki
)
1133 PW32THREAD W32Thread
;
1135 DECLARE_RETURN(UINT
);
1137 DPRINT("Enter NtUserSendInput\n");
1138 UserEnterExclusive();
1140 W32Thread
= PsGetWin32Thread();
1143 if(!W32Thread
->Desktop
)
1148 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1150 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1155 * FIXME - check access rights of the window station
1156 * e.g. services running in the service window station cannot block input
1158 if(!ThreadHasInputAccess(W32Thread
) ||
1159 !IntIsActiveDesktop(W32Thread
->Desktop
))
1161 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1171 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1172 if(!NT_SUCCESS(Status
))
1174 SetLastNtError(Status
);
1178 switch(SafeInput
.type
)
1181 if(IntMouseInput(&SafeInput
.mi
))
1186 case INPUT_KEYBOARD
:
1187 if(IntKeyboardInput(&SafeInput
.ki
))
1192 case INPUT_HARDWARE
:
1196 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1205 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);