2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
38 extern BYTE gQueueKeyStateTable
[];
39 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
41 /* GLOBALS *******************************************************************/
43 PTHREADINFO ptiRawInput
;
46 static HANDLE MouseDeviceHandle
;
47 static HANDLE MouseThreadHandle
;
48 static CLIENT_ID MouseThreadId
;
49 static HANDLE KeyboardThreadHandle
;
50 static CLIENT_ID KeyboardThreadId
;
51 static HANDLE KeyboardDeviceHandle
;
52 static HANDLE RawInputThreadHandle
;
53 static CLIENT_ID RawInputThreadId
;
54 static KEVENT InputThreadsStart
;
55 static BOOLEAN InputThreadsRunning
= FALSE
;
57 /* FUNCTIONS *****************************************************************/
58 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
);
60 #define ClearMouseInput(mi) \
66 #define SendMouseEvent(mi) \
67 if(mi.dx != 0 || mi.dy != 0) \
68 mi.dwFlags |= MOUSEEVENTF_MOVE; \
74 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
)
76 static DWORD LastInputTick
= 0;
77 if (LastInputTickSetGet
== TRUE
)
79 LARGE_INTEGER TickCount
;
80 KeQueryTickCount(&TickCount
);
81 LastInputTick
= TickCount
.u
.LowPart
* (KeQueryTimeIncrement() / 10000);
88 NtUserGetLastInputInfo(PLASTINPUTINFO plii
)
96 if (ProbeForReadUint(&plii
->cbSize
) != sizeof(LASTINPUTINFO
))
98 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
103 ProbeForWrite(plii
, sizeof(LASTINPUTINFO
), sizeof(DWORD
));
105 plii
->dwTime
= IntLastInputTick(FALSE
);
107 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
109 SetLastNtError(_SEH2_GetExceptionCode());
121 ProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
123 PMOUSE_INPUT_DATA mid
;
130 for(i
= 0; i
< InputCount
; i
++)
136 /* Check if the mouse move is absolute */
137 if (mid
->Flags
== MOUSE_MOVE_ABSOLUTE
)
139 /* Set flag and convert to screen location */
140 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
141 mi
.dx
= mi
.dx
/ (65535 / (UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) - 1));
142 mi
.dy
= mi
.dy
/ (65535 / (UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) - 1));
147 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
149 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
152 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
154 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
157 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
159 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
162 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
164 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
167 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
169 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
172 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
174 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
177 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
179 mi
.mouseData
|= XBUTTON1
;
180 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
183 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
185 mi
.mouseData
|= XBUTTON1
;
186 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
189 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
191 mi
.mouseData
|= XBUTTON2
;
192 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
195 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
197 mi
.mouseData
|= XBUTTON2
;
198 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
201 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
203 mi
.mouseData
= mid
->ButtonData
;
204 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
217 MouseThreadMain(PVOID StartContext
)
219 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
220 OBJECT_ATTRIBUTES MouseObjectAttributes
;
221 IO_STATUS_BLOCK Iosb
;
223 MOUSE_ATTRIBUTES MouseAttr
;
225 InitializeObjectAttributes(&MouseObjectAttributes
,
232 LARGE_INTEGER DueTime
;
234 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
235 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
236 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
237 Status
= NtOpenFile(&MouseDeviceHandle
,
239 &MouseObjectAttributes
,
242 FILE_SYNCHRONOUS_IO_ALERT
);
243 } while (!NT_SUCCESS(Status
));
245 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
246 LOW_REALTIME_PRIORITY
+ 3);
251 * Wait to start input.
253 DPRINT("Mouse Input Thread Waiting for start event\n");
254 Status
= KeWaitForSingleObject(&InputThreadsStart
,
259 DPRINT("Mouse Input Thread Starting...\n");
261 /*FIXME: Does mouse attributes need to be used for anything */
262 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
267 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
268 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
270 if(!NT_SUCCESS(Status
))
272 DPRINT("Failed to get mouse attributes\n");
276 * Receive and process mouse input.
278 while(InputThreadsRunning
)
280 MOUSE_INPUT_DATA MouseInput
;
281 Status
= NtReadFile(MouseDeviceHandle
,
287 sizeof(MOUSE_INPUT_DATA
),
290 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
294 if(Status
== STATUS_PENDING
)
296 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
297 Status
= Iosb
.Status
;
299 if(!NT_SUCCESS(Status
))
301 DPRINT1("Win32K: Failed to read from mouse.\n");
304 DPRINT("MouseEvent\n");
305 IntLastInputTick(TRUE
);
307 UserEnterExclusive();
309 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
313 DPRINT("Mouse Input Thread Stopped...\n");
317 /* Returns a value that indicates if the key is a modifier key, and
321 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
323 if (InputData
->Flags
& KEY_E1
)
326 if (!(InputData
->Flags
& KEY_E0
))
328 switch (InputData
->MakeCode
)
330 case 0x2a: /* left shift */
331 case 0x36: /* right shift */
334 case 0x1d: /* left control */
337 case 0x38: /* left alt */
346 switch (InputData
->MakeCode
)
348 case 0x1d: /* right control */
351 case 0x38: /* right alt */
354 case 0x5b: /* left gui (windows) */
355 case 0x5c: /* right gui (windows) */
364 /* Asks the keyboard driver to send a small table that shows which
365 * lights should connect with which scancodes
367 static NTSTATUS APIENTRY
368 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
369 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
373 IO_STATUS_BLOCK Block
;
374 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
376 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
378 Ret
= ExAllocatePoolWithTag(PagedPool
,
384 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
389 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
393 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
396 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
398 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
400 Ret
= ExAllocatePoolWithTag(PagedPool
,
406 return STATUS_INSUFFICIENT_RESOURCES
;
408 if (Status
!= STATUS_SUCCESS
)
410 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
414 *IndicatorTrans
= Ret
;
418 /* Sends the keyboard commands to turn on/off the lights.
420 static NTSTATUS APIENTRY
421 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
422 PKEYBOARD_INPUT_DATA KeyInput
,
423 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
427 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
428 IO_STATUS_BLOCK Block
;
431 return STATUS_NOT_SUPPORTED
;
433 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
434 return STATUS_SUCCESS
;
436 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
438 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
440 Indicators
.LedFlags
^=
441 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
443 /* Update the lights on the hardware */
445 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
450 IOCTL_KEYBOARD_SET_INDICATORS
,
451 &Indicators
, sizeof(Indicators
),
458 return STATUS_SUCCESS
;
462 IntKeyboardSendWinKeyMsg()
464 PWINDOW_OBJECT Window
;
467 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
469 DPRINT1("Couldn't find window to send Windows key message!\n");
473 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
474 Mesg
.message
= WM_SYSCOMMAND
;
475 Mesg
.wParam
= SC_TASKLIST
;
478 /* The QS_HOTKEY is just a guess */
479 MsqPostMessage(Window
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
483 co_IntKeyboardSendAltKeyMsg()
485 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
489 KeyboardThreadMain(PVOID StartContext
)
491 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
492 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
493 IO_STATUS_BLOCK Iosb
;
496 PUSER_MESSAGE_QUEUE FocusQueue
;
497 struct _ETHREAD
*FocusThread
;
499 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
500 UINT ModifierState
= 0;
501 USHORT LastMakeCode
= 0;
502 USHORT LastFlags
= 0;
503 UINT RepeatCount
= 0;
505 InitializeObjectAttributes(&KeyboardObjectAttributes
,
512 LARGE_INTEGER DueTime
;
514 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
515 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
516 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
517 Status
= NtOpenFile(&KeyboardDeviceHandle
,
519 &KeyboardObjectAttributes
,
522 FILE_SYNCHRONOUS_IO_ALERT
);
523 } while (!NT_SUCCESS(Status
));
525 /* Not sure if converting this thread to a win32 thread is such
526 a great idea. Since we're posting keyboard messages to the focus
527 window message queue, we'll be (indirectly) doing sendmessage
528 stuff from this thread (for WH_KEYBOARD_LL processing), which
529 means we need our own message queue. If keyboard messages were
530 instead queued to the system message queue, the thread removing
531 the message from the system message queue would be responsible
532 for WH_KEYBOARD_LL processing and we wouldn't need this thread
533 to be a win32 thread. */
534 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
535 if (!NT_SUCCESS(Status
))
537 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
541 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
542 LOW_REALTIME_PRIORITY
+ 3);
544 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
550 * Wait to start input.
552 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
553 Status
= KeWaitForSingleObject(&InputThreadsStart
,
559 DPRINT( "Keyboard Input Thread Starting...\n" );
561 * Receive and process keyboard input.
563 while (InputThreadsRunning
)
567 KEYBOARD_INPUT_DATA KeyInput
;
568 KEYBOARD_INPUT_DATA NextKeyInput
;
570 UINT fsModifiers
, fsNextModifiers
;
571 struct _ETHREAD
*Thread
;
575 DPRINT("KeyInput @ %08x\n", &KeyInput
);
577 Status
= NtReadFile (KeyboardDeviceHandle
,
583 sizeof(KEYBOARD_INPUT_DATA
),
587 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
591 if(Status
== STATUS_PENDING
)
593 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
594 Status
= Iosb
.Status
;
596 if(!NT_SUCCESS(Status
))
598 DPRINT1("Win32K: Failed to read from mouse.\n");
602 DPRINT("KeyRaw: %s %04x\n",
603 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
606 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
609 if (!NT_SUCCESS(Status
))
611 DPRINT1("Win32K: Failed to read from keyboard.\n");
615 /* Set LastInputTick */
616 IntLastInputTick(TRUE
);
618 /* Update modifier state */
619 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
623 if (KeyInput
.Flags
& KEY_BREAK
)
625 ModifierState
&= ~fsModifiers
;
626 if(fsModifiers
== MOD_ALT
)
628 if(KeyInput
.Flags
& KEY_E0
)
630 gQueueKeyStateTable
[VK_RMENU
] = 0;
634 gQueueKeyStateTable
[VK_LMENU
] = 0;
636 if (gQueueKeyStateTable
[VK_RMENU
] == 0 &&
637 gQueueKeyStateTable
[VK_LMENU
] == 0)
639 gQueueKeyStateTable
[VK_MENU
] = 0;
645 ModifierState
|= fsModifiers
;
647 if (ModifierState
== fsModifiers
&&
648 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
650 /* First send out special notifications
651 * (For alt, the message that turns on accelerator
652 * display, not sure what for win. Both TODO though.)
655 if(fsModifiers
== MOD_ALT
)
657 if(KeyInput
.Flags
& KEY_E0
)
659 gQueueKeyStateTable
[VK_RMENU
] = 0x80;
663 gQueueKeyStateTable
[VK_LMENU
] = 0x80;
667 gQueueKeyStateTable
[VK_MENU
] = 0x80;
670 /* Read the next key before sending this one */
673 Status
= NtReadFile (KeyboardDeviceHandle
,
679 sizeof(KEYBOARD_INPUT_DATA
),
682 DPRINT("KeyRaw: %s %04x\n",
683 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
684 NextKeyInput
.MakeCode
);
686 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
690 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
691 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
692 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
693 * code. I'm not caring about the counting, not sure
694 * if that matters. I think not.
697 /* If the ModifierState is now empty again, send a
698 * special notification and eat both keypresses
701 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
704 ModifierState
^= fsNextModifiers
;
706 if (ModifierState
== 0)
708 if (fsModifiers
== MOD_WIN
)
709 IntKeyboardSendWinKeyMsg();
710 else if (fsModifiers
== MOD_ALT
)
712 gQueueKeyStateTable
[VK_MENU
] = 0;
715 gQueueKeyStateTable
[VK_LMENU
] = 0;
719 gQueueKeyStateTable
[VK_RMENU
] = 0;
721 co_IntKeyboardSendAltKeyMsg();
731 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
736 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
740 /* While we are working, we set up lParam. The format is:
741 * 0-15: The number of times this key has autorepeated
742 * 16-23: The keyboard scancode
743 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
744 * Note that E1 is only used for PAUSE (E1-1D-45) and
745 * E0-45 happens not to be anything.
746 * 29: Alt is pressed ('Context code')
747 * 30: Previous state, if the key was down before this message
748 * This is a cheap way to ignore autorepeat keys
749 * 31: 1 if the key is being pressed
752 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
753 * and it's the same key as the last one, increase the repeat
757 if (!(KeyInput
.Flags
& KEY_BREAK
))
759 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
760 (KeyInput
.MakeCode
== LastMakeCode
))
768 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
769 LastMakeCode
= KeyInput
.MakeCode
;
775 LastMakeCode
= 0; /* Should never match */
776 lParam
|= (1 << 30) | (1 << 31);
779 lParam
|= RepeatCount
;
781 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
783 if (KeyInput
.Flags
& KEY_E0
)
786 if (ModifierState
& MOD_ALT
)
790 if (!(KeyInput
.Flags
& KEY_BREAK
))
791 msg
.message
= WM_SYSKEYDOWN
;
793 msg
.message
= WM_SYSKEYUP
;
797 if (!(KeyInput
.Flags
& KEY_BREAK
))
798 msg
.message
= WM_KEYDOWN
;
800 msg
.message
= WM_KEYUP
;
803 /* Find the target thread whose locale is in effect */
804 FocusQueue
= IntGetFocusMessageQueue();
806 /* This might cause us to lose hot keys, which are important
807 * (ctrl-alt-del secure attention sequence). Not sure if it
814 msg
.hwnd
= FocusQueue
->FocusWindow
;
816 FocusThread
= FocusQueue
->Thread
;
818 if (!(FocusThread
&& FocusThread
->Tcb
.Win32Thread
&&
819 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
))
822 /* This function uses lParam to fill wParam according to the
823 * keyboard layout in use.
825 W32kKeyProcessMessage(&msg
,
826 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
->KBTables
,
827 KeyInput
.Flags
& KEY_E0
? 0xE0 :
828 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
830 if (GetHotKey(ModifierState
,
836 if (!(KeyInput
.Flags
& KEY_BREAK
))
838 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
839 MsqPostHotKeyMessage (Thread
,
842 MAKELPARAM((WORD
)ModifierState
,
845 continue; /* Eat key up motion too */
849 * Post a keyboard message.
851 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
856 DPRINT( "KeyboardInput Thread Stopped...\n" );
861 static PVOID Objects
[2];
864 Since this relies on InputThreadsStart, just fake it.
867 RawInputThreadMain(PVOID StartContext
)
870 LARGE_INTEGER DueTime
;
872 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
877 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
878 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
879 } while (!NT_SUCCESS(Status
));
882 Objects
[0] = &InputThreadsStart
;
884 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), TAG_INPUT
);
887 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
890 KeInitializeTimer(MasterTimer
);
891 Objects
[1] = MasterTimer
;
893 // This thread requires win32k!
894 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
895 if (!NT_SUCCESS(Status
))
897 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
901 ptiRawInput
= PsGetCurrentThreadWin32Thread();
902 DPRINT1("\nRaw Input Thread 0x%x \n", ptiRawInput
);
905 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
906 LOW_REALTIME_PRIORITY
+ 3);
908 UserEnterExclusive();
913 // ATM, we just have one job to handle, merge the other two later.
917 DPRINT( "Raw Input Thread Waiting for start event\n" );
919 Status
= KeWaitForMultipleObjects( 2,
927 DPRINT( "Raw Input Thread Starting...\n" );
931 DPRINT1("Raw Input Thread Exit!\n");
939 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
941 /* Initialize the default keyboard layout */
942 if(!UserInitDefaultKeyboardLayout())
944 DPRINT1("Failed to initialize default keyboard layout!\n");
947 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
954 if (!NT_SUCCESS(Status
))
956 DPRINT1("Win32K: Failed to create raw thread.\n");
959 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
966 if (!NT_SUCCESS(Status
))
968 DPRINT1("Win32K: Failed to create keyboard thread.\n");
971 Status
= PsCreateSystemThread(&MouseThreadHandle
,
978 if (!NT_SUCCESS(Status
))
980 DPRINT1("Win32K: Failed to create mouse thread.\n");
983 InputThreadsRunning
= TRUE
;
984 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
986 return STATUS_SUCCESS
;
990 CleanupInputImp(VOID
)
992 return(STATUS_SUCCESS
);
999 POINT pt
) // Just like the User call.
1006 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
1008 PTHREADINFO OldBlock
;
1011 if(!W32Thread
->Desktop
|| (W32Thread
->IsExiting
&& BlockIt
))
1014 * fail blocking if exiting the thread
1021 * FIXME - check access rights of the window station
1022 * e.g. services running in the service window station cannot block input
1024 if(!ThreadHasInputAccess(W32Thread
) ||
1025 !IntIsActiveDesktop(W32Thread
->Desktop
))
1027 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1031 ASSERT(W32Thread
->Desktop
);
1032 OldBlock
= W32Thread
->Desktop
->BlockInputThread
;
1035 if(OldBlock
!= W32Thread
)
1037 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1040 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1041 return OldBlock
== NULL
;
1044 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1045 return OldBlock
== NULL
;
1053 DECLARE_RETURN(BOOLEAN
);
1055 DPRINT("Enter NtUserBlockInput\n");
1056 UserEnterExclusive();
1058 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1061 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1067 IntMouseInput(MOUSEINPUT
*mi
)
1069 const UINT SwapBtnMsg
[2][2] =
1072 WM_LBUTTONDOWN
, WM_RBUTTONDOWN
1074 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1076 const WPARAM SwapBtn
[2] =
1078 MK_LBUTTON
, MK_RBUTTON
1080 POINT MousePos
= {0}, OrgPos
;
1081 PSYSTEM_CURSORINFO CurInfo
;
1082 PWINSTATION_OBJECT WinSta
;
1083 BOOL DoMove
, SwapButtons
;
1088 PWINDOW_OBJECT DesktopWindow
;
1094 /* FIXME - get the screen dc from the window station or desktop */
1095 if(!(hDC
= IntGetScreenDC()))
1104 WinSta
= PsGetCurrentProcessWin32Process()->WindowStation
;
1106 /* FIXME - ugly hack but as long as we're using this dumb callback from the
1107 mouse class driver, we can't access the window station from the calling
1109 WinSta
= InputWindowStation
;
1114 CurInfo
= IntGetSysCursorInfo(WinSta
);
1118 LARGE_INTEGER LargeTickCount
;
1119 KeQueryTickCount(&LargeTickCount
);
1120 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1123 SwapButtons
= CurInfo
->SwapButtons
;
1126 IntGetCursorLocation(WinSta
, &MousePos
);
1127 OrgPos
.x
= MousePos
.x
;
1128 OrgPos
.y
= MousePos
.y
;
1130 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1132 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1134 MousePos
.x
= mi
->dx
;
1135 MousePos
.y
= mi
->dy
;
1139 MousePos
.x
+= mi
->dx
;
1140 MousePos
.y
+= mi
->dy
;
1143 DesktopWindow
= IntGetWindowObject(WinSta
->ActiveDesktop
->DesktopWindow
);
1147 if(MousePos
.x
>= DesktopWindow
->Wnd
->ClientRect
.right
)
1148 MousePos
.x
= DesktopWindow
->Wnd
->ClientRect
.right
- 1;
1149 if(MousePos
.y
>= DesktopWindow
->Wnd
->ClientRect
.bottom
)
1150 MousePos
.y
= DesktopWindow
->Wnd
->ClientRect
.bottom
- 1;
1151 UserDereferenceObject(DesktopWindow
);
1159 if(CurInfo
->CursorClipInfo
.IsClipped
)
1161 /* The mouse cursor needs to be clipped */
1163 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
1164 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
1165 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
1166 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
1167 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
1168 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
1169 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
1170 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
1173 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
1178 dc
= DC_LockDc(hDC
);
1181 psurf
= dc
->dclevel
.pSurface
;
1184 pso
= &psurf
->SurfObj
;
1186 if (CurInfo
->ShowingCursor
)
1188 IntEngMovePointer(pso
, MousePos
.x
, MousePos
.y
, &(GDIDEV(pso
)->Pointer
.Exclude
));
1190 /* Only now, update the info in the PDEVOBJ, so EngMovePointer can
1191 * use the old values to move the pointer image */
1192 gpsi
->ptCursor
.x
= MousePos
.x
;
1193 gpsi
->ptCursor
.y
= MousePos
.y
;
1201 * Insert the messages into the system queue
1204 Msg
.wParam
= CurInfo
->ButtonsDown
;
1205 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1208 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1210 Msg
.wParam
|= MK_SHIFT
;
1213 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1215 Msg
.wParam
|= MK_CONTROL
;
1220 Msg
.message
= WM_MOUSEMOVE
;
1221 MsqInsertSystemMessage(&Msg
);
1225 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1227 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1228 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1229 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1230 MsqInsertSystemMessage(&Msg
);
1232 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1234 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1235 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1236 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1237 MsqInsertSystemMessage(&Msg
);
1239 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1241 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1242 Msg
.message
= WM_MBUTTONDOWN
;
1243 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1244 MsqInsertSystemMessage(&Msg
);
1246 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1248 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1249 Msg
.message
= WM_MBUTTONUP
;
1250 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1251 MsqInsertSystemMessage(&Msg
);
1253 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1255 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1256 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1257 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1258 MsqInsertSystemMessage(&Msg
);
1260 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1262 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1263 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1264 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1265 MsqInsertSystemMessage(&Msg
);
1268 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1269 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1271 /* fail because both types of events use the mouseData field */
1275 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1277 Msg
.message
= WM_XBUTTONDOWN
;
1278 if(mi
->mouseData
& XBUTTON1
)
1280 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1281 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1282 CurInfo
->ButtonsDown
|= XBUTTON1
;
1283 MsqInsertSystemMessage(&Msg
);
1285 if(mi
->mouseData
& XBUTTON2
)
1287 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1288 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1289 CurInfo
->ButtonsDown
|= XBUTTON2
;
1290 MsqInsertSystemMessage(&Msg
);
1293 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1295 Msg
.message
= WM_XBUTTONUP
;
1296 if(mi
->mouseData
& XBUTTON1
)
1298 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1299 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1300 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1301 MsqInsertSystemMessage(&Msg
);
1303 if(mi
->mouseData
& XBUTTON2
)
1305 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1306 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1307 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1308 MsqInsertSystemMessage(&Msg
);
1311 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1313 Msg
.message
= WM_MOUSEWHEEL
;
1314 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1315 MsqInsertSystemMessage(&Msg
);
1322 IntKeyboardInput(KEYBDINPUT
*ki
)
1334 PTHREADINFO W32Thread
;
1336 DECLARE_RETURN(UINT
);
1338 DPRINT("Enter NtUserSendInput\n");
1339 UserEnterExclusive();
1341 W32Thread
= PsGetCurrentThreadWin32Thread();
1344 if(!W32Thread
->Desktop
)
1349 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1351 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1356 * FIXME - check access rights of the window station
1357 * e.g. services running in the service window station cannot block input
1359 if(!ThreadHasInputAccess(W32Thread
) ||
1360 !IntIsActiveDesktop(W32Thread
->Desktop
))
1362 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1372 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1373 if(!NT_SUCCESS(Status
))
1375 SetLastNtError(Status
);
1379 switch(SafeInput
.type
)
1382 if(IntMouseInput(&SafeInput
.mi
))
1387 case INPUT_KEYBOARD
:
1388 if(IntKeyboardInput(&SafeInput
.ki
))
1393 case INPUT_HARDWARE
:
1398 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1408 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);