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
)),
716 PKBL keyboardLayout
= NULL
;
719 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
723 /* While we are working, we set up lParam. The format is:
724 * 0-15: The number of times this key has autorepeated
725 * 16-23: The keyboard scancode
726 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
727 * Note that E1 is only used for PAUSE (E1-1D-45) and
728 * E0-45 happens not to be anything.
729 * 29: Alt is pressed ('Context code')
730 * 30: Previous state, if the key was down before this message
731 * This is a cheap way to ignore autorepeat keys
732 * 31: 1 if the key is being pressed
735 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
736 * and it's the same key as the last one, increase the repeat
740 if (!(KeyInput
.Flags
& KEY_BREAK
))
742 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
743 (KeyInput
.MakeCode
== LastMakeCode
))
751 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
752 LastMakeCode
= KeyInput
.MakeCode
;
758 LastMakeCode
= 0; /* Should never match */
759 lParam
|= (1 << 30) | (1 << 31);
762 lParam
|= RepeatCount
;
764 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
766 if (KeyInput
.Flags
& KEY_E0
)
769 if (ModifierState
& MOD_ALT
)
773 if (!(KeyInput
.Flags
& KEY_BREAK
))
774 msg
.message
= WM_SYSKEYDOWN
;
776 msg
.message
= WM_SYSKEYUP
;
780 if (!(KeyInput
.Flags
& KEY_BREAK
))
781 msg
.message
= WM_KEYDOWN
;
783 msg
.message
= WM_KEYUP
;
786 /* Find the target thread whose locale is in effect */
787 FocusQueue
= IntGetFocusMessageQueue();
791 msg
.hwnd
= FocusQueue
->FocusWindow
;
793 FocusThread
= FocusQueue
->Thread
;
794 if (FocusThread
&& FocusThread
->Tcb
.Win32Thread
)
796 keyboardLayout
= ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
;
801 keyboardLayout
= W32kGetDefaultKeyLayout();
806 /* This function uses lParam to fill wParam according to the
807 * keyboard layout in use.
809 W32kKeyProcessMessage(&msg
,
810 keyboardLayout
->KBTables
,
811 KeyInput
.Flags
& KEY_E0
? 0xE0 :
812 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
814 if (GetHotKey(ModifierState
,
820 if (!(KeyInput
.Flags
& KEY_BREAK
))
822 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
823 MsqPostHotKeyMessage (Thread
,
826 MAKELPARAM((WORD
)ModifierState
,
829 continue; /* Eat key up motion too */
834 /* There is no focused window to receive a keyboard message */
838 * Post a keyboard message.
840 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
845 DPRINT( "KeyboardInput Thread Stopped...\n" );
850 static PVOID Objects
[2];
853 Since this relies on InputThreadsStart, just fake it.
856 RawInputThreadMain(PVOID StartContext
)
859 LARGE_INTEGER DueTime
;
861 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
866 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
867 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
868 } while (!NT_SUCCESS(Status
));
871 Objects
[0] = &InputThreadsStart
;
873 MasterTimer
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(KTIMER
), TAG_INPUT
);
876 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
879 KeInitializeTimer(MasterTimer
);
880 Objects
[1] = MasterTimer
;
882 // This thread requires win32k!
883 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
884 if (!NT_SUCCESS(Status
))
886 DPRINT1("Win32K: Failed making Raw Input thread a win32 thread.\n");
890 ptiRawInput
= PsGetCurrentThreadWin32Thread();
891 DPRINT("\nRaw Input Thread 0x%x \n", ptiRawInput
);
894 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
895 LOW_REALTIME_PRIORITY
+ 3);
897 UserEnterExclusive();
902 // ATM, we just have one job to handle, merge the other two later.
906 DPRINT( "Raw Input Thread Waiting for start event\n" );
908 Status
= KeWaitForMultipleObjects( 2,
916 DPRINT( "Raw Input Thread Starting...\n" );
920 DPRINT1("Raw Input Thread Exit!\n");
928 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
930 /* Initialize the default keyboard layout */
931 if(!UserInitDefaultKeyboardLayout())
933 DPRINT1("Failed to initialize default keyboard layout!\n");
936 Status
= PsCreateSystemThread(&RawInputThreadHandle
,
943 if (!NT_SUCCESS(Status
))
945 DPRINT1("Win32K: Failed to create raw thread.\n");
948 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
955 if (!NT_SUCCESS(Status
))
957 DPRINT1("Win32K: Failed to create keyboard thread.\n");
960 Status
= PsCreateSystemThread(&MouseThreadHandle
,
967 if (!NT_SUCCESS(Status
))
969 DPRINT1("Win32K: Failed to create mouse thread.\n");
972 InputThreadsRunning
= TRUE
;
973 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
975 return STATUS_SUCCESS
;
979 CleanupInputImp(VOID
)
981 return(STATUS_SUCCESS
);
988 POINT pt
) // Just like the User call.
995 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
997 PTHREADINFO OldBlock
;
1000 if(!W32Thread
->rpdesk
|| ((W32Thread
->TIF_flags
& TIF_INCLEANUP
) && BlockIt
))
1003 * fail blocking if exiting the thread
1010 * FIXME - check access rights of the window station
1011 * e.g. services running in the service window station cannot block input
1013 if(!ThreadHasInputAccess(W32Thread
) ||
1014 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1016 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1020 ASSERT(W32Thread
->rpdesk
);
1021 OldBlock
= W32Thread
->rpdesk
->BlockInputThread
;
1024 if(OldBlock
!= W32Thread
)
1026 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1029 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1030 return OldBlock
== NULL
;
1033 W32Thread
->rpdesk
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
1034 return OldBlock
== NULL
;
1042 DECLARE_RETURN(BOOLEAN
);
1044 DPRINT("Enter NtUserBlockInput\n");
1045 UserEnterExclusive();
1047 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
1050 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
1056 IntMouseInput(MOUSEINPUT
*mi
)
1058 const UINT SwapBtnMsg
[2][2] =
1060 {WM_LBUTTONDOWN
, WM_RBUTTONDOWN
},
1061 {WM_LBUTTONUP
, WM_RBUTTONUP
}
1063 const WPARAM SwapBtn
[2] =
1065 MK_LBUTTON
, MK_RBUTTON
1068 PSYSTEM_CURSORINFO CurInfo
;
1074 CurInfo
= IntGetSysCursorInfo();
1078 LARGE_INTEGER LargeTickCount
;
1079 KeQueryTickCount(&LargeTickCount
);
1080 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1083 SwapButtons
= gspv
.bMouseBtnSwap
;
1085 MousePos
= gpsi
->ptCursor
;
1087 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1089 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1091 MousePos
.x
= mi
->dx
* UserGetSystemMetrics(SM_CXVIRTUALSCREEN
) >> 16;
1092 MousePos
.y
= mi
->dy
* UserGetSystemMetrics(SM_CYVIRTUALSCREEN
) >> 16;
1096 MousePos
.x
+= mi
->dx
;
1097 MousePos
.y
+= mi
->dy
;
1102 * Insert the messages into the system queue
1104 Msg
.wParam
= CurInfo
->ButtonsDown
;
1105 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1108 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1110 Msg
.wParam
|= MK_SHIFT
;
1113 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1115 Msg
.wParam
|= MK_CONTROL
;
1118 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1120 UserSetCursorPos(MousePos
.x
, MousePos
.y
);
1122 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1124 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1125 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1126 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1127 MsqInsertSystemMessage(&Msg
);
1129 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1131 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1132 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1133 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1134 MsqInsertSystemMessage(&Msg
);
1136 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1138 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1139 Msg
.message
= WM_MBUTTONDOWN
;
1140 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1141 MsqInsertSystemMessage(&Msg
);
1143 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1145 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1146 Msg
.message
= WM_MBUTTONUP
;
1147 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1148 MsqInsertSystemMessage(&Msg
);
1150 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1152 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1153 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1154 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1155 MsqInsertSystemMessage(&Msg
);
1157 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1159 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1160 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1161 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1162 MsqInsertSystemMessage(&Msg
);
1165 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1166 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1168 /* fail because both types of events use the mouseData field */
1172 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1174 Msg
.message
= WM_XBUTTONDOWN
;
1175 if(mi
->mouseData
& XBUTTON1
)
1177 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1178 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1179 CurInfo
->ButtonsDown
|= XBUTTON1
;
1180 MsqInsertSystemMessage(&Msg
);
1182 if(mi
->mouseData
& XBUTTON2
)
1184 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1185 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1186 CurInfo
->ButtonsDown
|= XBUTTON2
;
1187 MsqInsertSystemMessage(&Msg
);
1190 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1192 Msg
.message
= WM_XBUTTONUP
;
1193 if(mi
->mouseData
& XBUTTON1
)
1195 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1196 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1197 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1198 MsqInsertSystemMessage(&Msg
);
1200 if(mi
->mouseData
& XBUTTON2
)
1202 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1203 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1204 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1205 MsqInsertSystemMessage(&Msg
);
1208 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1210 Msg
.message
= WM_MOUSEWHEEL
;
1211 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1212 MsqInsertSystemMessage(&Msg
);
1219 IntKeyboardInput(KEYBDINPUT
*ki
)
1221 PUSER_MESSAGE_QUEUE FocusMessageQueue
;
1224 LARGE_INTEGER LargeTickCount
;
1225 KBDLLHOOKSTRUCT KbdHookData
;
1226 WORD flags
, wVkStripped
, wVkL
, wVkR
, wVk
= ki
->wVk
, vk_hook
= ki
->wVk
;
1227 BOOLEAN Entered
= FALSE
;
1231 // Condition may arise when calling MsqPostMessage and waiting for an event.
1232 if (!UserIsEntered())
1234 // Fixme: Not sure ATM if this thread is locked.
1235 UserEnterExclusive();
1241 flags
= LOBYTE(ki
->wScan
);
1243 if (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) flags
|= KF_EXTENDED
;
1244 /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
1246 /* strip left/right for menu, control, shift */
1252 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RMENU
: VK_LMENU
;
1253 wVkStripped
= VK_MENU
;
1260 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RCONTROL
: VK_LCONTROL
;
1261 wVkStripped
= VK_CONTROL
;
1268 wVk
= (ki
->dwFlags
& KEYEVENTF_EXTENDEDKEY
) ? VK_RSHIFT
: VK_LSHIFT
;
1269 wVkStripped
= VK_SHIFT
;
1274 wVkStripped
= wVkL
= wVkR
= wVk
;
1277 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1279 Msg
.message
= WM_KEYUP
;
1280 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80) &&
1281 ((wVkStripped
== VK_MENU
) || (wVkStripped
== VK_CONTROL
)
1282 || !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80)))
1284 if( TrackSysKey
== VK_MENU
|| /* <ALT>-down/<ALT>-up sequence */
1285 (wVkStripped
!= VK_MENU
)) /* <ALT>-down...<something else>-up */
1286 Msg
.message
= WM_SYSKEYUP
;
1289 flags
|= KF_REPEAT
| KF_UP
;
1293 Msg
.message
= WM_KEYDOWN
;
1294 if ((gQueueKeyStateTable
[VK_MENU
] & 0x80 || wVkStripped
== VK_MENU
) &&
1295 !(gQueueKeyStateTable
[VK_CONTROL
] & 0x80 || wVkStripped
== VK_CONTROL
))
1297 Msg
.message
= WM_SYSKEYDOWN
;
1298 TrackSysKey
= wVkStripped
;
1300 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
) && gQueueKeyStateTable
[wVk
] & 0x80) flags
|= KF_REPEAT
;
1303 if (ki
->dwFlags
& KEYEVENTF_UNICODE
)
1305 vk_hook
= Msg
.wParam
= wVk
= VK_PACKET
;
1306 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, ki
->wScan
);
1309 FocusMessageQueue
= IntGetFocusMessageQueue();
1313 if (FocusMessageQueue
&& (FocusMessageQueue
->FocusWindow
!= (HWND
)0))
1314 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1318 KeQueryTickCount(&LargeTickCount
);
1319 Msg
.time
= MsqCalculateMessageTime(&LargeTickCount
);
1322 Msg
.time
= ki
->time
;
1324 /* All messages have to contain the cursor point. */
1325 pti
= PsGetCurrentThreadWin32Thread();
1326 Msg
.pt
= gpsi
->ptCursor
;
1328 DPRINT1("Kbd Hook msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1329 Msg
.message
, vk_hook
, Msg
.lParam
);
1331 KbdHookData
.vkCode
= vk_hook
;
1332 KbdHookData
.scanCode
= ki
->wScan
;
1333 KbdHookData
.flags
= flags
>> 8;
1334 KbdHookData
.time
= Msg
.time
;
1335 KbdHookData
.dwExtraInfo
= ki
->dwExtraInfo
;
1336 if (co_HOOK_CallHooks(WH_KEYBOARD_LL
, HC_ACTION
, Msg
.message
, (LPARAM
) &KbdHookData
))
1338 DPRINT("Kbd msg %d wParam %d lParam 0x%08x dropped by WH_KEYBOARD_LL hook\n",
1339 Msg
.message
, vk_hook
, Msg
.lParam
);
1340 if (Entered
) UserLeave();
1344 if (!(ki
->dwFlags
& KEYEVENTF_UNICODE
))
1346 if (ki
->dwFlags
& KEYEVENTF_KEYUP
)
1348 gQueueKeyStateTable
[wVk
] &= ~0x80;
1349 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1353 if (!(gQueueKeyStateTable
[wVk
] & 0x80)) gQueueKeyStateTable
[wVk
] ^= 0x01;
1354 gQueueKeyStateTable
[wVk
] |= 0xc0;
1355 gQueueKeyStateTable
[wVkStripped
] = gQueueKeyStateTable
[wVkL
] | gQueueKeyStateTable
[wVkR
];
1358 if (gQueueKeyStateTable
[VK_MENU
] & 0x80) flags
|= KF_ALTDOWN
;
1360 if (wVkStripped
== VK_SHIFT
) flags
&= ~KF_EXTENDED
;
1362 Msg
.lParam
= MAKELPARAM(1 /* repeat count */, flags
);
1365 if (FocusMessageQueue
== NULL
)
1367 DPRINT("No focus message queue\n");
1368 if (Entered
) UserLeave();
1372 if (FocusMessageQueue
->FocusWindow
!= (HWND
)0)
1374 Msg
.hwnd
= FocusMessageQueue
->FocusWindow
;
1375 DPRINT("Msg.hwnd = %x\n", Msg
.hwnd
);
1377 FocusMessageQueue
->Desktop
->pDeskInfo
->LastInputWasKbd
= TRUE
;
1379 Msg
.pt
= gpsi
->ptCursor
;
1381 MsqPostMessage(FocusMessageQueue
, &Msg
, FALSE
, QS_KEY
);
1385 DPRINT("Invalid focus window handle\n");
1388 if (Entered
) UserLeave();
1394 UserAttachThreadInput( PTHREADINFO pti
, PTHREADINFO ptiTo
, BOOL fAttach
)
1398 /* Can not be the same thread.*/
1399 if (pti
== ptiTo
) return FALSE
;
1401 /* Do not attach to system threads or between different desktops. */
1402 if ( pti
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1403 ptiTo
->TIF_flags
& TIF_DONTATTACHQUEUE
||
1404 pti
->rpdesk
!= ptiTo
->rpdesk
)
1407 /* If Attach set, allocate and link. */
1410 pai
= ExAllocatePoolWithTag(PagedPool
, sizeof(ATTACHINFO
), TAG_ATTACHINFO
);
1411 if ( !pai
) return FALSE
;
1413 pai
->paiNext
= gpai
;
1418 else /* If clear, unlink and free it. */
1420 PATTACHINFO paiprev
= NULL
;
1422 if ( !gpai
) return FALSE
;
1426 /* Search list and free if found or return false. */
1429 if ( pai
->pti2
== ptiTo
&& pai
->pti1
== pti
) break;
1434 if ( !pai
) return FALSE
;
1436 if (paiprev
) paiprev
->paiNext
= pai
->paiNext
;
1438 ExFreePoolWithTag(pai
, TAG_ATTACHINFO
);
1451 PTHREADINFO W32Thread
;
1453 DECLARE_RETURN(UINT
);
1455 DPRINT("Enter NtUserSendInput\n");
1456 UserEnterExclusive();
1458 W32Thread
= PsGetCurrentThreadWin32Thread();
1461 if(!W32Thread
->rpdesk
)
1466 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1468 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1473 * FIXME - check access rights of the window station
1474 * e.g. services running in the service window station cannot block input
1476 if(!ThreadHasInputAccess(W32Thread
) ||
1477 !IntIsActiveDesktop(W32Thread
->rpdesk
))
1479 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1489 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1490 if(!NT_SUCCESS(Status
))
1492 SetLastNtError(Status
);
1496 switch(SafeInput
.type
)
1499 if(IntMouseInput(&SafeInput
.mi
))
1504 case INPUT_KEYBOARD
:
1505 if(IntKeyboardInput(&SafeInput
.ki
))
1510 case INPUT_HARDWARE
:
1515 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1525 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);