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 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
208 if (!NT_SUCCESS(Status
))
210 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
214 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
215 LOW_REALTIME_PRIORITY
+ 3);
217 InitializeObjectAttributes(&MouseObjectAttributes
,
224 LARGE_INTEGER DueTime
;
226 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
227 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
228 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
229 Status
= NtOpenFile(&MouseDeviceHandle
,
231 &MouseObjectAttributes
,
234 FILE_SYNCHRONOUS_IO_ALERT
);
235 } while (!NT_SUCCESS(Status
));
237 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
238 LOW_REALTIME_PRIORITY
+ 3);
243 * Wait to start input.
245 DPRINT("Mouse Input Thread Waiting for start event\n");
246 Status
= KeWaitForSingleObject(&InputThreadsStart
,
251 DPRINT("Mouse Input Thread Starting...\n");
253 /*FIXME: Does mouse attributes need to be used for anything */
254 Status
= NtDeviceIoControlFile(MouseDeviceHandle
,
259 IOCTL_MOUSE_QUERY_ATTRIBUTES
,
260 &MouseAttr
, sizeof(MOUSE_ATTRIBUTES
),
262 if(!NT_SUCCESS(Status
))
264 DPRINT("Failed to get mouse attributes\n");
268 * Receive and process mouse input.
270 while(InputThreadsRunning
)
272 MOUSE_INPUT_DATA MouseInput
;
273 Status
= NtReadFile(MouseDeviceHandle
,
279 sizeof(MOUSE_INPUT_DATA
),
282 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
286 if(Status
== STATUS_PENDING
)
288 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
289 Status
= Iosb
.Status
;
291 if(!NT_SUCCESS(Status
))
293 DPRINT1("Win32K: Failed to read from mouse.\n");
296 DPRINT("MouseEvent\n");
297 IntLastInputTick(TRUE
);
299 UserEnterExclusive();
301 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
305 DPRINT("Mouse Input Thread Stopped...\n");
309 /* Returns a value that indicates if the key is a modifier key, and
313 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
315 if (InputData
->Flags
& KEY_E1
)
318 if (!(InputData
->Flags
& KEY_E0
))
320 switch (InputData
->MakeCode
)
322 case 0x2a: /* left shift */
323 case 0x36: /* right shift */
326 case 0x1d: /* left control */
329 case 0x38: /* left alt */
338 switch (InputData
->MakeCode
)
340 case 0x1d: /* right control */
343 case 0x38: /* right alt */
346 case 0x5b: /* left gui (windows) */
347 case 0x5c: /* right gui (windows) */
356 /* Asks the keyboard driver to send a small table that shows which
357 * lights should connect with which scancodes
359 static NTSTATUS APIENTRY
360 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
361 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
365 IO_STATUS_BLOCK Block
;
366 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
368 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
370 Ret
= ExAllocatePoolWithTag(PagedPool
,
376 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
381 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
385 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
388 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
390 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
392 Ret
= ExAllocatePoolWithTag(PagedPool
,
398 return STATUS_INSUFFICIENT_RESOURCES
;
400 if (Status
!= STATUS_SUCCESS
)
402 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
406 *IndicatorTrans
= Ret
;
410 /* Sends the keyboard commands to turn on/off the lights.
412 static NTSTATUS APIENTRY
413 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
414 PKEYBOARD_INPUT_DATA KeyInput
,
415 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
419 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
420 IO_STATUS_BLOCK Block
;
423 return STATUS_NOT_SUPPORTED
;
425 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
426 return STATUS_SUCCESS
;
428 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
430 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
432 Indicators
.LedFlags
^=
433 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
435 /* Update the lights on the hardware */
437 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
442 IOCTL_KEYBOARD_SET_INDICATORS
,
443 &Indicators
, sizeof(Indicators
),
450 return STATUS_SUCCESS
;
454 IntKeyboardSendWinKeyMsg()
456 PWINDOW_OBJECT Window
;
459 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
461 DPRINT1("Couldn't find window to send Windows key message!\n");
465 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
466 Mesg
.message
= WM_SYSCOMMAND
;
467 Mesg
.wParam
= SC_TASKLIST
;
470 /* The QS_HOTKEY is just a guess */
471 MsqPostMessage(Window
->pti
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
475 co_IntKeyboardSendAltKeyMsg()
477 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
481 KeyboardThreadMain(PVOID StartContext
)
483 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
484 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
485 IO_STATUS_BLOCK Iosb
;
488 PUSER_MESSAGE_QUEUE FocusQueue
;
489 struct _ETHREAD
*FocusThread
;
491 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
492 UINT ModifierState
= 0;
493 USHORT LastMakeCode
= 0;
494 USHORT LastFlags
= 0;
495 UINT RepeatCount
= 0;
497 InitializeObjectAttributes(&KeyboardObjectAttributes
,
504 LARGE_INTEGER DueTime
;
506 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
507 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
508 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
509 Status
= NtOpenFile(&KeyboardDeviceHandle
,
511 &KeyboardObjectAttributes
,
514 FILE_SYNCHRONOUS_IO_ALERT
);
515 } while (!NT_SUCCESS(Status
));
517 /* Not sure if converting this thread to a win32 thread is such
518 a great idea. Since we're posting keyboard messages to the focus
519 window message queue, we'll be (indirectly) doing sendmessage
520 stuff from this thread (for WH_KEYBOARD_LL processing), which
521 means we need our own message queue. If keyboard messages were
522 instead queued to the system message queue, the thread removing
523 the message from the system message queue would be responsible
524 for WH_KEYBOARD_LL processing and we wouldn't need this thread
525 to be a win32 thread. */
526 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
527 if (!NT_SUCCESS(Status
))
529 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
533 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
534 LOW_REALTIME_PRIORITY
+ 3);
536 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
542 * Wait to start input.
544 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
545 Status
= KeWaitForSingleObject(&InputThreadsStart
,
551 DPRINT( "Keyboard Input Thread Starting...\n" );
553 * Receive and process keyboard input.
555 while (InputThreadsRunning
)
559 KEYBOARD_INPUT_DATA KeyInput
;
560 KEYBOARD_INPUT_DATA NextKeyInput
;
562 UINT fsModifiers
, fsNextModifiers
;
563 struct _ETHREAD
*Thread
;
567 DPRINT("KeyInput @ %08x\n", &KeyInput
);
569 Status
= NtReadFile (KeyboardDeviceHandle
,
575 sizeof(KEYBOARD_INPUT_DATA
),
579 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
583 if(Status
== STATUS_PENDING
)
585 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
586 Status
= Iosb
.Status
;
588 if(!NT_SUCCESS(Status
))
590 DPRINT1("Win32K: Failed to read from mouse.\n");
594 DPRINT("KeyRaw: %s %04x\n",
595 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
598 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
601 if (!NT_SUCCESS(Status
))
603 DPRINT1("Win32K: Failed to read from keyboard.\n");
607 /* Set LastInputTick */
608 IntLastInputTick(TRUE
);
610 /* Update modifier state */
611 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
615 if (KeyInput
.Flags
& KEY_BREAK
)
617 ModifierState
&= ~fsModifiers
;
618 if(fsModifiers
== MOD_ALT
)
620 if(KeyInput
.Flags
& KEY_E0
)
622 gQueueKeyStateTable
[VK_RMENU
] = 0;
626 gQueueKeyStateTable
[VK_LMENU
] = 0;
628 if (gQueueKeyStateTable
[VK_RMENU
] == 0 &&
629 gQueueKeyStateTable
[VK_LMENU
] == 0)
631 gQueueKeyStateTable
[VK_MENU
] = 0;
637 ModifierState
|= fsModifiers
;
639 if (ModifierState
== fsModifiers
&&
640 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
642 /* First send out special notifications
643 * (For alt, the message that turns on accelerator
644 * display, not sure what for win. Both TODO though.)
647 if(fsModifiers
== MOD_ALT
)
649 if(KeyInput
.Flags
& KEY_E0
)
651 gQueueKeyStateTable
[VK_RMENU
] = 0x80;
655 gQueueKeyStateTable
[VK_LMENU
] = 0x80;
659 gQueueKeyStateTable
[VK_MENU
] = 0x80;
662 /* Read the next key before sending this one */
665 Status
= NtReadFile (KeyboardDeviceHandle
,
671 sizeof(KEYBOARD_INPUT_DATA
),
674 DPRINT("KeyRaw: %s %04x\n",
675 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
676 NextKeyInput
.MakeCode
);
678 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
682 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
683 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
684 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
685 * code. I'm not caring about the counting, not sure
686 * if that matters. I think not.
689 /* If the ModifierState is now empty again, send a
690 * special notification and eat both keypresses
693 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
696 ModifierState
^= fsNextModifiers
;
698 if (ModifierState
== 0)
700 if (fsModifiers
== MOD_WIN
)
701 IntKeyboardSendWinKeyMsg();
702 else if (fsModifiers
== MOD_ALT
)
704 gQueueKeyStateTable
[VK_MENU
] = 0;
707 gQueueKeyStateTable
[VK_LMENU
] = 0;
711 gQueueKeyStateTable
[VK_RMENU
] = 0;
713 co_IntKeyboardSendAltKeyMsg();
723 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
726 PKBL keyboardLayout
= NULL
;
729 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
733 /* While we are working, we set up lParam. The format is:
734 * 0-15: The number of times this key has autorepeated
735 * 16-23: The keyboard scancode
736 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
737 * Note that E1 is only used for PAUSE (E1-1D-45) and
738 * E0-45 happens not to be anything.
739 * 29: Alt is pressed ('Context code')
740 * 30: Previous state, if the key was down before this message
741 * This is a cheap way to ignore autorepeat keys
742 * 31: 1 if the key is being pressed
745 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
746 * and it's the same key as the last one, increase the repeat
750 if (!(KeyInput
.Flags
& KEY_BREAK
))
752 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
753 (KeyInput
.MakeCode
== LastMakeCode
))
761 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
762 LastMakeCode
= KeyInput
.MakeCode
;
768 LastMakeCode
= 0; /* Should never match */
769 lParam
|= (1 << 30) | (1 << 31);
772 lParam
|= RepeatCount
;
774 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
776 if (KeyInput
.Flags
& KEY_E0
)
779 if (ModifierState
& MOD_ALT
)
783 if (!(KeyInput
.Flags
& KEY_BREAK
))
784 msg
.message
= WM_SYSKEYDOWN
;
786 msg
.message
= WM_SYSKEYUP
;
790 if (!(KeyInput
.Flags
& KEY_BREAK
))
791 msg
.message
= WM_KEYDOWN
;
793 msg
.message
= WM_KEYUP
;
796 /* Find the target thread whose locale is in effect */
797 FocusQueue
= IntGetFocusMessageQueue();
801 msg
.hwnd
= FocusQueue
->FocusWindow
;
803 FocusThread
= FocusQueue
->Thread
;
804 if (FocusThread
&& FocusThread
->Tcb
.Win32Thread
)
806 keyboardLayout
= ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
;
811 keyboardLayout
= W32kGetDefaultKeyLayout();
816 /* This function uses lParam to fill wParam according to the
817 * keyboard layout in use.
819 W32kKeyProcessMessage(&msg
,
820 keyboardLayout
->KBTables
,
821 KeyInput
.Flags
& KEY_E0
? 0xE0 :
822 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
824 if (GetHotKey(ModifierState
,
830 if (!(KeyInput
.Flags
& KEY_BREAK
))
832 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
833 MsqPostHotKeyMessage (Thread
,
836 MAKELPARAM((WORD
)ModifierState
,
839 continue; /* Eat key up motion too */
844 /* There is no focused window to receive a keyboard message */
848 * Post a keyboard message.
850 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
855 DPRINT( "KeyboardInput Thread Stopped...\n" );
860 static PVOID Objects
[2];
863 Since this relies on InputThreadsStart, just fake it.
866 RawInputThreadMain(PVOID StartContext
)
869 LARGE_INTEGER DueTime
;
871 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
876 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
877 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
878 } while (!NT_SUCCESS(Status
));
881 Objects
[0] = &InputThreadsStart
;
883 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), TAG_INPUT
);
886 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
889 KeInitializeTimer(MasterTimer
);
890 Objects
[1] = MasterTimer
;
892 // This thread requires win32k!
893 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
894 if (!NT_SUCCESS(Status
))
896 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
900 ptiRawInput
= PsGetCurrentThreadWin32Thread();
901 DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput
);
904 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
905 LOW_REALTIME_PRIORITY
+ 3);
907 UserEnterExclusive();
912 // ATM, we just have one job to handle, merge the other two later.
916 DPRINT( "Raw Input Thread Waiting for start event\n" );
918 Status
= KeWaitForMultipleObjects( 2,
926 DPRINT( "Raw Input Thread Starting...\n" );
930 DPRINT1("Raw Input Thread Exit!\n");
938 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
940 /* Initialize the default keyboard layout */
941 if(!UserInitDefaultKeyboardLayout())
943 DPRINT1("Failed to initialize default keyboard layout!\n");
946 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
953 if (!NT_SUCCESS(Status
))
955 DPRINT1("Win32K: Failed to create raw thread.\n");
958 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
965 if (!NT_SUCCESS(Status
))
967 DPRINT1("Win32K: Failed to create keyboard thread.\n");
970 Status
= PsCreateSystemThread(&MouseThreadHandle
,
977 if (!NT_SUCCESS(Status
))
979 DPRINT1("Win32K: Failed to create mouse thread.\n");
982 InputThreadsRunning
= TRUE
;
983 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
985 return STATUS_SUCCESS
;
989 CleanupInputImp(VOID
)
991 return(STATUS_SUCCESS
);
998 POINT pt
) // Just like the User call.
1005 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
1007 PTHREADINFO OldBlock
;
1010 if(!W32Thread
->rpdesk
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
1013 * fail blocking if exiting the thread
1020 * FIXME - check access rights of the window station
1021 * e.g. services running in the service window station cannot block input
1023 if(!ThreadHasInputAccess(W32Thread
) ||
1024 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1026 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1030 ASSERT(W32Thread
->rpdesk
);
1031 OldBlock
= W32Thread
->rpdesk
->BlockInputThread
;
1034 if(OldBlock
!= W32Thread
)
1036 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1039 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1040 return OldBlock
== NULL
;
1043 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1044 return OldBlock
== NULL
;
1052 DECLARE_RETURN(BOOLEAN
);
1054 DPRINT("Enter NtUserBlockInput\n");
1055 UserEnterExclusive();
1057 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1060 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1066 IntMouseInput(MOUSEINPUT
*mi
)
1068 const UINT SwapBtnMsg
[2][2] =
1070 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
1071 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1073 const WPARAM SwapBtn
[2] =
1075 MK_LBUTTON
, MK_RBUTTON
1078 PSYSTEM_CURSORINFO CurInfo
;
1084 CurInfo
= IntGetSysCursorInfo();
1088 LARGE_INTEGER LargeTickCount
;
1089 KeQueryTickCount(&LargeTickCount
);
1090 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1093 SwapButtons
= gspv
.bMouseBtnSwap
;
1095 MousePos
= gpsi
->ptCursor
;
1097 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1099 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1101 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
1102 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
1106 MousePos
.x
+= mi
->dx
;
1107 MousePos
.y
+= mi
->dy
;
1112 * Insert the messages into the system queue
1115 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1118 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1120 Msg
.wParam
|= MK_SHIFT
;
1123 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1125 Msg
.wParam
|= MK_CONTROL
;
1128 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1130 UserSetCursorPos(MousePos
.x
, MousePos
.y
);
1132 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1134 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1135 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1136 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1137 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1138 MsqInsertSystemMessage(&Msg
);
1140 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1142 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1143 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1144 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1145 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1146 MsqInsertSystemMessage(&Msg
);
1148 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1150 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1151 Msg
.message
= WM_MBUTTONDOWN
;
1152 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1153 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1154 MsqInsertSystemMessage(&Msg
);
1156 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1158 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1159 Msg
.message
= WM_MBUTTONUP
;
1160 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1161 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1162 MsqInsertSystemMessage(&Msg
);
1164 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1166 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1167 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1168 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1169 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1170 MsqInsertSystemMessage(&Msg
);
1172 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1174 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1175 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1176 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1177 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1178 MsqInsertSystemMessage(&Msg
);
1181 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1182 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1184 /* fail because both types of events use the mouseData field */
1188 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1190 Msg
.message
= WM_XBUTTONDOWN
;
1191 if(mi
->mouseData
& XBUTTON1
)
1193 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1194 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
1195 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1196 MsqInsertSystemMessage(&Msg
);
1198 if(mi
->mouseData
& XBUTTON2
)
1200 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1201 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
1202 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1203 MsqInsertSystemMessage(&Msg
);
1206 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1208 Msg
.message
= WM_XBUTTONUP
;
1209 if(mi
->mouseData
& XBUTTON1
)
1211 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1212 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
1213 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1214 MsqInsertSystemMessage(&Msg
);
1216 if(mi
->mouseData
& XBUTTON2
)
1218 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1219 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
1220 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1221 MsqInsertSystemMessage(&Msg
);
1224 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1226 Msg
.message
= WM_MOUSEWHEEL
;
1227 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1228 MsqInsertSystemMessage(&Msg
);
1235 IntKeyboardInput(KEYBDINPUT
*ki
)
1237 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1240 LARGE_INTEGER LargeTickCount
;
1241 KBDLLHOOKSTRUCT KbdHookData
;
1242 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1243 BOOLEAN Entered
= FALSE
;
1247 // Condition may arise when calling MsqPostMessage and waiting for an event.
1248 if (!UserIsEntered())
1250 // Fixme: Not sure ATM if this thread is locked.
1251 UserEnterExclusive();
1257 flags
= LOBYTE(ki
->wScan
);
1259 if (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1260 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1262 /* strip left/right for menu, control, shift */
1268 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1269 wVkStripped
= VK_MENU
;
1276 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1277 wVkStripped
= VK_CONTROL
;
1284 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1285 wVkStripped
= VK_SHIFT
;
1290 wVkStripped
= wVkL
= wVkR
= wVk
;
1293 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1295 Msg
.message
= WM_KEYUP
;
1296 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80) &&
1297 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1298 || !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80)))
1300 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1301 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1302 Msg
.message
= WM_SYSKEYUP
;
1305 flags
|= KF_REPEAT
| KF_UP
;
1309 Msg
.message
= WM_KEYDOWN
;
1310 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1311 !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
))
1313 Msg
.message
= WM_SYSKEYDOWN
;
1314 TrackSysKey
= wVkStripped
;
1316 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
) && gQueueKeyStateTable
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1319 if (ki
->dwFlags
& KEYEVENTF_UNICODE
)
1321 vk_hook
= Msg
.wParam
= wVk
= VK_PACKET
;
1322 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, ki
->wScan
);
1325 FocusMessageQueue
= IntGetFocusMessageQueue();
1329 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
1330 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1334 KeQueryTickCount(&LargeTickCount
);
1335 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1338 Msg
.time
= ki
->time
;
1340 /* All messages have to contain the cursor point. */
1341 pti
= PsGetCurrentThreadWin32Thread();
1342 Msg
.pt
= gpsi
->ptCursor
;
1344 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1345 Msg
.message
, vk_hook
, Msg
.lParam
);
1347 KbdHookData
.vkCode
= vk_hook
;
1348 KbdHookData
.scanCode
= ki
->wScan
;
1349 KbdHookData
.flags
= flags
>> 8;
1350 KbdHookData
.time
= Msg
.time
;
1351 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1352 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1354 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1355 Msg
.message
, vk_hook
, Msg
.lParam
);
1356 if (Entered
) UserLeave();
1360 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1362 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1364 gQueueKeyStateTable
[wVk
] &= ~0x80;
1365 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1369 if (!(gQueueKeyStateTable
[wVk
] & 0x80)) gQueueKeyStateTable
[wVk
] ^= 0x01;
1370 gQueueKeyStateTable
[wVk
] |= 0xc0;
1371 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1374 if (gQueueKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1376 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1378 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1381 if (FocusMessageQueue
== NULL
)
1383 DPRINT("No focus message queue\n");
1384 if (Entered
) UserLeave();
1388 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1390 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1391 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
1393 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
1395 Msg
.pt
= gpsi
->ptCursor
;
1397 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
1401 DPRINT("Invalid focus window handle\n");
1404 if (Entered
) UserLeave();
1410 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1414 /* Can not be the same thread.*/
1415 if (pti
== ptiTo
) return FALSE
;
1417 /* Do not attach to system threads or between different desktops. */
1418 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1419 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1420 pti
->rpdesk
!= ptiTo
->rpdesk
)
1423 /* If Attach set, allocate and link. */
1426 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), TAG_ATTACHINFO
);
1427 if ( !pai
) return FALSE
;
1429 pai
->paiNext
= gpai
;
1434 else /* If clear, unlink and free it. */
1436 PATTACHINFO paiprev
= NULL
;
1438 if ( !gpai
) return FALSE
;
1442 /* Search list and free if found or return false. */
1445 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1450 if ( !pai
) return FALSE
;
1452 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1454 ExFreePoolWithTag(pai
, TAG_ATTACHINFO
);
1467 PTHREADINFO W32Thread
;
1469 DECLARE_RETURN(UINT
);
1471 DPRINT("Enter NtUserSendInput\n");
1472 UserEnterExclusive();
1474 W32Thread
= PsGetCurrentThreadWin32Thread();
1477 if(!W32Thread
->rpdesk
)
1482 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1484 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1489 * FIXME - check access rights of the window station
1490 * e.g. services running in the service window station cannot block input
1492 if(!ThreadHasInputAccess(W32Thread
) ||
1493 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1495 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1505 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1506 if(!NT_SUCCESS(Status
))
1508 SetLastNtError(Status
);
1512 switch(SafeInput
.type
)
1515 if(IntMouseInput(&SafeInput
.mi
))
1520 case INPUT_KEYBOARD
:
1521 if(IntKeyboardInput(&SafeInput
.ki
))
1526 case INPUT_HARDWARE
:
1531 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1541 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);