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 BYTE gKeyStateTable
[];
14 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
15 extern PPROCESSINFO ppiScrnSaver
;
17 /* GLOBALS *******************************************************************/
19 PTHREADINFO ptiRawInput
;
20 PTHREADINFO ptiKeyboard
;
22 PKTIMER MasterTimer
= NULL
;
23 PATTACHINFO gpai
= NULL
;
24 HANDLE ghKeyboardDevice
;
26 static DWORD LastInputTick
= 0;
27 static HANDLE MouseDeviceHandle
;
28 static HANDLE MouseThreadHandle
;
29 static CLIENT_ID MouseThreadId
;
30 static HANDLE KeyboardThreadHandle
;
31 static CLIENT_ID KeyboardThreadId
;
32 static HANDLE RawInputThreadHandle
;
33 static CLIENT_ID RawInputThreadId
;
34 static KEVENT InputThreadsStart
;
35 static BOOLEAN InputThreadsRunning
= FALSE
;
37 /* FUNCTIONS *****************************************************************/
39 #define ClearMouseInput(mi) \
45 #define SendMouseEvent(mi) \
46 if(mi.dx != 0 || mi.dy != 0) \
47 mi.dwFlags |= MOUSEEVENTF_MOVE; \
49 IntMouseInput(&mi,FALSE); \
53 IntLastInputTick(BOOL bUpdate
)
57 LARGE_INTEGER TickCount
;
58 KeQueryTickCount(&TickCount
);
59 LastInputTick
= MsqCalculateMessageTime(&TickCount
);
60 if (gpsi
) gpsi
->dwLastRITEventTickCount
= LastInputTick
;
66 DoTheScreenSaver(VOID
)
68 LARGE_INTEGER TickCount
;
71 if (gspv
.iScrSaverTimeout
> 0) // Zero means Off.
73 KeQueryTickCount(&TickCount
);
74 Test
= MsqCalculateMessageTime(&TickCount
);
75 Test
= Test
- LastInputTick
;
76 TO
= 1000 * gspv
.iScrSaverTimeout
;
79 TRACE("Screensaver Message Start! Tick %d Timeout %d \n", Test
, gspv
.iScrSaverTimeout
);
81 if (ppiScrnSaver
) // We are or we are not the screensaver, prevent reentry...
83 if (!(ppiScrnSaver
->W32PF_flags
& W32PF_IDLESCREENSAVER
))
85 ppiScrnSaver
->W32PF_flags
|= W32PF_IDLESCREENSAVER
;
86 ERR("Screensaver is Idle\n");
91 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
92 if (ForegroundQueue
&& ForegroundQueue
->ActiveWindow
)
93 UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_START_SCREENSAVE
, 1); // lParam 1 == Secure
95 UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_START_SCREENSAVE
, 0);
102 IntProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
104 PMOUSE_INPUT_DATA mid
;
111 for(i
= 0; i
< InputCount
; i
++)
117 /* Check if the mouse move is absolute */
118 if (mid
->Flags
== MOUSE_MOVE_ABSOLUTE
)
120 /* Set flag to convert to screen location */
121 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
126 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
128 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
131 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
133 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
136 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
138 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
141 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
143 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
146 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
148 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
151 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
153 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
156 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
158 mi
.mouseData
|= XBUTTON1
;
159 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
162 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
164 mi
.mouseData
|= XBUTTON1
;
165 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
168 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
170 mi
.mouseData
|= XBUTTON2
;
171 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
174 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
176 mi
.mouseData
|= XBUTTON2
;
177 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
180 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
182 mi
.mouseData
= mid
->ButtonData
;
183 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
193 MouseThreadMain(PVOID StartContext
)
195 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
196 OBJECT_ATTRIBUTES MouseObjectAttributes
;
197 IO_STATUS_BLOCK Iosb
;
199 MOUSE_ATTRIBUTES MouseAttr
;
201 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
202 LOW_REALTIME_PRIORITY
+ 3);
204 InitializeObjectAttributes(&MouseObjectAttributes
,
211 LARGE_INTEGER DueTime
;
213 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
214 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
215 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
216 Status
= NtOpenFile(&MouseDeviceHandle
,
218 &MouseObjectAttributes
,
221 FILE_SYNCHRONOUS_IO_ALERT
);
222 } while (!NT_SUCCESS(Status
));
224 /* Need to setup basic win32k for this thread to process WH_MOUSE_LL messages. */
225 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
226 if (!NT_SUCCESS(Status
))
228 ERR("Win32K: Failed making mouse thread a win32 thread.\n");
232 ptiMouse
= PsGetCurrentThreadWin32Thread();
233 ptiMouse
->TIF_flags
|= TIF_SYSTEMTHREAD
;
234 TRACE("Mouse Thread 0x%x \n", ptiMouse
);
236 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
237 LOW_REALTIME_PRIORITY
+ 3);
242 * Wait to start input.
244 TRACE("Mouse Input Thread Waiting for start event\n");
245 Status
= KeWaitForSingleObject(&InputThreadsStart
,
250 TRACE("Mouse Input Thread Starting...\n");
252 /*FIXME: Does mouse attributes need to be used for anything */
253 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
258 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
259 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
261 if(!NT_SUCCESS(Status
))
263 TRACE("Failed to get mouse attributes\n");
267 * Receive and process mouse input.
269 while(InputThreadsRunning
)
271 MOUSE_INPUT_DATA MouseInput
;
272 Status
= NtReadFile(MouseDeviceHandle
,
278 sizeof(MOUSE_INPUT_DATA
),
281 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
285 if(Status
== STATUS_PENDING
)
287 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
288 Status
= Iosb
.Status
;
290 if(!NT_SUCCESS(Status
))
292 ERR("Win32K: Failed to read from mouse.\n");
295 TRACE("MouseEvent\n");
296 IntLastInputTick(TRUE
);
298 UserEnterExclusive();
300 IntProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
304 TRACE("Mouse Input Thread Stopped...\n");
309 KeyboardThreadMain(PVOID StartContext
)
311 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
312 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
313 IO_STATUS_BLOCK Iosb
;
316 InitializeObjectAttributes(&KeyboardObjectAttributes
,
323 LARGE_INTEGER DueTime
;
325 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
326 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
327 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
328 Status
= NtOpenFile(&ghKeyboardDevice
,
330 &KeyboardObjectAttributes
,
333 FILE_SYNCHRONOUS_IO_ALERT
);
334 } while (!NT_SUCCESS(Status
));
336 /* Not sure if converting this thread to a win32 thread is such
337 a great idea. Since we're posting keyboard messages to the focus
338 window message queue, we'll be (indirectly) doing sendmessage
339 stuff from this thread (for WH_KEYBOARD_LL processing), which
340 means we need our own message queue. If keyboard messages were
341 instead queued to the system message queue, the thread removing
342 the message from the system message queue would be responsible
343 for WH_KEYBOARD_LL processing and we wouldn't need this thread
344 to be a win32 thread. */
345 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
346 if (!NT_SUCCESS(Status
))
348 ERR("Win32K: Failed making keyboard thread a win32 thread.\n");
352 ptiKeyboard
= PsGetCurrentThreadWin32Thread();
353 ptiKeyboard
->TIF_flags
|= TIF_SYSTEMTHREAD
;
354 TRACE("Keyboard Thread 0x%x \n", ptiKeyboard
);
356 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
357 LOW_REALTIME_PRIORITY
+ 3);
359 //IntKeyboardGetIndicatorTrans(ghKeyboardDevice,
365 * Wait to start input.
367 TRACE( "Keyboard Input Thread Waiting for start event\n" );
368 Status
= KeWaitForSingleObject(&InputThreadsStart
,
374 TRACE( "Keyboard Input Thread Starting...\n" );
376 * Receive and process keyboard input.
378 while (InputThreadsRunning
)
380 KEYBOARD_INPUT_DATA KeyInput
;
382 TRACE("KeyInput @ %08x\n", &KeyInput
);
384 Status
= NtReadFile (ghKeyboardDevice
,
390 sizeof(KEYBOARD_INPUT_DATA
),
394 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
398 if(Status
== STATUS_PENDING
)
400 NtWaitForSingleObject(ghKeyboardDevice
, FALSE
, NULL
);
401 Status
= Iosb
.Status
;
403 if(!NT_SUCCESS(Status
))
405 ERR("Win32K: Failed to read from keyboard.\n");
409 TRACE("KeyRaw: %s %04x\n",
410 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
413 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
416 if (!NT_SUCCESS(Status
))
418 ERR("Win32K: Failed to read from keyboard.\n");
422 /* Set LastInputTick */
423 IntLastInputTick(TRUE
);
426 UserEnterExclusive();
427 UserProcessKeyboardInput(&KeyInput
);
431 TRACE( "KeyboardInput Thread Stopped...\n" );
436 static PVOID Objects
[2];
439 Since this relies on InputThreadsStart, just fake it.
442 RawInputThreadMain(PVOID StartContext
)
445 LARGE_INTEGER DueTime
;
447 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
452 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
453 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
454 } while (!NT_SUCCESS(Status
));
457 Objects
[0] = &InputThreadsStart
;
458 Objects
[1] = MasterTimer
;
460 // This thread requires win32k!
461 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
462 if (!NT_SUCCESS(Status
))
464 ERR("Win32K: Failed making Raw Input thread a win32 thread.\n");
468 ptiRawInput
= PsGetCurrentThreadWin32Thread();
469 ptiRawInput
->TIF_flags
|= TIF_SYSTEMTHREAD
;
470 TRACE("Raw Input Thread 0x%x \n", ptiRawInput
);
472 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
473 LOW_REALTIME_PRIORITY
+ 3);
475 UserEnterExclusive();
480 // ATM, we just have one job to handle, merge the other two later.
484 TRACE( "Raw Input Thread Waiting for start event\n" );
486 Status
= KeWaitForMultipleObjects( 2,
494 TRACE( "Raw Input Thread Starting...\n" );
498 ERR("Raw Input Thread Exit!\n");
508 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
510 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), USERTAG_SYSTEM
);
513 ERR("Win32K: Failed making Raw Input thread a win32 thread.\n");
515 return STATUS_UNSUCCESSFUL
;
517 KeInitializeTimer(MasterTimer
);
519 /* Initialize the default keyboard layout */
520 if(!UserInitDefaultKeyboardLayout())
522 ERR("Failed to initialize default keyboard layout!\n");
525 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
532 if (!NT_SUCCESS(Status
))
534 ERR("Win32K: Failed to create raw thread.\n");
537 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
544 if (!NT_SUCCESS(Status
))
546 ERR("Win32K: Failed to create keyboard thread.\n");
549 Status
= PsCreateSystemThread(&MouseThreadHandle
,
556 if (!NT_SUCCESS(Status
))
558 ERR("Win32K: Failed to create mouse thread.\n");
561 InputThreadsRunning
= TRUE
;
562 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
564 return STATUS_SUCCESS
;
568 CleanupInputImp(VOID
)
570 return(STATUS_SUCCESS
);
574 IntBlockInput(PTHREADINFO pti
, BOOL BlockIt
)
576 PTHREADINFO OldBlock
;
579 if(!pti
->rpdesk
|| ((pti
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
582 * fail blocking if exiting the thread
589 * FIXME - check access rights of the window station
590 * e.g. services running in the service window station cannot block input
592 if(!ThreadHasInputAccess(pti
) ||
593 !IntIsActiveDesktop(pti
->rpdesk
))
595 EngSetLastError(ERROR_ACCESS_DENIED
);
600 OldBlock
= pti
->rpdesk
->BlockInputThread
;
605 EngSetLastError(ERROR_ACCESS_DENIED
);
608 pti
->rpdesk
->BlockInputThread
= (BlockIt
? pti
: NULL
);
609 return OldBlock
== NULL
;
612 pti
->rpdesk
->BlockInputThread
= (BlockIt
? pti
: NULL
);
613 return OldBlock
== NULL
;
621 DECLARE_RETURN(BOOLEAN
);
623 TRACE("Enter NtUserBlockInput\n");
624 UserEnterExclusive();
626 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
629 TRACE("Leave NtUserBlockInput, ret=%i\n", _ret_
);
635 IntMouseInput(MOUSEINPUT
*mi
, BOOL Injected
)
637 const UINT SwapBtnMsg
[2][2] =
639 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
640 {WM_LBUTTONUP
, WM_RBUTTONUP
}
642 const WPARAM SwapBtn
[2] =
644 MK_LBUTTON
, MK_RBUTTON
647 PSYSTEM_CURSORINFO CurInfo
;
653 CurInfo
= IntGetSysCursorInfo();
657 LARGE_INTEGER LargeTickCount
;
658 KeQueryTickCount(&LargeTickCount
);
659 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
662 SwapButtons
= gspv
.bMouseBtnSwap
;
664 MousePos
= gpsi
->ptCursor
;
666 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
668 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
670 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
671 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
675 MousePos
.x
+= mi
->dx
;
676 MousePos
.y
+= mi
->dy
;
681 * Insert the messages into the system queue
684 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
687 if (gKeyStateTable
[VK_SHIFT
] & KS_DOWN_BIT
)
689 Msg
.wParam
|= MK_SHIFT
;
692 if (gKeyStateTable
[VK_CONTROL
] & KS_DOWN_BIT
)
694 Msg
.wParam
|= MK_CONTROL
;
697 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
699 UserSetCursorPos(MousePos
.x
, MousePos
.y
, Injected
, mi
->dwExtraInfo
, TRUE
);
701 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
703 gKeyStateTable
[VK_LBUTTON
] |= KS_DOWN_BIT
;
704 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
705 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
706 Msg
.wParam
|= CurInfo
->ButtonsDown
;
707 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
709 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
711 gKeyStateTable
[VK_LBUTTON
] &= ~KS_DOWN_BIT
;
712 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
713 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
714 Msg
.wParam
|= CurInfo
->ButtonsDown
;
715 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
717 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
719 gKeyStateTable
[VK_MBUTTON
] |= KS_DOWN_BIT
;
720 Msg
.message
= WM_MBUTTONDOWN
;
721 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
722 Msg
.wParam
|= CurInfo
->ButtonsDown
;
723 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
725 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
727 gKeyStateTable
[VK_MBUTTON
] &= ~KS_DOWN_BIT
;
728 Msg
.message
= WM_MBUTTONUP
;
729 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
730 Msg
.wParam
|= CurInfo
->ButtonsDown
;
731 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
733 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
735 gKeyStateTable
[VK_RBUTTON
] |= KS_DOWN_BIT
;
736 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
737 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
738 Msg
.wParam
|= CurInfo
->ButtonsDown
;
739 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
741 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
743 gKeyStateTable
[VK_RBUTTON
] &= ~KS_DOWN_BIT
;
744 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
745 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
746 Msg
.wParam
|= CurInfo
->ButtonsDown
;
747 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
750 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
751 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
753 /* fail because both types of events use the mouseData field */
757 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
759 Msg
.message
= WM_XBUTTONDOWN
;
760 if(mi
->mouseData
& XBUTTON1
)
762 gKeyStateTable
[VK_XBUTTON1
] |= KS_DOWN_BIT
;
763 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
764 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
765 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
767 if(mi
->mouseData
& XBUTTON2
)
769 gKeyStateTable
[VK_XBUTTON2
] |= KS_DOWN_BIT
;
770 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
771 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
772 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
775 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
777 Msg
.message
= WM_XBUTTONUP
;
778 if(mi
->mouseData
& XBUTTON1
)
780 gKeyStateTable
[VK_XBUTTON1
] &= ~KS_DOWN_BIT
;
781 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
782 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
783 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
785 if(mi
->mouseData
& XBUTTON2
)
787 gKeyStateTable
[VK_XBUTTON2
] &= ~KS_DOWN_BIT
;
788 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
789 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
790 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
793 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
795 Msg
.message
= WM_MOUSEWHEEL
;
796 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
797 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
804 UserAttachThreadInput(PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
808 /* Can not be the same thread.*/
809 if (pti
== ptiTo
) return FALSE
;
811 /* Do not attach to system threads or between different desktops. */
812 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
813 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
814 pti
->rpdesk
!= ptiTo
->rpdesk
)
817 /* If Attach set, allocate and link. */
820 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), USERTAG_ATTACHINFO
);
821 if ( !pai
) return FALSE
;
828 else /* If clear, unlink and free it. */
830 PATTACHINFO paiprev
= NULL
;
832 if ( !gpai
) return FALSE
;
836 /* Search list and free if found or return false. */
839 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
844 if ( !pai
) return FALSE
;
846 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
848 ExFreePoolWithTag(pai
, USERTAG_ATTACHINFO
);
863 DECLARE_RETURN(UINT
);
865 TRACE("Enter NtUserSendInput\n");
866 UserEnterExclusive();
868 pti
= PsGetCurrentThreadWin32Thread();
876 if (!nInputs
|| !pInput
|| cbSize
!= sizeof(INPUT
))
878 EngSetLastError(ERROR_INVALID_PARAMETER
);
883 * FIXME - check access rights of the window station
884 * e.g. services running in the service window station cannot block input
886 if (!ThreadHasInputAccess(pti
) ||
887 !IntIsActiveDesktop(pti
->rpdesk
))
889 EngSetLastError(ERROR_ACCESS_DENIED
);
899 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
900 if (!NT_SUCCESS(Status
))
902 SetLastNtError(Status
);
906 switch (SafeInput
.type
)
909 if (IntMouseInput(&SafeInput
.mi
, TRUE
))
913 if (UserSendKeyboardInput(&SafeInput
.ki
, TRUE
))
919 ERR("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
927 TRACE("Leave NtUserSendInput, ret=%i\n", _ret_
);
934 IntQueryTrackMouseEvent(
935 LPTRACKMOUSEEVENT lpEventTrack
)
940 pti
= PsGetCurrentThreadWin32Thread();
943 /* Always cleared with size set and return true. */
944 RtlZeroMemory(lpEventTrack
, sizeof(TRACKMOUSEEVENT
));
945 lpEventTrack
->cbSize
= sizeof(TRACKMOUSEEVENT
);
947 if ( pDesk
->dwDTFlags
& (DF_TME_LEAVE
| DF_TME_HOVER
) &&
949 pti
->MessageQueue
== pDesk
->spwndTrack
->head
.pti
->MessageQueue
)
951 if ( pDesk
->htEx
!= HTCLIENT
)
952 lpEventTrack
->dwFlags
|= TME_NONCLIENT
;
954 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
955 lpEventTrack
->dwFlags
|= TME_LEAVE
;
957 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
959 lpEventTrack
->dwFlags
|= TME_HOVER
;
960 lpEventTrack
->dwHoverTime
= pDesk
->dwMouseHoverTime
;
962 lpEventTrack
->hwndTrack
= UserHMGetHandle(pDesk
->spwndTrack
);
970 LPTRACKMOUSEEVENT lpEventTrack
)
977 pti
= PsGetCurrentThreadWin32Thread();
980 if (!(pWnd
= UserGetWindowObject(lpEventTrack
->hwndTrack
)))
983 /* Tracking spwndTrack same as pWnd */
984 if ( lpEventTrack
->dwFlags
& TME_CANCEL
) // Canceled mode.
986 if ( lpEventTrack
->dwFlags
& TME_LEAVE
)
987 pDesk
->dwDTFlags
&= ~DF_TME_LEAVE
;
989 if ( lpEventTrack
->dwFlags
& TME_HOVER
)
991 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
992 { // Kill hover timer.
993 IntKillTimer(pWnd
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
994 pDesk
->dwDTFlags
&= ~DF_TME_HOVER
;
998 else // Not Canceled.
1000 pDesk
->spwndTrack
= pWnd
;
1001 if ( lpEventTrack
->dwFlags
& TME_LEAVE
)
1002 pDesk
->dwDTFlags
|= DF_TME_LEAVE
;
1004 if ( lpEventTrack
->dwFlags
& TME_HOVER
)
1006 pDesk
->dwDTFlags
|= DF_TME_HOVER
;
1008 if ( !lpEventTrack
->dwHoverTime
|| lpEventTrack
->dwHoverTime
== HOVER_DEFAULT
)
1009 pDesk
->dwMouseHoverTime
= gspv
.iMouseHoverTime
; // use the system default hover time-out.
1011 pDesk
->dwMouseHoverTime
= lpEventTrack
->dwHoverTime
;
1012 // Start timer for the hover period.
1013 IntSetTimer( pWnd
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1014 // Get windows thread message points.
1015 point
= pWnd
->head
.pti
->ptLast
;
1016 // Set desktop mouse hover from the system default hover rectangle.
1017 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1018 point
.x
- gspv
.iMouseHoverWidth
/ 2,
1019 point
.y
- gspv
.iMouseHoverHeight
/ 2,
1020 point
.x
+ gspv
.iMouseHoverWidth
/ 2,
1021 point
.y
+ gspv
.iMouseHoverHeight
/ 2);
1029 NtUserTrackMouseEvent(
1030 LPTRACKMOUSEEVENT lpEventTrack
)
1032 TRACKMOUSEEVENT saveTME
;
1035 TRACE("Enter NtUserTrackMouseEvent\n");
1036 UserEnterExclusive();
1040 ProbeForRead(lpEventTrack
, sizeof(TRACKMOUSEEVENT
), 1);
1041 RtlCopyMemory(&saveTME
, lpEventTrack
, sizeof(TRACKMOUSEEVENT
));
1043 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1045 SetLastNtError(_SEH2_GetExceptionCode());
1046 _SEH2_YIELD(goto Exit
;)
1050 if ( saveTME
.cbSize
!= sizeof(TRACKMOUSEEVENT
) )
1052 EngSetLastError(ERROR_INVALID_PARAMETER
);
1056 if (saveTME
.dwFlags
& ~(TME_CANCEL
| TME_QUERY
| TME_NONCLIENT
| TME_LEAVE
| TME_HOVER
) )
1058 EngSetLastError(ERROR_INVALID_FLAGS
);
1062 if ( saveTME
.dwFlags
& TME_QUERY
)
1064 Ret
= IntQueryTrackMouseEvent(&saveTME
);
1067 ProbeForWrite(lpEventTrack
, sizeof(TRACKMOUSEEVENT
), 1);
1068 RtlCopyMemory(lpEventTrack
, &saveTME
, sizeof(TRACKMOUSEEVENT
));
1070 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1072 SetLastNtError(_SEH2_GetExceptionCode());
1079 Ret
= IntTrackMouseEvent(&saveTME
);
1083 TRACE("Leave NtUserTrackMouseEvent, ret=%i\n", Ret
);
1088 extern MOUSEMOVEPOINT MouseHistoryOfMoves
[];
1089 extern INT gcur_count
;
1093 NtUserGetMouseMovePointsEx(
1095 LPMOUSEMOVEPOINT lpptIn
,
1096 LPMOUSEMOVEPOINT lpptOut
,
1100 MOUSEMOVEPOINT Safeppt
;
1103 DECLARE_RETURN(DWORD
);
1105 TRACE("Enter NtUserGetMouseMovePointsEx\n");
1106 UserEnterExclusive();
1108 if ((cbSize
!= sizeof(MOUSEMOVEPOINT
)) || (nBufPoints
< 0) || (nBufPoints
> 64))
1110 EngSetLastError(ERROR_INVALID_PARAMETER
);
1114 if (!lpptIn
|| (!lpptOut
&& nBufPoints
))
1116 EngSetLastError(ERROR_NOACCESS
);
1122 ProbeForRead( lpptIn
, cbSize
, 1);
1123 RtlCopyMemory(&Safeppt
, lpptIn
, cbSize
);
1125 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1127 SetLastNtError(_SEH2_GetExceptionCode());
1128 _SEH2_YIELD(RETURN( -1))
1132 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
1133 // This explains the math issues in transforming points.
1134 Count
= gcur_count
; // FIFO is forward so retrieve backward.
1138 if (Safeppt
.x
== 0 && Safeppt
.y
== 0)
1140 // Finds the point, it returns the last nBufPoints prior to and including the supplied point.
1141 if (MouseHistoryOfMoves
[Count
].x
== Safeppt
.x
&& MouseHistoryOfMoves
[Count
].y
== Safeppt
.y
)
1143 if ( Safeppt
.time
) // Now test time and it seems to be absolute.
1145 if (Safeppt
.time
== MouseHistoryOfMoves
[Count
].time
)
1152 if (--Count
< 0) Count
= 63;
1159 if (--Count
< 0) Count
= 63;
1161 while ( Count
!= gcur_count
);
1165 case GMMP_USE_DISPLAY_POINTS
:
1170 ProbeForWrite(lpptOut
, cbSize
, 1);
1172 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1174 SetLastNtError(_SEH2_GetExceptionCode());
1175 _SEH2_YIELD(RETURN( -1))
1181 case GMMP_USE_HIGH_RESOLUTION_POINTS
:
1184 EngSetLastError(ERROR_POINT_NOT_FOUND
);
1191 TRACE("Leave NtUserGetMouseMovePointsEx, ret=%i\n", _ret_
);