2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Window classes
5 * FILE: subsys/win32k/ntuser/class.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
;
26 PATTACHINFO gpai
= NULL
;
28 static HANDLE MouseDeviceHandle
;
29 static HANDLE MouseThreadHandle
;
30 static CLIENT_ID MouseThreadId
;
31 static HANDLE KeyboardThreadHandle
;
32 static CLIENT_ID KeyboardThreadId
;
33 static HANDLE KeyboardDeviceHandle
;
34 static HANDLE RawInputThreadHandle
;
35 static CLIENT_ID RawInputThreadId
;
36 static KEVENT InputThreadsStart
;
37 static BOOLEAN InputThreadsRunning
= FALSE
;
38 static BYTE TrackSysKey
= 0; /* determine whether ALT key up will cause a WM_SYSKEYUP
39 or a WM_KEYUP message */
41 /* FUNCTIONS *****************************************************************/
42 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
);
44 #define ClearMouseInput(mi) \
50 #define SendMouseEvent(mi) \
51 if(mi.dx != 0 || mi.dy != 0) \
52 mi.dwFlags |= MOUSEEVENTF_MOVE; \
58 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
)
60 static DWORD LastInputTick
= 0;
61 if (LastInputTickSetGet
== TRUE
)
63 LARGE_INTEGER TickCount
;
64 KeQueryTickCount(&TickCount
);
65 LastInputTick
= TickCount
.u
.LowPart
* (KeQueryTimeIncrement() / 10000);
72 NtUserGetLastInputInfo(PLASTINPUTINFO plii
)
80 if (ProbeForReadUint(&plii
->cbSize
) != sizeof(LASTINPUTINFO
))
82 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
87 ProbeForWrite(plii
, sizeof(LASTINPUTINFO
), sizeof(DWORD
));
89 plii
->dwTime
= IntLastInputTick(FALSE
);
91 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
93 SetLastNtError(_SEH2_GetExceptionCode());
105 ProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
107 PMOUSE_INPUT_DATA mid
;
114 for(i
= 0; i
< InputCount
; i
++)
120 /* Check if the mouse move is absolute */
121 if (mid
->Flags
== MOUSE_MOVE_ABSOLUTE
)
123 /* Set flag and convert to screen location */
124 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
125 mi
.dx
= mi
.dx
/ (65535 / (UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) - 1));
126 mi
.dy
= mi
.dy
/ (65535 / (UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) - 1));
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 InitializeObjectAttributes(&MouseObjectAttributes
,
216 LARGE_INTEGER DueTime
;
218 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
219 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
220 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
221 Status
= NtOpenFile(&MouseDeviceHandle
,
223 &MouseObjectAttributes
,
226 FILE_SYNCHRONOUS_IO_ALERT
);
227 } while (!NT_SUCCESS(Status
));
229 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
230 LOW_REALTIME_PRIORITY
+ 3);
235 * Wait to start input.
237 DPRINT("Mouse Input Thread Waiting for start event\n");
238 Status
= KeWaitForSingleObject(&InputThreadsStart
,
243 DPRINT("Mouse Input Thread Starting...\n");
245 /*FIXME: Does mouse attributes need to be used for anything */
246 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
251 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
252 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
254 if(!NT_SUCCESS(Status
))
256 DPRINT("Failed to get mouse attributes\n");
260 * Receive and process mouse input.
262 while(InputThreadsRunning
)
264 MOUSE_INPUT_DATA MouseInput
;
265 Status
= NtReadFile(MouseDeviceHandle
,
271 sizeof(MOUSE_INPUT_DATA
),
274 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
278 if(Status
== STATUS_PENDING
)
280 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
281 Status
= Iosb
.Status
;
283 if(!NT_SUCCESS(Status
))
285 DPRINT1("Win32K: Failed to read from mouse.\n");
288 DPRINT("MouseEvent\n");
289 IntLastInputTick(TRUE
);
291 UserEnterExclusive();
293 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
297 DPRINT("Mouse Input Thread Stopped...\n");
301 /* Returns a value that indicates if the key is a modifier key, and
305 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
307 if (InputData
->Flags
& KEY_E1
)
310 if (!(InputData
->Flags
& KEY_E0
))
312 switch (InputData
->MakeCode
)
314 case 0x2a: /* left shift */
315 case 0x36: /* right shift */
318 case 0x1d: /* left control */
321 case 0x38: /* left alt */
330 switch (InputData
->MakeCode
)
332 case 0x1d: /* right control */
335 case 0x38: /* right alt */
338 case 0x5b: /* left gui (windows) */
339 case 0x5c: /* right gui (windows) */
348 /* Asks the keyboard driver to send a small table that shows which
349 * lights should connect with which scancodes
351 static NTSTATUS APIENTRY
352 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
353 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
357 IO_STATUS_BLOCK Block
;
358 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
360 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
362 Ret
= ExAllocatePoolWithTag(PagedPool
,
368 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
373 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
377 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
380 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
382 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
384 Ret
= ExAllocatePoolWithTag(PagedPool
,
390 return STATUS_INSUFFICIENT_RESOURCES
;
392 if (Status
!= STATUS_SUCCESS
)
394 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
398 *IndicatorTrans
= Ret
;
402 /* Sends the keyboard commands to turn on/off the lights.
404 static NTSTATUS APIENTRY
405 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
406 PKEYBOARD_INPUT_DATA KeyInput
,
407 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
411 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
412 IO_STATUS_BLOCK Block
;
415 return STATUS_NOT_SUPPORTED
;
417 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
418 return STATUS_SUCCESS
;
420 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
422 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
424 Indicators
.LedFlags
^=
425 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
427 /* Update the lights on the hardware */
429 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
434 IOCTL_KEYBOARD_SET_INDICATORS
,
435 &Indicators
, sizeof(Indicators
),
442 return STATUS_SUCCESS
;
446 IntKeyboardSendWinKeyMsg()
448 PWINDOW_OBJECT Window
;
451 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
453 DPRINT1("Couldn't find window to send Windows key message!\n");
457 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
458 Mesg
.message
= WM_SYSCOMMAND
;
459 Mesg
.wParam
= SC_TASKLIST
;
462 /* The QS_HOTKEY is just a guess */
463 MsqPostMessage(Window
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
467 co_IntKeyboardSendAltKeyMsg()
469 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
473 KeyboardThreadMain(PVOID StartContext
)
475 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
476 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
477 IO_STATUS_BLOCK Iosb
;
480 PUSER_MESSAGE_QUEUE FocusQueue
;
481 struct _ETHREAD
*FocusThread
;
483 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
484 UINT ModifierState
= 0;
485 USHORT LastMakeCode
= 0;
486 USHORT LastFlags
= 0;
487 UINT RepeatCount
= 0;
489 InitializeObjectAttributes(&KeyboardObjectAttributes
,
496 LARGE_INTEGER DueTime
;
498 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
499 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
500 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
501 Status
= NtOpenFile(&KeyboardDeviceHandle
,
503 &KeyboardObjectAttributes
,
506 FILE_SYNCHRONOUS_IO_ALERT
);
507 } while (!NT_SUCCESS(Status
));
509 /* Not sure if converting this thread to a win32 thread is such
510 a great idea. Since we're posting keyboard messages to the focus
511 window message queue, we'll be (indirectly) doing sendmessage
512 stuff from this thread (for WH_KEYBOARD_LL processing), which
513 means we need our own message queue. If keyboard messages were
514 instead queued to the system message queue, the thread removing
515 the message from the system message queue would be responsible
516 for WH_KEYBOARD_LL processing and we wouldn't need this thread
517 to be a win32 thread. */
518 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
519 if (!NT_SUCCESS(Status
))
521 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
525 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
526 LOW_REALTIME_PRIORITY
+ 3);
528 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
534 * Wait to start input.
536 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
537 Status
= KeWaitForSingleObject(&InputThreadsStart
,
543 DPRINT( "Keyboard Input Thread Starting...\n" );
545 * Receive and process keyboard input.
547 while (InputThreadsRunning
)
551 KEYBOARD_INPUT_DATA KeyInput
;
552 KEYBOARD_INPUT_DATA NextKeyInput
;
554 UINT fsModifiers
, fsNextModifiers
;
555 struct _ETHREAD
*Thread
;
559 DPRINT("KeyInput @ %08x\n", &KeyInput
);
561 Status
= NtReadFile (KeyboardDeviceHandle
,
567 sizeof(KEYBOARD_INPUT_DATA
),
571 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
575 if(Status
== STATUS_PENDING
)
577 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
578 Status
= Iosb
.Status
;
580 if(!NT_SUCCESS(Status
))
582 DPRINT1("Win32K: Failed to read from mouse.\n");
586 DPRINT("KeyRaw: %s %04x\n",
587 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
590 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
593 if (!NT_SUCCESS(Status
))
595 DPRINT1("Win32K: Failed to read from keyboard.\n");
599 /* Set LastInputTick */
600 IntLastInputTick(TRUE
);
602 /* Update modifier state */
603 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
607 if (KeyInput
.Flags
& KEY_BREAK
)
609 ModifierState
&= ~fsModifiers
;
610 if(fsModifiers
== MOD_ALT
)
612 if(KeyInput
.Flags
& KEY_E0
)
614 gQueueKeyStateTable
[VK_RMENU
] = 0;
618 gQueueKeyStateTable
[VK_LMENU
] = 0;
620 if (gQueueKeyStateTable
[VK_RMENU
] == 0 &&
621 gQueueKeyStateTable
[VK_LMENU
] == 0)
623 gQueueKeyStateTable
[VK_MENU
] = 0;
629 ModifierState
|= fsModifiers
;
631 if (ModifierState
== fsModifiers
&&
632 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
634 /* First send out special notifications
635 * (For alt, the message that turns on accelerator
636 * display, not sure what for win. Both TODO though.)
639 if(fsModifiers
== MOD_ALT
)
641 if(KeyInput
.Flags
& KEY_E0
)
643 gQueueKeyStateTable
[VK_RMENU
] = 0x80;
647 gQueueKeyStateTable
[VK_LMENU
] = 0x80;
651 gQueueKeyStateTable
[VK_MENU
] = 0x80;
654 /* Read the next key before sending this one */
657 Status
= NtReadFile (KeyboardDeviceHandle
,
663 sizeof(KEYBOARD_INPUT_DATA
),
666 DPRINT("KeyRaw: %s %04x\n",
667 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
668 NextKeyInput
.MakeCode
);
670 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
674 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
675 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
676 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
677 * code. I'm not caring about the counting, not sure
678 * if that matters. I think not.
681 /* If the ModifierState is now empty again, send a
682 * special notification and eat both keypresses
685 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
688 ModifierState
^= fsNextModifiers
;
690 if (ModifierState
== 0)
692 if (fsModifiers
== MOD_WIN
)
693 IntKeyboardSendWinKeyMsg();
694 else if (fsModifiers
== MOD_ALT
)
696 gQueueKeyStateTable
[VK_MENU
] = 0;
699 gQueueKeyStateTable
[VK_LMENU
] = 0;
703 gQueueKeyStateTable
[VK_RMENU
] = 0;
705 co_IntKeyboardSendAltKeyMsg();
715 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
720 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
724 /* While we are working, we set up lParam. The format is:
725 * 0-15: The number of times this key has autorepeated
726 * 16-23: The keyboard scancode
727 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
728 * Note that E1 is only used for PAUSE (E1-1D-45) and
729 * E0-45 happens not to be anything.
730 * 29: Alt is pressed ('Context code')
731 * 30: Previous state, if the key was down before this message
732 * This is a cheap way to ignore autorepeat keys
733 * 31: 1 if the key is being pressed
736 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
737 * and it's the same key as the last one, increase the repeat
741 if (!(KeyInput
.Flags
& KEY_BREAK
))
743 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
744 (KeyInput
.MakeCode
== LastMakeCode
))
752 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
753 LastMakeCode
= KeyInput
.MakeCode
;
759 LastMakeCode
= 0; /* Should never match */
760 lParam
|= (1 << 30) | (1 << 31);
763 lParam
|= RepeatCount
;
765 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
767 if (KeyInput
.Flags
& KEY_E0
)
770 if (ModifierState
& MOD_ALT
)
774 if (!(KeyInput
.Flags
& KEY_BREAK
))
775 msg
.message
= WM_SYSKEYDOWN
;
777 msg
.message
= WM_SYSKEYUP
;
781 if (!(KeyInput
.Flags
& KEY_BREAK
))
782 msg
.message
= WM_KEYDOWN
;
784 msg
.message
= WM_KEYUP
;
787 /* Find the target thread whose locale is in effect */
788 FocusQueue
= IntGetFocusMessageQueue();
790 /* This might cause us to lose hot keys, which are important
791 * (ctrl-alt-del secure attention sequence). Not sure if it
798 msg
.hwnd
= FocusQueue
->FocusWindow
;
800 FocusThread
= FocusQueue
->Thread
;
802 if (!(FocusThread
&& FocusThread
->Tcb
.Win32Thread
&&
803 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
))
806 /* This function uses lParam to fill wParam according to the
807 * keyboard layout in use.
809 W32kKeyProcessMessage(&msg
,
810 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
->KBTables
,
811 KeyInput
.Flags
& KEY_E0
? 0xE0 :
812 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
814 if (GetHotKey(ModifierState
,
820 if (!(KeyInput
.Flags
& KEY_BREAK
))
822 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
823 MsqPostHotKeyMessage (Thread
,
826 MAKELPARAM((WORD
)ModifierState
,
829 continue; /* Eat key up motion too */
833 * Post a keyboard message.
835 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
840 DPRINT( "KeyboardInput Thread Stopped...\n" );
845 static PVOID Objects
[2];
848 Since this relies on InputThreadsStart, just fake it.
851 RawInputThreadMain(PVOID StartContext
)
854 LARGE_INTEGER DueTime
;
856 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
861 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
862 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
863 } while (!NT_SUCCESS(Status
));
866 Objects
[0] = &InputThreadsStart
;
868 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), TAG_INPUT
);
871 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
874 KeInitializeTimer(MasterTimer
);
875 Objects
[1] = MasterTimer
;
877 // This thread requires win32k!
878 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
879 if (!NT_SUCCESS(Status
))
881 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
885 ptiRawInput
= PsGetCurrentThreadWin32Thread();
886 DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput
);
889 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
890 LOW_REALTIME_PRIORITY
+ 3);
892 UserEnterExclusive();
897 // ATM, we just have one job to handle, merge the other two later.
901 DPRINT( "Raw Input Thread Waiting for start event\n" );
903 Status
= KeWaitForMultipleObjects( 2,
911 DPRINT( "Raw Input Thread Starting...\n" );
915 DPRINT1("Raw Input Thread Exit!\n");
923 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
925 /* Initialize the default keyboard layout */
926 if(!UserInitDefaultKeyboardLayout())
928 DPRINT1("Failed to initialize default keyboard layout!\n");
931 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
938 if (!NT_SUCCESS(Status
))
940 DPRINT1("Win32K: Failed to create raw thread.\n");
943 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
950 if (!NT_SUCCESS(Status
))
952 DPRINT1("Win32K: Failed to create keyboard thread.\n");
955 Status
= PsCreateSystemThread(&MouseThreadHandle
,
962 if (!NT_SUCCESS(Status
))
964 DPRINT1("Win32K: Failed to create mouse thread.\n");
967 InputThreadsRunning
= TRUE
;
968 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
970 return STATUS_SUCCESS
;
974 CleanupInputImp(VOID
)
976 return(STATUS_SUCCESS
);
983 POINT pt
) // Just like the User call.
990 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
992 PTHREADINFO OldBlock
;
995 if(!W32Thread
->Desktop
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
998 * fail blocking if exiting the thread
1005 * FIXME - check access rights of the window station
1006 * e.g. services running in the service window station cannot block input
1008 if(!ThreadHasInputAccess(W32Thread
) ||
1009 !IntIsActiveDesktop(W32Thread
->Desktop
))
1011 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1015 ASSERT(W32Thread
->Desktop
);
1016 OldBlock
= W32Thread
->Desktop
->BlockInputThread
;
1019 if(OldBlock
!= W32Thread
)
1021 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1024 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1025 return OldBlock
== NULL
;
1028 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1029 return OldBlock
== NULL
;
1037 DECLARE_RETURN(BOOLEAN
);
1039 DPRINT("Enter NtUserBlockInput\n");
1040 UserEnterExclusive();
1042 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1045 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1051 IntMouseInput(MOUSEINPUT
*mi
)
1053 const UINT SwapBtnMsg
[2][2] =
1056 WM_LBUTTONDOWN
, WM_RBUTTONDOWN
1058 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1060 const WPARAM SwapBtn
[2] =
1062 MK_LBUTTON
, MK_RBUTTON
1064 POINT MousePos
= {0}, OrgPos
;
1065 PSYSTEM_CURSORINFO CurInfo
;
1066 PWINSTATION_OBJECT WinSta
;
1067 BOOL DoMove
, SwapButtons
;
1072 PWINDOW_OBJECT DesktopWindow
;
1078 /* FIXME - get the screen dc from the window station or desktop */
1079 if(!(hDC
= IntGetScreenDC()))
1088 WinSta
= PsGetCurrentProcessWin32Process()->WindowStation
;
1090 /* FIXME - ugly hack but as long as we're using this dumb callback from the
1091 mouse class driver, we can't access the window station from the calling
1093 WinSta
= InputWindowStation
;
1098 CurInfo
= IntGetSysCursorInfo(WinSta
);
1102 LARGE_INTEGER LargeTickCount
;
1103 KeQueryTickCount(&LargeTickCount
);
1104 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1107 SwapButtons
= gspv
.bMouseBtnSwap
;
1110 IntGetCursorLocation(WinSta
, &MousePos
);
1111 OrgPos
.x
= MousePos
.x
;
1112 OrgPos
.y
= MousePos
.y
;
1114 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1116 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1118 MousePos
.x
= mi
->dx
;
1119 MousePos
.y
= mi
->dy
;
1123 MousePos
.x
+= mi
->dx
;
1124 MousePos
.y
+= mi
->dy
;
1127 DesktopWindow
= IntGetWindowObject(WinSta
->ActiveDesktop
->DesktopWindow
);
1131 if(MousePos
.x
>= DesktopWindow
->Wnd
->rcClient
.right
)
1132 MousePos
.x
= DesktopWindow
->Wnd
->rcClient
.right
- 1;
1133 if(MousePos
.y
>= DesktopWindow
->Wnd
->rcClient
.bottom
)
1134 MousePos
.y
= DesktopWindow
->Wnd
->rcClient
.bottom
- 1;
1135 UserDereferenceObject(DesktopWindow
);
1143 if(CurInfo
->CursorClipInfo
.IsClipped
)
1145 /* The mouse cursor needs to be clipped */
1147 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
1148 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
1149 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
1150 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
1151 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
1152 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
1153 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
1154 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
1157 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
1162 dc
= DC_LockDc(hDC
);
1165 psurf
= dc
->dclevel
.pSurface
;
1168 pso
= &psurf
->SurfObj
;
1170 if (CurInfo
->ShowingCursor
)
1172 IntEngMovePointer(pso
, MousePos
.x
, MousePos
.y
, &(GDIDEV(pso
)->Pointer
.Exclude
));
1174 /* Only now, update the info in the PDEVOBJ, so EngMovePointer can
1175 * use the old values to move the pointer image */
1176 gpsi
->ptCursor
.x
= MousePos
.x
;
1177 gpsi
->ptCursor
.y
= MousePos
.y
;
1185 * Insert the messages into the system queue
1188 Msg
.wParam
= CurInfo
->ButtonsDown
;
1189 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1192 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1194 Msg
.wParam
|= MK_SHIFT
;
1197 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1199 Msg
.wParam
|= MK_CONTROL
;
1204 Msg
.message
= WM_MOUSEMOVE
;
1205 MsqInsertSystemMessage(&Msg
);
1209 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1211 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1212 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1213 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1214 MsqInsertSystemMessage(&Msg
);
1216 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1218 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1219 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1220 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1221 MsqInsertSystemMessage(&Msg
);
1223 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1225 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1226 Msg
.message
= WM_MBUTTONDOWN
;
1227 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1228 MsqInsertSystemMessage(&Msg
);
1230 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1232 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1233 Msg
.message
= WM_MBUTTONUP
;
1234 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1235 MsqInsertSystemMessage(&Msg
);
1237 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1239 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1240 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1241 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1242 MsqInsertSystemMessage(&Msg
);
1244 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1246 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1247 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1248 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1249 MsqInsertSystemMessage(&Msg
);
1252 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1253 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1255 /* fail because both types of events use the mouseData field */
1259 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1261 Msg
.message
= WM_XBUTTONDOWN
;
1262 if(mi
->mouseData
& XBUTTON1
)
1264 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1265 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1266 CurInfo
->ButtonsDown
|= XBUTTON1
;
1267 MsqInsertSystemMessage(&Msg
);
1269 if(mi
->mouseData
& XBUTTON2
)
1271 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1272 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1273 CurInfo
->ButtonsDown
|= XBUTTON2
;
1274 MsqInsertSystemMessage(&Msg
);
1277 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1279 Msg
.message
= WM_XBUTTONUP
;
1280 if(mi
->mouseData
& XBUTTON1
)
1282 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1283 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1284 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1285 MsqInsertSystemMessage(&Msg
);
1287 if(mi
->mouseData
& XBUTTON2
)
1289 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1290 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1291 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1292 MsqInsertSystemMessage(&Msg
);
1295 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1297 Msg
.message
= WM_MOUSEWHEEL
;
1298 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1299 MsqInsertSystemMessage(&Msg
);
1306 IntKeyboardInput(KEYBDINPUT
*ki
)
1308 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1311 LARGE_INTEGER LargeTickCount
;
1312 KBDLLHOOKSTRUCT KbdHookData
;
1313 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1314 BOOLEAN Entered
= FALSE
;
1318 // Condition may arise when calling MsqPostMessage and waiting for an event.
1319 if (!UserIsEntered())
1321 // Fixme: Not sure ATM if this thread is locked.
1322 UserEnterExclusive();
1328 flags
= LOBYTE(ki
->wScan
);
1330 if (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1331 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1333 /* strip left/right for menu, control, shift */
1339 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1340 wVkStripped
= VK_MENU
;
1347 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1348 wVkStripped
= VK_CONTROL
;
1355 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1356 wVkStripped
= VK_SHIFT
;
1361 wVkStripped
= wVkL
= wVkR
= wVk
;
1364 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1366 Msg
.message
= WM_KEYUP
;
1367 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80) &&
1368 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1369 || !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80)))
1371 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1372 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1373 Msg
.message
= WM_SYSKEYUP
;
1376 flags
|= KF_REPEAT
| KF_UP
;
1380 Msg
.message
= WM_KEYDOWN
;
1381 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1382 !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
))
1384 Msg
.message
= WM_SYSKEYDOWN
;
1385 TrackSysKey
= wVkStripped
;
1387 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
) && gQueueKeyStateTable
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1390 if (ki
->dwFlags
& KEYEVENTF_UNICODE
)
1392 vk_hook
= Msg
.wParam
= wVk
= VK_PACKET
;
1393 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, ki
->wScan
);
1396 FocusMessageQueue
= IntGetFocusMessageQueue();
1400 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
1401 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1405 KeQueryTickCount(&LargeTickCount
);
1406 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1409 Msg
.time
= ki
->time
;
1411 /* All messages have to contain the cursor point. */
1412 pti
= PsGetCurrentThreadWin32Thread();
1413 IntGetCursorLocation(pti
->Desktop
->WindowStation
,
1416 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1417 Msg
.message
, vk_hook
, Msg
.lParam
);
1419 KbdHookData
.vkCode
= vk_hook
;
1420 KbdHookData
.scanCode
= ki
->wScan
;
1421 KbdHookData
.flags
= flags
>> 8;
1422 KbdHookData
.time
= Msg
.time
;
1423 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1424 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1426 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1427 Msg
.message
, vk_hook
, Msg
.lParam
);
1428 if (Entered
) UserLeave();
1432 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1434 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1436 gQueueKeyStateTable
[wVk
] &= ~0x80;
1437 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1441 if (!(gQueueKeyStateTable
[wVk
] & 0x80)) gQueueKeyStateTable
[wVk
] ^= 0x01;
1442 gQueueKeyStateTable
[wVk
] |= 0xc0;
1443 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1446 if (gQueueKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1448 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1450 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1453 if (FocusMessageQueue
== NULL
)
1455 DPRINT("No focus message queue\n");
1456 if (Entered
) UserLeave();
1460 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1462 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1463 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
1465 FocusMessageQueue
->Desktop
->DesktopInfo
->LastInputWasKbd
= TRUE
;
1467 IntGetCursorLocation(FocusMessageQueue
->Desktop
->WindowStation
,
1469 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
1473 DPRINT("Invalid focus window handle\n");
1476 if (Entered
) UserLeave();
1482 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1486 /* Can not be the same thread.*/
1487 if (pti
== ptiTo
) return FALSE
;
1489 /* Do not attach to system threads or between different desktops. */
1490 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1491 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1492 pti
->Desktop
!= ptiTo
->Desktop
)
1495 /* If Attach set, allocate and link. */
1498 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), TAG_ATTACHINFO
);
1499 if ( !pai
) return FALSE
;
1501 pai
->paiNext
= gpai
;
1506 else /* If clear, unlink and free it. */
1508 PATTACHINFO paiprev
= NULL
;
1510 if ( !gpai
) return FALSE
;
1514 /* Search list and free if found or return false. */
1517 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1522 if ( !pai
) return FALSE
;
1524 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1526 ExFreePoolWithTag(pai
, TAG_ATTACHINFO
);
1539 PTHREADINFO W32Thread
;
1541 DECLARE_RETURN(UINT
);
1543 DPRINT("Enter NtUserSendInput\n");
1544 UserEnterExclusive();
1546 W32Thread
= PsGetCurrentThreadWin32Thread();
1549 if(!W32Thread
->Desktop
)
1554 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1556 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1561 * FIXME - check access rights of the window station
1562 * e.g. services running in the service window station cannot block input
1564 if(!ThreadHasInputAccess(W32Thread
) ||
1565 !IntIsActiveDesktop(W32Thread
->Desktop
))
1567 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1577 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1578 if(!NT_SUCCESS(Status
))
1580 SetLastNtError(Status
);
1584 switch(SafeInput
.type
)
1587 if(IntMouseInput(&SafeInput
.mi
))
1592 case INPUT_KEYBOARD
:
1593 if(IntKeyboardInput(&SafeInput
.ki
))
1598 case INPUT_HARDWARE
:
1603 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1613 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);