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\\PointerClass0");
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
"\\Device\\KeyboardClass0");
408 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
409 IO_STATUS_BLOCK Iosb
;
412 PUSER_MESSAGE_QUEUE FocusQueue
;
413 struct _ETHREAD
*FocusThread
;
414 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
416 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
417 UINT ModifierState
= 0;
418 USHORT LastMakeCode
= 0;
419 USHORT LastFlags
= 0;
420 UINT RepeatCount
= 0;
422 InitializeObjectAttributes(&KeyboardObjectAttributes
,
429 LARGE_INTEGER DueTime
;
431 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
432 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
433 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
434 Status
= NtOpenFile(&KeyboardDeviceHandle
,
436 &KeyboardObjectAttributes
,
439 FILE_SYNCHRONOUS_IO_ALERT
);
440 } while (!NT_SUCCESS(Status
));
442 /* Not sure if converting this thread to a win32 thread is such
443 a great idea. Since we're posting keyboard messages to the focus
444 window message queue, we'll be (indirectly) doing sendmessage
445 stuff from this thread (for WH_KEYBOARD_LL processing), which
446 means we need our own message queue. If keyboard messages were
447 instead queued to the system message queue, the thread removing
448 the message from the system message queue would be responsible
449 for WH_KEYBOARD_LL processing and we wouldn't need this thread
450 to be a win32 thread. */
451 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
452 if (!NT_SUCCESS(Status
))
454 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
458 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
464 * Wait to start input.
466 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
467 Status
= KeWaitForSingleObject(&InputThreadsStart
,
472 DPRINT( "Keyboard Input Thread Starting...\n" );
475 * Receive and process keyboard input.
477 while (InputThreadsRunning
)
480 KEYBOARD_INPUT_DATA KeyInput
;
481 KEYBOARD_INPUT_DATA NextKeyInput
;
483 UINT fsModifiers
, fsNextModifiers
;
484 struct _ETHREAD
*Thread
;
488 DPRINT("KeyInput @ %08x\n", &KeyInput
);
490 Status
= NtReadFile (KeyboardDeviceHandle
,
496 sizeof(KEYBOARD_INPUT_DATA
),
500 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
504 if(Status
== STATUS_PENDING
)
506 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
507 Status
= Iosb
.Status
;
509 if(!NT_SUCCESS(Status
))
511 DPRINT1("Win32K: Failed to read from mouse.\n");
515 DPRINT("KeyRaw: %s %04x\n",
516 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
519 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
522 if (!NT_SUCCESS(Status
))
524 DPRINT1("Win32K: Failed to read from keyboard.\n");
528 /* Update modifier state */
529 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
533 if (KeyInput
.Flags
& KEY_BREAK
)
535 ModifierState
&= ~fsModifiers
;
539 ModifierState
|= fsModifiers
;
541 if (ModifierState
== fsModifiers
&&
542 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
544 /* First send out special notifications
545 * (For alt, the message that turns on accelerator
546 * display, not sure what for win. Both TODO though.)
549 /* Read the next key before sending this one */
552 Status
= NtReadFile (KeyboardDeviceHandle
,
558 sizeof(KEYBOARD_INPUT_DATA
),
561 DPRINT("KeyRaw: %s %04x\n",
562 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
563 NextKeyInput
.MakeCode
);
565 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
569 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
570 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
571 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
572 * code. I'm not caring about the counting, not sure
573 * if that matters. I think not.
576 /* If the ModifierState is now empty again, send a
577 * special notification and eat both keypresses
580 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
583 ModifierState
^= fsNextModifiers
;
585 if (ModifierState
== 0)
587 if (fsModifiers
== MOD_WIN
)
588 IntKeyboardSendWinKeyMsg();
589 else if (fsModifiers
== MOD_ALT
)
590 co_IntKeyboardSendAltKeyMsg();
599 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
604 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
608 /* While we are working, we set up lParam. The format is:
609 * 0-15: The number of times this key has autorepeated
610 * 16-23: The keyboard scancode
611 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
612 * Note that E1 is only used for PAUSE (E1-1D-45) and
613 * E0-45 happens not to be anything.
614 * 29: Alt is pressed ('Context code')
615 * 30: Previous state, if the key was down before this message
616 * This is a cheap way to ignore autorepeat keys
617 * 31: 1 if the key is being pressed
620 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
621 * and it's the same key as the last one, increase the repeat
625 if (!(KeyInput
.Flags
& KEY_BREAK
))
627 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
628 (KeyInput
.MakeCode
== LastMakeCode
))
636 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
637 LastMakeCode
= KeyInput
.MakeCode
;
643 LastMakeCode
= 0; /* Should never match */
644 lParam
|= (1 << 30) | (1 << 31);
647 lParam
|= RepeatCount
;
649 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
651 if (KeyInput
.Flags
& KEY_E0
)
654 if (ModifierState
& MOD_ALT
)
658 if (!(KeyInput
.Flags
& KEY_BREAK
))
659 msg
.message
= WM_SYSKEYDOWN
;
661 msg
.message
= WM_SYSKEYUP
;
665 if (!(KeyInput
.Flags
& KEY_BREAK
))
666 msg
.message
= WM_KEYDOWN
;
668 msg
.message
= WM_KEYUP
;
671 /* Find the target thread whose locale is in effect */
672 if (!IntGetScreenDC())
673 FocusQueue
= W32kGetPrimitiveMessageQueue();
675 FocusQueue
= IntGetFocusMessageQueue();
677 /* This might cause us to lose hot keys, which are important
678 * (ctrl-alt-del secure attention sequence). Not sure if it
685 msg
.hwnd
= FocusQueue
->FocusWindow
;
687 FocusThread
= FocusQueue
->Thread
;
689 if (!(FocusThread
&& FocusThread
->Tcb
.Win32Thread
&&
690 ((PW32THREAD
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
))
693 /* This function uses lParam to fill wParam according to the
694 * keyboard layout in use.
696 W32kKeyProcessMessage(&msg
,
697 ((PW32THREAD
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
,
698 KeyInput
.Flags
& KEY_E0
? 0xE0 :
699 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
701 if (GetHotKey(ModifierState
,
707 if (!(KeyInput
.Flags
& KEY_BREAK
))
709 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
710 MsqPostHotKeyMessage (Thread
,
713 MAKELPARAM((WORD
)ModifierState
,
716 continue; /* Eat key up motion too */
720 * Post a keyboard message.
722 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
727 DPRINT( "KeyboardInput Thread Stopped...\n" );
733 UserAcquireOrReleaseInputOwnership(BOOLEAN Release
)
735 if (Release
&& InputThreadsRunning
&& !pmPrimitiveMessageQueue
)
737 DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue
);
738 KeClearEvent(&InputThreadsStart
);
739 InputThreadsRunning
= FALSE
;
741 NtAlertThread(KeyboardThreadHandle
);
742 NtAlertThread(MouseThreadHandle
);
744 else if (!Release
&& !InputThreadsRunning
)
746 InputThreadsRunning
= TRUE
;
747 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
750 return(STATUS_SUCCESS
);
755 NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release
)
757 DECLARE_RETURN(NTSTATUS
);
759 DPRINT("Enter NtUserAcquireOrReleaseInputOwnership\n");
760 UserEnterExclusive();
762 RETURN(UserAcquireOrReleaseInputOwnership(Release
));
765 DPRINT("Leave NtUserAcquireOrReleaseInputOwnership, ret=%i\n",_ret_
);
776 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
778 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
785 if (!NT_SUCCESS(Status
))
787 DPRINT1("Win32K: Failed to create keyboard thread.\n");
790 /* Initialize the default keyboard layout */
791 (VOID
)W32kGetDefaultKeyLayout();
794 Status
= PsCreateSystemThread(&MouseThreadHandle
,
801 if (!NT_SUCCESS(Status
))
803 DPRINT1("Win32K: Failed to create mouse thread.\n");
806 return STATUS_SUCCESS
;
810 CleanupInputImp(VOID
)
812 return(STATUS_SUCCESS
);
827 IntBlockInput(PW32THREAD W32Thread
, BOOL BlockIt
)
832 if(!W32Thread
->Desktop
|| (W32Thread
->IsExiting
&& BlockIt
))
835 * fail blocking if exiting the thread
842 * FIXME - check access rights of the window station
843 * e.g. services running in the service window station cannot block input
845 if(!ThreadHasInputAccess(W32Thread
) ||
846 !IntIsActiveDesktop(W32Thread
->Desktop
))
848 SetLastWin32Error(ERROR_ACCESS_DENIED
);
852 ASSERT(W32Thread
->Desktop
);
853 OldBlock
= W32Thread
->Desktop
->BlockInputThread
;
856 if(OldBlock
!= W32Thread
)
858 SetLastWin32Error(ERROR_ACCESS_DENIED
);
861 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
862 return OldBlock
== NULL
;
865 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
866 return OldBlock
== NULL
;
874 DECLARE_RETURN(BOOLEAN
);
876 DPRINT("Enter NtUserBlockInput\n");
877 UserEnterExclusive();
879 RETURN( IntBlockInput(PsGetWin32Thread(), BlockIt
));
882 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
888 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject
, BOOL Swap
)
890 PSYSTEM_CURSORINFO CurInfo
;
893 CurInfo
= IntGetSysCursorInfo(WinStaObject
);
894 res
= CurInfo
->SwapButtons
;
895 CurInfo
->SwapButtons
= Swap
;
900 IntMouseInput(MOUSEINPUT
*mi
)
902 const UINT SwapBtnMsg
[2][2] =
905 WM_LBUTTONDOWN
, WM_RBUTTONDOWN
907 {WM_LBUTTONUP
, WM_RBUTTONUP
}
909 const WPARAM SwapBtn
[2] =
911 MK_LBUTTON
, MK_RBUTTON
913 POINT MousePos
, OrgPos
;
914 PSYSTEM_CURSORINFO CurInfo
;
915 PWINSTATION_OBJECT WinSta
;
916 BOOL DoMove
, SwapButtons
;
919 BITMAPOBJ
*BitmapObj
;
922 PWINDOW_OBJECT DesktopWindow
;
928 /* FIXME - get the screen dc from the window station or desktop */
929 if(!(hDC
= IntGetScreenDC()))
938 WinSta
= PsGetWin32Process()->WindowStation
;
940 /* FIXME - ugly hack but as long as we're using this dumb callback from the
941 mouse class driver, we can't access the window station from the calling
943 WinSta
= InputWindowStation
;
948 CurInfo
= IntGetSysCursorInfo(WinSta
);
952 LARGE_INTEGER LargeTickCount
;
953 KeQueryTickCount(&LargeTickCount
);
954 mi
->time
= LargeTickCount
.u
.LowPart
;
957 SwapButtons
= CurInfo
->SwapButtons
;
960 IntGetCursorLocation(WinSta
, &MousePos
);
961 OrgPos
.x
= MousePos
.x
;
962 OrgPos
.y
= MousePos
.y
;
964 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
966 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
973 MousePos
.x
+= mi
->dx
;
974 MousePos
.y
+= mi
->dy
;
977 DesktopWindow
= IntGetWindowObject(WinSta
->ActiveDesktop
->DesktopWindow
);
981 if(MousePos
.x
>= DesktopWindow
->ClientRect
.right
)
982 MousePos
.x
= DesktopWindow
->ClientRect
.right
- 1;
983 if(MousePos
.y
>= DesktopWindow
->ClientRect
.bottom
)
984 MousePos
.y
= DesktopWindow
->ClientRect
.bottom
- 1;
985 ObmDereferenceObject(DesktopWindow
);
993 if(CurInfo
->CursorClipInfo
.IsClipped
)
995 /* The mouse cursor needs to be clipped */
997 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
998 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
999 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
1000 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
1001 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
1002 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
1003 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
1004 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
1007 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
1012 dc
= DC_LockDc(hDC
);
1015 hBitmap
= dc
->w
.hBitmap
;
1018 BitmapObj
= BITMAPOBJ_LockBitmap(hBitmap
);
1021 SurfObj
= &BitmapObj
->SurfObj
;
1023 IntEngMovePointer(SurfObj
, MousePos
.x
, MousePos
.y
, &(GDIDEV(SurfObj
)->Pointer
.Exclude
));
1024 /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
1025 * use the old values to move the pointer image */
1026 GDIDEV(SurfObj
)->Pointer
.Pos
.x
= MousePos
.x
;
1027 GDIDEV(SurfObj
)->Pointer
.Pos
.y
= MousePos
.y
;
1029 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1035 * Insert the messages into the system queue
1038 Msg
.wParam
= CurInfo
->ButtonsDown
;
1039 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1043 Msg
.message
= WM_MOUSEMOVE
;
1044 MsqInsertSystemMessage(&Msg
);
1048 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1050 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1051 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1052 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1053 MsqInsertSystemMessage(&Msg
);
1055 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1057 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1058 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1059 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1060 MsqInsertSystemMessage(&Msg
);
1062 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1064 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1065 Msg
.message
= WM_MBUTTONDOWN
;
1066 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1067 MsqInsertSystemMessage(&Msg
);
1069 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1071 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1072 Msg
.message
= WM_MBUTTONUP
;
1073 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1074 MsqInsertSystemMessage(&Msg
);
1076 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1078 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1079 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1080 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1081 MsqInsertSystemMessage(&Msg
);
1083 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1085 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1086 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1087 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1088 MsqInsertSystemMessage(&Msg
);
1091 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1092 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1094 /* fail because both types of events use the mouseData field */
1098 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1100 Msg
.message
= WM_XBUTTONDOWN
;
1101 if(mi
->mouseData
& XBUTTON1
)
1103 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1104 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1105 CurInfo
->ButtonsDown
|= XBUTTON1
;
1106 MsqInsertSystemMessage(&Msg
);
1108 if(mi
->mouseData
& XBUTTON2
)
1110 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1111 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1112 CurInfo
->ButtonsDown
|= XBUTTON2
;
1113 MsqInsertSystemMessage(&Msg
);
1116 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1118 Msg
.message
= WM_XBUTTONUP
;
1119 if(mi
->mouseData
& XBUTTON1
)
1121 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1122 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1123 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1124 MsqInsertSystemMessage(&Msg
);
1126 if(mi
->mouseData
& XBUTTON2
)
1128 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1129 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1130 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1131 MsqInsertSystemMessage(&Msg
);
1134 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1136 Msg
.message
= WM_MOUSEWHEEL
;
1137 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1138 MsqInsertSystemMessage(&Msg
);
1145 IntKeyboardInput(KEYBDINPUT
*ki
)
1157 PW32THREAD W32Thread
;
1159 DECLARE_RETURN(UINT
);
1161 DPRINT("Enter NtUserSendInput\n");
1162 UserEnterExclusive();
1164 W32Thread
= PsGetWin32Thread();
1167 if(!W32Thread
->Desktop
)
1172 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1174 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1179 * FIXME - check access rights of the window station
1180 * e.g. services running in the service window station cannot block input
1182 if(!ThreadHasInputAccess(W32Thread
) ||
1183 !IntIsActiveDesktop(W32Thread
->Desktop
))
1185 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1195 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1196 if(!NT_SUCCESS(Status
))
1198 SetLastNtError(Status
);
1202 switch(SafeInput
.type
)
1205 if(IntMouseInput(&SafeInput
.mi
))
1210 case INPUT_KEYBOARD
:
1211 if(IntKeyboardInput(&SafeInput
.ki
))
1216 case INPUT_HARDWARE
:
1221 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1231 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);