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 to convert to screen location */
124 mi
.dwFlags
|= MOUSEEVENTF_ABSOLUTE
;
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
->pti
->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
->rpdesk
|| ((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
->rpdesk
))
1009 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1013 ASSERT(W32Thread
->rpdesk
);
1014 OldBlock
= W32Thread
->rpdesk
->BlockInputThread
;
1017 if(OldBlock
!= W32Thread
)
1019 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1022 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1023 return OldBlock
== NULL
;
1026 W32Thread
->rpdesk
->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] =
1053 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
1054 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1056 const WPARAM SwapBtn
[2] =
1058 MK_LBUTTON
, MK_RBUTTON
1061 PSYSTEM_CURSORINFO CurInfo
;
1067 CurInfo
= IntGetSysCursorInfo();
1071 LARGE_INTEGER LargeTickCount
;
1072 KeQueryTickCount(&LargeTickCount
);
1073 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1076 SwapButtons
= gspv
.bMouseBtnSwap
;
1078 MousePos
= gpsi
->ptCursor
;
1080 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1082 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1084 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
1085 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
1089 MousePos
.x
+= mi
->dx
;
1090 MousePos
.y
+= mi
->dy
;
1095 * Insert the messages into the system queue
1097 Msg
.wParam
= CurInfo
->ButtonsDown
;
1098 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1101 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1103 Msg
.wParam
|= MK_SHIFT
;
1106 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1108 Msg
.wParam
|= MK_CONTROL
;
1111 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1113 UserSetCursorPos(MousePos
.x
, MousePos
.y
);
1115 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1117 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1118 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1119 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1120 MsqInsertSystemMessage(&Msg
);
1122 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1124 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1125 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1126 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1127 MsqInsertSystemMessage(&Msg
);
1129 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1131 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1132 Msg
.message
= WM_MBUTTONDOWN
;
1133 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1134 MsqInsertSystemMessage(&Msg
);
1136 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1138 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1139 Msg
.message
= WM_MBUTTONUP
;
1140 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1141 MsqInsertSystemMessage(&Msg
);
1143 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1145 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1146 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1147 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1148 MsqInsertSystemMessage(&Msg
);
1150 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1152 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1153 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1154 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1155 MsqInsertSystemMessage(&Msg
);
1158 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1159 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1161 /* fail because both types of events use the mouseData field */
1165 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1167 Msg
.message
= WM_XBUTTONDOWN
;
1168 if(mi
->mouseData
& XBUTTON1
)
1170 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1171 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1172 CurInfo
->ButtonsDown
|= XBUTTON1
;
1173 MsqInsertSystemMessage(&Msg
);
1175 if(mi
->mouseData
& XBUTTON2
)
1177 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1178 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1179 CurInfo
->ButtonsDown
|= XBUTTON2
;
1180 MsqInsertSystemMessage(&Msg
);
1183 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1185 Msg
.message
= WM_XBUTTONUP
;
1186 if(mi
->mouseData
& XBUTTON1
)
1188 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1189 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1190 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1191 MsqInsertSystemMessage(&Msg
);
1193 if(mi
->mouseData
& XBUTTON2
)
1195 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1196 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1197 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1198 MsqInsertSystemMessage(&Msg
);
1201 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1203 Msg
.message
= WM_MOUSEWHEEL
;
1204 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1205 MsqInsertSystemMessage(&Msg
);
1212 IntKeyboardInput(KEYBDINPUT
*ki
)
1214 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1217 LARGE_INTEGER LargeTickCount
;
1218 KBDLLHOOKSTRUCT KbdHookData
;
1219 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1220 BOOLEAN Entered
= FALSE
;
1224 // Condition may arise when calling MsqPostMessage and waiting for an event.
1225 if (!UserIsEntered())
1227 // Fixme: Not sure ATM if this thread is locked.
1228 UserEnterExclusive();
1234 flags
= LOBYTE(ki
->wScan
);
1236 if (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1237 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1239 /* strip left/right for menu, control, shift */
1245 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1246 wVkStripped
= VK_MENU
;
1253 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1254 wVkStripped
= VK_CONTROL
;
1261 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1262 wVkStripped
= VK_SHIFT
;
1267 wVkStripped
= wVkL
= wVkR
= wVk
;
1270 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1272 Msg
.message
= WM_KEYUP
;
1273 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80) &&
1274 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1275 || !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80)))
1277 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1278 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1279 Msg
.message
= WM_SYSKEYUP
;
1282 flags
|= KF_REPEAT
| KF_UP
;
1286 Msg
.message
= WM_KEYDOWN
;
1287 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1288 !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
))
1290 Msg
.message
= WM_SYSKEYDOWN
;
1291 TrackSysKey
= wVkStripped
;
1293 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
) && gQueueKeyStateTable
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1296 if (ki
->dwFlags
& KEYEVENTF_UNICODE
)
1298 vk_hook
= Msg
.wParam
= wVk
= VK_PACKET
;
1299 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, ki
->wScan
);
1302 FocusMessageQueue
= IntGetFocusMessageQueue();
1306 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
1307 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1311 KeQueryTickCount(&LargeTickCount
);
1312 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1315 Msg
.time
= ki
->time
;
1317 /* All messages have to contain the cursor point. */
1318 pti
= PsGetCurrentThreadWin32Thread();
1319 Msg
.pt
= gpsi
->ptCursor
;
1321 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1322 Msg
.message
, vk_hook
, Msg
.lParam
);
1324 KbdHookData
.vkCode
= vk_hook
;
1325 KbdHookData
.scanCode
= ki
->wScan
;
1326 KbdHookData
.flags
= flags
>> 8;
1327 KbdHookData
.time
= Msg
.time
;
1328 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1329 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1331 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1332 Msg
.message
, vk_hook
, Msg
.lParam
);
1333 if (Entered
) UserLeave();
1337 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1339 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1341 gQueueKeyStateTable
[wVk
] &= ~0x80;
1342 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1346 if (!(gQueueKeyStateTable
[wVk
] & 0x80)) gQueueKeyStateTable
[wVk
] ^= 0x01;
1347 gQueueKeyStateTable
[wVk
] |= 0xc0;
1348 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1351 if (gQueueKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1353 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1355 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1358 if (FocusMessageQueue
== NULL
)
1360 DPRINT("No focus message queue\n");
1361 if (Entered
) UserLeave();
1365 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1367 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1368 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
1370 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
1372 Msg
.pt
= gpsi
->ptCursor
;
1374 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
1378 DPRINT("Invalid focus window handle\n");
1381 if (Entered
) UserLeave();
1387 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1391 /* Can not be the same thread.*/
1392 if (pti
== ptiTo
) return FALSE
;
1394 /* Do not attach to system threads or between different desktops. */
1395 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1396 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1397 pti
->rpdesk
!= ptiTo
->rpdesk
)
1400 /* If Attach set, allocate and link. */
1403 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), TAG_ATTACHINFO
);
1404 if ( !pai
) return FALSE
;
1406 pai
->paiNext
= gpai
;
1411 else /* If clear, unlink and free it. */
1413 PATTACHINFO paiprev
= NULL
;
1415 if ( !gpai
) return FALSE
;
1419 /* Search list and free if found or return false. */
1422 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1427 if ( !pai
) return FALSE
;
1429 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1431 ExFreePoolWithTag(pai
, TAG_ATTACHINFO
);
1444 PTHREADINFO W32Thread
;
1446 DECLARE_RETURN(UINT
);
1448 DPRINT("Enter NtUserSendInput\n");
1449 UserEnterExclusive();
1451 W32Thread
= PsGetCurrentThreadWin32Thread();
1454 if(!W32Thread
->rpdesk
)
1459 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1461 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1466 * FIXME - check access rights of the window station
1467 * e.g. services running in the service window station cannot block input
1469 if(!ThreadHasInputAccess(W32Thread
) ||
1470 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1472 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1482 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1483 if(!NT_SUCCESS(Status
))
1485 SetLastNtError(Status
);
1489 switch(SafeInput
.type
)
1492 if(IntMouseInput(&SafeInput
.mi
))
1497 case INPUT_KEYBOARD
:
1498 if(IntKeyboardInput(&SafeInput
.ki
))
1503 case INPUT_HARDWARE
:
1508 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1518 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);