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; \
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 SetLastWin32Error(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
, TAG_KEYBOARD
);
397 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
399 Ret
= ExAllocatePoolWithTag(PagedPool
,
405 return STATUS_INSUFFICIENT_RESOURCES
;
407 if (Status
!= STATUS_SUCCESS
)
409 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
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 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
488 KeyboardThreadMain(PVOID StartContext
)
490 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
491 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
492 IO_STATUS_BLOCK Iosb
;
495 PUSER_MESSAGE_QUEUE FocusQueue
;
496 struct _ETHREAD
*FocusThread
;
498 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
499 UINT ModifierState
= 0;
500 USHORT LastMakeCode
= 0;
501 USHORT LastFlags
= 0;
502 UINT RepeatCount
= 0;
504 InitializeObjectAttributes(&KeyboardObjectAttributes
,
511 LARGE_INTEGER DueTime
;
513 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
514 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
515 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
516 Status
= NtOpenFile(&KeyboardDeviceHandle
,
518 &KeyboardObjectAttributes
,
521 FILE_SYNCHRONOUS_IO_ALERT
);
522 } while (!NT_SUCCESS(Status
));
524 /* Not sure if converting this thread to a win32 thread is such
525 a great idea. Since we're posting keyboard messages to the focus
526 window message queue, we'll be (indirectly) doing sendmessage
527 stuff from this thread (for WH_KEYBOARD_LL processing), which
528 means we need our own message queue. If keyboard messages were
529 instead queued to the system message queue, the thread removing
530 the message from the system message queue would be responsible
531 for WH_KEYBOARD_LL processing and we wouldn't need this thread
532 to be a win32 thread. */
533 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
540 ptiKeyboard
= PsGetCurrentThreadWin32Thread();
541 ptiKeyboard
->TIF_flags
|= TIF_SYSTEMTHREAD
;
542 DPRINT("Keyboard Thread 0x%x \n", ptiKeyboard
);
544 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
545 LOW_REALTIME_PRIORITY
+ 3);
547 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
553 * Wait to start input.
555 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
556 Status
= KeWaitForSingleObject(&InputThreadsStart
,
562 DPRINT( "Keyboard Input Thread Starting...\n" );
564 * Receive and process keyboard input.
566 while (InputThreadsRunning
)
570 KEYBOARD_INPUT_DATA KeyInput
;
571 KEYBOARD_INPUT_DATA NextKeyInput
;
573 UINT fsModifiers
, fsNextModifiers
;
574 struct _ETHREAD
*Thread
;
578 DPRINT("KeyInput @ %08x\n", &KeyInput
);
580 Status
= NtReadFile (KeyboardDeviceHandle
,
586 sizeof(KEYBOARD_INPUT_DATA
),
590 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
594 if(Status
== STATUS_PENDING
)
596 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
597 Status
= Iosb
.Status
;
599 if(!NT_SUCCESS(Status
))
601 DPRINT1("Win32K: Failed to read from mouse.\n");
605 DPRINT("KeyRaw: %s %04x\n",
606 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
609 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
612 if (!NT_SUCCESS(Status
))
614 DPRINT1("Win32K: Failed to read from keyboard.\n");
618 /* Set LastInputTick */
619 IntLastInputTick(TRUE
);
621 /* Update modifier state */
622 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
626 if (KeyInput
.Flags
& KEY_BREAK
)
628 ModifierState
&= ~fsModifiers
;
629 if(fsModifiers
== MOD_ALT
)
631 if(KeyInput
.Flags
& KEY_E0
)
633 gQueueKeyStateTable
[VK_RMENU
] = 0;
637 gQueueKeyStateTable
[VK_LMENU
] = 0;
639 if (gQueueKeyStateTable
[VK_RMENU
] == 0 &&
640 gQueueKeyStateTable
[VK_LMENU
] == 0)
642 gQueueKeyStateTable
[VK_MENU
] = 0;
648 ModifierState
|= fsModifiers
;
650 if (ModifierState
== fsModifiers
&&
651 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
653 /* First send out special notifications
654 * (For alt, the message that turns on accelerator
655 * display, not sure what for win. Both TODO though.)
658 if(fsModifiers
== MOD_ALT
)
660 if(KeyInput
.Flags
& KEY_E0
)
662 gQueueKeyStateTable
[VK_RMENU
] = 0x80;
666 gQueueKeyStateTable
[VK_LMENU
] = 0x80;
670 gQueueKeyStateTable
[VK_MENU
] = 0x80;
673 /* Read the next key before sending this one */
676 Status
= NtReadFile (KeyboardDeviceHandle
,
682 sizeof(KEYBOARD_INPUT_DATA
),
685 DPRINT("KeyRaw: %s %04x\n",
686 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
687 NextKeyInput
.MakeCode
);
689 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
693 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
694 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
695 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
696 * code. I'm not caring about the counting, not sure
697 * if that matters. I think not.
700 /* If the ModifierState is now empty again, send a
701 * special notification and eat both keypresses
704 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
707 ModifierState
^= fsNextModifiers
;
709 if (ModifierState
== 0)
711 if (fsModifiers
== MOD_WIN
)
712 IntKeyboardSendWinKeyMsg();
713 else if (fsModifiers
== MOD_ALT
)
715 gQueueKeyStateTable
[VK_MENU
] = 0;
718 gQueueKeyStateTable
[VK_LMENU
] = 0;
722 gQueueKeyStateTable
[VK_RMENU
] = 0;
724 co_IntKeyboardSendAltKeyMsg();
734 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
737 PKBL keyboardLayout
= NULL
;
740 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
744 /* While we are working, we set up lParam. The format is:
745 * 0-15: The number of times this key has autorepeated
746 * 16-23: The keyboard scancode
747 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
748 * Note that E1 is only used for PAUSE (E1-1D-45) and
749 * E0-45 happens not to be anything.
750 * 29: Alt is pressed ('Context code')
751 * 30: Previous state, if the key was down before this message
752 * This is a cheap way to ignore autorepeat keys
753 * 31: 1 if the key is being pressed
756 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
757 * and it's the same key as the last one, increase the repeat
761 if (!(KeyInput
.Flags
& KEY_BREAK
))
763 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
764 (KeyInput
.MakeCode
== LastMakeCode
))
772 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
773 LastMakeCode
= KeyInput
.MakeCode
;
779 LastMakeCode
= 0; /* Should never match */
780 lParam
|= (1 << 30) | (1 << 31);
783 lParam
|= RepeatCount
;
785 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
787 if (KeyInput
.Flags
& KEY_E0
)
790 if (ModifierState
& MOD_ALT
)
794 if (!(KeyInput
.Flags
& KEY_BREAK
))
795 msg
.message
= WM_SYSKEYDOWN
;
797 msg
.message
= WM_SYSKEYUP
;
801 if (!(KeyInput
.Flags
& KEY_BREAK
))
802 msg
.message
= WM_KEYDOWN
;
804 msg
.message
= WM_KEYUP
;
807 /* Find the target thread whose locale is in effect */
808 FocusQueue
= IntGetFocusMessageQueue();
812 msg
.hwnd
= FocusQueue
->FocusWindow
;
814 FocusThread
= FocusQueue
->Thread
;
815 if (FocusThread
&& FocusThread
->Tcb
.Win32Thread
)
817 keyboardLayout
= ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
;
822 keyboardLayout
= W32kGetDefaultKeyLayout();
827 /* This function uses lParam to fill wParam according to the
828 * keyboard layout in use.
830 W32kKeyProcessMessage(&msg
,
831 keyboardLayout
->KBTables
,
832 KeyInput
.Flags
& KEY_E0
? 0xE0 :
833 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
835 if (GetHotKey(ModifierState
,
841 if (!(KeyInput
.Flags
& KEY_BREAK
))
843 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
844 MsqPostHotKeyMessage (Thread
,
847 MAKELPARAM((WORD
)ModifierState
,
850 continue; /* Eat key up motion too */
855 /* There is no focused window to receive a keyboard message */
859 * Post a keyboard message.
861 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
866 DPRINT( "KeyboardInput Thread Stopped...\n" );
871 static PVOID Objects
[2];
874 Since this relies on InputThreadsStart, just fake it.
877 RawInputThreadMain(PVOID StartContext
)
880 LARGE_INTEGER DueTime
;
882 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
887 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
888 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
889 } while (!NT_SUCCESS(Status
));
892 Objects
[0] = &InputThreadsStart
;
893 Objects
[1] = MasterTimer
;
895 // This thread requires win32k!
896 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
897 if (!NT_SUCCESS(Status
))
899 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
903 ptiRawInput
= PsGetCurrentThreadWin32Thread();
904 ptiRawInput
->TIF_flags
|= TIF_SYSTEMTHREAD
;
905 DPRINT("Raw Input Thread 0x%x \n", ptiRawInput
);
907 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
908 LOW_REALTIME_PRIORITY
+ 3);
910 UserEnterExclusive();
915 // ATM, we just have one job to handle, merge the other two later.
919 DPRINT( "Raw Input Thread Waiting for start event\n" );
921 Status
= KeWaitForMultipleObjects( 2,
929 DPRINT( "Raw Input Thread Starting...\n" );
933 DPRINT1("Raw Input Thread Exit!\n");
943 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
945 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), TAG_INPUT
);
948 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
950 return STATUS_UNSUCCESSFUL
;
952 KeInitializeTimer(MasterTimer
);
954 /* Initialize the default keyboard layout */
955 if(!UserInitDefaultKeyboardLayout())
957 DPRINT1("Failed to initialize default keyboard layout!\n");
960 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
967 if (!NT_SUCCESS(Status
))
969 DPRINT1("Win32K: Failed to create raw thread.\n");
972 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
979 if (!NT_SUCCESS(Status
))
981 DPRINT1("Win32K: Failed to create keyboard thread.\n");
984 Status
= PsCreateSystemThread(&MouseThreadHandle
,
991 if (!NT_SUCCESS(Status
))
993 DPRINT1("Win32K: Failed to create mouse thread.\n");
996 InputThreadsRunning
= TRUE
;
997 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
999 return STATUS_SUCCESS
;
1003 CleanupInputImp(VOID
)
1005 return(STATUS_SUCCESS
);
1009 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
1011 PTHREADINFO OldBlock
;
1014 if(!W32Thread
->rpdesk
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
1017 * fail blocking if exiting the thread
1024 * FIXME - check access rights of the window station
1025 * e.g. services running in the service window station cannot block input
1027 if(!ThreadHasInputAccess(W32Thread
) ||
1028 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1030 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1034 ASSERT(W32Thread
->rpdesk
);
1035 OldBlock
= W32Thread
->rpdesk
->BlockInputThread
;
1038 if(OldBlock
!= W32Thread
)
1040 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1043 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1044 return OldBlock
== NULL
;
1047 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1048 return OldBlock
== NULL
;
1056 DECLARE_RETURN(BOOLEAN
);
1058 DPRINT("Enter NtUserBlockInput\n");
1059 UserEnterExclusive();
1061 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1064 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1070 IntMouseInput(MOUSEINPUT
*mi
)
1072 const UINT SwapBtnMsg
[2][2] =
1074 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
1075 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1077 const WPARAM SwapBtn
[2] =
1079 MK_LBUTTON
, MK_RBUTTON
1082 PSYSTEM_CURSORINFO CurInfo
;
1088 CurInfo
= IntGetSysCursorInfo();
1092 LARGE_INTEGER LargeTickCount
;
1093 KeQueryTickCount(&LargeTickCount
);
1094 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1097 SwapButtons
= gspv
.bMouseBtnSwap
;
1099 MousePos
= gpsi
->ptCursor
;
1101 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1103 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1105 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
1106 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
1110 MousePos
.x
+= mi
->dx
;
1111 MousePos
.y
+= mi
->dy
;
1116 * Insert the messages into the system queue
1119 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1122 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1124 Msg
.wParam
|= MK_SHIFT
;
1127 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1129 Msg
.wParam
|= MK_CONTROL
;
1132 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1134 UserSetCursorPos(MousePos
.x
, MousePos
.y
, TRUE
);
1136 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1138 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1139 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1140 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1141 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1142 co_MsqInsertMouseMessage(&Msg
);
1144 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1146 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1147 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1148 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1149 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1150 co_MsqInsertMouseMessage(&Msg
);
1152 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1154 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1155 Msg
.message
= WM_MBUTTONDOWN
;
1156 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1157 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1158 co_MsqInsertMouseMessage(&Msg
);
1160 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1162 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1163 Msg
.message
= WM_MBUTTONUP
;
1164 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1165 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1166 co_MsqInsertMouseMessage(&Msg
);
1168 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1170 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1171 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1172 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1173 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1174 co_MsqInsertMouseMessage(&Msg
);
1176 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1178 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1179 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1180 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1181 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1182 co_MsqInsertMouseMessage(&Msg
);
1185 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1186 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1188 /* fail because both types of events use the mouseData field */
1192 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1194 Msg
.message
= WM_XBUTTONDOWN
;
1195 if(mi
->mouseData
& XBUTTON1
)
1197 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1198 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
1199 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1200 co_MsqInsertMouseMessage(&Msg
);
1202 if(mi
->mouseData
& XBUTTON2
)
1204 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1205 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
1206 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1207 co_MsqInsertMouseMessage(&Msg
);
1210 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1212 Msg
.message
= WM_XBUTTONUP
;
1213 if(mi
->mouseData
& XBUTTON1
)
1215 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1216 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
1217 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1218 co_MsqInsertMouseMessage(&Msg
);
1220 if(mi
->mouseData
& XBUTTON2
)
1222 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1223 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
1224 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1225 co_MsqInsertMouseMessage(&Msg
);
1228 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1230 Msg
.message
= WM_MOUSEWHEEL
;
1231 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1232 co_MsqInsertMouseMessage(&Msg
);
1239 IntKeyboardInput(KEYBDINPUT
*ki
)
1241 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1243 LARGE_INTEGER LargeTickCount
;
1244 KBDLLHOOKSTRUCT KbdHookData
;
1245 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1246 BOOLEAN Entered
= FALSE
;
1250 // Condition may arise when calling MsqPostMessage and waiting for an event.
1251 if (!UserIsEntered())
1253 // Fixme: Not sure ATM if this thread is locked.
1254 UserEnterExclusive();
1260 flags
= LOBYTE(ki
->wScan
);
1262 if (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1263 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1265 /* strip left/right for menu, control, shift */
1271 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1272 wVkStripped
= VK_MENU
;
1279 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1280 wVkStripped
= VK_CONTROL
;
1287 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1288 wVkStripped
= VK_SHIFT
;
1293 wVkStripped
= wVkL
= wVkR
= wVk
;
1296 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1298 Msg
.message
= WM_KEYUP
;
1299 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80) &&
1300 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1301 || !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80)))
1303 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1304 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1305 Msg
.message
= WM_SYSKEYUP
;
1308 flags
|= KF_REPEAT
| KF_UP
;
1312 Msg
.message
= WM_KEYDOWN
;
1313 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1314 !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
))
1316 Msg
.message
= WM_SYSKEYDOWN
;
1317 TrackSysKey
= wVkStripped
;
1319 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
) && gQueueKeyStateTable
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1322 if (ki
->dwFlags
& KEYEVENTF_UNICODE
)
1324 vk_hook
= Msg
.wParam
= wVk
= VK_PACKET
;
1325 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, ki
->wScan
);
1328 FocusMessageQueue
= IntGetFocusMessageQueue();
1332 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
1333 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1337 KeQueryTickCount(&LargeTickCount
);
1338 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1341 Msg
.time
= ki
->time
;
1343 /* All messages have to contain the cursor point. */
1344 Msg
.pt
= gpsi
->ptCursor
;
1346 KbdHookData
.vkCode
= vk_hook
;
1347 KbdHookData
.scanCode
= ki
->wScan
;
1348 KbdHookData
.flags
= flags
>> 8;
1349 KbdHookData
.time
= Msg
.time
;
1350 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1351 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1353 DPRINT1("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1354 Msg
.message
, vk_hook
, Msg
.lParam
);
1355 if (Entered
) UserLeave();
1359 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1361 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1363 gQueueKeyStateTable
[wVk
] &= ~0x80;
1364 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1368 if (!(gQueueKeyStateTable
[wVk
] & 0x80)) gQueueKeyStateTable
[wVk
] ^= 0x01;
1369 gQueueKeyStateTable
[wVk
] |= 0xc0;
1370 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1373 if (gQueueKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1375 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1377 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1380 if (FocusMessageQueue
== NULL
)
1382 DPRINT("No focus message queue\n");
1383 if (Entered
) UserLeave();
1387 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1389 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1390 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
1392 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
1394 Msg
.pt
= gpsi
->ptCursor
;
1395 // Post to hardware queue, based on the first part of wine "some GetMessage tests"
1396 // in test_PeekMessage()
1397 MsqPostMessage(FocusMessageQueue
, &Msg
, TRUE
, QS_KEY
);
1401 DPRINT("Invalid focus window handle\n");
1404 if (Entered
) UserLeave();
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
), TAG_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
, TAG_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 SetLastWin32Error(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 SetLastWin32Error(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
))
1520 case INPUT_KEYBOARD
:
1521 if(IntKeyboardInput(&SafeInput
.ki
))
1526 case INPUT_HARDWARE
:
1531 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1541 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);