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
;
25 PKTIMER MasterTimer
= NULL
;
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()
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
->head
.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
;
882 Objects
[1] = MasterTimer
;
884 // This thread requires win32k!
885 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
886 if (!NT_SUCCESS(Status
))
888 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
892 ptiRawInput
= PsGetCurrentThreadWin32Thread();
893 DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput
);
896 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
897 LOW_REALTIME_PRIORITY
+ 3);
899 UserEnterExclusive();
904 // ATM, we just have one job to handle, merge the other two later.
908 DPRINT( "Raw Input Thread Waiting for start event\n" );
910 Status
= KeWaitForMultipleObjects( 2,
918 DPRINT( "Raw Input Thread Starting...\n" );
922 DPRINT1("Raw Input Thread Exit!\n");
930 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
932 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), TAG_INPUT
);
935 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
937 return STATUS_UNSUCCESSFUL
;
939 KeInitializeTimer(MasterTimer
);
941 /* Initialize the default keyboard layout */
942 if(!UserInitDefaultKeyboardLayout())
944 DPRINT1("Failed to initialize default keyboard layout!\n");
947 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
954 if (!NT_SUCCESS(Status
))
956 DPRINT1("Win32K: Failed to create raw thread.\n");
959 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
966 if (!NT_SUCCESS(Status
))
968 DPRINT1("Win32K: Failed to create keyboard thread.\n");
971 Status
= PsCreateSystemThread(&MouseThreadHandle
,
978 if (!NT_SUCCESS(Status
))
980 DPRINT1("Win32K: Failed to create mouse thread.\n");
983 InputThreadsRunning
= TRUE
;
984 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
986 return STATUS_SUCCESS
;
990 CleanupInputImp(VOID
)
992 return(STATUS_SUCCESS
);
999 POINT pt
) // Just like the User call.
1006 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
1008 PTHREADINFO OldBlock
;
1011 if(!W32Thread
->rpdesk
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
1014 * fail blocking if exiting the thread
1021 * FIXME - check access rights of the window station
1022 * e.g. services running in the service window station cannot block input
1024 if(!ThreadHasInputAccess(W32Thread
) ||
1025 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1027 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1031 ASSERT(W32Thread
->rpdesk
);
1032 OldBlock
= W32Thread
->rpdesk
->BlockInputThread
;
1035 if(OldBlock
!= W32Thread
)
1037 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1040 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1041 return OldBlock
== NULL
;
1044 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1045 return OldBlock
== NULL
;
1053 DECLARE_RETURN(BOOLEAN
);
1055 DPRINT("Enter NtUserBlockInput\n");
1056 UserEnterExclusive();
1058 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1061 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1067 IntMouseInput(MOUSEINPUT
*mi
)
1069 const UINT SwapBtnMsg
[2][2] =
1071 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
1072 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1074 const WPARAM SwapBtn
[2] =
1076 MK_LBUTTON
, MK_RBUTTON
1079 PSYSTEM_CURSORINFO CurInfo
;
1085 CurInfo
= IntGetSysCursorInfo();
1089 LARGE_INTEGER LargeTickCount
;
1090 KeQueryTickCount(&LargeTickCount
);
1091 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1094 SwapButtons
= gspv
.bMouseBtnSwap
;
1096 MousePos
= gpsi
->ptCursor
;
1098 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1100 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1102 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
1103 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
1107 MousePos
.x
+= mi
->dx
;
1108 MousePos
.y
+= mi
->dy
;
1113 * Insert the messages into the system queue
1116 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1119 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1121 Msg
.wParam
|= MK_SHIFT
;
1124 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1126 Msg
.wParam
|= MK_CONTROL
;
1129 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1131 UserSetCursorPos(MousePos
.x
, MousePos
.y
, TRUE
);
1133 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1135 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1136 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1137 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1138 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1139 MsqInsertSystemMessage(&Msg
);
1141 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1143 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1144 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1145 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1146 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1147 MsqInsertSystemMessage(&Msg
);
1149 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1151 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1152 Msg
.message
= WM_MBUTTONDOWN
;
1153 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1154 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1155 MsqInsertSystemMessage(&Msg
);
1157 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1159 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1160 Msg
.message
= WM_MBUTTONUP
;
1161 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1162 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1163 MsqInsertSystemMessage(&Msg
);
1165 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1167 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1168 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1169 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1170 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1171 MsqInsertSystemMessage(&Msg
);
1173 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1175 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1176 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1177 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1178 Msg
.wParam
|= CurInfo
->ButtonsDown
;
1179 MsqInsertSystemMessage(&Msg
);
1182 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1183 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1185 /* fail because both types of events use the mouseData field */
1189 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1191 Msg
.message
= WM_XBUTTONDOWN
;
1192 if(mi
->mouseData
& XBUTTON1
)
1194 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1195 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
1196 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1197 MsqInsertSystemMessage(&Msg
);
1199 if(mi
->mouseData
& XBUTTON2
)
1201 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1202 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
1203 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1204 MsqInsertSystemMessage(&Msg
);
1207 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1209 Msg
.message
= WM_XBUTTONUP
;
1210 if(mi
->mouseData
& XBUTTON1
)
1212 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1213 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
1214 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1215 MsqInsertSystemMessage(&Msg
);
1217 if(mi
->mouseData
& XBUTTON2
)
1219 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1220 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
1221 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1222 MsqInsertSystemMessage(&Msg
);
1225 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1227 Msg
.message
= WM_MOUSEWHEEL
;
1228 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1229 MsqInsertSystemMessage(&Msg
);
1236 IntKeyboardInput(KEYBDINPUT
*ki
)
1238 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 Msg
.pt
= gpsi
->ptCursor
;
1343 KbdHookData
.vkCode
= vk_hook
;
1344 KbdHookData
.scanCode
= ki
->wScan
;
1345 KbdHookData
.flags
= flags
>> 8;
1346 KbdHookData
.time
= Msg
.time
;
1347 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1348 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1350 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1351 Msg
.message
, vk_hook
, Msg
.lParam
);
1352 if (Entered
) UserLeave();
1356 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1358 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1360 gQueueKeyStateTable
[wVk
] &= ~0x80;
1361 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1365 if (!(gQueueKeyStateTable
[wVk
] & 0x80)) gQueueKeyStateTable
[wVk
] ^= 0x01;
1366 gQueueKeyStateTable
[wVk
] |= 0xc0;
1367 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1370 if (gQueueKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1372 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1374 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1377 if (FocusMessageQueue
== NULL
)
1379 DPRINT("No focus message queue\n");
1380 if (Entered
) UserLeave();
1384 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1386 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1387 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
1389 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
1391 Msg
.pt
= gpsi
->ptCursor
;
1393 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
1397 DPRINT("Invalid focus window handle\n");
1400 if (Entered
) UserLeave();
1406 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1410 /* Can not be the same thread.*/
1411 if (pti
== ptiTo
) return FALSE
;
1413 /* Do not attach to system threads or between different desktops. */
1414 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1415 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1416 pti
->rpdesk
!= ptiTo
->rpdesk
)
1419 /* If Attach set, allocate and link. */
1422 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), TAG_ATTACHINFO
);
1423 if ( !pai
) return FALSE
;
1425 pai
->paiNext
= gpai
;
1430 else /* If clear, unlink and free it. */
1432 PATTACHINFO paiprev
= NULL
;
1434 if ( !gpai
) return FALSE
;
1438 /* Search list and free if found or return false. */
1441 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1446 if ( !pai
) return FALSE
;
1448 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1450 ExFreePoolWithTag(pai
, TAG_ATTACHINFO
);
1463 PTHREADINFO W32Thread
;
1465 DECLARE_RETURN(UINT
);
1467 DPRINT("Enter NtUserSendInput\n");
1468 UserEnterExclusive();
1470 W32Thread
= PsGetCurrentThreadWin32Thread();
1473 if(!W32Thread
->rpdesk
)
1478 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1480 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1485 * FIXME - check access rights of the window station
1486 * e.g. services running in the service window station cannot block input
1488 if(!ThreadHasInputAccess(W32Thread
) ||
1489 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1491 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1501 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1502 if(!NT_SUCCESS(Status
))
1504 SetLastNtError(Status
);
1508 switch(SafeInput
.type
)
1511 if(IntMouseInput(&SafeInput
.mi
))
1516 case INPUT_KEYBOARD
:
1517 if(IntKeyboardInput(&SafeInput
.ki
))
1522 case INPUT_HARDWARE
:
1527 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1537 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);