2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsystems/win32/win32k/ntuser/input.c
6 * PROGRAMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Rafal Harabien (rafalh@reactos.org)
11 DBG_DEFAULT_CHANNEL(UserInput
);
13 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
14 extern PPROCESSINFO ppiScrnSaver
;
16 /* GLOBALS *******************************************************************/
18 PTHREADINFO ptiRawInput
;
19 PTHREADINFO ptiKeyboard
;
21 PKTIMER MasterTimer
= NULL
;
22 PATTACHINFO gpai
= NULL
;
23 HANDLE ghKeyboardDevice
;
25 static DWORD LastInputTick
= 0;
26 static HANDLE MouseDeviceHandle
;
27 static HANDLE MouseThreadHandle
;
28 static CLIENT_ID MouseThreadId
;
29 static HANDLE KeyboardThreadHandle
;
30 static CLIENT_ID KeyboardThreadId
;
31 static HANDLE RawInputThreadHandle
;
32 static CLIENT_ID RawInputThreadId
;
33 static KEVENT InputThreadsStart
;
34 static BOOLEAN InputThreadsRunning
= FALSE
;
36 /* FUNCTIONS *****************************************************************/
38 #define ClearMouseInput(mi) \
44 #define SendMouseEvent(mi) \
45 if(mi.dx != 0 || mi.dy != 0) \
46 mi.dwFlags |= MOUSEEVENTF_MOVE; \
48 IntMouseInput(&mi,FALSE); \
52 IntLastInputTick(BOOL bUpdate
)
56 LARGE_INTEGER TickCount
;
57 KeQueryTickCount(&TickCount
);
58 LastInputTick
= MsqCalculateMessageTime(&TickCount
);
59 if (gpsi
) gpsi
->dwLastRITEventTickCount
= LastInputTick
;
65 DoTheScreenSaver(VOID
)
67 LARGE_INTEGER TickCount
;
70 if (gspv
.iScrSaverTimeout
> 0) // Zero means Off.
72 KeQueryTickCount(&TickCount
);
73 Test
= MsqCalculateMessageTime(&TickCount
);
74 Test
= Test
- LastInputTick
;
75 TO
= 1000 * gspv
.iScrSaverTimeout
;
78 TRACE("Screensaver Message Start! Tick %d Timeout %d \n", Test
, gspv
.iScrSaverTimeout
);
80 if (ppiScrnSaver
) // We are or we are not the screensaver, prevent reentry...
82 if (!(ppiScrnSaver
->W32PF_flags
& W32PF_IDLESCREENSAVER
))
84 ppiScrnSaver
->W32PF_flags
|= W32PF_IDLESCREENSAVER
;
85 ERR("Screensaver is Idle\n");
90 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
91 if (ForegroundQueue
&& ForegroundQueue
->ActiveWindow
)
92 UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_START_SCREENSAVE
, 1); // lParam 1 == Secure
94 UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_START_SCREENSAVE
, 0);
101 IntProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
103 PMOUSE_INPUT_DATA mid
;
110 for(i
= 0; i
< InputCount
; i
++)
116 /* Check if the mouse move is absolute */
117 if (mid
->Flags
== MOUSE_MOVE_ABSOLUTE
)
119 /* Set flag to convert to screen location */
120 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
125 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
127 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
130 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
132 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
135 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
137 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
140 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
142 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
145 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
147 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
150 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
152 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
155 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
157 mi
.mouseData
|= XBUTTON1
;
158 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
161 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
163 mi
.mouseData
|= XBUTTON1
;
164 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
167 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
169 mi
.mouseData
|= XBUTTON2
;
170 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
173 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
175 mi
.mouseData
|= XBUTTON2
;
176 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
179 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
181 mi
.mouseData
= mid
->ButtonData
;
182 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
192 MouseThreadMain(PVOID StartContext
)
194 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
195 OBJECT_ATTRIBUTES MouseObjectAttributes
;
196 IO_STATUS_BLOCK Iosb
;
198 MOUSE_ATTRIBUTES MouseAttr
;
200 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
201 LOW_REALTIME_PRIORITY
+ 3);
203 InitializeObjectAttributes(&MouseObjectAttributes
,
210 LARGE_INTEGER DueTime
;
212 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
213 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
214 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
215 Status
= NtOpenFile(&MouseDeviceHandle
,
217 &MouseObjectAttributes
,
220 FILE_SYNCHRONOUS_IO_ALERT
);
221 } while (!NT_SUCCESS(Status
));
223 /* Need to setup basic win32k for this thread to process WH_MOUSE_LL messages. */
224 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
225 if (!NT_SUCCESS(Status
))
227 ERR("Win32K: Failed making mouse thread a win32 thread.\n");
231 ptiMouse
= PsGetCurrentThreadWin32Thread();
232 ptiMouse
->TIF_flags
|= TIF_SYSTEMTHREAD
;
233 TRACE("Mouse Thread 0x%x \n", ptiMouse
);
235 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
236 LOW_REALTIME_PRIORITY
+ 3);
241 * Wait to start input.
243 TRACE("Mouse Input Thread Waiting for start event\n");
244 Status
= KeWaitForSingleObject(&InputThreadsStart
,
249 TRACE("Mouse Input Thread Starting...\n");
251 /*FIXME: Does mouse attributes need to be used for anything */
252 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
257 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
258 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
260 if(!NT_SUCCESS(Status
))
262 TRACE("Failed to get mouse attributes\n");
266 * Receive and process mouse input.
268 while(InputThreadsRunning
)
270 MOUSE_INPUT_DATA MouseInput
;
271 Status
= NtReadFile(MouseDeviceHandle
,
277 sizeof(MOUSE_INPUT_DATA
),
280 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
284 if(Status
== STATUS_PENDING
)
286 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
287 Status
= Iosb
.Status
;
289 if(!NT_SUCCESS(Status
))
291 ERR("Win32K: Failed to read from mouse.\n");
294 TRACE("MouseEvent\n");
295 IntLastInputTick(TRUE
);
297 UserEnterExclusive();
299 IntProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
303 TRACE("Mouse Input Thread Stopped...\n");
308 KeyboardThreadMain(PVOID StartContext
)
310 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
311 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
312 IO_STATUS_BLOCK Iosb
;
315 InitializeObjectAttributes(&KeyboardObjectAttributes
,
322 LARGE_INTEGER DueTime
;
324 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
325 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
326 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
327 Status
= NtOpenFile(&ghKeyboardDevice
,
329 &KeyboardObjectAttributes
,
332 FILE_SYNCHRONOUS_IO_ALERT
);
333 } while (!NT_SUCCESS(Status
));
335 /* Not sure if converting this thread to a win32 thread is such
336 a great idea. Since we're posting keyboard messages to the focus
337 window message queue, we'll be (indirectly) doing sendmessage
338 stuff from this thread (for WH_KEYBOARD_LL processing), which
339 means we need our own message queue. If keyboard messages were
340 instead queued to the system message queue, the thread removing
341 the message from the system message queue would be responsible
342 for WH_KEYBOARD_LL processing and we wouldn't need this thread
343 to be a win32 thread. */
344 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
345 if (!NT_SUCCESS(Status
))
347 ERR("Win32K: Failed making keyboard thread a win32 thread.\n");
351 ptiKeyboard
= PsGetCurrentThreadWin32Thread();
352 ptiKeyboard
->TIF_flags
|= TIF_SYSTEMTHREAD
;
353 TRACE("Keyboard Thread 0x%x \n", ptiKeyboard
);
355 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
356 LOW_REALTIME_PRIORITY
+ 3);
358 //IntKeyboardGetIndicatorTrans(ghKeyboardDevice,
364 * Wait to start input.
366 TRACE( "Keyboard Input Thread Waiting for start event\n" );
367 Status
= KeWaitForSingleObject(&InputThreadsStart
,
373 TRACE( "Keyboard Input Thread Starting...\n" );
375 * Receive and process keyboard input.
377 while (InputThreadsRunning
)
379 KEYBOARD_INPUT_DATA KeyInput
;
381 TRACE("KeyInput @ %08x\n", &KeyInput
);
383 Status
= NtReadFile (ghKeyboardDevice
,
389 sizeof(KEYBOARD_INPUT_DATA
),
393 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
397 if(Status
== STATUS_PENDING
)
399 NtWaitForSingleObject(ghKeyboardDevice
, FALSE
, NULL
);
400 Status
= Iosb
.Status
;
402 if(!NT_SUCCESS(Status
))
404 ERR("Win32K: Failed to read from keyboard.\n");
408 TRACE("KeyRaw: %s %04x\n",
409 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
412 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
415 if (!NT_SUCCESS(Status
))
417 ERR("Win32K: Failed to read from keyboard.\n");
421 /* Set LastInputTick */
422 IntLastInputTick(TRUE
);
425 UserEnterExclusive();
426 UserProcessKeyboardInput(&KeyInput
);
430 TRACE( "KeyboardInput Thread Stopped...\n" );
435 static PVOID Objects
[2];
438 Since this relies on InputThreadsStart, just fake it.
441 RawInputThreadMain(PVOID StartContext
)
444 LARGE_INTEGER DueTime
;
446 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
451 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
452 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
453 } while (!NT_SUCCESS(Status
));
456 Objects
[0] = &InputThreadsStart
;
457 Objects
[1] = MasterTimer
;
459 // This thread requires win32k!
460 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
461 if (!NT_SUCCESS(Status
))
463 ERR("Win32K: Failed making Raw Input thread a win32 thread.\n");
467 ptiRawInput
= PsGetCurrentThreadWin32Thread();
468 ptiRawInput
->TIF_flags
|= TIF_SYSTEMTHREAD
;
469 TRACE("Raw Input Thread 0x%x \n", ptiRawInput
);
471 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
472 LOW_REALTIME_PRIORITY
+ 3);
474 UserEnterExclusive();
479 // ATM, we just have one job to handle, merge the other two later.
483 TRACE( "Raw Input Thread Waiting for start event\n" );
485 Status
= KeWaitForMultipleObjects( 2,
493 TRACE( "Raw Input Thread Starting...\n" );
497 ERR("Raw Input Thread Exit!\n");
507 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
509 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), USERTAG_SYSTEM
);
512 ERR("Win32K: Failed making Raw Input thread a win32 thread.\n");
514 return STATUS_UNSUCCESSFUL
;
516 KeInitializeTimer(MasterTimer
);
518 /* Initialize the default keyboard layout */
519 if(!UserInitDefaultKeyboardLayout())
521 ERR("Failed to initialize default keyboard layout!\n");
524 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
531 if (!NT_SUCCESS(Status
))
533 ERR("Win32K: Failed to create raw thread.\n");
536 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
543 if (!NT_SUCCESS(Status
))
545 ERR("Win32K: Failed to create keyboard thread.\n");
548 Status
= PsCreateSystemThread(&MouseThreadHandle
,
555 if (!NT_SUCCESS(Status
))
557 ERR("Win32K: Failed to create mouse thread.\n");
560 InputThreadsRunning
= TRUE
;
561 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
563 return STATUS_SUCCESS
;
567 CleanupInputImp(VOID
)
569 return(STATUS_SUCCESS
);
573 IntBlockInput(PTHREADINFO pti
, BOOL BlockIt
)
575 PTHREADINFO OldBlock
;
578 if(!pti
->rpdesk
|| ((pti
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
581 * fail blocking if exiting the thread
588 * FIXME - check access rights of the window station
589 * e.g. services running in the service window station cannot block input
591 if(!ThreadHasInputAccess(pti
) ||
592 !IntIsActiveDesktop(pti
->rpdesk
))
594 EngSetLastError(ERROR_ACCESS_DENIED
);
599 OldBlock
= pti
->rpdesk
->BlockInputThread
;
604 EngSetLastError(ERROR_ACCESS_DENIED
);
607 pti
->rpdesk
->BlockInputThread
= (BlockIt
? pti
: NULL
);
608 return OldBlock
== NULL
;
611 pti
->rpdesk
->BlockInputThread
= (BlockIt
? pti
: NULL
);
612 return OldBlock
== NULL
;
620 DECLARE_RETURN(BOOLEAN
);
622 TRACE("Enter NtUserBlockInput\n");
623 UserEnterExclusive();
625 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
628 TRACE("Leave NtUserBlockInput, ret=%i\n", _ret_
);
634 IntMouseInput(MOUSEINPUT
*mi
, BOOL Injected
)
636 const UINT SwapBtnMsg
[2][2] =
638 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
639 {WM_LBUTTONUP
, WM_RBUTTONUP
}
641 const WPARAM SwapBtn
[2] =
643 MK_LBUTTON
, MK_RBUTTON
646 PSYSTEM_CURSORINFO CurInfo
;
652 CurInfo
= IntGetSysCursorInfo();
656 LARGE_INTEGER LargeTickCount
;
657 KeQueryTickCount(&LargeTickCount
);
658 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
661 SwapButtons
= gspv
.bMouseBtnSwap
;
663 MousePos
= gpsi
->ptCursor
;
665 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
667 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
669 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
670 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
674 MousePos
.x
+= mi
->dx
;
675 MousePos
.y
+= mi
->dy
;
680 * Insert the messages into the system queue
683 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
686 if (gafAsyncKeyState
[VK_SHIFT
] & KS_DOWN_BIT
)
688 Msg
.wParam
|= MK_SHIFT
;
691 if (gafAsyncKeyState
[VK_CONTROL
] & KS_DOWN_BIT
)
693 Msg
.wParam
|= MK_CONTROL
;
696 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
698 UserSetCursorPos(MousePos
.x
, MousePos
.y
, Injected
, mi
->dwExtraInfo
, TRUE
);
700 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
702 gafAsyncKeyState
[VK_LBUTTON
] |= KS_DOWN_BIT
;
703 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
704 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
705 Msg
.wParam
|= CurInfo
->ButtonsDown
;
706 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
708 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
710 gafAsyncKeyState
[VK_LBUTTON
] &= ~KS_DOWN_BIT
;
711 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
712 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
713 Msg
.wParam
|= CurInfo
->ButtonsDown
;
714 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
716 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
718 gafAsyncKeyState
[VK_MBUTTON
] |= KS_DOWN_BIT
;
719 Msg
.message
= WM_MBUTTONDOWN
;
720 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
721 Msg
.wParam
|= CurInfo
->ButtonsDown
;
722 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
724 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
726 gafAsyncKeyState
[VK_MBUTTON
] &= ~KS_DOWN_BIT
;
727 Msg
.message
= WM_MBUTTONUP
;
728 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
729 Msg
.wParam
|= CurInfo
->ButtonsDown
;
730 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
732 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
734 gafAsyncKeyState
[VK_RBUTTON
] |= KS_DOWN_BIT
;
735 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
736 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
737 Msg
.wParam
|= CurInfo
->ButtonsDown
;
738 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
740 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
742 gafAsyncKeyState
[VK_RBUTTON
] &= ~KS_DOWN_BIT
;
743 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
744 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
745 Msg
.wParam
|= CurInfo
->ButtonsDown
;
746 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
749 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
750 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
752 /* fail because both types of events use the mouseData field */
756 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
758 Msg
.message
= WM_XBUTTONDOWN
;
759 if(mi
->mouseData
& XBUTTON1
)
761 gafAsyncKeyState
[VK_XBUTTON1
] |= KS_DOWN_BIT
;
762 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
763 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
764 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
766 if(mi
->mouseData
& XBUTTON2
)
768 gafAsyncKeyState
[VK_XBUTTON2
] |= KS_DOWN_BIT
;
769 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
770 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
771 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
774 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
776 Msg
.message
= WM_XBUTTONUP
;
777 if(mi
->mouseData
& XBUTTON1
)
779 gafAsyncKeyState
[VK_XBUTTON1
] &= ~KS_DOWN_BIT
;
780 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
781 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
782 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
784 if(mi
->mouseData
& XBUTTON2
)
786 gafAsyncKeyState
[VK_XBUTTON2
] &= ~KS_DOWN_BIT
;
787 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
788 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
789 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
792 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
794 Msg
.message
= WM_MOUSEWHEEL
;
795 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
796 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
803 UserAttachThreadInput(PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
807 /* Can not be the same thread.*/
808 if (pti
== ptiTo
) return FALSE
;
810 /* Do not attach to system threads or between different desktops. */
811 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
812 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
813 pti
->rpdesk
!= ptiTo
->rpdesk
)
816 /* If Attach set, allocate and link. */
819 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), USERTAG_ATTACHINFO
);
820 if ( !pai
) return FALSE
;
827 else /* If clear, unlink and free it. */
829 PATTACHINFO paiprev
= NULL
;
831 if ( !gpai
) return FALSE
;
835 /* Search list and free if found or return false. */
838 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
843 if ( !pai
) return FALSE
;
845 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
847 ExFreePoolWithTag(pai
, USERTAG_ATTACHINFO
);
862 DECLARE_RETURN(UINT
);
864 TRACE("Enter NtUserSendInput\n");
865 UserEnterExclusive();
867 pti
= PsGetCurrentThreadWin32Thread();
875 if (!nInputs
|| !pInput
|| cbSize
!= sizeof(INPUT
))
877 EngSetLastError(ERROR_INVALID_PARAMETER
);
882 * FIXME - check access rights of the window station
883 * e.g. services running in the service window station cannot block input
885 if (!ThreadHasInputAccess(pti
) ||
886 !IntIsActiveDesktop(pti
->rpdesk
))
888 EngSetLastError(ERROR_ACCESS_DENIED
);
898 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
899 if (!NT_SUCCESS(Status
))
901 SetLastNtError(Status
);
905 switch (SafeInput
.type
)
908 if (IntMouseInput(&SafeInput
.mi
, TRUE
))
912 if (UserSendKeyboardInput(&SafeInput
.ki
, TRUE
))
918 ERR("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
926 TRACE("Leave NtUserSendInput, ret=%i\n", _ret_
);
933 IntQueryTrackMouseEvent(
934 LPTRACKMOUSEEVENT lpEventTrack
)
939 pti
= PsGetCurrentThreadWin32Thread();
942 /* Always cleared with size set and return true. */
943 RtlZeroMemory(lpEventTrack
, sizeof(TRACKMOUSEEVENT
));
944 lpEventTrack
->cbSize
= sizeof(TRACKMOUSEEVENT
);
946 if ( pDesk
->dwDTFlags
& (DF_TME_LEAVE
| DF_TME_HOVER
) &&
948 pti
->MessageQueue
== pDesk
->spwndTrack
->head
.pti
->MessageQueue
)
950 if ( pDesk
->htEx
!= HTCLIENT
)
951 lpEventTrack
->dwFlags
|= TME_NONCLIENT
;
953 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
954 lpEventTrack
->dwFlags
|= TME_LEAVE
;
956 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
958 lpEventTrack
->dwFlags
|= TME_HOVER
;
959 lpEventTrack
->dwHoverTime
= pDesk
->dwMouseHoverTime
;
961 lpEventTrack
->hwndTrack
= UserHMGetHandle(pDesk
->spwndTrack
);
969 LPTRACKMOUSEEVENT lpEventTrack
)
976 pti
= PsGetCurrentThreadWin32Thread();
979 if (!(pWnd
= UserGetWindowObject(lpEventTrack
->hwndTrack
)))
982 /* Tracking spwndTrack same as pWnd */
983 if ( lpEventTrack
->dwFlags
& TME_CANCEL
) // Canceled mode.
985 if ( lpEventTrack
->dwFlags
& TME_LEAVE
)
986 pDesk
->dwDTFlags
&= ~DF_TME_LEAVE
;
988 if ( lpEventTrack
->dwFlags
& TME_HOVER
)
990 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
991 { // Kill hover timer.
992 IntKillTimer(pWnd
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
993 pDesk
->dwDTFlags
&= ~DF_TME_HOVER
;
997 else // Not Canceled.
999 pDesk
->spwndTrack
= pWnd
;
1000 if ( lpEventTrack
->dwFlags
& TME_LEAVE
)
1001 pDesk
->dwDTFlags
|= DF_TME_LEAVE
;
1003 if ( lpEventTrack
->dwFlags
& TME_HOVER
)
1005 pDesk
->dwDTFlags
|= DF_TME_HOVER
;
1007 if ( !lpEventTrack
->dwHoverTime
|| lpEventTrack
->dwHoverTime
== HOVER_DEFAULT
)
1008 pDesk
->dwMouseHoverTime
= gspv
.iMouseHoverTime
; // use the system default hover time-out.
1010 pDesk
->dwMouseHoverTime
= lpEventTrack
->dwHoverTime
;
1011 // Start timer for the hover period.
1012 IntSetTimer( pWnd
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1013 // Get windows thread message points.
1014 point
= pWnd
->head
.pti
->ptLast
;
1015 // Set desktop mouse hover from the system default hover rectangle.
1016 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1017 point
.x
- gspv
.iMouseHoverWidth
/ 2,
1018 point
.y
- gspv
.iMouseHoverHeight
/ 2,
1019 point
.x
+ gspv
.iMouseHoverWidth
/ 2,
1020 point
.y
+ gspv
.iMouseHoverHeight
/ 2);
1028 NtUserTrackMouseEvent(
1029 LPTRACKMOUSEEVENT lpEventTrack
)
1031 TRACKMOUSEEVENT saveTME
;
1034 TRACE("Enter NtUserTrackMouseEvent\n");
1035 UserEnterExclusive();
1039 ProbeForRead(lpEventTrack
, sizeof(TRACKMOUSEEVENT
), 1);
1040 RtlCopyMemory(&saveTME
, lpEventTrack
, sizeof(TRACKMOUSEEVENT
));
1042 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1044 SetLastNtError(_SEH2_GetExceptionCode());
1045 _SEH2_YIELD(goto Exit
;)
1049 if ( saveTME
.cbSize
!= sizeof(TRACKMOUSEEVENT
) )
1051 EngSetLastError(ERROR_INVALID_PARAMETER
);
1055 if (saveTME
.dwFlags
& ~(TME_CANCEL
| TME_QUERY
| TME_NONCLIENT
| TME_LEAVE
| TME_HOVER
) )
1057 EngSetLastError(ERROR_INVALID_FLAGS
);
1061 if ( saveTME
.dwFlags
& TME_QUERY
)
1063 Ret
= IntQueryTrackMouseEvent(&saveTME
);
1066 ProbeForWrite(lpEventTrack
, sizeof(TRACKMOUSEEVENT
), 1);
1067 RtlCopyMemory(lpEventTrack
, &saveTME
, sizeof(TRACKMOUSEEVENT
));
1069 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1071 SetLastNtError(_SEH2_GetExceptionCode());
1078 Ret
= IntTrackMouseEvent(&saveTME
);
1082 TRACE("Leave NtUserTrackMouseEvent, ret=%i\n", Ret
);
1087 extern MOUSEMOVEPOINT MouseHistoryOfMoves
[];
1088 extern INT gcur_count
;
1092 NtUserGetMouseMovePointsEx(
1094 LPMOUSEMOVEPOINT lpptIn
,
1095 LPMOUSEMOVEPOINT lpptOut
,
1099 MOUSEMOVEPOINT Safeppt
;
1102 DECLARE_RETURN(DWORD
);
1104 TRACE("Enter NtUserGetMouseMovePointsEx\n");
1105 UserEnterExclusive();
1107 if ((cbSize
!= sizeof(MOUSEMOVEPOINT
)) || (nBufPoints
< 0) || (nBufPoints
> 64))
1109 EngSetLastError(ERROR_INVALID_PARAMETER
);
1113 if (!lpptIn
|| (!lpptOut
&& nBufPoints
))
1115 EngSetLastError(ERROR_NOACCESS
);
1121 ProbeForRead( lpptIn
, cbSize
, 1);
1122 RtlCopyMemory(&Safeppt
, lpptIn
, cbSize
);
1124 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1126 SetLastNtError(_SEH2_GetExceptionCode());
1127 _SEH2_YIELD(RETURN( -1))
1131 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
1132 // This explains the math issues in transforming points.
1133 Count
= gcur_count
; // FIFO is forward so retrieve backward.
1137 if (Safeppt
.x
== 0 && Safeppt
.y
== 0)
1139 // Finds the point, it returns the last nBufPoints prior to and including the supplied point.
1140 if (MouseHistoryOfMoves
[Count
].x
== Safeppt
.x
&& MouseHistoryOfMoves
[Count
].y
== Safeppt
.y
)
1142 if ( Safeppt
.time
) // Now test time and it seems to be absolute.
1144 if (Safeppt
.time
== MouseHistoryOfMoves
[Count
].time
)
1151 if (--Count
< 0) Count
= 63;
1158 if (--Count
< 0) Count
= 63;
1160 while ( Count
!= gcur_count
);
1164 case GMMP_USE_DISPLAY_POINTS
:
1169 ProbeForWrite(lpptOut
, cbSize
, 1);
1171 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1173 SetLastNtError(_SEH2_GetExceptionCode());
1174 _SEH2_YIELD(RETURN( -1))
1180 case GMMP_USE_HIGH_RESOLUTION_POINTS
:
1183 EngSetLastError(ERROR_POINT_NOT_FOUND
);
1190 TRACE("Leave NtUserGetMouseMovePointsEx, ret=%i\n", _ret_
);