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
1114 Msg
.wParam
= CurInfo
->ButtonsDown
;
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 MsqInsertSystemMessage(&Msg
);
1139 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1141 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1142 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1143 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1144 MsqInsertSystemMessage(&Msg
);
1146 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1148 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1149 Msg
.message
= WM_MBUTTONDOWN
;
1150 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1151 MsqInsertSystemMessage(&Msg
);
1153 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1155 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1156 Msg
.message
= WM_MBUTTONUP
;
1157 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1158 MsqInsertSystemMessage(&Msg
);
1160 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1162 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1163 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1164 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1165 MsqInsertSystemMessage(&Msg
);
1167 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1169 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1170 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1171 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1172 MsqInsertSystemMessage(&Msg
);
1175 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1176 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1178 /* fail because both types of events use the mouseData field */
1182 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1184 Msg
.message
= WM_XBUTTONDOWN
;
1185 if(mi
->mouseData
& XBUTTON1
)
1187 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1188 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1189 CurInfo
->ButtonsDown
|= XBUTTON1
;
1190 MsqInsertSystemMessage(&Msg
);
1192 if(mi
->mouseData
& XBUTTON2
)
1194 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1195 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1196 CurInfo
->ButtonsDown
|= XBUTTON2
;
1197 MsqInsertSystemMessage(&Msg
);
1200 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1202 Msg
.message
= WM_XBUTTONUP
;
1203 if(mi
->mouseData
& XBUTTON1
)
1205 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1206 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1207 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1208 MsqInsertSystemMessage(&Msg
);
1210 if(mi
->mouseData
& XBUTTON2
)
1212 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1213 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1214 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1215 MsqInsertSystemMessage(&Msg
);
1218 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1220 Msg
.message
= WM_MOUSEWHEEL
;
1221 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1222 MsqInsertSystemMessage(&Msg
);
1229 IntKeyboardInput(KEYBDINPUT
*ki
)
1231 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1234 LARGE_INTEGER LargeTickCount
;
1235 KBDLLHOOKSTRUCT KbdHookData
;
1236 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1237 BOOLEAN Entered
= FALSE
;
1241 // Condition may arise when calling MsqPostMessage and waiting for an event.
1242 if (!UserIsEntered())
1244 // Fixme: Not sure ATM if this thread is locked.
1245 UserEnterExclusive();
1251 flags
= LOBYTE(ki
->wScan
);
1253 if (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1254 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1256 /* strip left/right for menu, control, shift */
1262 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1263 wVkStripped
= VK_MENU
;
1270 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1271 wVkStripped
= VK_CONTROL
;
1278 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1279 wVkStripped
= VK_SHIFT
;
1284 wVkStripped
= wVkL
= wVkR
= wVk
;
1287 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1289 Msg
.message
= WM_KEYUP
;
1290 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80) &&
1291 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1292 || !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80)))
1294 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1295 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1296 Msg
.message
= WM_SYSKEYUP
;
1299 flags
|= KF_REPEAT
| KF_UP
;
1303 Msg
.message
= WM_KEYDOWN
;
1304 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1305 !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
))
1307 Msg
.message
= WM_SYSKEYDOWN
;
1308 TrackSysKey
= wVkStripped
;
1310 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
) && gQueueKeyStateTable
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1313 if (ki
->dwFlags
& KEYEVENTF_UNICODE
)
1315 vk_hook
= Msg
.wParam
= wVk
= VK_PACKET
;
1316 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, ki
->wScan
);
1319 FocusMessageQueue
= IntGetFocusMessageQueue();
1323 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
1324 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1328 KeQueryTickCount(&LargeTickCount
);
1329 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1332 Msg
.time
= ki
->time
;
1334 /* All messages have to contain the cursor point. */
1335 pti
= PsGetCurrentThreadWin32Thread();
1336 Msg
.pt
= gpsi
->ptCursor
;
1338 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1339 Msg
.message
, vk_hook
, Msg
.lParam
);
1341 KbdHookData
.vkCode
= vk_hook
;
1342 KbdHookData
.scanCode
= ki
->wScan
;
1343 KbdHookData
.flags
= flags
>> 8;
1344 KbdHookData
.time
= Msg
.time
;
1345 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1346 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1348 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1349 Msg
.message
, vk_hook
, Msg
.lParam
);
1350 if (Entered
) UserLeave();
1354 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1356 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1358 gQueueKeyStateTable
[wVk
] &= ~0x80;
1359 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1363 if (!(gQueueKeyStateTable
[wVk
] & 0x80)) gQueueKeyStateTable
[wVk
] ^= 0x01;
1364 gQueueKeyStateTable
[wVk
] |= 0xc0;
1365 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1368 if (gQueueKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1370 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1372 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1375 if (FocusMessageQueue
== NULL
)
1377 DPRINT("No focus message queue\n");
1378 if (Entered
) UserLeave();
1382 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1384 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1385 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
1387 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
1389 Msg
.pt
= gpsi
->ptCursor
;
1391 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
1395 DPRINT("Invalid focus window handle\n");
1398 if (Entered
) UserLeave();
1404 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1408 /* Can not be the same thread.*/
1409 if (pti
== ptiTo
) return FALSE
;
1411 /* Do not attach to system threads or between different desktops. */
1412 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1413 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1414 pti
->rpdesk
!= ptiTo
->rpdesk
)
1417 /* If Attach set, allocate and link. */
1420 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), TAG_ATTACHINFO
);
1421 if ( !pai
) return FALSE
;
1423 pai
->paiNext
= gpai
;
1428 else /* If clear, unlink and free it. */
1430 PATTACHINFO paiprev
= NULL
;
1432 if ( !gpai
) return FALSE
;
1436 /* Search list and free if found or return false. */
1439 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1444 if ( !pai
) return FALSE
;
1446 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1448 ExFreePoolWithTag(pai
, TAG_ATTACHINFO
);
1461 PTHREADINFO W32Thread
;
1463 DECLARE_RETURN(UINT
);
1465 DPRINT("Enter NtUserSendInput\n");
1466 UserEnterExclusive();
1468 W32Thread
= PsGetCurrentThreadWin32Thread();
1471 if(!W32Thread
->rpdesk
)
1476 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1478 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1483 * FIXME - check access rights of the window station
1484 * e.g. services running in the service window station cannot block input
1486 if(!ThreadHasInputAccess(W32Thread
) ||
1487 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1489 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1499 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1500 if(!NT_SUCCESS(Status
))
1502 SetLastNtError(Status
);
1506 switch(SafeInput
.type
)
1509 if(IntMouseInput(&SafeInput
.mi
))
1514 case INPUT_KEYBOARD
:
1515 if(IntKeyboardInput(&SafeInput
.ki
))
1520 case INPUT_HARDWARE
:
1525 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1535 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);