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 *****************************************************************/
59 IntSystemParametersInfo(UINT uiAction
, UINT uiParam
,PVOID pvParam
, UINT fWinIni
);
60 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
);
62 #define ClearMouseInput(mi) \
68 #define SendMouseEvent(mi) \
69 if(mi.dx != 0 || mi.dy != 0) \
70 mi.dwFlags |= MOUSEEVENTF_MOVE; \
76 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
)
78 static DWORD LastInputTick
= 0;
79 if (LastInputTickSetGet
== TRUE
)
81 LARGE_INTEGER TickCount
;
82 KeQueryTickCount(&TickCount
);
83 LastInputTick
= TickCount
.u
.LowPart
* (KeQueryTimeIncrement() / 10000);
90 NtUserGetLastInputInfo(PLASTINPUTINFO plii
)
98 if (ProbeForReadUint(&plii
->cbSize
) != sizeof(LASTINPUTINFO
))
100 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
105 ProbeForWrite(plii
, sizeof(LASTINPUTINFO
), sizeof(DWORD
));
107 plii
->dwTime
= IntLastInputTick(FALSE
);
109 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
111 SetLastNtError(_SEH2_GetExceptionCode());
123 ProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
125 PMOUSE_INPUT_DATA mid
;
132 for(i
= 0; i
< InputCount
; i
++)
138 /* Check if the mouse move is absolute */
139 if (mid
->Flags
== MOUSE_MOVE_ABSOLUTE
)
141 /* Set flag and convert to screen location */
142 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
143 mi
.dx
= mi
.dx
/ (65535 / (UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) - 1));
144 mi
.dy
= mi
.dy
/ (65535 / (UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) - 1));
149 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
151 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
154 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
156 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
159 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
161 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
164 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
166 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
169 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
171 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
174 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
176 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
179 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
181 mi
.mouseData
|= XBUTTON1
;
182 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
185 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
187 mi
.mouseData
|= XBUTTON1
;
188 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
191 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
193 mi
.mouseData
|= XBUTTON2
;
194 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
197 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
199 mi
.mouseData
|= XBUTTON2
;
200 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
203 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
205 mi
.mouseData
= mid
->ButtonData
;
206 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
219 MouseThreadMain(PVOID StartContext
)
221 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
222 OBJECT_ATTRIBUTES MouseObjectAttributes
;
223 IO_STATUS_BLOCK Iosb
;
225 MOUSE_ATTRIBUTES MouseAttr
;
227 InitializeObjectAttributes(&MouseObjectAttributes
,
234 LARGE_INTEGER DueTime
;
236 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
237 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
238 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
239 Status
= NtOpenFile(&MouseDeviceHandle
,
241 &MouseObjectAttributes
,
244 FILE_SYNCHRONOUS_IO_ALERT
);
245 } while (!NT_SUCCESS(Status
));
247 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
248 LOW_REALTIME_PRIORITY
+ 3);
253 * Wait to start input.
255 DPRINT("Mouse Input Thread Waiting for start event\n");
256 Status
= KeWaitForSingleObject(&InputThreadsStart
,
261 DPRINT("Mouse Input Thread Starting...\n");
263 /*FIXME: Does mouse attributes need to be used for anything */
264 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
269 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
270 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
272 if(!NT_SUCCESS(Status
))
274 DPRINT("Failed to get mouse attributes\n");
278 * Receive and process mouse input.
280 while(InputThreadsRunning
)
282 MOUSE_INPUT_DATA MouseInput
;
283 Status
= NtReadFile(MouseDeviceHandle
,
289 sizeof(MOUSE_INPUT_DATA
),
292 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
296 if(Status
== STATUS_PENDING
)
298 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
299 Status
= Iosb
.Status
;
301 if(!NT_SUCCESS(Status
))
303 DPRINT1("Win32K: Failed to read from mouse.\n");
306 DPRINT("MouseEvent\n");
307 IntLastInputTick(TRUE
);
309 UserEnterExclusive();
311 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
315 DPRINT("Mouse Input Thread Stopped...\n");
319 /* Returns a value that indicates if the key is a modifier key, and
323 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
325 if (InputData
->Flags
& KEY_E1
)
328 if (!(InputData
->Flags
& KEY_E0
))
330 switch (InputData
->MakeCode
)
332 case 0x2a: /* left shift */
333 case 0x36: /* right shift */
336 case 0x1d: /* left control */
339 case 0x38: /* left alt */
348 switch (InputData
->MakeCode
)
350 case 0x1d: /* right control */
353 case 0x38: /* right alt */
356 case 0x5b: /* left gui (windows) */
357 case 0x5c: /* right gui (windows) */
366 /* Asks the keyboard driver to send a small table that shows which
367 * lights should connect with which scancodes
369 static NTSTATUS APIENTRY
370 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
371 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
375 IO_STATUS_BLOCK Block
;
376 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
378 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
380 Ret
= ExAllocatePoolWithTag(PagedPool
,
386 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
391 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
395 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
398 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
400 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
402 Ret
= ExAllocatePoolWithTag(PagedPool
,
408 return STATUS_INSUFFICIENT_RESOURCES
;
410 if (Status
!= STATUS_SUCCESS
)
412 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
416 *IndicatorTrans
= Ret
;
420 /* Sends the keyboard commands to turn on/off the lights.
422 static NTSTATUS APIENTRY
423 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
424 PKEYBOARD_INPUT_DATA KeyInput
,
425 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
429 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
430 IO_STATUS_BLOCK Block
;
433 return STATUS_NOT_SUPPORTED
;
435 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
436 return STATUS_SUCCESS
;
438 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
440 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
442 Indicators
.LedFlags
^=
443 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
445 /* Update the lights on the hardware */
447 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
452 IOCTL_KEYBOARD_SET_INDICATORS
,
453 &Indicators
, sizeof(Indicators
),
460 return STATUS_SUCCESS
;
464 IntKeyboardSendWinKeyMsg()
466 PWINDOW_OBJECT Window
;
469 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
471 DPRINT1("Couldn't find window to send Windows key message!\n");
475 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
476 Mesg
.message
= WM_SYSCOMMAND
;
477 Mesg
.wParam
= SC_TASKLIST
;
480 /* The QS_HOTKEY is just a guess */
481 MsqPostMessage(Window
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
485 co_IntKeyboardSendAltKeyMsg()
487 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
491 KeyboardThreadMain(PVOID StartContext
)
493 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
494 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
495 IO_STATUS_BLOCK Iosb
;
498 PUSER_MESSAGE_QUEUE FocusQueue
;
499 struct _ETHREAD
*FocusThread
;
501 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
502 UINT ModifierState
= 0;
503 USHORT LastMakeCode
= 0;
504 USHORT LastFlags
= 0;
505 UINT RepeatCount
= 0;
507 InitializeObjectAttributes(&KeyboardObjectAttributes
,
514 LARGE_INTEGER DueTime
;
516 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
517 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
518 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
519 Status
= NtOpenFile(&KeyboardDeviceHandle
,
521 &KeyboardObjectAttributes
,
524 FILE_SYNCHRONOUS_IO_ALERT
);
525 } while (!NT_SUCCESS(Status
));
527 /* Not sure if converting this thread to a win32 thread is such
528 a great idea. Since we're posting keyboard messages to the focus
529 window message queue, we'll be (indirectly) doing sendmessage
530 stuff from this thread (for WH_KEYBOARD_LL processing), which
531 means we need our own message queue. If keyboard messages were
532 instead queued to the system message queue, the thread removing
533 the message from the system message queue would be responsible
534 for WH_KEYBOARD_LL processing and we wouldn't need this thread
535 to be a win32 thread. */
536 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
537 if (!NT_SUCCESS(Status
))
539 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
543 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
544 LOW_REALTIME_PRIORITY
+ 3);
546 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
552 * Wait to start input.
554 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
555 Status
= KeWaitForSingleObject(&InputThreadsStart
,
561 DPRINT( "Keyboard Input Thread Starting...\n" );
563 * Receive and process keyboard input.
565 while (InputThreadsRunning
)
569 KEYBOARD_INPUT_DATA KeyInput
;
570 KEYBOARD_INPUT_DATA NextKeyInput
;
572 UINT fsModifiers
, fsNextModifiers
;
573 struct _ETHREAD
*Thread
;
577 DPRINT("KeyInput @ %08x\n", &KeyInput
);
579 Status
= NtReadFile (KeyboardDeviceHandle
,
585 sizeof(KEYBOARD_INPUT_DATA
),
589 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
593 if(Status
== STATUS_PENDING
)
595 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
596 Status
= Iosb
.Status
;
598 if(!NT_SUCCESS(Status
))
600 DPRINT1("Win32K: Failed to read from mouse.\n");
604 DPRINT("KeyRaw: %s %04x\n",
605 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
608 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
611 if (!NT_SUCCESS(Status
))
613 DPRINT1("Win32K: Failed to read from keyboard.\n");
617 /* Set LastInputTick */
618 IntLastInputTick(TRUE
);
620 /* Update modifier state */
621 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
625 if (KeyInput
.Flags
& KEY_BREAK
)
627 ModifierState
&= ~fsModifiers
;
628 if(fsModifiers
== MOD_ALT
)
630 if(KeyInput
.Flags
& KEY_E0
)
632 gQueueKeyStateTable
[VK_RMENU
] = 0;
636 gQueueKeyStateTable
[VK_LMENU
] = 0;
638 if (gQueueKeyStateTable
[VK_RMENU
] == 0 &&
639 gQueueKeyStateTable
[VK_LMENU
] == 0)
641 gQueueKeyStateTable
[VK_MENU
] = 0;
647 ModifierState
|= fsModifiers
;
649 if (ModifierState
== fsModifiers
&&
650 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
652 /* First send out special notifications
653 * (For alt, the message that turns on accelerator
654 * display, not sure what for win. Both TODO though.)
657 if(fsModifiers
== MOD_ALT
)
659 if(KeyInput
.Flags
& KEY_E0
)
661 gQueueKeyStateTable
[VK_RMENU
] = 0x80;
665 gQueueKeyStateTable
[VK_LMENU
] = 0x80;
669 gQueueKeyStateTable
[VK_MENU
] = 0x80;
672 /* Read the next key before sending this one */
675 Status
= NtReadFile (KeyboardDeviceHandle
,
681 sizeof(KEYBOARD_INPUT_DATA
),
684 DPRINT("KeyRaw: %s %04x\n",
685 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
686 NextKeyInput
.MakeCode
);
688 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
692 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
693 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
694 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
695 * code. I'm not caring about the counting, not sure
696 * if that matters. I think not.
699 /* If the ModifierState is now empty again, send a
700 * special notification and eat both keypresses
703 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
706 ModifierState
^= fsNextModifiers
;
708 if (ModifierState
== 0)
710 if (fsModifiers
== MOD_WIN
)
711 IntKeyboardSendWinKeyMsg();
712 else if (fsModifiers
== MOD_ALT
)
714 gQueueKeyStateTable
[VK_MENU
] = 0;
717 gQueueKeyStateTable
[VK_LMENU
] = 0;
721 gQueueKeyStateTable
[VK_RMENU
] = 0;
723 co_IntKeyboardSendAltKeyMsg();
733 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
738 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
742 /* While we are working, we set up lParam. The format is:
743 * 0-15: The number of times this key has autorepeated
744 * 16-23: The keyboard scancode
745 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
746 * Note that E1 is only used for PAUSE (E1-1D-45) and
747 * E0-45 happens not to be anything.
748 * 29: Alt is pressed ('Context code')
749 * 30: Previous state, if the key was down before this message
750 * This is a cheap way to ignore autorepeat keys
751 * 31: 1 if the key is being pressed
754 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
755 * and it's the same key as the last one, increase the repeat
759 if (!(KeyInput
.Flags
& KEY_BREAK
))
761 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
762 (KeyInput
.MakeCode
== LastMakeCode
))
770 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
771 LastMakeCode
= KeyInput
.MakeCode
;
777 LastMakeCode
= 0; /* Should never match */
778 lParam
|= (1 << 30) | (1 << 31);
781 lParam
|= RepeatCount
;
783 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
785 if (KeyInput
.Flags
& KEY_E0
)
788 if (ModifierState
& MOD_ALT
)
792 if (!(KeyInput
.Flags
& KEY_BREAK
))
793 msg
.message
= WM_SYSKEYDOWN
;
795 msg
.message
= WM_SYSKEYUP
;
799 if (!(KeyInput
.Flags
& KEY_BREAK
))
800 msg
.message
= WM_KEYDOWN
;
802 msg
.message
= WM_KEYUP
;
805 /* Find the target thread whose locale is in effect */
806 FocusQueue
= IntGetFocusMessageQueue();
808 /* This might cause us to lose hot keys, which are important
809 * (ctrl-alt-del secure attention sequence). Not sure if it
816 msg
.hwnd
= FocusQueue
->FocusWindow
;
818 FocusThread
= FocusQueue
->Thread
;
820 if (!(FocusThread
&& FocusThread
->Tcb
.Win32Thread
&&
821 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
))
824 /* This function uses lParam to fill wParam according to the
825 * keyboard layout in use.
827 W32kKeyProcessMessage(&msg
,
828 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
->KBTables
,
829 KeyInput
.Flags
& KEY_E0
? 0xE0 :
830 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
832 if (GetHotKey(ModifierState
,
838 if (!(KeyInput
.Flags
& KEY_BREAK
))
840 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
841 MsqPostHotKeyMessage (Thread
,
844 MAKELPARAM((WORD
)ModifierState
,
847 continue; /* Eat key up motion too */
851 * Post a keyboard message.
853 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
858 DPRINT( "KeyboardInput Thread Stopped...\n" );
863 static PVOID Objects
[2];
866 Since this relies on InputThreadsStart, just fake it.
869 RawInputThreadMain(PVOID StartContext
)
872 LARGE_INTEGER DueTime
;
874 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
879 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
880 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
881 } while (!NT_SUCCESS(Status
));
884 Objects
[0] = &InputThreadsStart
;
886 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), TAG_INPUT
);
889 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
892 KeInitializeTimer(MasterTimer
);
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 DPRINT1("\nRaw 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");
941 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
943 /* Initialize the default keyboard layout */
944 if(!UserInitDefaultKeyboardLayout())
946 DPRINT1("Failed to initialize default keyboard layout!\n");
949 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
956 if (!NT_SUCCESS(Status
))
958 DPRINT1("Win32K: Failed to create raw thread.\n");
961 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
968 if (!NT_SUCCESS(Status
))
970 DPRINT1("Win32K: Failed to create keyboard thread.\n");
973 Status
= PsCreateSystemThread(&MouseThreadHandle
,
980 if (!NT_SUCCESS(Status
))
982 DPRINT1("Win32K: Failed to create mouse thread.\n");
985 InputThreadsRunning
= TRUE
;
986 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
988 return STATUS_SUCCESS
;
992 CleanupInputImp(VOID
)
994 return(STATUS_SUCCESS
);
1001 POINT pt
) // Just like the User call.
1008 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
1010 PTHREADINFO OldBlock
;
1013 if(!W32Thread
->Desktop
|| (W32Thread
->IsExiting
&& BlockIt
))
1016 * fail blocking if exiting the thread
1023 * FIXME - check access rights of the window station
1024 * e.g. services running in the service window station cannot block input
1026 if(!ThreadHasInputAccess(W32Thread
) ||
1027 !IntIsActiveDesktop(W32Thread
->Desktop
))
1029 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1033 ASSERT(W32Thread
->Desktop
);
1034 OldBlock
= W32Thread
->Desktop
->BlockInputThread
;
1037 if(OldBlock
!= W32Thread
)
1039 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1042 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1043 return OldBlock
== NULL
;
1046 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1047 return OldBlock
== NULL
;
1055 DECLARE_RETURN(BOOLEAN
);
1057 DPRINT("Enter NtUserBlockInput\n");
1058 UserEnterExclusive();
1060 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1063 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1069 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject
, BOOL Swap
)
1071 PSYSTEM_CURSORINFO CurInfo
;
1074 CurInfo
= IntGetSysCursorInfo(WinStaObject
);
1075 res
= CurInfo
->SwapButtons
;
1076 CurInfo
->SwapButtons
= Swap
;
1081 IntMouseInput(MOUSEINPUT
*mi
)
1083 const UINT SwapBtnMsg
[2][2] =
1086 WM_LBUTTONDOWN
, WM_RBUTTONDOWN
1088 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1090 const WPARAM SwapBtn
[2] =
1092 MK_LBUTTON
, MK_RBUTTON
1094 POINT MousePos
= {0}, OrgPos
;
1095 PSYSTEM_CURSORINFO CurInfo
;
1096 PWINSTATION_OBJECT WinSta
;
1097 BOOL DoMove
, SwapButtons
;
1102 PWINDOW_OBJECT DesktopWindow
;
1108 /* FIXME - get the screen dc from the window station or desktop */
1109 if(!(hDC
= IntGetScreenDC()))
1118 WinSta
= PsGetCurrentProcessWin32Process()->WindowStation
;
1120 /* FIXME - ugly hack but as long as we're using this dumb callback from the
1121 mouse class driver, we can't access the window station from the calling
1123 WinSta
= InputWindowStation
;
1128 CurInfo
= IntGetSysCursorInfo(WinSta
);
1132 LARGE_INTEGER LargeTickCount
;
1133 KeQueryTickCount(&LargeTickCount
);
1134 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1137 SwapButtons
= CurInfo
->SwapButtons
;
1140 IntGetCursorLocation(WinSta
, &MousePos
);
1141 OrgPos
.x
= MousePos
.x
;
1142 OrgPos
.y
= MousePos
.y
;
1144 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1146 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1148 MousePos
.x
= mi
->dx
;
1149 MousePos
.y
= mi
->dy
;
1153 MousePos
.x
+= mi
->dx
;
1154 MousePos
.y
+= mi
->dy
;
1157 DesktopWindow
= IntGetWindowObject(WinSta
->ActiveDesktop
->DesktopWindow
);
1161 if(MousePos
.x
>= DesktopWindow
->Wnd
->ClientRect
.right
)
1162 MousePos
.x
= DesktopWindow
->Wnd
->ClientRect
.right
- 1;
1163 if(MousePos
.y
>= DesktopWindow
->Wnd
->ClientRect
.bottom
)
1164 MousePos
.y
= DesktopWindow
->Wnd
->ClientRect
.bottom
- 1;
1165 UserDereferenceObject(DesktopWindow
);
1173 if(CurInfo
->CursorClipInfo
.IsClipped
)
1175 /* The mouse cursor needs to be clipped */
1177 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
1178 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
1179 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
1180 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
1181 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
1182 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
1183 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
1184 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
1187 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
1192 dc
= DC_LockDc(hDC
);
1195 psurf
= dc
->dclevel
.pSurface
;
1198 pso
= &psurf
->SurfObj
;
1200 if (CurInfo
->ShowingCursor
)
1202 IntEngMovePointer(pso
, MousePos
.x
, MousePos
.y
, &(GDIDEV(pso
)->Pointer
.Exclude
));
1204 /* Only now, update the info in the PDEVOBJ, so EngMovePointer can
1205 * use the old values to move the pointer image */
1206 gpsi
->ptCursor
.x
= MousePos
.x
;
1207 gpsi
->ptCursor
.y
= MousePos
.y
;
1215 * Insert the messages into the system queue
1218 Msg
.wParam
= CurInfo
->ButtonsDown
;
1219 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1222 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1224 Msg
.wParam
|= MK_SHIFT
;
1227 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1229 Msg
.wParam
|= MK_CONTROL
;
1234 Msg
.message
= WM_MOUSEMOVE
;
1235 MsqInsertSystemMessage(&Msg
);
1239 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1241 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1242 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1243 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1244 MsqInsertSystemMessage(&Msg
);
1246 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1248 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1249 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1250 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1251 MsqInsertSystemMessage(&Msg
);
1253 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1255 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1256 Msg
.message
= WM_MBUTTONDOWN
;
1257 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1258 MsqInsertSystemMessage(&Msg
);
1260 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1262 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1263 Msg
.message
= WM_MBUTTONUP
;
1264 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1265 MsqInsertSystemMessage(&Msg
);
1267 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1269 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1270 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1271 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1272 MsqInsertSystemMessage(&Msg
);
1274 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1276 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1277 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1278 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1279 MsqInsertSystemMessage(&Msg
);
1282 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1283 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1285 /* fail because both types of events use the mouseData field */
1289 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1291 Msg
.message
= WM_XBUTTONDOWN
;
1292 if(mi
->mouseData
& XBUTTON1
)
1294 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1295 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1296 CurInfo
->ButtonsDown
|= XBUTTON1
;
1297 MsqInsertSystemMessage(&Msg
);
1299 if(mi
->mouseData
& XBUTTON2
)
1301 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1302 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1303 CurInfo
->ButtonsDown
|= XBUTTON2
;
1304 MsqInsertSystemMessage(&Msg
);
1307 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1309 Msg
.message
= WM_XBUTTONUP
;
1310 if(mi
->mouseData
& XBUTTON1
)
1312 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1313 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1314 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1315 MsqInsertSystemMessage(&Msg
);
1317 if(mi
->mouseData
& XBUTTON2
)
1319 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1320 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1321 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1322 MsqInsertSystemMessage(&Msg
);
1325 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1327 Msg
.message
= WM_MOUSEWHEEL
;
1328 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1329 MsqInsertSystemMessage(&Msg
);
1336 IntKeyboardInput(KEYBDINPUT
*ki
)
1348 PTHREADINFO W32Thread
;
1350 DECLARE_RETURN(UINT
);
1352 DPRINT("Enter NtUserSendInput\n");
1353 UserEnterExclusive();
1355 W32Thread
= PsGetCurrentThreadWin32Thread();
1358 if(!W32Thread
->Desktop
)
1363 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1365 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1370 * FIXME - check access rights of the window station
1371 * e.g. services running in the service window station cannot block input
1373 if(!ThreadHasInputAccess(W32Thread
) ||
1374 !IntIsActiveDesktop(W32Thread
->Desktop
))
1376 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1386 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1387 if(!NT_SUCCESS(Status
))
1389 SetLastNtError(Status
);
1393 switch(SafeInput
.type
)
1396 if(IntMouseInput(&SafeInput
.mi
))
1401 case INPUT_KEYBOARD
:
1402 if(IntKeyboardInput(&SafeInput
.ki
))
1407 case INPUT_HARDWARE
:
1412 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1422 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);