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 ******************************************************************/
16 DBG_DEFAULT_CHANNEL(UserInput
);
18 extern BYTE gKeyStateTable
[];
19 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
20 extern PPROCESSINFO ppiScrnSaver
;
22 /* GLOBALS *******************************************************************/
24 PTHREADINFO ptiRawInput
;
25 PTHREADINFO ptiKeyboard
;
27 PKTIMER MasterTimer
= NULL
;
28 PATTACHINFO gpai
= NULL
;
30 static DWORD LastInputTick
= 0;
31 static HANDLE MouseDeviceHandle
;
32 static HANDLE MouseThreadHandle
;
33 static CLIENT_ID MouseThreadId
;
34 static HANDLE KeyboardThreadHandle
;
35 static CLIENT_ID KeyboardThreadId
;
36 static HANDLE KeyboardDeviceHandle
;
37 static HANDLE RawInputThreadHandle
;
38 static CLIENT_ID RawInputThreadId
;
39 static KEVENT InputThreadsStart
;
40 static BOOLEAN InputThreadsRunning
= FALSE
;
41 static BYTE TrackSysKey
= 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
42 or a WM_KEYUP message */
44 /* FUNCTIONS *****************************************************************/
45 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
);
47 #define ClearMouseInput(mi) \
53 #define SendMouseEvent(mi) \
54 if(mi.dx != 0 || mi.dy != 0) \
55 mi.dwFlags |= MOUSEEVENTF_MOVE; \
57 IntMouseInput(&mi,FALSE); \
61 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
)
63 if (LastInputTickSetGet
== TRUE
)
65 LARGE_INTEGER TickCount
;
66 KeQueryTickCount(&TickCount
);
67 LastInputTick
= MsqCalculateMessageTime(&TickCount
);
68 if (gpsi
) gpsi
->dwLastRITEventTickCount
= LastInputTick
;
74 VOID FASTCALL
DoTheScreenSaver(VOID
)
76 LARGE_INTEGER TickCount
;
79 if (gspv
.iScrSaverTimeout
> 0) // Zero means Off.
81 KeQueryTickCount(&TickCount
);
82 Test
= MsqCalculateMessageTime(&TickCount
);
83 Test
= Test
- LastInputTick
;
84 TO
= 1000 * gspv
.iScrSaverTimeout
;
87 TRACE("Screensaver Message Start! Tick %d Timeout %d \n", Test
, gspv
.iScrSaverTimeout
);
89 if (ppiScrnSaver
) // We are or we are not the screensaver, prevent reentry...
91 if (!(ppiScrnSaver
->W32PF_flags
& W32PF_IDLESCREENSAVER
))
93 ppiScrnSaver
->W32PF_flags
|= W32PF_IDLESCREENSAVER
;
94 ERR("Screensaver is Idle\n");
99 PUSER_MESSAGE_QUEUE ForegroundQueue
= IntGetFocusMessageQueue();
100 if (ForegroundQueue
&& ForegroundQueue
->ActiveWindow
)
101 UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_START_SCREENSAVE
, 1); // lParam 1 == Secure
103 UserPostMessage(hwndSAS
, WM_LOGONNOTIFY
, LN_START_SCREENSAVE
, 0);
110 ProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
112 PMOUSE_INPUT_DATA mid
;
119 for(i
= 0; i
< InputCount
; i
++)
125 /* Check if the mouse move is absolute */
126 if (mid
->Flags
== MOUSE_MOVE_ABSOLUTE
)
128 /* Set flag to convert to screen location */
129 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
134 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
136 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
139 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
141 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
144 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
146 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
149 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
151 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
154 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
156 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
159 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
161 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
164 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
166 mi
.mouseData
|= XBUTTON1
;
167 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
170 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
172 mi
.mouseData
|= XBUTTON1
;
173 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
176 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
178 mi
.mouseData
|= XBUTTON2
;
179 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
182 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
184 mi
.mouseData
|= XBUTTON2
;
185 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
188 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
190 mi
.mouseData
= mid
->ButtonData
;
191 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
204 MouseThreadMain(PVOID StartContext
)
206 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
207 OBJECT_ATTRIBUTES MouseObjectAttributes
;
208 IO_STATUS_BLOCK Iosb
;
210 MOUSE_ATTRIBUTES MouseAttr
;
212 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
213 LOW_REALTIME_PRIORITY
+ 3);
215 InitializeObjectAttributes(&MouseObjectAttributes
,
222 LARGE_INTEGER DueTime
;
224 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
225 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
226 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
227 Status
= NtOpenFile(&MouseDeviceHandle
,
229 &MouseObjectAttributes
,
232 FILE_SYNCHRONOUS_IO_ALERT
);
233 } while (!NT_SUCCESS(Status
));
235 /* Need to setup basic win32k for this thread to process WH_MOUSE_LL messages. */
236 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
237 if (!NT_SUCCESS(Status
))
239 ERR("Win32K: Failed making mouse thread a win32 thread.\n");
243 ptiMouse
= PsGetCurrentThreadWin32Thread();
244 ptiMouse
->TIF_flags
|= TIF_SYSTEMTHREAD
;
245 TRACE("Mouse Thread 0x%x \n", ptiMouse
);
247 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
248 LOW_REALTIME_PRIORITY
+ 3);
253 * Wait to start input.
255 TRACE("Mouse Input Thread Waiting for start event\n");
256 Status
= KeWaitForSingleObject(&InputThreadsStart
,
261 TRACE("Mouse Input Thread Starting...\n");
263 /*FIXME: Does mouse attributes need to be used for anything */
264 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
269 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
270 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
272 if(!NT_SUCCESS(Status
))
274 TRACE("Failed to get mouse attributes\n");
278 * Receive and process mouse input.
280 while(InputThreadsRunning
)
282 MOUSE_INPUT_DATA MouseInput
;
283 Status
= NtReadFile(MouseDeviceHandle
,
289 sizeof(MOUSE_INPUT_DATA
),
292 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
296 if(Status
== STATUS_PENDING
)
298 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
299 Status
= Iosb
.Status
;
301 if(!NT_SUCCESS(Status
))
303 ERR("Win32K: Failed to read from mouse.\n");
306 TRACE("MouseEvent\n");
307 IntLastInputTick(TRUE
);
309 UserEnterExclusive();
311 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
315 TRACE("Mouse Input Thread Stopped...\n");
319 /* Returns a value that indicates if the key is a modifier key, and
323 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
325 if (InputData
->Flags
& KEY_E1
)
328 if (!(InputData
->Flags
& KEY_E0
))
330 switch (InputData
->MakeCode
)
332 case 0x2a: /* left shift */
333 case 0x36: /* right shift */
336 case 0x1d: /* left control */
339 case 0x38: /* left alt */
348 switch (InputData
->MakeCode
)
350 case 0x1d: /* right control */
353 case 0x38: /* right alt */
356 case 0x5b: /* left gui (windows) */
357 case 0x5c: /* right gui (windows) */
366 /* Asks the keyboard driver to send a small table that shows which
367 * lights should connect with which scancodes
369 static NTSTATUS APIENTRY
370 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
371 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
375 IO_STATUS_BLOCK Block
;
376 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
378 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
380 Ret
= ExAllocatePoolWithTag(PagedPool
,
386 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
391 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
395 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
398 ExFreePoolWithTag(Ret
, USERTAG_KBDTABLE
);
400 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
402 Ret
= ExAllocatePoolWithTag(PagedPool
,
408 return STATUS_INSUFFICIENT_RESOURCES
;
410 if (Status
!= STATUS_SUCCESS
)
412 ExFreePoolWithTag(Ret
, USERTAG_KBDTABLE
);
416 *IndicatorTrans
= Ret
;
420 /* Sends the keyboard commands to turn on/off the lights.
422 static NTSTATUS APIENTRY
423 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
424 PKEYBOARD_INPUT_DATA KeyInput
,
425 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
429 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
430 IO_STATUS_BLOCK Block
;
433 return STATUS_NOT_SUPPORTED
;
435 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
436 return STATUS_SUCCESS
;
438 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
440 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
442 Indicators
.LedFlags
^=
443 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
445 /* Update the lights on the hardware */
447 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
452 IOCTL_KEYBOARD_SET_INDICATORS
,
453 &Indicators
, sizeof(Indicators
),
460 return STATUS_SUCCESS
;
464 IntKeyboardSendWinKeyMsg()
469 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
471 ERR("Couldn't find window to send Windows key message!\n");
475 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
476 Mesg
.message
= WM_SYSCOMMAND
;
477 Mesg
.wParam
= SC_TASKLIST
;
480 /* The QS_HOTKEY is just a guess */
481 MsqPostMessage(Window
->head
.pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
485 co_IntKeyboardSendAltKeyMsg()
487 ERR("co_IntKeyboardSendAltKeyMsg\n");
488 // co_MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0); // This sends everything into a msg loop!
492 KeyboardThreadMain(PVOID StartContext
)
494 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
495 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
496 IO_STATUS_BLOCK Iosb
;
499 PUSER_MESSAGE_QUEUE FocusQueue
;
500 struct _ETHREAD
*FocusThread
;
502 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
503 UINT ModifierState
= 0;
504 USHORT LastMakeCode
= 0;
505 USHORT LastFlags
= 0;
506 UINT RepeatCount
= 0;
508 InitializeObjectAttributes(&KeyboardObjectAttributes
,
515 LARGE_INTEGER DueTime
;
517 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
518 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
519 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
520 Status
= NtOpenFile(&KeyboardDeviceHandle
,
522 &KeyboardObjectAttributes
,
525 FILE_SYNCHRONOUS_IO_ALERT
);
526 } while (!NT_SUCCESS(Status
));
528 /* Not sure if converting this thread to a win32 thread is such
529 a great idea. Since we're posting keyboard messages to the focus
530 window message queue, we'll be (indirectly) doing sendmessage
531 stuff from this thread (for WH_KEYBOARD_LL processing), which
532 means we need our own message queue. If keyboard messages were
533 instead queued to the system message queue, the thread removing
534 the message from the system message queue would be responsible
535 for WH_KEYBOARD_LL processing and we wouldn't need this thread
536 to be a win32 thread. */
537 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
538 if (!NT_SUCCESS(Status
))
540 ERR("Win32K: Failed making keyboard thread a win32 thread.\n");
544 ptiKeyboard
= PsGetCurrentThreadWin32Thread();
545 ptiKeyboard
->TIF_flags
|= TIF_SYSTEMTHREAD
;
546 TRACE("Keyboard Thread 0x%x \n", ptiKeyboard
);
548 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
549 LOW_REALTIME_PRIORITY
+ 3);
551 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
557 * Wait to start input.
559 TRACE( "Keyboard Input Thread Waiting for start event\n" );
560 Status
= KeWaitForSingleObject(&InputThreadsStart
,
566 TRACE( "Keyboard Input Thread Starting...\n" );
568 * Receive and process keyboard input.
570 while (InputThreadsRunning
)
574 KEYBOARD_INPUT_DATA KeyInput
;
575 KEYBOARD_INPUT_DATA NextKeyInput
;
577 UINT fsModifiers
, fsNextModifiers
;
578 struct _ETHREAD
*Thread
;
582 TRACE("KeyInput @ %08x\n", &KeyInput
);
584 Status
= NtReadFile (KeyboardDeviceHandle
,
590 sizeof(KEYBOARD_INPUT_DATA
),
594 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
598 if(Status
== STATUS_PENDING
)
600 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
601 Status
= Iosb
.Status
;
603 if(!NT_SUCCESS(Status
))
605 ERR("Win32K: Failed to read from keyboard.\n");
609 TRACE("KeyRaw: %s %04x\n",
610 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
613 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
616 if (!NT_SUCCESS(Status
))
618 ERR("Win32K: Failed to read from keyboard.\n");
622 /* Set LastInputTick */
623 IntLastInputTick(TRUE
);
625 /* Update modifier state */
626 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
630 if (KeyInput
.Flags
& KEY_BREAK
)
632 ModifierState
&= ~fsModifiers
;
633 if(fsModifiers
== MOD_ALT
)
635 if(KeyInput
.Flags
& KEY_E0
)
637 gKeyStateTable
[VK_RMENU
] = 0;
641 gKeyStateTable
[VK_LMENU
] = 0;
643 if (gKeyStateTable
[VK_RMENU
] == 0 &&
644 gKeyStateTable
[VK_LMENU
] == 0)
646 gKeyStateTable
[VK_MENU
] = 0;
652 ModifierState
|= fsModifiers
;
654 if (ModifierState
== fsModifiers
&&
655 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
657 /* First send out special notifications
658 * (For alt, the message that turns on accelerator
659 * display, not sure what for win. Both TODO though.)
662 if(fsModifiers
== MOD_ALT
)
664 if(KeyInput
.Flags
& KEY_E0
)
666 gKeyStateTable
[VK_RMENU
] = KS_DOWN_BIT
;
670 gKeyStateTable
[VK_LMENU
] = KS_DOWN_BIT
;
674 gKeyStateTable
[VK_MENU
] = KS_DOWN_BIT
;
677 /* Read the next key before sending this one */
680 Status
= NtReadFile (KeyboardDeviceHandle
,
686 sizeof(KEYBOARD_INPUT_DATA
),
689 TRACE("KeyRaw: %s %04x\n",
690 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
691 NextKeyInput
.MakeCode
);
693 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
697 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
698 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
699 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
700 * code. I'm not caring about the counting, not sure
701 * if that matters. I think not.
704 /* If the ModifierState is now empty again, send a
705 * special notification and eat both keypresses
708 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
711 ModifierState
^= fsNextModifiers
;
713 if (ModifierState
== 0)
715 UserEnterExclusive();
716 if (fsModifiers
== MOD_WIN
)
717 IntKeyboardSendWinKeyMsg();
718 else if (fsModifiers
== MOD_ALT
)
720 gKeyStateTable
[VK_MENU
] = 0;
723 gKeyStateTable
[VK_LMENU
] = 0;
727 gKeyStateTable
[VK_RMENU
] = 0;
729 co_IntKeyboardSendAltKeyMsg();
740 UserEnterExclusive();
742 for (; NumKeys
; memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
745 PKBL keyboardLayout
= NULL
;
748 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
752 /* While we are working, we set up lParam. The format is:
753 * 0-15: The number of times this key has autorepeated
754 * 16-23: The keyboard scancode
755 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
756 * Note that E1 is only used for PAUSE (E1-1D-45) and
757 * E0-45 happens not to be anything.
758 * 29: Alt is pressed ('Context code')
759 * 30: Previous state, if the key was down before this message
760 * This is a cheap way to ignore autorepeat keys
761 * 31: 1 if the key is being pressed
764 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
765 * and it's the same key as the last one, increase the repeat
769 if (!(KeyInput
.Flags
& KEY_BREAK
))
771 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
772 (KeyInput
.MakeCode
== LastMakeCode
))
775 lParam
|= (KF_REPEAT
<< 16);
780 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
781 LastMakeCode
= KeyInput
.MakeCode
;
787 LastMakeCode
= 0; /* Should never match */
788 lParam
|= (KF_UP
<< 16) | (KF_REPEAT
<< 16);
791 lParam
|= RepeatCount
;
793 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
795 if (KeyInput
.Flags
& KEY_E0
)
796 lParam
|= (KF_EXTENDED
<< 16);
798 if (ModifierState
& MOD_ALT
)
800 lParam
|= (KF_ALTDOWN
<< 16);
802 if (!(KeyInput
.Flags
& KEY_BREAK
))
803 msg
.message
= WM_SYSKEYDOWN
;
805 msg
.message
= WM_SYSKEYUP
;
809 if (!(KeyInput
.Flags
& KEY_BREAK
))
810 msg
.message
= WM_KEYDOWN
;
812 msg
.message
= WM_KEYUP
;
815 /* Find the target thread whose locale is in effect */
816 FocusQueue
= IntGetFocusMessageQueue();
820 msg
.hwnd
= FocusQueue
->FocusWindow
;
822 FocusThread
= FocusQueue
->Thread
;
823 if (FocusThread
&& FocusThread
->Tcb
.Win32Thread
)
825 keyboardLayout
= ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
;
827 if ( FocusQueue
->QF_flags
& QF_DIALOGACTIVE
)
828 lParam
|= (KF_DLGMODE
<< 16);
829 if ( FocusQueue
->MenuOwner
)//FocusQueue->MenuState ) // MenuState needs a start flag...
830 lParam
|= (KF_MENUMODE
<< 16);
834 keyboardLayout
= W32kGetDefaultKeyLayout();
839 /* This function uses lParam to fill wParam according to the
840 * keyboard layout in use.
842 W32kKeyProcessMessage(&msg
,
843 keyboardLayout
->KBTables
,
844 KeyInput
.Flags
& KEY_E0
? 0xE0 :
845 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
847 if (GetHotKey(ModifierState
,
853 if (!(KeyInput
.Flags
& KEY_BREAK
))
855 TRACE("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
856 MsqPostHotKeyMessage (Thread
,
859 MAKELPARAM((WORD
)ModifierState
,
862 continue; /* Eat key up motion too */
867 /* There is no focused window to receive a keyboard message */
870 if ( msg
.wParam
== VK_F10
) // Bypass this key before it is in the queue.
872 if (msg
.message
== WM_KEYUP
) msg
.message
= WM_SYSKEYUP
;
873 if (msg
.message
== WM_KEYDOWN
) msg
.message
= WM_SYSKEYDOWN
;
876 * Post a keyboard message.
878 co_MsqPostKeyboardMessage(msg
.message
, msg
.wParam
, msg
.lParam
);
885 TRACE( "KeyboardInput Thread Stopped...\n" );
890 static PVOID Objects
[2];
893 Since this relies on InputThreadsStart, just fake it.
896 RawInputThreadMain(PVOID StartContext
)
899 LARGE_INTEGER DueTime
;
901 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
906 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
907 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
908 } while (!NT_SUCCESS(Status
));
911 Objects
[0] = &InputThreadsStart
;
912 Objects
[1] = MasterTimer
;
914 // This thread requires win32k!
915 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
916 if (!NT_SUCCESS(Status
))
918 ERR("Win32K: Failed making Raw Input thread a win32 thread.\n");
922 ptiRawInput
= PsGetCurrentThreadWin32Thread();
923 ptiRawInput
->TIF_flags
|= TIF_SYSTEMTHREAD
;
924 TRACE("Raw Input Thread 0x%x \n", ptiRawInput
);
926 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
927 LOW_REALTIME_PRIORITY
+ 3);
929 UserEnterExclusive();
934 // ATM, we just have one job to handle, merge the other two later.
938 TRACE( "Raw Input Thread Waiting for start event\n" );
940 Status
= KeWaitForMultipleObjects( 2,
948 TRACE( "Raw Input Thread Starting...\n" );
952 ERR("Raw Input Thread Exit!\n");
962 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
964 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), USERTAG_SYSTEM
);
967 ERR("Win32K: Failed making Raw Input thread a win32 thread.\n");
969 return STATUS_UNSUCCESSFUL
;
971 KeInitializeTimer(MasterTimer
);
973 /* Initialize the default keyboard layout */
974 if(!UserInitDefaultKeyboardLayout())
976 ERR("Failed to initialize default keyboard layout!\n");
979 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
986 if (!NT_SUCCESS(Status
))
988 ERR("Win32K: Failed to create raw thread.\n");
991 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
998 if (!NT_SUCCESS(Status
))
1000 ERR("Win32K: Failed to create keyboard thread.\n");
1003 Status
= PsCreateSystemThread(&MouseThreadHandle
,
1010 if (!NT_SUCCESS(Status
))
1012 ERR("Win32K: Failed to create mouse thread.\n");
1015 InputThreadsRunning
= TRUE
;
1016 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
1018 return STATUS_SUCCESS
;
1022 CleanupInputImp(VOID
)
1024 return(STATUS_SUCCESS
);
1028 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
1030 PTHREADINFO OldBlock
;
1033 if(!W32Thread
->rpdesk
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
1036 * fail blocking if exiting the thread
1043 * FIXME - check access rights of the window station
1044 * e.g. services running in the service window station cannot block input
1046 if(!ThreadHasInputAccess(W32Thread
) ||
1047 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1049 EngSetLastError(ERROR_ACCESS_DENIED
);
1053 ASSERT(W32Thread
->rpdesk
);
1054 OldBlock
= W32Thread
->rpdesk
->BlockInputThread
;
1057 if(OldBlock
!= W32Thread
)
1059 EngSetLastError(ERROR_ACCESS_DENIED
);
1062 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1063 return OldBlock
== NULL
;
1066 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1067 return OldBlock
== NULL
;
1075 DECLARE_RETURN(BOOLEAN
);
1077 TRACE("Enter NtUserBlockInput\n");
1078 UserEnterExclusive();
1080 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1083 TRACE("Leave NtUserBlockInput, ret=%i\n", _ret_
);
1089 IntMouseInput(MOUSEINPUT
*mi
, BOOL Injected
)
1091 const UINT SwapBtnMsg
[2][2] =
1093 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
1094 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1096 const WPARAM SwapBtn
[2] =
1098 MK_LBUTTON
, MK_RBUTTON
1101 PSYSTEM_CURSORINFO CurInfo
;
1107 CurInfo
= IntGetSysCursorInfo();
1111 LARGE_INTEGER LargeTickCount
;
1112 KeQueryTickCount(&LargeTickCount
);
1113 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1116 SwapButtons
= gspv
.bMouseBtnSwap
;
1118 MousePos
= gpsi
->ptCursor
;
1120 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1122 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1124 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
1125 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
1129 MousePos
.x
+= mi
->dx
;
1130 MousePos
.y
+= mi
->dy
;
1135 * Insert the messages into the system queue
1138 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1141 if (gKeyStateTable
[VK_SHIFT
] & KS_DOWN_BIT
)
1143 Msg
.wParam
|= MK_SHIFT
;
1146 if (gKeyStateTable
[VK_CONTROL
] & KS_DOWN_BIT
)
1148 Msg
.wParam
|= MK_CONTROL
;
1151 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1153 UserSetCursorPos(MousePos
.x
, MousePos
.y
, Injected
, mi
->dwExtraInfo
, TRUE
);
1155 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1157 gKeyStateTable
[VK_LBUTTON
] |= KS_DOWN_BIT
;
1158 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1159 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1160 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1161 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1163 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1165 gKeyStateTable
[VK_LBUTTON
] &= ~KS_DOWN_BIT
;
1166 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1167 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1168 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1169 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1171 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1173 gKeyStateTable
[VK_MBUTTON
] |= KS_DOWN_BIT
;
1174 Msg
.message
= WM_MBUTTONDOWN
;
1175 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1176 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1177 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1179 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1181 gKeyStateTable
[VK_MBUTTON
] &= ~KS_DOWN_BIT
;
1182 Msg
.message
= WM_MBUTTONUP
;
1183 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1184 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1185 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1187 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1189 gKeyStateTable
[VK_RBUTTON
] |= KS_DOWN_BIT
;
1190 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1191 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1192 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1193 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1195 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1197 gKeyStateTable
[VK_RBUTTON
] &= ~KS_DOWN_BIT
;
1198 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1199 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1200 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1201 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1204 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1205 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1207 /* fail because both types of events use the mouseData field */
1211 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1213 Msg
.message
= WM_XBUTTONDOWN
;
1214 if(mi
->mouseData
& XBUTTON1
)
1216 gKeyStateTable
[VK_XBUTTON1
] |= KS_DOWN_BIT
;
1217 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
1218 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1219 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1221 if(mi
->mouseData
& XBUTTON2
)
1223 gKeyStateTable
[VK_XBUTTON2
] |= KS_DOWN_BIT
;
1224 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
1225 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1226 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1229 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1231 Msg
.message
= WM_XBUTTONUP
;
1232 if(mi
->mouseData
& XBUTTON1
)
1234 gKeyStateTable
[VK_XBUTTON1
] &= ~KS_DOWN_BIT
;
1235 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
1236 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1237 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1239 if(mi
->mouseData
& XBUTTON2
)
1241 gKeyStateTable
[VK_XBUTTON2
] &= ~KS_DOWN_BIT
;
1242 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
1243 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1244 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1247 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1249 Msg
.message
= WM_MOUSEWHEEL
;
1250 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1251 co_MsqInsertMouseMessage(&Msg
, Injected
, mi
->dwExtraInfo
, TRUE
);
1258 IntKeyboardInput(KEYBDINPUT
*ki
, BOOL Injected
)
1260 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1262 LARGE_INTEGER LargeTickCount
;
1263 KBDLLHOOKSTRUCT KbdHookData
;
1264 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1268 // Condition may arise when calling MsqPostMessage and waiting for an event.
1269 ASSERT (UserIsEntered());
1273 flags
= LOBYTE(ki
->wScan
);
1275 FocusMessageQueue
= IntGetFocusMessageQueue();
1277 if (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1278 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1279 if ( FocusMessageQueue
&& FocusMessageQueue
->QF_flags
& QF_DIALOGACTIVE
)
1280 flags
|= KF_DLGMODE
;
1281 if ( FocusMessageQueue
&& FocusMessageQueue
->MenuOwner
)//FocusMessageQueue->MenuState ) // MenuState needs a start flag...
1282 flags
|= KF_MENUMODE
;
1284 /* strip left/right for menu, control, shift */
1290 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1291 wVkStripped
= VK_MENU
;
1298 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1299 wVkStripped
= VK_CONTROL
;
1306 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1307 wVkStripped
= VK_SHIFT
;
1312 wVkStripped
= wVkL
= wVkR
= wVk
;
1315 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1317 Msg
.message
= WM_KEYUP
;
1318 if (((gKeyStateTable
[VK_MENU
] & KS_DOWN_BIT
) &&
1319 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1320 || !(gKeyStateTable
[VK_CONTROL
] & KS_DOWN_BIT
)))
1321 || (wVkStripped
== VK_F10
))
1323 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1324 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1325 Msg
.message
= WM_SYSKEYUP
;
1328 flags
|= KF_REPEAT
| KF_UP
;
1332 Msg
.message
= WM_KEYDOWN
;
1333 if (((gKeyStateTable
[VK_MENU
] & KS_DOWN_BIT
|| wVkStripped
== VK_MENU
) &&
1334 !(gKeyStateTable
[VK_CONTROL
] & KS_DOWN_BIT
|| wVkStripped
== VK_CONTROL
))
1335 || (wVkStripped
== VK_F10
))
1337 Msg
.message
= WM_SYSKEYDOWN
;
1338 TrackSysKey
= wVkStripped
;
1340 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
) && gKeyStateTable
[wVk
] & KS_DOWN_BIT
) flags
|= KF_REPEAT
;
1343 if (ki
->dwFlags
& KEYEVENTF_UNICODE
)
1345 vk_hook
= Msg
.wParam
= wVk
= VK_PACKET
;
1346 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, ki
->wScan
);
1349 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1351 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1353 gKeyStateTable
[wVk
] &= ~KS_DOWN_BIT
;
1354 gKeyStateTable
[wVkStripped
] = gKeyStateTable
[wVkL
] | gKeyStateTable
[wVkR
];
1358 if (!(gKeyStateTable
[wVk
] & KS_DOWN_BIT
)) gKeyStateTable
[wVk
] ^= KS_LOCK_BIT
;
1359 gKeyStateTable
[wVk
] |= KS_DOWN_BIT
;
1360 gKeyStateTable
[wVkStripped
] = gKeyStateTable
[wVkL
] | gKeyStateTable
[wVkR
];
1363 if (gKeyStateTable
[VK_MENU
] & KS_DOWN_BIT
) flags
|= KF_ALTDOWN
;
1365 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1367 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1372 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
1373 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1377 KeQueryTickCount(&LargeTickCount
);
1378 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1381 Msg
.time
= ki
->time
;
1383 /* All messages have to contain the cursor point. */
1384 Msg
.pt
= gpsi
->ptCursor
;
1386 KbdHookData
.vkCode
= vk_hook
;
1387 KbdHookData
.scanCode
= ki
->wScan
;
1388 KbdHookData
.flags
= (flags
& (KF_EXTENDED
| KF_ALTDOWN
| KF_UP
)) >> 8;
1389 if (Injected
) KbdHookData
.flags
|= LLKHF_INJECTED
;
1390 KbdHookData
.time
= Msg
.time
;
1391 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1392 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1394 ERR("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1395 Msg
.message
, vk_hook
, Msg
.lParam
);
1400 if (FocusMessageQueue
== NULL
)
1402 TRACE("No focus message queue\n");
1407 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1409 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1410 TRACE("Msg.hwnd = %x\n", Msg
.hwnd
);
1412 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
1414 // Post to hardware queue, based on the first part of wine "some GetMessage tests"
1415 // in test_PeekMessage()
1416 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
1420 TRACE("Invalid focus window handle\n");
1427 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1431 /* Can not be the same thread.*/
1432 if (pti
== ptiTo
) return FALSE
;
1434 /* Do not attach to system threads or between different desktops. */
1435 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1436 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1437 pti
->rpdesk
!= ptiTo
->rpdesk
)
1440 /* If Attach set, allocate and link. */
1443 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), USERTAG_ATTACHINFO
);
1444 if ( !pai
) return FALSE
;
1446 pai
->paiNext
= gpai
;
1451 else /* If clear, unlink and free it. */
1453 PATTACHINFO paiprev
= NULL
;
1455 if ( !gpai
) return FALSE
;
1459 /* Search list and free if found or return false. */
1462 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1467 if ( !pai
) return FALSE
;
1469 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1471 ExFreePoolWithTag(pai
, USERTAG_ATTACHINFO
);
1484 PTHREADINFO W32Thread
;
1486 DECLARE_RETURN(UINT
);
1488 TRACE("Enter NtUserSendInput\n");
1489 UserEnterExclusive();
1491 W32Thread
= PsGetCurrentThreadWin32Thread();
1494 if(!W32Thread
->rpdesk
)
1499 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1501 EngSetLastError(ERROR_INVALID_PARAMETER
);
1506 * FIXME - check access rights of the window station
1507 * e.g. services running in the service window station cannot block input
1509 if(!ThreadHasInputAccess(W32Thread
) ||
1510 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1512 EngSetLastError(ERROR_ACCESS_DENIED
);
1522 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1523 if(!NT_SUCCESS(Status
))
1525 SetLastNtError(Status
);
1529 switch(SafeInput
.type
)
1532 if(IntMouseInput(&SafeInput
.mi
, TRUE
))
1537 case INPUT_KEYBOARD
:
1538 if(IntKeyboardInput(&SafeInput
.ki
, TRUE
))
1543 case INPUT_HARDWARE
:
1548 ERR("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1558 TRACE("Leave NtUserSendInput, ret=%i\n", _ret_
);
1565 IntQueryTrackMouseEvent(
1566 LPTRACKMOUSEEVENT lpEventTrack
)
1571 pti
= PsGetCurrentThreadWin32Thread();
1572 pDesk
= pti
->rpdesk
;
1574 /* Always cleared with size set and return true. */
1575 RtlZeroMemory(lpEventTrack
, sizeof(TRACKMOUSEEVENT
));
1576 lpEventTrack
->cbSize
= sizeof(TRACKMOUSEEVENT
);
1578 if ( pDesk
->dwDTFlags
& (DF_TME_LEAVE
| DF_TME_HOVER
) &&
1579 pDesk
->spwndTrack
&&
1580 pti
->MessageQueue
== pDesk
->spwndTrack
->head
.pti
->MessageQueue
)
1582 if ( pDesk
->htEx
!= HTCLIENT
)
1583 lpEventTrack
->dwFlags
|= TME_NONCLIENT
;
1585 if ( pDesk
->dwDTFlags
& DF_TME_LEAVE
)
1586 lpEventTrack
->dwFlags
|= TME_LEAVE
;
1588 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1590 lpEventTrack
->dwFlags
|= TME_HOVER
;
1591 lpEventTrack
->dwHoverTime
= pDesk
->dwMouseHoverTime
;
1593 lpEventTrack
->hwndTrack
= UserHMGetHandle(pDesk
->spwndTrack
);
1601 LPTRACKMOUSEEVENT lpEventTrack
)
1608 pti
= PsGetCurrentThreadWin32Thread();
1609 pDesk
= pti
->rpdesk
;
1611 if (!(pWnd
= UserGetWindowObject(lpEventTrack
->hwndTrack
)))
1614 /* Tracking spwndTrack same as pWnd */
1615 if ( lpEventTrack
->dwFlags
& TME_CANCEL
) // Canceled mode.
1617 if ( lpEventTrack
->dwFlags
& TME_LEAVE
)
1618 pDesk
->dwDTFlags
&= ~DF_TME_LEAVE
;
1620 if ( lpEventTrack
->dwFlags
& TME_HOVER
)
1622 if ( pDesk
->dwDTFlags
& DF_TME_HOVER
)
1623 { // Kill hover timer.
1624 IntKillTimer(pWnd
, ID_EVENT_SYSTIMER_MOUSEHOVER
, TRUE
);
1625 pDesk
->dwDTFlags
&= ~DF_TME_HOVER
;
1629 else // Not Canceled.
1631 pDesk
->spwndTrack
= pWnd
;
1632 if ( lpEventTrack
->dwFlags
& TME_LEAVE
)
1633 pDesk
->dwDTFlags
|= DF_TME_LEAVE
;
1635 if ( lpEventTrack
->dwFlags
& TME_HOVER
)
1637 pDesk
->dwDTFlags
|= DF_TME_HOVER
;
1639 if ( !lpEventTrack
->dwHoverTime
|| lpEventTrack
->dwHoverTime
== HOVER_DEFAULT
)
1640 pDesk
->dwMouseHoverTime
= gspv
.iMouseHoverTime
; // use the system default hover time-out.
1642 pDesk
->dwMouseHoverTime
= lpEventTrack
->dwHoverTime
;
1643 // Start timer for the hover period.
1644 IntSetTimer( pWnd
, ID_EVENT_SYSTIMER_MOUSEHOVER
, pDesk
->dwMouseHoverTime
, SystemTimerProc
, TMRF_SYSTEM
);
1645 // Get windows thread message points.
1646 point
= pWnd
->head
.pti
->ptLast
;
1647 // Set desktop mouse hover from the system default hover rectangle.
1648 RECTL_vSetRect(&pDesk
->rcMouseHover
,
1649 point
.x
- gspv
.iMouseHoverWidth
/ 2,
1650 point
.y
- gspv
.iMouseHoverHeight
/ 2,
1651 point
.x
+ gspv
.iMouseHoverWidth
/ 2,
1652 point
.y
+ gspv
.iMouseHoverHeight
/ 2);
1660 NtUserTrackMouseEvent(
1661 LPTRACKMOUSEEVENT lpEventTrack
)
1663 TRACKMOUSEEVENT saveTME
;
1666 TRACE("Enter NtUserTrackMouseEvent\n");
1667 UserEnterExclusive();
1671 ProbeForRead(lpEventTrack
, sizeof(TRACKMOUSEEVENT
), 1);
1672 RtlCopyMemory(&saveTME
, lpEventTrack
, sizeof(TRACKMOUSEEVENT
));
1674 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1676 SetLastNtError(_SEH2_GetExceptionCode());
1677 _SEH2_YIELD(goto Exit
;)
1681 if ( saveTME
.cbSize
!= sizeof(TRACKMOUSEEVENT
) )
1683 EngSetLastError(ERROR_INVALID_PARAMETER
);
1687 if (saveTME
.dwFlags
& ~(TME_CANCEL
| TME_QUERY
| TME_NONCLIENT
| TME_LEAVE
| TME_HOVER
) )
1689 EngSetLastError(ERROR_INVALID_FLAGS
);
1693 if ( saveTME
.dwFlags
& TME_QUERY
)
1695 Ret
= IntQueryTrackMouseEvent(&saveTME
);
1698 ProbeForWrite(lpEventTrack
, sizeof(TRACKMOUSEEVENT
), 1);
1699 RtlCopyMemory(lpEventTrack
, &saveTME
, sizeof(TRACKMOUSEEVENT
));
1701 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1703 SetLastNtError(_SEH2_GetExceptionCode());
1710 Ret
= IntTrackMouseEvent(&saveTME
);
1714 TRACE("Leave NtUserTrackMouseEvent, ret=%i\n", Ret
);
1719 extern MOUSEMOVEPOINT MouseHistoryOfMoves
[];
1720 extern INT gcur_count
;
1724 NtUserGetMouseMovePointsEx(
1726 LPMOUSEMOVEPOINT lpptIn
,
1727 LPMOUSEMOVEPOINT lpptOut
,
1731 MOUSEMOVEPOINT Safeppt
;
1734 DECLARE_RETURN(DWORD
);
1736 TRACE("Enter NtUserGetMouseMovePointsEx\n");
1737 UserEnterExclusive();
1739 if ((cbSize
!= sizeof(MOUSEMOVEPOINT
)) || (nBufPoints
< 0) || (nBufPoints
> 64))
1741 EngSetLastError(ERROR_INVALID_PARAMETER
);
1745 if (!lpptIn
|| (!lpptOut
&& nBufPoints
))
1747 EngSetLastError(ERROR_NOACCESS
);
1753 ProbeForRead( lpptIn
, cbSize
, 1);
1754 RtlCopyMemory(&Safeppt
, lpptIn
, cbSize
);
1756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1758 SetLastNtError(_SEH2_GetExceptionCode());
1759 _SEH2_YIELD(RETURN( -1))
1763 // http://msdn.microsoft.com/en-us/library/ms646259(v=vs.85).aspx
1764 // This explains the math issues in transforming points.
1765 Count
= gcur_count
; // FIFO is forward so retrieve backward.
1769 if (Safeppt
.x
== 0 && Safeppt
.y
== 0)
1771 // Finds the point, it returns the last nBufPoints prior to and including the supplied point.
1772 if (MouseHistoryOfMoves
[Count
].x
== Safeppt
.x
&& MouseHistoryOfMoves
[Count
].y
== Safeppt
.y
)
1774 if ( Safeppt
.time
) // Now test time and it seems to be absolute.
1776 if (Safeppt
.time
== MouseHistoryOfMoves
[Count
].time
)
1783 if (--Count
< 0) Count
= 63;
1790 if (--Count
< 0) Count
= 63;
1792 while ( Count
!= gcur_count
);
1796 case GMMP_USE_DISPLAY_POINTS
:
1801 ProbeForWrite(lpptOut
, cbSize
, 1);
1803 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1805 SetLastNtError(_SEH2_GetExceptionCode());
1806 _SEH2_YIELD(RETURN( -1))
1812 case GMMP_USE_HIGH_RESOLUTION_POINTS
:
1815 EngSetLastError(ERROR_POINT_NOT_FOUND
);
1822 TRACE("Leave NtUserGetMouseMovePointsEx, ret=%i\n", _ret_
);