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 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * 06-06-2001 CSH Created
11 /* INCLUDES ******************************************************************/
19 extern BYTE gQueueKeyStateTable
[];
20 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
22 /* GLOBALS *******************************************************************/
24 PTHREADINFO ptiRawInput
;
25 PTHREADINFO ptiKeyboard
;
27 PKTIMER MasterTimer
= NULL
;
28 PATTACHINFO gpai
= NULL
;
30 static HANDLE MouseDeviceHandle
;
31 static HANDLE MouseThreadHandle
;
32 static CLIENT_ID MouseThreadId
;
33 static HANDLE KeyboardThreadHandle
;
34 static CLIENT_ID KeyboardThreadId
;
35 static HANDLE KeyboardDeviceHandle
;
36 static HANDLE RawInputThreadHandle
;
37 static CLIENT_ID RawInputThreadId
;
38 static KEVENT InputThreadsStart
;
39 static BOOLEAN InputThreadsRunning
= FALSE
;
40 static BYTE TrackSysKey
= 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
41 or a WM_KEYUP message */
43 /* FUNCTIONS *****************************************************************/
44 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
);
46 #define ClearMouseInput(mi) \
52 #define SendMouseEvent(mi) \
53 if(mi.dx != 0 || mi.dy != 0) \
54 mi.dwFlags |= MOUSEEVENTF_MOVE; \
56 IntMouseInput(&mi,FALSE); \
60 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
)
62 static DWORD LastInputTick
= 0;
63 if (LastInputTickSetGet
== TRUE
)
65 LARGE_INTEGER TickCount
;
66 KeQueryTickCount(&TickCount
);
67 LastInputTick
= TickCount
.u
.LowPart
* (KeQueryTimeIncrement() / 10000);
74 NtUserGetLastInputInfo(PLASTINPUTINFO plii
)
82 if (ProbeForReadUint(&plii
->cbSize
) != sizeof(LASTINPUTINFO
))
84 EngSetLastError(ERROR_INVALID_PARAMETER
);
89 ProbeForWrite(plii
, sizeof(LASTINPUTINFO
), sizeof(DWORD
));
91 plii
->dwTime
= IntLastInputTick(FALSE
);
93 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
95 SetLastNtError(_SEH2_GetExceptionCode());
107 ProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
109 PMOUSE_INPUT_DATA mid
;
116 for(i
= 0; i
< InputCount
; i
++)
122 /* Check if the mouse move is absolute */
123 if (mid
->Flags
== MOUSE_MOVE_ABSOLUTE
)
125 /* Set flag to convert to screen location */
126 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
131 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
133 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
136 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
138 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
141 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
143 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
146 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
148 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
151 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
153 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
156 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
158 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
161 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
163 mi
.mouseData
|= XBUTTON1
;
164 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
167 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
169 mi
.mouseData
|= XBUTTON1
;
170 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
173 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
175 mi
.mouseData
|= XBUTTON2
;
176 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
179 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
181 mi
.mouseData
|= XBUTTON2
;
182 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
185 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
187 mi
.mouseData
= mid
->ButtonData
;
188 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
201 MouseThreadMain(PVOID StartContext
)
203 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
204 OBJECT_ATTRIBUTES MouseObjectAttributes
;
205 IO_STATUS_BLOCK Iosb
;
207 MOUSE_ATTRIBUTES MouseAttr
;
209 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
210 LOW_REALTIME_PRIORITY
+ 3);
212 InitializeObjectAttributes(&MouseObjectAttributes
,
219 LARGE_INTEGER DueTime
;
221 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
222 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
223 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
224 Status
= NtOpenFile(&MouseDeviceHandle
,
226 &MouseObjectAttributes
,
229 FILE_SYNCHRONOUS_IO_ALERT
);
230 } while (!NT_SUCCESS(Status
));
232 /* Need to setup basic win32k for this thread to process WH_MOUSE_LL messages. */
233 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
234 if (!NT_SUCCESS(Status
))
236 DPRINT1("Win32K: Failed making mouse thread a win32 thread.\n");
240 ptiMouse
= PsGetCurrentThreadWin32Thread();
241 ptiMouse
->TIF_flags
|= TIF_SYSTEMTHREAD
;
242 DPRINT("Mouse Thread 0x%x \n", ptiMouse
);
244 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
245 LOW_REALTIME_PRIORITY
+ 3);
250 * Wait to start input.
252 DPRINT("Mouse Input Thread Waiting for start event\n");
253 Status
= KeWaitForSingleObject(&InputThreadsStart
,
258 DPRINT("Mouse Input Thread Starting...\n");
260 /*FIXME: Does mouse attributes need to be used for anything */
261 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
266 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
267 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
269 if(!NT_SUCCESS(Status
))
271 DPRINT("Failed to get mouse attributes\n");
275 * Receive and process mouse input.
277 while(InputThreadsRunning
)
279 MOUSE_INPUT_DATA MouseInput
;
280 Status
= NtReadFile(MouseDeviceHandle
,
286 sizeof(MOUSE_INPUT_DATA
),
289 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
293 if(Status
== STATUS_PENDING
)
295 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
296 Status
= Iosb
.Status
;
298 if(!NT_SUCCESS(Status
))
300 DPRINT1("Win32K: Failed to read from mouse.\n");
303 DPRINT("MouseEvent\n");
304 IntLastInputTick(TRUE
);
306 UserEnterExclusive();
308 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
312 DPRINT("Mouse Input Thread Stopped...\n");
316 /* Returns a value that indicates if the key is a modifier key, and
320 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
322 if (InputData
->Flags
& KEY_E1
)
325 if (!(InputData
->Flags
& KEY_E0
))
327 switch (InputData
->MakeCode
)
329 case 0x2a: /* left shift */
330 case 0x36: /* right shift */
333 case 0x1d: /* left control */
336 case 0x38: /* left alt */
345 switch (InputData
->MakeCode
)
347 case 0x1d: /* right control */
350 case 0x38: /* right alt */
353 case 0x5b: /* left gui (windows) */
354 case 0x5c: /* right gui (windows) */
363 /* Asks the keyboard driver to send a small table that shows which
364 * lights should connect with which scancodes
366 static NTSTATUS APIENTRY
367 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
368 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
372 IO_STATUS_BLOCK Block
;
373 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
375 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
377 Ret
= ExAllocatePoolWithTag(PagedPool
,
383 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
388 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
392 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
395 ExFreePoolWithTag(Ret
, USERTAG_KBDTABLE
);
397 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
399 Ret
= ExAllocatePoolWithTag(PagedPool
,
405 return STATUS_INSUFFICIENT_RESOURCES
;
407 if (Status
!= STATUS_SUCCESS
)
409 ExFreePoolWithTag(Ret
, USERTAG_KBDTABLE
);
413 *IndicatorTrans
= Ret
;
417 /* Sends the keyboard commands to turn on/off the lights.
419 static NTSTATUS APIENTRY
420 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
421 PKEYBOARD_INPUT_DATA KeyInput
,
422 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
426 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
427 IO_STATUS_BLOCK Block
;
430 return STATUS_NOT_SUPPORTED
;
432 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
433 return STATUS_SUCCESS
;
435 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
437 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
439 Indicators
.LedFlags
^=
440 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
442 /* Update the lights on the hardware */
444 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
449 IOCTL_KEYBOARD_SET_INDICATORS
,
450 &Indicators
, sizeof(Indicators
),
457 return STATUS_SUCCESS
;
461 IntKeyboardSendWinKeyMsg()
466 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
468 DPRINT1("Couldn't find window to send Windows key message!\n");
472 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
473 Mesg
.message
= WM_SYSCOMMAND
;
474 Mesg
.wParam
= SC_TASKLIST
;
477 /* The QS_HOTKEY is just a guess */
478 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
482 co_IntKeyboardSendAltKeyMsg()
484 DPRINT1("co_IntKeyboardSendAltKeyMsg\n");
485 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
489 KeyboardThreadMain(PVOID StartContext
)
491 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
492 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
493 IO_STATUS_BLOCK Iosb
;
496 PUSER_MESSAGE_QUEUE FocusQueue
;
497 struct _ETHREAD
*FocusThread
;
499 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
500 UINT ModifierState
= 0;
501 USHORT LastMakeCode
= 0;
502 USHORT LastFlags
= 0;
503 UINT RepeatCount
= 0;
505 InitializeObjectAttributes(&KeyboardObjectAttributes
,
512 LARGE_INTEGER DueTime
;
514 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
515 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
516 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
517 Status
= NtOpenFile(&KeyboardDeviceHandle
,
519 &KeyboardObjectAttributes
,
522 FILE_SYNCHRONOUS_IO_ALERT
);
523 } while (!NT_SUCCESS(Status
));
525 /* Not sure if converting this thread to a win32 thread is such
526 a great idea. Since we're posting keyboard messages to the focus
527 window message queue, we'll be (indirectly) doing sendmessage
528 stuff from this thread (for WH_KEYBOARD_LL processing), which
529 means we need our own message queue. If keyboard messages were
530 instead queued to the system message queue, the thread removing
531 the message from the system message queue would be responsible
532 for WH_KEYBOARD_LL processing and we wouldn't need this thread
533 to be a win32 thread. */
534 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
535 if (!NT_SUCCESS(Status
))
537 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
541 ptiKeyboard
= PsGetCurrentThreadWin32Thread();
542 ptiKeyboard
->TIF_flags
|= TIF_SYSTEMTHREAD
;
543 DPRINT("Keyboard Thread 0x%x \n", ptiKeyboard
);
545 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
546 LOW_REALTIME_PRIORITY
+ 3);
548 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
554 * Wait to start input.
556 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
557 Status
= KeWaitForSingleObject(&InputThreadsStart
,
563 DPRINT( "Keyboard Input Thread Starting...\n" );
565 * Receive and process keyboard input.
567 while (InputThreadsRunning
)
571 KEYBOARD_INPUT_DATA KeyInput
;
572 KEYBOARD_INPUT_DATA NextKeyInput
;
574 UINT fsModifiers
, fsNextModifiers
;
575 struct _ETHREAD
*Thread
;
579 DPRINT("KeyInput @ %08x\n", &KeyInput
);
581 Status
= NtReadFile (KeyboardDeviceHandle
,
587 sizeof(KEYBOARD_INPUT_DATA
),
591 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
595 if(Status
== STATUS_PENDING
)
597 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
598 Status
= Iosb
.Status
;
600 if(!NT_SUCCESS(Status
))
602 DPRINT1("Win32K: Failed to read from mouse.\n");
606 DPRINT("KeyRaw: %s %04x\n",
607 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
610 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
613 if (!NT_SUCCESS(Status
))
615 DPRINT1("Win32K: Failed to read from keyboard.\n");
619 /* Set LastInputTick */
620 IntLastInputTick(TRUE
);
622 /* Update modifier state */
623 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
627 if (KeyInput
.Flags
& KEY_BREAK
)
629 ModifierState
&= ~fsModifiers
;
630 if(fsModifiers
== MOD_ALT
)
632 if(KeyInput
.Flags
& KEY_E0
)
634 gQueueKeyStateTable
[VK_RMENU
] = 0;
638 gQueueKeyStateTable
[VK_LMENU
] = 0;
640 if (gQueueKeyStateTable
[VK_RMENU
] == 0 &&
641 gQueueKeyStateTable
[VK_LMENU
] == 0)
643 gQueueKeyStateTable
[VK_MENU
] = 0;
649 ModifierState
|= fsModifiers
;
651 if (ModifierState
== fsModifiers
&&
652 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
654 /* First send out special notifications
655 * (For alt, the message that turns on accelerator
656 * display, not sure what for win. Both TODO though.)
659 if(fsModifiers
== MOD_ALT
)
661 if(KeyInput
.Flags
& KEY_E0
)
663 gQueueKeyStateTable
[VK_RMENU
] = 0x80;
667 gQueueKeyStateTable
[VK_LMENU
] = 0x80;
671 gQueueKeyStateTable
[VK_MENU
] = 0x80;
674 /* Read the next key before sending this one */
677 Status
= NtReadFile (KeyboardDeviceHandle
,
683 sizeof(KEYBOARD_INPUT_DATA
),
686 DPRINT("KeyRaw: %s %04x\n",
687 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
688 NextKeyInput
.MakeCode
);
690 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
694 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
695 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
696 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
697 * code. I'm not caring about the counting, not sure
698 * if that matters. I think not.
701 /* If the ModifierState is now empty again, send a
702 * special notification and eat both keypresses
705 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
708 ModifierState
^= fsNextModifiers
;
710 if (ModifierState
== 0)
712 UserEnterExclusive();
713 if (fsModifiers
== MOD_WIN
)
714 IntKeyboardSendWinKeyMsg();
715 else if (fsModifiers
== MOD_ALT
)
717 gQueueKeyStateTable
[VK_MENU
] = 0;
720 gQueueKeyStateTable
[VK_LMENU
] = 0;
724 gQueueKeyStateTable
[VK_RMENU
] = 0;
726 co_IntKeyboardSendAltKeyMsg();
737 UserEnterExclusive();
739 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
742 PKBL keyboardLayout
= NULL
;
745 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
749 /* While we are working, we set up lParam. The format is:
750 * 0-15: The number of times this key has autorepeated
751 * 16-23: The keyboard scancode
752 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
753 * Note that E1 is only used for PAUSE (E1-1D-45) and
754 * E0-45 happens not to be anything.
755 * 29: Alt is pressed ('Context code')
756 * 30: Previous state, if the key was down before this message
757 * This is a cheap way to ignore autorepeat keys
758 * 31: 1 if the key is being pressed
761 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
762 * and it's the same key as the last one, increase the repeat
766 if (!(KeyInput
.Flags
& KEY_BREAK
))
768 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
769 (KeyInput
.MakeCode
== LastMakeCode
))
777 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
778 LastMakeCode
= KeyInput
.MakeCode
;
784 LastMakeCode
= 0; /* Should never match */
785 lParam
|= (1 << 30) | (1 << 31);
788 lParam
|= RepeatCount
;
790 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
792 if (KeyInput
.Flags
& KEY_E0
)
795 if (ModifierState
& MOD_ALT
)
799 if (!(KeyInput
.Flags
& KEY_BREAK
))
800 msg
.message
= WM_SYSKEYDOWN
;
802 msg
.message
= WM_SYSKEYUP
;
806 if (!(KeyInput
.Flags
& KEY_BREAK
))
807 msg
.message
= WM_KEYDOWN
;
809 msg
.message
= WM_KEYUP
;
812 /* Find the target thread whose locale is in effect */
813 FocusQueue
= IntGetFocusMessageQueue();
817 msg
.hwnd
= FocusQueue
->FocusWindow
;
819 FocusThread
= FocusQueue
->Thread
;
820 if (FocusThread
&& FocusThread
->Tcb
.Win32Thread
)
822 keyboardLayout
= ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
;
827 keyboardLayout
= W32kGetDefaultKeyLayout();
832 /* This function uses lParam to fill wParam according to the
833 * keyboard layout in use.
835 W32kKeyProcessMessage(&msg
,
836 keyboardLayout
->KBTables
,
837 KeyInput
.Flags
& KEY_E0
? 0xE0 :
838 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
840 if (GetHotKey(ModifierState
,
846 if (!(KeyInput
.Flags
& KEY_BREAK
))
848 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
849 MsqPostHotKeyMessage (Thread
,
852 MAKELPARAM((WORD
)ModifierState
,
855 continue; /* Eat key up motion too */
860 /* There is no focused window to receive a keyboard message */
864 * Post a keyboard message.
866 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
873 DPRINT( "KeyboardInput Thread Stopped...\n" );
878 static PVOID Objects
[2];
881 Since this relies on InputThreadsStart, just fake it.
884 RawInputThreadMain(PVOID StartContext
)
887 LARGE_INTEGER DueTime
;
889 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
894 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
895 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
896 } while (!NT_SUCCESS(Status
));
899 Objects
[0] = &InputThreadsStart
;
900 Objects
[1] = MasterTimer
;
902 // This thread requires win32k!
903 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
904 if (!NT_SUCCESS(Status
))
906 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
910 ptiRawInput
= PsGetCurrentThreadWin32Thread();
911 ptiRawInput
->TIF_flags
|= TIF_SYSTEMTHREAD
;
912 DPRINT("Raw Input Thread 0x%x \n", ptiRawInput
);
914 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
915 LOW_REALTIME_PRIORITY
+ 3);
917 UserEnterExclusive();
922 // ATM, we just have one job to handle, merge the other two later.
926 DPRINT( "Raw Input Thread Waiting for start event\n" );
928 Status
= KeWaitForMultipleObjects( 2,
936 DPRINT( "Raw Input Thread Starting...\n" );
940 DPRINT1("Raw Input Thread Exit!\n");
950 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
952 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), USERTAG_SYSTEM
);
955 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
957 return STATUS_UNSUCCESSFUL
;
959 KeInitializeTimer(MasterTimer
);
961 /* Initialize the default keyboard layout */
962 if(!UserInitDefaultKeyboardLayout())
964 DPRINT1("Failed to initialize default keyboard layout!\n");
967 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
974 if (!NT_SUCCESS(Status
))
976 DPRINT1("Win32K: Failed to create raw thread.\n");
979 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
986 if (!NT_SUCCESS(Status
))
988 DPRINT1("Win32K: Failed to create keyboard thread.\n");
991 Status
= PsCreateSystemThread(&MouseThreadHandle
,
998 if (!NT_SUCCESS(Status
))
1000 DPRINT1("Win32K: Failed to create mouse thread.\n");
1003 InputThreadsRunning
= TRUE
;
1004 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
1006 return STATUS_SUCCESS
;
1010 CleanupInputImp(VOID
)
1012 return(STATUS_SUCCESS
);
1016 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
1018 PTHREADINFO OldBlock
;
1021 if(!W32Thread
->rpdesk
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
1024 * fail blocking if exiting the thread
1031 * FIXME - check access rights of the window station
1032 * e.g. services running in the service window station cannot block input
1034 if(!ThreadHasInputAccess(W32Thread
) ||
1035 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1037 EngSetLastError(ERROR_ACCESS_DENIED
);
1041 ASSERT(W32Thread
->rpdesk
);
1042 OldBlock
= W32Thread
->rpdesk
->BlockInputThread
;
1045 if(OldBlock
!= W32Thread
)
1047 EngSetLastError(ERROR_ACCESS_DENIED
);
1050 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1051 return OldBlock
== NULL
;
1054 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1055 return OldBlock
== NULL
;
1063 DECLARE_RETURN(BOOLEAN
);
1065 DPRINT("Enter NtUserBlockInput\n");
1066 UserEnterExclusive();
1068 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1071 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1077 IntMouseInput(MOUSEINPUT
*mi
, BOOL Injected
)
1079 const UINT SwapBtnMsg
[2][2] =
1081 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
1082 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1084 const WPARAM SwapBtn
[2] =
1086 MK_LBUTTON
, MK_RBUTTON
1089 PSYSTEM_CURSORINFO CurInfo
;
1095 CurInfo
= IntGetSysCursorInfo();
1099 LARGE_INTEGER LargeTickCount
;
1100 KeQueryTickCount(&LargeTickCount
);
1101 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1104 SwapButtons
= gspv
.bMouseBtnSwap
;
1106 MousePos
= gpsi
->ptCursor
;
1108 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1110 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1112 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
1113 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
1117 MousePos
.x
+= mi
->dx
;
1118 MousePos
.y
+= mi
->dy
;
1123 * Insert the messages into the system queue
1126 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1129 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1131 Msg
.wParam
|= MK_SHIFT
;
1134 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1136 Msg
.wParam
|= MK_CONTROL
;
1139 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1141 UserSetCursorPos(MousePos
.x
, MousePos
.y
, Injected
, mi
->dwExtraInfo
, TRUE
);
1143 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1145 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1146 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1147 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1148 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1149 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1151 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1153 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1154 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1155 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1156 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1157 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1159 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1161 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1162 Msg
.message
= WM_MBUTTONDOWN
;
1163 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1164 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1165 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1167 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1169 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1170 Msg
.message
= WM_MBUTTONUP
;
1171 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1172 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1173 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1175 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1177 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1178 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1179 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1180 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1181 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1183 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1185 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1186 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1187 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1188 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1189 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1192 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1193 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1195 /* fail because both types of events use the mouseData field */
1199 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1201 Msg
.message
= WM_XBUTTONDOWN
;
1202 if(mi
->mouseData
& XBUTTON1
)
1204 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1205 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
1206 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1207 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1209 if(mi
->mouseData
& XBUTTON2
)
1211 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1212 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
1213 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1214 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1217 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1219 Msg
.message
= WM_XBUTTONUP
;
1220 if(mi
->mouseData
& XBUTTON1
)
1222 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1223 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
1224 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1225 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1227 if(mi
->mouseData
& XBUTTON2
)
1229 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1230 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
1231 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1232 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1235 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1237 Msg
.message
= WM_MOUSEWHEEL
;
1238 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1239 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1246 IntKeyboardInput(KEYBDINPUT
*ki
, BOOL Injected
)
1248 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1250 LARGE_INTEGER LargeTickCount
;
1251 KBDLLHOOKSTRUCT KbdHookData
;
1252 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1256 // Condition may arise when calling MsqPostMessage and waiting for an event.
1257 ASSERT (UserIsEntered());
1261 flags
= LOBYTE(ki
->wScan
);
1263 if (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1264 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1266 /* strip left/right for menu, control, shift */
1272 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1273 wVkStripped
= VK_MENU
;
1280 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1281 wVkStripped
= VK_CONTROL
;
1288 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1289 wVkStripped
= VK_SHIFT
;
1294 wVkStripped
= wVkL
= wVkR
= wVk
;
1297 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1299 Msg
.message
= WM_KEYUP
;
1300 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80) &&
1301 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1302 || !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80)))
1304 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1305 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1306 Msg
.message
= WM_SYSKEYUP
;
1309 flags
|= KF_REPEAT
| KF_UP
;
1313 Msg
.message
= WM_KEYDOWN
;
1314 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1315 !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
))
1317 Msg
.message
= WM_SYSKEYDOWN
;
1318 TrackSysKey
= wVkStripped
;
1320 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
) && gQueueKeyStateTable
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1323 if (ki
->dwFlags
& KEYEVENTF_UNICODE
)
1325 vk_hook
= Msg
.wParam
= wVk
= VK_PACKET
;
1326 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, ki
->wScan
);
1329 FocusMessageQueue
= IntGetFocusMessageQueue();
1333 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
1334 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1338 KeQueryTickCount(&LargeTickCount
);
1339 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1342 Msg
.time
= ki
->time
;
1344 /* All messages have to contain the cursor point. */
1345 Msg
.pt
= gpsi
->ptCursor
;
1347 KbdHookData
.vkCode
= vk_hook
;
1348 KbdHookData
.scanCode
= ki
->wScan
;
1349 KbdHookData
.flags
= flags
>> 8;
1350 if (Injected
) KbdHookData
.flags
|= LLKHF_INJECTED
;
1351 KbdHookData
.time
= Msg
.time
;
1352 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1353 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1355 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1356 Msg
.message
, vk_hook
, Msg
.lParam
);
1361 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1363 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1365 gQueueKeyStateTable
[wVk
] &= ~0x80;
1366 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1370 if (!(gQueueKeyStateTable
[wVk
] & 0x80)) gQueueKeyStateTable
[wVk
] ^= 0x01;
1371 gQueueKeyStateTable
[wVk
] |= 0xc0;
1372 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1375 if (gQueueKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1377 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1379 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1382 if (FocusMessageQueue
== NULL
)
1384 DPRINT("No focus message queue\n");
1389 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1391 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1392 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
1394 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
1396 Msg
.pt
= gpsi
->ptCursor
;
1397 // Post to hardware queue, based on the first part of wine "some GetMessage tests"
1398 // in test_PeekMessage()
1399 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
1403 DPRINT("Invalid focus window handle\n");
1410 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1414 /* Can not be the same thread.*/
1415 if (pti
== ptiTo
) return FALSE
;
1417 /* Do not attach to system threads or between different desktops. */
1418 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1419 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1420 pti
->rpdesk
!= ptiTo
->rpdesk
)
1423 /* If Attach set, allocate and link. */
1426 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), USERTAG_ATTACHINFO
);
1427 if ( !pai
) return FALSE
;
1429 pai
->paiNext
= gpai
;
1434 else /* If clear, unlink and free it. */
1436 PATTACHINFO paiprev
= NULL
;
1438 if ( !gpai
) return FALSE
;
1442 /* Search list and free if found or return false. */
1445 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1450 if ( !pai
) return FALSE
;
1452 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1454 ExFreePoolWithTag(pai
, USERTAG_ATTACHINFO
);
1467 PTHREADINFO W32Thread
;
1469 DECLARE_RETURN(UINT
);
1471 DPRINT("Enter NtUserSendInput\n");
1472 UserEnterExclusive();
1474 W32Thread
= PsGetCurrentThreadWin32Thread();
1477 if(!W32Thread
->rpdesk
)
1482 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1484 EngSetLastError(ERROR_INVALID_PARAMETER
);
1489 * FIXME - check access rights of the window station
1490 * e.g. services running in the service window station cannot block input
1492 if(!ThreadHasInputAccess(W32Thread
) ||
1493 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1495 EngSetLastError(ERROR_ACCESS_DENIED
);
1505 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1506 if(!NT_SUCCESS(Status
))
1508 SetLastNtError(Status
);
1512 switch(SafeInput
.type
)
1515 if(IntMouseInput(&SafeInput
.mi
, TRUE
))
1520 case INPUT_KEYBOARD
:
1521 if(IntKeyboardInput(&SafeInput
.ki
, TRUE
))
1526 case INPUT_HARDWARE
:
1531 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1541 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);
1548 IntQueryTrackMouseEvent(
1549 LPTRACKMOUSEEVENT lpEventTrack
)
1554 pti
= PsGetCurrentThreadWin32Thread();
1555 pDesk
= pti
->rpdesk
;
1557 /* Always cleared with size set and return true. */
1558 RtlZeroMemory(lpEventTrack
,sizeof(TRACKMOUSEEVENT
));
1559 lpEventTrack
->cbSize
= sizeof(TRACKMOUSEEVENT
);
1561 if ( pDesk
->dwDTFlags
& (DF_TME_LEAVE
|DF_TME_HOVER
) &&
1562 pDesk
->spwndTrack
&&
1563 pti
->MessageQueue
== pDesk
->spwndTrack
->head
.pti
->MessageQueue
)
1565 if ( pDesk
->htEx
!= HTCLIENT
)
1566 lpEventTrack
->dwFlags
|= TME_NONCLIENT
;
1568 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1569 lpEventTrack
->dwFlags
|= TME_LEAVE
;
1571 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1573 lpEventTrack
->dwFlags
|= TME_HOVER
;
1574 lpEventTrack
->dwHoverTime
= pDesk
->dwMouseHoverTime
;
1576 lpEventTrack
->hwndTrack
= UserHMGetHandle(pDesk
->spwndTrack
);
1584 LPTRACKMOUSEEVENT lpEventTrack
)
1591 pti
= PsGetCurrentThreadWin32Thread();
1592 pDesk
= pti
->rpdesk
;
1594 if (!(pWnd
= UserGetWindowObject(lpEventTrack
->hwndTrack
)))
1597 if ( pDesk
->spwndTrack
!= pWnd
||
1598 (pDesk
->htEx
!= HTCLIENT
) ^ !!(lpEventTrack
->dwFlags
& TME_NONCLIENT
) )
1600 if ( lpEventTrack
->dwFlags
& TME_LEAVE
&& !(lpEventTrack
->dwFlags
& TME_CANCEL
) )
1602 UserPostMessage( lpEventTrack
->hwndTrack
,
1603 lpEventTrack
->dwFlags
& TME_NONCLIENT
? WM_NCMOUSELEAVE
: WM_MOUSELEAVE
,
1606 DPRINT("IntTrackMouseEvent spwndTrack 0x%x pwnd 0x%x\n", pDesk
->spwndTrack
,pWnd
);
1610 /* Tracking spwndTrack same as pWnd */
1611 if ( lpEventTrack
->dwFlags
& TME_CANCEL
) // Canceled mode.
1613 if ( lpEventTrack
->dwFlags
& TME_LEAVE
)
1614 pDesk
->dwDTFlags
&= ~DF_TME_LEAVE
;
1616 if ( lpEventTrack
->dwFlags
& TME_HOVER
)
1618 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1619 { // Kill hover timer.
1620 IntKillTimer(pWnd
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1621 pDesk
->dwDTFlags
&= ~DF_TME_HOVER
;
1625 else // Not Canceled.
1627 if ( lpEventTrack
->dwFlags
& TME_LEAVE
)
1628 pDesk
->dwDTFlags
|= DF_TME_LEAVE
;
1630 if ( lpEventTrack
->dwFlags
& TME_HOVER
)
1632 pDesk
->dwDTFlags
|= DF_TME_HOVER
;
1634 if ( !lpEventTrack
->dwHoverTime
|| lpEventTrack
->dwHoverTime
== HOVER_DEFAULT
)
1635 pDesk
->dwMouseHoverTime
= gspv
.iMouseHoverTime
; // use the system default hover time-out.
1637 pDesk
->dwMouseHoverTime
= lpEventTrack
->dwHoverTime
;
1638 // Start timer for the hover period.
1639 IntSetTimer( pWnd
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1640 // Get windows thread message points.
1641 point
= pWnd
->head
.pti
->ptLast
;
1642 // Set desktop mouse hover from the system default hover rectangle.
1643 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1644 point
.x
- gspv
.iMouseHoverWidth
/ 2,
1645 point
.y
- gspv
.iMouseHoverHeight
/ 2,
1646 point
.x
+ gspv
.iMouseHoverWidth
/ 2,
1647 point
.y
+ gspv
.iMouseHoverHeight
/ 2);
1655 NtUserTrackMouseEvent(
1656 LPTRACKMOUSEEVENT lpEventTrack
)
1658 TRACKMOUSEEVENT saveTME
;
1661 DPRINT("Enter NtUserTrackMouseEvent\n");
1662 UserEnterExclusive();
1666 ProbeForRead(lpEventTrack
, sizeof(TRACKMOUSEEVENT
), 1);
1667 RtlCopyMemory(&saveTME
, lpEventTrack
, sizeof(TRACKMOUSEEVENT
));
1669 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1671 SetLastNtError(_SEH2_GetExceptionCode());
1672 _SEH2_YIELD(goto Exit
;)
1676 if ( saveTME
.cbSize
!= sizeof(TRACKMOUSEEVENT
) )
1678 EngSetLastError(ERROR_INVALID_PARAMETER
);
1682 if (saveTME
.dwFlags
& ~(TME_CANCEL
|TME_QUERY
|TME_NONCLIENT
|TME_LEAVE
|TME_HOVER
) )
1684 EngSetLastError(ERROR_INVALID_FLAGS
);
1688 if ( saveTME
.dwFlags
& TME_QUERY
)
1690 Ret
= IntQueryTrackMouseEvent(&saveTME
);
1693 ProbeForWrite(lpEventTrack
, sizeof(TRACKMOUSEEVENT
), 1);
1694 RtlCopyMemory(lpEventTrack
, &saveTME
, sizeof(TRACKMOUSEEVENT
));
1696 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1698 SetLastNtError(_SEH2_GetExceptionCode());
1705 Ret
= IntTrackMouseEvent(&saveTME
);
1709 DPRINT("Leave NtUserTrackMouseEvent, ret=%i\n",Ret
);
1714 extern MOUSEMOVEPOINT MouseHistoryOfMoves
[];
1715 extern INT gcur_count
;
1719 NtUserGetMouseMovePointsEx(
1721 LPMOUSEMOVEPOINT lpptIn
,
1722 LPMOUSEMOVEPOINT lpptOut
,
1726 MOUSEMOVEPOINT Safeppt
;
1729 DECLARE_RETURN(DWORD
);
1731 DPRINT("Enter NtUserGetMouseMovePointsEx\n");
1732 UserEnterExclusive();
1734 if ((cbSize
!= sizeof(MOUSEMOVEPOINT
)) || (nBufPoints
< 0) || (nBufPoints
> 64))
1736 EngSetLastError(ERROR_INVALID_PARAMETER
);
1740 if (!lpptIn
|| (!lpptOut
&& nBufPoints
))
1742 EngSetLastError(ERROR_NOACCESS
);
1748 ProbeForRead( lpptIn
, cbSize
, 1);
1749 RtlCopyMemory(&Safeppt
, lpptIn
, cbSize
);
1751 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1753 SetLastNtError(_SEH2_GetExceptionCode());
1754 _SEH2_YIELD(RETURN( -1))
1758 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
1759 // This explains the math issues in transforming points.
1760 Count
= gcur_count
; // FIFO is forward so retrieve backward.
1764 if (Safeppt
.x
== 0 && Safeppt
.y
== 0)
1766 // Finds the point, it returns the last nBufPoints prior to and including the supplied point.
1767 if (MouseHistoryOfMoves
[Count
].x
== Safeppt
.x
&& MouseHistoryOfMoves
[Count
].y
== Safeppt
.y
)
1769 if ( Safeppt
.time
) // Now test time and it seems to be absolute.
1771 if (Safeppt
.time
== MouseHistoryOfMoves
[Count
].time
)
1778 if (--Count
< 0) Count
= 63;
1785 if (--Count
< 0) Count
= 63;
1787 while ( Count
!= gcur_count
);
1791 case GMMP_USE_DISPLAY_POINTS
:
1796 ProbeForWrite(lpptOut
, cbSize
, 1);
1798 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1800 SetLastNtError(_SEH2_GetExceptionCode());
1801 _SEH2_YIELD(RETURN( -1))
1807 case GMMP_USE_HIGH_RESOLUTION_POINTS
:
1810 EngSetLastError(ERROR_POINT_NOT_FOUND
);
1817 DPRINT("Leave NtUserGetMouseMovePointsEx, ret=%i\n",_ret_
);