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 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 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 UserEnterExclusive();
712 if (fsModifiers
== MOD_WIN
)
713 IntKeyboardSendWinKeyMsg();
714 else if (fsModifiers
== MOD_ALT
)
716 gQueueKeyStateTable
[VK_MENU
] = 0;
719 gQueueKeyStateTable
[VK_LMENU
] = 0;
723 gQueueKeyStateTable
[VK_RMENU
] = 0;
725 co_IntKeyboardSendAltKeyMsg();
736 UserEnterExclusive();
738 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
741 PKBL keyboardLayout
= NULL
;
744 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
748 /* While we are working, we set up lParam. The format is:
749 * 0-15: The number of times this key has autorepeated
750 * 16-23: The keyboard scancode
751 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
752 * Note that E1 is only used for PAUSE (E1-1D-45) and
753 * E0-45 happens not to be anything.
754 * 29: Alt is pressed ('Context code')
755 * 30: Previous state, if the key was down before this message
756 * This is a cheap way to ignore autorepeat keys
757 * 31: 1 if the key is being pressed
760 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
761 * and it's the same key as the last one, increase the repeat
765 if (!(KeyInput
.Flags
& KEY_BREAK
))
767 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
768 (KeyInput
.MakeCode
== LastMakeCode
))
776 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
777 LastMakeCode
= KeyInput
.MakeCode
;
783 LastMakeCode
= 0; /* Should never match */
784 lParam
|= (1 << 30) | (1 << 31);
787 lParam
|= RepeatCount
;
789 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
791 if (KeyInput
.Flags
& KEY_E0
)
794 if (ModifierState
& MOD_ALT
)
798 if (!(KeyInput
.Flags
& KEY_BREAK
))
799 msg
.message
= WM_SYSKEYDOWN
;
801 msg
.message
= WM_SYSKEYUP
;
805 if (!(KeyInput
.Flags
& KEY_BREAK
))
806 msg
.message
= WM_KEYDOWN
;
808 msg
.message
= WM_KEYUP
;
811 /* Find the target thread whose locale is in effect */
812 FocusQueue
= IntGetFocusMessageQueue();
816 msg
.hwnd
= FocusQueue
->FocusWindow
;
818 FocusThread
= FocusQueue
->Thread
;
819 if (FocusThread
&& FocusThread
->Tcb
.Win32Thread
)
821 keyboardLayout
= ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
;
826 keyboardLayout
= W32kGetDefaultKeyLayout();
831 /* This function uses lParam to fill wParam according to the
832 * keyboard layout in use.
834 W32kKeyProcessMessage(&msg
,
835 keyboardLayout
->KBTables
,
836 KeyInput
.Flags
& KEY_E0
? 0xE0 :
837 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
839 if (GetHotKey(ModifierState
,
845 if (!(KeyInput
.Flags
& KEY_BREAK
))
847 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
848 MsqPostHotKeyMessage (Thread
,
851 MAKELPARAM((WORD
)ModifierState
,
854 continue; /* Eat key up motion too */
859 /* There is no focused window to receive a keyboard message */
863 * Post a keyboard message.
865 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
872 DPRINT( "KeyboardInput Thread Stopped...\n" );
877 static PVOID Objects
[2];
880 Since this relies on InputThreadsStart, just fake it.
883 RawInputThreadMain(PVOID StartContext
)
886 LARGE_INTEGER DueTime
;
888 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
893 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
894 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
895 } while (!NT_SUCCESS(Status
));
898 Objects
[0] = &InputThreadsStart
;
899 Objects
[1] = MasterTimer
;
901 // This thread requires win32k!
902 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
903 if (!NT_SUCCESS(Status
))
905 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
909 ptiRawInput
= PsGetCurrentThreadWin32Thread();
910 ptiRawInput
->TIF_flags
|= TIF_SYSTEMTHREAD
;
911 DPRINT("Raw Input Thread 0x%x \n", ptiRawInput
);
913 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
914 LOW_REALTIME_PRIORITY
+ 3);
916 UserEnterExclusive();
921 // ATM, we just have one job to handle, merge the other two later.
925 DPRINT( "Raw Input Thread Waiting for start event\n" );
927 Status
= KeWaitForMultipleObjects( 2,
935 DPRINT( "Raw Input Thread Starting...\n" );
939 DPRINT1("Raw Input Thread Exit!\n");
949 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
951 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), USERTAG_SYSTEM
);
954 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
956 return STATUS_UNSUCCESSFUL
;
958 KeInitializeTimer(MasterTimer
);
960 /* Initialize the default keyboard layout */
961 if(!UserInitDefaultKeyboardLayout())
963 DPRINT1("Failed to initialize default keyboard layout!\n");
966 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
973 if (!NT_SUCCESS(Status
))
975 DPRINT1("Win32K: Failed to create raw thread.\n");
978 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
985 if (!NT_SUCCESS(Status
))
987 DPRINT1("Win32K: Failed to create keyboard thread.\n");
990 Status
= PsCreateSystemThread(&MouseThreadHandle
,
997 if (!NT_SUCCESS(Status
))
999 DPRINT1("Win32K: Failed to create mouse thread.\n");
1002 InputThreadsRunning
= TRUE
;
1003 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
1005 return STATUS_SUCCESS
;
1009 CleanupInputImp(VOID
)
1011 return(STATUS_SUCCESS
);
1015 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
1017 PTHREADINFO OldBlock
;
1020 if(!W32Thread
->rpdesk
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
1023 * fail blocking if exiting the thread
1030 * FIXME - check access rights of the window station
1031 * e.g. services running in the service window station cannot block input
1033 if(!ThreadHasInputAccess(W32Thread
) ||
1034 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1036 EngSetLastError(ERROR_ACCESS_DENIED
);
1040 ASSERT(W32Thread
->rpdesk
);
1041 OldBlock
= W32Thread
->rpdesk
->BlockInputThread
;
1044 if(OldBlock
!= W32Thread
)
1046 EngSetLastError(ERROR_ACCESS_DENIED
);
1049 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1050 return OldBlock
== NULL
;
1053 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1054 return OldBlock
== NULL
;
1062 DECLARE_RETURN(BOOLEAN
);
1064 DPRINT("Enter NtUserBlockInput\n");
1065 UserEnterExclusive();
1067 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1070 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1076 IntMouseInput(MOUSEINPUT
*mi
)
1078 const UINT SwapBtnMsg
[2][2] =
1080 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
1081 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1083 const WPARAM SwapBtn
[2] =
1085 MK_LBUTTON
, MK_RBUTTON
1088 PSYSTEM_CURSORINFO CurInfo
;
1094 CurInfo
= IntGetSysCursorInfo();
1098 LARGE_INTEGER LargeTickCount
;
1099 KeQueryTickCount(&LargeTickCount
);
1100 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1103 SwapButtons
= gspv
.bMouseBtnSwap
;
1105 MousePos
= gpsi
->ptCursor
;
1107 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1109 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1111 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
1112 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
1116 MousePos
.x
+= mi
->dx
;
1117 MousePos
.y
+= mi
->dy
;
1122 * Insert the messages into the system queue
1125 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1128 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1130 Msg
.wParam
|= MK_SHIFT
;
1133 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1135 Msg
.wParam
|= MK_CONTROL
;
1138 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1140 UserSetCursorPos(MousePos
.x
, MousePos
.y
, TRUE
);
1142 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1144 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1145 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1146 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1147 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1148 co_MsqInsertMouseMessage(&Msg
);
1150 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1152 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1153 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1154 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1155 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1156 co_MsqInsertMouseMessage(&Msg
);
1158 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1160 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1161 Msg
.message
= WM_MBUTTONDOWN
;
1162 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1163 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1164 co_MsqInsertMouseMessage(&Msg
);
1166 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1168 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1169 Msg
.message
= WM_MBUTTONUP
;
1170 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1171 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1172 co_MsqInsertMouseMessage(&Msg
);
1174 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1176 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1177 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1178 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1179 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1180 co_MsqInsertMouseMessage(&Msg
);
1182 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1184 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1185 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1186 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1187 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1188 co_MsqInsertMouseMessage(&Msg
);
1191 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1192 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1194 /* fail because both types of events use the mouseData field */
1198 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1200 Msg
.message
= WM_XBUTTONDOWN
;
1201 if(mi
->mouseData
& XBUTTON1
)
1203 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1204 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
1205 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1206 co_MsqInsertMouseMessage(&Msg
);
1208 if(mi
->mouseData
& XBUTTON2
)
1210 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1211 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
1212 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1213 co_MsqInsertMouseMessage(&Msg
);
1216 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1218 Msg
.message
= WM_XBUTTONUP
;
1219 if(mi
->mouseData
& XBUTTON1
)
1221 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1222 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
1223 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1224 co_MsqInsertMouseMessage(&Msg
);
1226 if(mi
->mouseData
& XBUTTON2
)
1228 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1229 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
1230 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1231 co_MsqInsertMouseMessage(&Msg
);
1234 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1236 Msg
.message
= WM_MOUSEWHEEL
;
1237 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1238 co_MsqInsertMouseMessage(&Msg
);
1245 IntKeyboardInput(KEYBDINPUT
*ki
)
1247 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1249 LARGE_INTEGER LargeTickCount
;
1250 KBDLLHOOKSTRUCT KbdHookData
;
1251 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1255 // Condition may arise when calling MsqPostMessage and waiting for an event.
1256 ASSERT (UserIsEntered());
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
);
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");
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");
1408 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1412 /* Can not be the same thread.*/
1413 if (pti
== ptiTo
) return FALSE
;
1415 /* Do not attach to system threads or between different desktops. */
1416 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1417 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1418 pti
->rpdesk
!= ptiTo
->rpdesk
)
1421 /* If Attach set, allocate and link. */
1424 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), USERTAG_ATTACHINFO
);
1425 if ( !pai
) return FALSE
;
1427 pai
->paiNext
= gpai
;
1432 else /* If clear, unlink and free it. */
1434 PATTACHINFO paiprev
= NULL
;
1436 if ( !gpai
) return FALSE
;
1440 /* Search list and free if found or return false. */
1443 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1448 if ( !pai
) return FALSE
;
1450 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1452 ExFreePoolWithTag(pai
, USERTAG_ATTACHINFO
);
1465 PTHREADINFO W32Thread
;
1467 DECLARE_RETURN(UINT
);
1469 DPRINT("Enter NtUserSendInput\n");
1470 UserEnterExclusive();
1472 W32Thread
= PsGetCurrentThreadWin32Thread();
1475 if(!W32Thread
->rpdesk
)
1480 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1482 EngSetLastError(ERROR_INVALID_PARAMETER
);
1487 * FIXME - check access rights of the window station
1488 * e.g. services running in the service window station cannot block input
1490 if(!ThreadHasInputAccess(W32Thread
) ||
1491 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1493 EngSetLastError(ERROR_ACCESS_DENIED
);
1503 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1504 if(!NT_SUCCESS(Status
))
1506 SetLastNtError(Status
);
1510 switch(SafeInput
.type
)
1513 if(IntMouseInput(&SafeInput
.mi
))
1518 case INPUT_KEYBOARD
:
1519 if(IntKeyboardInput(&SafeInput
.ki
))
1524 case INPUT_HARDWARE
:
1529 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1539 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);