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
;
39 /* FUNCTIONS *****************************************************************/
40 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
);
42 #define ClearMouseInput(mi) \
48 #define SendMouseEvent(mi) \
49 if(mi.dx != 0 || mi.dy != 0) \
50 mi.dwFlags |= MOUSEEVENTF_MOVE; \
56 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
)
58 static DWORD LastInputTick
= 0;
59 if (LastInputTickSetGet
== TRUE
)
61 LARGE_INTEGER TickCount
;
62 KeQueryTickCount(&TickCount
);
63 LastInputTick
= TickCount
.u
.LowPart
* (KeQueryTimeIncrement() / 10000);
70 NtUserGetLastInputInfo(PLASTINPUTINFO plii
)
78 if (ProbeForReadUint(&plii
->cbSize
) != sizeof(LASTINPUTINFO
))
80 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
85 ProbeForWrite(plii
, sizeof(LASTINPUTINFO
), sizeof(DWORD
));
87 plii
->dwTime
= IntLastInputTick(FALSE
);
89 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
91 SetLastNtError(_SEH2_GetExceptionCode());
103 ProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
105 PMOUSE_INPUT_DATA mid
;
112 for(i
= 0; i
< InputCount
; i
++)
118 /* Check if the mouse move is absolute */
119 if (mid
->Flags
== MOUSE_MOVE_ABSOLUTE
)
121 /* Set flag and convert to screen location */
122 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
123 mi
.dx
= mi
.dx
/ (65535 / (UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) - 1));
124 mi
.dy
= mi
.dy
/ (65535 / (UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) - 1));
129 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
131 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
134 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
136 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
139 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
141 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
144 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
146 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
149 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
151 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
154 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
156 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
159 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
161 mi
.mouseData
|= XBUTTON1
;
162 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
165 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
167 mi
.mouseData
|= XBUTTON1
;
168 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
171 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
173 mi
.mouseData
|= XBUTTON2
;
174 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
177 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
179 mi
.mouseData
|= XBUTTON2
;
180 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
183 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
185 mi
.mouseData
= mid
->ButtonData
;
186 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
199 MouseThreadMain(PVOID StartContext
)
201 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
202 OBJECT_ATTRIBUTES MouseObjectAttributes
;
203 IO_STATUS_BLOCK Iosb
;
205 MOUSE_ATTRIBUTES MouseAttr
;
207 InitializeObjectAttributes(&MouseObjectAttributes
,
214 LARGE_INTEGER DueTime
;
216 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
217 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
218 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
219 Status
= NtOpenFile(&MouseDeviceHandle
,
221 &MouseObjectAttributes
,
224 FILE_SYNCHRONOUS_IO_ALERT
);
225 } while (!NT_SUCCESS(Status
));
227 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
228 LOW_REALTIME_PRIORITY
+ 3);
233 * Wait to start input.
235 DPRINT("Mouse Input Thread Waiting for start event\n");
236 Status
= KeWaitForSingleObject(&InputThreadsStart
,
241 DPRINT("Mouse Input Thread Starting...\n");
243 /*FIXME: Does mouse attributes need to be used for anything */
244 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
249 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
250 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
252 if(!NT_SUCCESS(Status
))
254 DPRINT("Failed to get mouse attributes\n");
258 * Receive and process mouse input.
260 while(InputThreadsRunning
)
262 MOUSE_INPUT_DATA MouseInput
;
263 Status
= NtReadFile(MouseDeviceHandle
,
269 sizeof(MOUSE_INPUT_DATA
),
272 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
276 if(Status
== STATUS_PENDING
)
278 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
279 Status
= Iosb
.Status
;
281 if(!NT_SUCCESS(Status
))
283 DPRINT1("Win32K: Failed to read from mouse.\n");
286 DPRINT("MouseEvent\n");
287 IntLastInputTick(TRUE
);
289 UserEnterExclusive();
291 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
295 DPRINT("Mouse Input Thread Stopped...\n");
299 /* Returns a value that indicates if the key is a modifier key, and
303 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
305 if (InputData
->Flags
& KEY_E1
)
308 if (!(InputData
->Flags
& KEY_E0
))
310 switch (InputData
->MakeCode
)
312 case 0x2a: /* left shift */
313 case 0x36: /* right shift */
316 case 0x1d: /* left control */
319 case 0x38: /* left alt */
328 switch (InputData
->MakeCode
)
330 case 0x1d: /* right control */
333 case 0x38: /* right alt */
336 case 0x5b: /* left gui (windows) */
337 case 0x5c: /* right gui (windows) */
346 /* Asks the keyboard driver to send a small table that shows which
347 * lights should connect with which scancodes
349 static NTSTATUS APIENTRY
350 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
351 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
355 IO_STATUS_BLOCK Block
;
356 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
358 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
360 Ret
= ExAllocatePoolWithTag(PagedPool
,
366 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
371 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
375 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
378 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
380 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
382 Ret
= ExAllocatePoolWithTag(PagedPool
,
388 return STATUS_INSUFFICIENT_RESOURCES
;
390 if (Status
!= STATUS_SUCCESS
)
392 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
396 *IndicatorTrans
= Ret
;
400 /* Sends the keyboard commands to turn on/off the lights.
402 static NTSTATUS APIENTRY
403 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
404 PKEYBOARD_INPUT_DATA KeyInput
,
405 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
409 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
410 IO_STATUS_BLOCK Block
;
413 return STATUS_NOT_SUPPORTED
;
415 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
416 return STATUS_SUCCESS
;
418 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
420 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
422 Indicators
.LedFlags
^=
423 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
425 /* Update the lights on the hardware */
427 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
432 IOCTL_KEYBOARD_SET_INDICATORS
,
433 &Indicators
, sizeof(Indicators
),
440 return STATUS_SUCCESS
;
444 IntKeyboardSendWinKeyMsg()
446 PWINDOW_OBJECT Window
;
449 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
451 DPRINT1("Couldn't find window to send Windows key message!\n");
455 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
456 Mesg
.message
= WM_SYSCOMMAND
;
457 Mesg
.wParam
= SC_TASKLIST
;
460 /* The QS_HOTKEY is just a guess */
461 MsqPostMessage(Window
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
465 co_IntKeyboardSendAltKeyMsg()
467 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
471 KeyboardThreadMain(PVOID StartContext
)
473 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
474 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
475 IO_STATUS_BLOCK Iosb
;
478 PUSER_MESSAGE_QUEUE FocusQueue
;
479 struct _ETHREAD
*FocusThread
;
481 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
482 UINT ModifierState
= 0;
483 USHORT LastMakeCode
= 0;
484 USHORT LastFlags
= 0;
485 UINT RepeatCount
= 0;
487 InitializeObjectAttributes(&KeyboardObjectAttributes
,
494 LARGE_INTEGER DueTime
;
496 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
497 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
498 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
499 Status
= NtOpenFile(&KeyboardDeviceHandle
,
501 &KeyboardObjectAttributes
,
504 FILE_SYNCHRONOUS_IO_ALERT
);
505 } while (!NT_SUCCESS(Status
));
507 /* Not sure if converting this thread to a win32 thread is such
508 a great idea. Since we're posting keyboard messages to the focus
509 window message queue, we'll be (indirectly) doing sendmessage
510 stuff from this thread (for WH_KEYBOARD_LL processing), which
511 means we need our own message queue. If keyboard messages were
512 instead queued to the system message queue, the thread removing
513 the message from the system message queue would be responsible
514 for WH_KEYBOARD_LL processing and we wouldn't need this thread
515 to be a win32 thread. */
516 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
517 if (!NT_SUCCESS(Status
))
519 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
523 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
524 LOW_REALTIME_PRIORITY
+ 3);
526 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
532 * Wait to start input.
534 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
535 Status
= KeWaitForSingleObject(&InputThreadsStart
,
541 DPRINT( "Keyboard Input Thread Starting...\n" );
543 * Receive and process keyboard input.
545 while (InputThreadsRunning
)
549 KEYBOARD_INPUT_DATA KeyInput
;
550 KEYBOARD_INPUT_DATA NextKeyInput
;
552 UINT fsModifiers
, fsNextModifiers
;
553 struct _ETHREAD
*Thread
;
557 DPRINT("KeyInput @ %08x\n", &KeyInput
);
559 Status
= NtReadFile (KeyboardDeviceHandle
,
565 sizeof(KEYBOARD_INPUT_DATA
),
569 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
573 if(Status
== STATUS_PENDING
)
575 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
576 Status
= Iosb
.Status
;
578 if(!NT_SUCCESS(Status
))
580 DPRINT1("Win32K: Failed to read from mouse.\n");
584 DPRINT("KeyRaw: %s %04x\n",
585 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
588 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
591 if (!NT_SUCCESS(Status
))
593 DPRINT1("Win32K: Failed to read from keyboard.\n");
597 /* Set LastInputTick */
598 IntLastInputTick(TRUE
);
600 /* Update modifier state */
601 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
605 if (KeyInput
.Flags
& KEY_BREAK
)
607 ModifierState
&= ~fsModifiers
;
608 if(fsModifiers
== MOD_ALT
)
610 if(KeyInput
.Flags
& KEY_E0
)
612 gQueueKeyStateTable
[VK_RMENU
] = 0;
616 gQueueKeyStateTable
[VK_LMENU
] = 0;
618 if (gQueueKeyStateTable
[VK_RMENU
] == 0 &&
619 gQueueKeyStateTable
[VK_LMENU
] == 0)
621 gQueueKeyStateTable
[VK_MENU
] = 0;
627 ModifierState
|= fsModifiers
;
629 if (ModifierState
== fsModifiers
&&
630 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
632 /* First send out special notifications
633 * (For alt, the message that turns on accelerator
634 * display, not sure what for win. Both TODO though.)
637 if(fsModifiers
== MOD_ALT
)
639 if(KeyInput
.Flags
& KEY_E0
)
641 gQueueKeyStateTable
[VK_RMENU
] = 0x80;
645 gQueueKeyStateTable
[VK_LMENU
] = 0x80;
649 gQueueKeyStateTable
[VK_MENU
] = 0x80;
652 /* Read the next key before sending this one */
655 Status
= NtReadFile (KeyboardDeviceHandle
,
661 sizeof(KEYBOARD_INPUT_DATA
),
664 DPRINT("KeyRaw: %s %04x\n",
665 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
666 NextKeyInput
.MakeCode
);
668 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
672 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
673 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
674 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
675 * code. I'm not caring about the counting, not sure
676 * if that matters. I think not.
679 /* If the ModifierState is now empty again, send a
680 * special notification and eat both keypresses
683 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
686 ModifierState
^= fsNextModifiers
;
688 if (ModifierState
== 0)
690 if (fsModifiers
== MOD_WIN
)
691 IntKeyboardSendWinKeyMsg();
692 else if (fsModifiers
== MOD_ALT
)
694 gQueueKeyStateTable
[VK_MENU
] = 0;
697 gQueueKeyStateTable
[VK_LMENU
] = 0;
701 gQueueKeyStateTable
[VK_RMENU
] = 0;
703 co_IntKeyboardSendAltKeyMsg();
713 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
718 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
722 /* While we are working, we set up lParam. The format is:
723 * 0-15: The number of times this key has autorepeated
724 * 16-23: The keyboard scancode
725 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
726 * Note that E1 is only used for PAUSE (E1-1D-45) and
727 * E0-45 happens not to be anything.
728 * 29: Alt is pressed ('Context code')
729 * 30: Previous state, if the key was down before this message
730 * This is a cheap way to ignore autorepeat keys
731 * 31: 1 if the key is being pressed
734 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
735 * and it's the same key as the last one, increase the repeat
739 if (!(KeyInput
.Flags
& KEY_BREAK
))
741 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
742 (KeyInput
.MakeCode
== LastMakeCode
))
750 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
751 LastMakeCode
= KeyInput
.MakeCode
;
757 LastMakeCode
= 0; /* Should never match */
758 lParam
|= (1 << 30) | (1 << 31);
761 lParam
|= RepeatCount
;
763 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
765 if (KeyInput
.Flags
& KEY_E0
)
768 if (ModifierState
& MOD_ALT
)
772 if (!(KeyInput
.Flags
& KEY_BREAK
))
773 msg
.message
= WM_SYSKEYDOWN
;
775 msg
.message
= WM_SYSKEYUP
;
779 if (!(KeyInput
.Flags
& KEY_BREAK
))
780 msg
.message
= WM_KEYDOWN
;
782 msg
.message
= WM_KEYUP
;
785 /* Find the target thread whose locale is in effect */
786 FocusQueue
= IntGetFocusMessageQueue();
788 /* This might cause us to lose hot keys, which are important
789 * (ctrl-alt-del secure attention sequence). Not sure if it
796 msg
.hwnd
= FocusQueue
->FocusWindow
;
798 FocusThread
= FocusQueue
->Thread
;
800 if (!(FocusThread
&& FocusThread
->Tcb
.Win32Thread
&&
801 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
))
804 /* This function uses lParam to fill wParam according to the
805 * keyboard layout in use.
807 W32kKeyProcessMessage(&msg
,
808 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
->KBTables
,
809 KeyInput
.Flags
& KEY_E0
? 0xE0 :
810 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
812 if (GetHotKey(ModifierState
,
818 if (!(KeyInput
.Flags
& KEY_BREAK
))
820 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
821 MsqPostHotKeyMessage (Thread
,
824 MAKELPARAM((WORD
)ModifierState
,
827 continue; /* Eat key up motion too */
831 * Post a keyboard message.
833 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
838 DPRINT( "KeyboardInput Thread Stopped...\n" );
843 static PVOID Objects
[2];
846 Since this relies on InputThreadsStart, just fake it.
849 RawInputThreadMain(PVOID StartContext
)
852 LARGE_INTEGER DueTime
;
854 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
859 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
860 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
861 } while (!NT_SUCCESS(Status
));
864 Objects
[0] = &InputThreadsStart
;
866 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), TAG_INPUT
);
869 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
872 KeInitializeTimer(MasterTimer
);
873 Objects
[1] = MasterTimer
;
875 // This thread requires win32k!
876 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
877 if (!NT_SUCCESS(Status
))
879 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
883 ptiRawInput
= PsGetCurrentThreadWin32Thread();
884 DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput
);
887 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
888 LOW_REALTIME_PRIORITY
+ 3);
890 UserEnterExclusive();
895 // ATM, we just have one job to handle, merge the other two later.
899 DPRINT( "Raw Input Thread Waiting for start event\n" );
901 Status
= KeWaitForMultipleObjects( 2,
909 DPRINT( "Raw Input Thread Starting...\n" );
913 DPRINT1("Raw Input Thread Exit!\n");
921 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
923 /* Initialize the default keyboard layout */
924 if(!UserInitDefaultKeyboardLayout())
926 DPRINT1("Failed to initialize default keyboard layout!\n");
929 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
936 if (!NT_SUCCESS(Status
))
938 DPRINT1("Win32K: Failed to create raw thread.\n");
941 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
948 if (!NT_SUCCESS(Status
))
950 DPRINT1("Win32K: Failed to create keyboard thread.\n");
953 Status
= PsCreateSystemThread(&MouseThreadHandle
,
960 if (!NT_SUCCESS(Status
))
962 DPRINT1("Win32K: Failed to create mouse thread.\n");
965 InputThreadsRunning
= TRUE
;
966 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
968 return STATUS_SUCCESS
;
972 CleanupInputImp(VOID
)
974 return(STATUS_SUCCESS
);
981 POINT pt
) // Just like the User call.
988 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
990 PTHREADINFO OldBlock
;
993 if(!W32Thread
->Desktop
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
996 * fail blocking if exiting the thread
1003 * FIXME - check access rights of the window station
1004 * e.g. services running in the service window station cannot block input
1006 if(!ThreadHasInputAccess(W32Thread
) ||
1007 !IntIsActiveDesktop(W32Thread
->Desktop
))
1009 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1013 ASSERT(W32Thread
->Desktop
);
1014 OldBlock
= W32Thread
->Desktop
->BlockInputThread
;
1017 if(OldBlock
!= W32Thread
)
1019 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1022 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1023 return OldBlock
== NULL
;
1026 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1027 return OldBlock
== NULL
;
1035 DECLARE_RETURN(BOOLEAN
);
1037 DPRINT("Enter NtUserBlockInput\n");
1038 UserEnterExclusive();
1040 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1043 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1049 IntMouseInput(MOUSEINPUT
*mi
)
1051 const UINT SwapBtnMsg
[2][2] =
1054 WM_LBUTTONDOWN
, WM_RBUTTONDOWN
1056 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1058 const WPARAM SwapBtn
[2] =
1060 MK_LBUTTON
, MK_RBUTTON
1062 POINT MousePos
= {0}, OrgPos
;
1063 PSYSTEM_CURSORINFO CurInfo
;
1064 PWINSTATION_OBJECT WinSta
;
1065 BOOL DoMove
, SwapButtons
;
1070 PWINDOW_OBJECT DesktopWindow
;
1076 /* FIXME - get the screen dc from the window station or desktop */
1077 if(!(hDC
= IntGetScreenDC()))
1086 WinSta
= PsGetCurrentProcessWin32Process()->WindowStation
;
1088 /* FIXME - ugly hack but as long as we're using this dumb callback from the
1089 mouse class driver, we can't access the window station from the calling
1091 WinSta
= InputWindowStation
;
1096 CurInfo
= IntGetSysCursorInfo(WinSta
);
1100 LARGE_INTEGER LargeTickCount
;
1101 KeQueryTickCount(&LargeTickCount
);
1102 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1105 SwapButtons
= gspv
.bMouseBtnSwap
;
1108 IntGetCursorLocation(WinSta
, &MousePos
);
1109 OrgPos
.x
= MousePos
.x
;
1110 OrgPos
.y
= MousePos
.y
;
1112 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1114 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1116 MousePos
.x
= mi
->dx
;
1117 MousePos
.y
= mi
->dy
;
1121 MousePos
.x
+= mi
->dx
;
1122 MousePos
.y
+= mi
->dy
;
1125 DesktopWindow
= IntGetWindowObject(WinSta
->ActiveDesktop
->DesktopWindow
);
1129 if(MousePos
.x
>= DesktopWindow
->Wnd
->rcClient
.right
)
1130 MousePos
.x
= DesktopWindow
->Wnd
->rcClient
.right
- 1;
1131 if(MousePos
.y
>= DesktopWindow
->Wnd
->rcClient
.bottom
)
1132 MousePos
.y
= DesktopWindow
->Wnd
->rcClient
.bottom
- 1;
1133 UserDereferenceObject(DesktopWindow
);
1141 if(CurInfo
->CursorClipInfo
.IsClipped
)
1143 /* The mouse cursor needs to be clipped */
1145 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
1146 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
1147 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
1148 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
1149 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
1150 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
1151 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
1152 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
1155 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
1160 dc
= DC_LockDc(hDC
);
1163 psurf
= dc
->dclevel
.pSurface
;
1166 pso
= &psurf
->SurfObj
;
1168 if (CurInfo
->ShowingCursor
)
1170 IntEngMovePointer(pso
, MousePos
.x
, MousePos
.y
, &(GDIDEV(pso
)->Pointer
.Exclude
));
1172 /* Only now, update the info in the PDEVOBJ, so EngMovePointer can
1173 * use the old values to move the pointer image */
1174 gpsi
->ptCursor
.x
= MousePos
.x
;
1175 gpsi
->ptCursor
.y
= MousePos
.y
;
1183 * Insert the messages into the system queue
1186 Msg
.wParam
= CurInfo
->ButtonsDown
;
1187 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1190 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1192 Msg
.wParam
|= MK_SHIFT
;
1195 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1197 Msg
.wParam
|= MK_CONTROL
;
1202 Msg
.message
= WM_MOUSEMOVE
;
1203 MsqInsertSystemMessage(&Msg
);
1207 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1209 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1210 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1211 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1212 MsqInsertSystemMessage(&Msg
);
1214 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1216 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1217 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1218 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1219 MsqInsertSystemMessage(&Msg
);
1221 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1223 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1224 Msg
.message
= WM_MBUTTONDOWN
;
1225 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1226 MsqInsertSystemMessage(&Msg
);
1228 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1230 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1231 Msg
.message
= WM_MBUTTONUP
;
1232 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1233 MsqInsertSystemMessage(&Msg
);
1235 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1237 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1238 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1239 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1240 MsqInsertSystemMessage(&Msg
);
1242 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1244 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1245 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1246 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1247 MsqInsertSystemMessage(&Msg
);
1250 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1251 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1253 /* fail because both types of events use the mouseData field */
1257 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1259 Msg
.message
= WM_XBUTTONDOWN
;
1260 if(mi
->mouseData
& XBUTTON1
)
1262 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1263 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1264 CurInfo
->ButtonsDown
|= XBUTTON1
;
1265 MsqInsertSystemMessage(&Msg
);
1267 if(mi
->mouseData
& XBUTTON2
)
1269 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1270 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1271 CurInfo
->ButtonsDown
|= XBUTTON2
;
1272 MsqInsertSystemMessage(&Msg
);
1275 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1277 Msg
.message
= WM_XBUTTONUP
;
1278 if(mi
->mouseData
& XBUTTON1
)
1280 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1281 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1282 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1283 MsqInsertSystemMessage(&Msg
);
1285 if(mi
->mouseData
& XBUTTON2
)
1287 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1288 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1289 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1290 MsqInsertSystemMessage(&Msg
);
1293 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1295 Msg
.message
= WM_MOUSEWHEEL
;
1296 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1297 MsqInsertSystemMessage(&Msg
);
1304 IntKeyboardInput(KEYBDINPUT
*ki
)
1310 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1314 /* Can not be the same thread.*/
1315 if (pti
== ptiTo
) return FALSE
;
1317 /* Do not attach to system threads or between different desktops. */
1318 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1319 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1320 pti
->Desktop
!= ptiTo
->Desktop
)
1323 /* If Attach set, allocate and link. */
1326 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), TAG_ATTACHINFO
);
1327 if ( !pai
) return FALSE
;
1329 pai
->paiNext
= gpai
;
1334 else /* If clear, unlink and free it. */
1336 PATTACHINFO paiprev
= NULL
;
1338 if ( !gpai
) return FALSE
;
1342 /* Search list and free if found or return false. */
1345 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1350 if ( !pai
) return FALSE
;
1352 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1354 ExFreePoolWithTag(pai
, TAG_ATTACHINFO
);
1367 PTHREADINFO W32Thread
;
1369 DECLARE_RETURN(UINT
);
1371 DPRINT("Enter NtUserSendInput\n");
1372 UserEnterExclusive();
1374 W32Thread
= PsGetCurrentThreadWin32Thread();
1377 if(!W32Thread
->Desktop
)
1382 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1384 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1389 * FIXME - check access rights of the window station
1390 * e.g. services running in the service window station cannot block input
1392 if(!ThreadHasInputAccess(W32Thread
) ||
1393 !IntIsActiveDesktop(W32Thread
->Desktop
))
1395 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1405 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1406 if(!NT_SUCCESS(Status
))
1408 SetLastNtError(Status
);
1412 switch(SafeInput
.type
)
1415 if(IntMouseInput(&SafeInput
.mi
))
1420 case INPUT_KEYBOARD
:
1421 if(IntKeyboardInput(&SafeInput
.ki
))
1426 case INPUT_HARDWARE
:
1431 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1441 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);