2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Window classes
24 * FILE: subsys/win32k/ntuser/class.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * 06-06-2001 CSH Created
30 /* INCLUDES ******************************************************************/
38 extern BYTE gQueueKeyStateTable
[];
40 /* GLOBALS *******************************************************************/
43 static HANDLE MouseDeviceHandle
;
44 static HANDLE MouseThreadHandle
;
45 static CLIENT_ID MouseThreadId
;
46 static HANDLE KeyboardThreadHandle
;
47 static CLIENT_ID KeyboardThreadId
;
48 static HANDLE KeyboardDeviceHandle
;
49 static KEVENT InputThreadsStart
;
50 static BOOLEAN InputThreadsRunning
= FALSE
;
52 /* FUNCTIONS *****************************************************************/
54 IntSystemParametersInfo(UINT uiAction
, UINT uiParam
,PVOID pvParam
, UINT fWinIni
);
55 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
);
57 #define ClearMouseInput(mi) \
63 #define SendMouseEvent(mi) \
64 if(mi.dx != 0 || mi.dy != 0) \
65 mi.dwFlags |= MOUSEEVENTF_MOVE; \
71 DWORD
IntLastInputTick(BOOL LastInputTickSetGet
)
73 static DWORD LastInputTick
= 0;
74 if (LastInputTickSetGet
== TRUE
)
76 LARGE_INTEGER TickCount
;
77 KeQueryTickCount(&TickCount
);
78 LastInputTick
= TickCount
.u
.LowPart
* (KeQueryTimeIncrement() / 10000);
85 NtUserGetLastInputInfo(PLASTINPUTINFO plii
)
93 if (ProbeForReadUint(&plii
->cbSize
) != sizeof(LASTINPUTINFO
))
95 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
100 ProbeForWrite(plii
, sizeof(LASTINPUTINFO
), sizeof(DWORD
));
102 plii
->dwTime
= IntLastInputTick(FALSE
);
106 SetLastNtError(_SEH_GetExceptionCode());
118 ProcessMouseInputData(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
120 PMOUSE_INPUT_DATA mid
;
127 for(i
= 0; i
< InputCount
; i
++)
135 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
)
137 mi
.dwFlags
|= MOUSEEVENTF_LEFTDOWN
;
140 if(mid
->ButtonFlags
& MOUSE_LEFT_BUTTON_UP
)
142 mi
.dwFlags
|= MOUSEEVENTF_LEFTUP
;
145 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
)
147 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEDOWN
;
150 if(mid
->ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
)
152 mi
.dwFlags
|= MOUSEEVENTF_MIDDLEUP
;
155 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
)
157 mi
.dwFlags
|= MOUSEEVENTF_RIGHTDOWN
;
160 if(mid
->ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
)
162 mi
.dwFlags
|= MOUSEEVENTF_RIGHTUP
;
165 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_DOWN
)
167 mi
.mouseData
|= XBUTTON1
;
168 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
171 if(mid
->ButtonFlags
& MOUSE_BUTTON_4_UP
)
173 mi
.mouseData
|= XBUTTON1
;
174 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
177 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_DOWN
)
179 mi
.mouseData
|= XBUTTON2
;
180 mi
.dwFlags
|= MOUSEEVENTF_XDOWN
;
183 if(mid
->ButtonFlags
& MOUSE_BUTTON_5_UP
)
185 mi
.mouseData
|= XBUTTON2
;
186 mi
.dwFlags
|= MOUSEEVENTF_XUP
;
189 if(mid
->ButtonFlags
& MOUSE_WHEEL
)
191 mi
.mouseData
= mid
->ButtonData
;
192 mi
.dwFlags
|= MOUSEEVENTF_WHEEL
;
205 MouseThreadMain(PVOID StartContext
)
207 UNICODE_STRING MouseDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\PointerClass0");
208 OBJECT_ATTRIBUTES MouseObjectAttributes
;
209 IO_STATUS_BLOCK Iosb
;
212 InitializeObjectAttributes(&MouseObjectAttributes
,
219 LARGE_INTEGER DueTime
;
221 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
222 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
223 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
224 Status
= NtOpenFile(&MouseDeviceHandle
,
226 &MouseObjectAttributes
,
229 FILE_SYNCHRONOUS_IO_ALERT
);
230 } while (!NT_SUCCESS(Status
));
232 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
233 LOW_REALTIME_PRIORITY
+ 3);
238 * Wait to start input.
240 DPRINT("Mouse Input Thread Waiting for start event\n");
241 Status
= KeWaitForSingleObject(&InputThreadsStart
,
246 DPRINT("Mouse Input Thread Starting...\n");
249 * Receive and process mouse input.
251 while(InputThreadsRunning
)
253 MOUSE_INPUT_DATA MouseInput
;
254 Status
= NtReadFile(MouseDeviceHandle
,
260 sizeof(MOUSE_INPUT_DATA
),
263 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
267 if(Status
== STATUS_PENDING
)
269 NtWaitForSingleObject(MouseDeviceHandle
, FALSE
, NULL
);
270 Status
= Iosb
.Status
;
272 if(!NT_SUCCESS(Status
))
274 DPRINT1("Win32K: Failed to read from mouse.\n");
277 DPRINT("MouseEvent\n");
278 IntLastInputTick(TRUE
);
280 UserEnterExclusive();
282 ProcessMouseInputData(&MouseInput
, Iosb
.Information
/ sizeof(MOUSE_INPUT_DATA
));
286 DPRINT("Mouse Input Thread Stopped...\n");
290 /* Returns a value that indicates if the key is a modifier key, and
294 IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA
*InputData
)
296 if (InputData
->Flags
& KEY_E1
)
299 if (!(InputData
->Flags
& KEY_E0
))
301 switch (InputData
->MakeCode
)
303 case 0x2a: /* left shift */
304 case 0x36: /* right shift */
307 case 0x1d: /* left control */
310 case 0x38: /* left alt */
319 switch (InputData
->MakeCode
)
321 case 0x1d: /* right control */
324 case 0x38: /* right alt */
327 case 0x5b: /* left gui (windows) */
328 case 0x5c: /* right gui (windows) */
337 /* Asks the keyboard driver to send a small table that shows which
338 * lights should connect with which scancodes
340 static NTSTATUS STDCALL
341 IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle
,
342 PKEYBOARD_INDICATOR_TRANSLATION
*IndicatorTrans
)
346 IO_STATUS_BLOCK Block
;
347 PKEYBOARD_INDICATOR_TRANSLATION Ret
;
349 Size
= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
351 Ret
= ExAllocatePoolWithTag(PagedPool
,
357 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
362 IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
,
366 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
369 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
371 Size
+= sizeof(KEYBOARD_INDICATOR_TRANSLATION
);
373 Ret
= ExAllocatePoolWithTag(PagedPool
,
379 return STATUS_INSUFFICIENT_RESOURCES
;
381 if (Status
!= STATUS_SUCCESS
)
383 ExFreePoolWithTag(Ret
, TAG_KEYBOARD
);
387 *IndicatorTrans
= Ret
;
391 /* Sends the keyboard commands to turn on/off the lights.
393 static NTSTATUS STDCALL
394 IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle
,
395 PKEYBOARD_INPUT_DATA KeyInput
,
396 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
)
400 static KEYBOARD_INDICATOR_PARAMETERS Indicators
;
401 IO_STATUS_BLOCK Block
;
404 return STATUS_NOT_SUPPORTED
;
406 if (KeyInput
->Flags
& (KEY_E0
| KEY_E1
| KEY_BREAK
))
407 return STATUS_SUCCESS
;
409 for (Count
= 0; Count
< IndicatorTrans
->NumberOfIndicatorKeys
; Count
++)
411 if (KeyInput
->MakeCode
== IndicatorTrans
->IndicatorList
[Count
].MakeCode
)
413 Indicators
.LedFlags
^=
414 IndicatorTrans
->IndicatorList
[Count
].IndicatorFlags
;
416 /* Update the lights on the hardware */
418 Status
= NtDeviceIoControlFile(KeyboardDeviceHandle
,
423 IOCTL_KEYBOARD_SET_INDICATORS
,
424 &Indicators
, sizeof(Indicators
),
431 return STATUS_SUCCESS
;
435 IntKeyboardSendWinKeyMsg()
437 PWINDOW_OBJECT Window
;
440 if (!(Window
= UserGetWindowObject(InputWindowStation
->ShellWindow
)))
442 DPRINT1("Couldn't find window to send Windows key message!\n");
446 Mesg
.hwnd
= InputWindowStation
->ShellWindow
;
447 Mesg
.message
= WM_SYSCOMMAND
;
448 Mesg
.wParam
= SC_TASKLIST
;
451 /* The QS_HOTKEY is just a guess */
452 MsqPostMessage(Window
->MessageQueue
, &Mesg
, FALSE
, QS_HOTKEY
);
456 co_IntKeyboardSendAltKeyMsg()
458 co_MsqPostKeyboardMessage(WM_SYSCOMMAND
,SC_KEYMENU
,0);
462 KeyboardThreadMain(PVOID StartContext
)
464 UNICODE_STRING KeyboardDeviceName
= RTL_CONSTANT_STRING(L
"\\Device\\KeyboardClass0");
465 OBJECT_ATTRIBUTES KeyboardObjectAttributes
;
466 IO_STATUS_BLOCK Iosb
;
469 PUSER_MESSAGE_QUEUE FocusQueue
;
470 struct _ETHREAD
*FocusThread
;
471 extern NTSTATUS
Win32kInitWin32Thread(PETHREAD Thread
);
473 PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans
= NULL
;
474 UINT ModifierState
= 0;
475 USHORT LastMakeCode
= 0;
476 USHORT LastFlags
= 0;
477 UINT RepeatCount
= 0;
479 InitializeObjectAttributes(&KeyboardObjectAttributes
,
486 LARGE_INTEGER DueTime
;
488 DueTime
.QuadPart
= (LONGLONG
)(-10000000);
489 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
490 Status
= KeWaitForSingleObject(&Event
, Executive
, KernelMode
, FALSE
, &DueTime
);
491 Status
= NtOpenFile(&KeyboardDeviceHandle
,
493 &KeyboardObjectAttributes
,
496 FILE_SYNCHRONOUS_IO_ALERT
);
497 } while (!NT_SUCCESS(Status
));
499 /* Not sure if converting this thread to a win32 thread is such
500 a great idea. Since we're posting keyboard messages to the focus
501 window message queue, we'll be (indirectly) doing sendmessage
502 stuff from this thread (for WH_KEYBOARD_LL processing), which
503 means we need our own message queue. If keyboard messages were
504 instead queued to the system message queue, the thread removing
505 the message from the system message queue would be responsible
506 for WH_KEYBOARD_LL processing and we wouldn't need this thread
507 to be a win32 thread. */
508 Status
= Win32kInitWin32Thread(PsGetCurrentThread());
509 if (!NT_SUCCESS(Status
))
511 DPRINT1("Win32K: Failed making keyboard thread a win32 thread.\n");
515 KeSetPriorityThread(&PsGetCurrentThread()->Tcb
,
516 LOW_REALTIME_PRIORITY
+ 3);
518 IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle
,
524 * Wait to start input.
526 DPRINT( "Keyboard Input Thread Waiting for start event\n" );
527 Status
= KeWaitForSingleObject(&InputThreadsStart
,
533 DPRINT( "Keyboard Input Thread Starting...\n" );
535 * Receive and process keyboard input.
537 while (InputThreadsRunning
)
541 KEYBOARD_INPUT_DATA KeyInput
;
542 KEYBOARD_INPUT_DATA NextKeyInput
;
544 UINT fsModifiers
, fsNextModifiers
;
545 struct _ETHREAD
*Thread
;
549 DPRINT("KeyInput @ %08x\n", &KeyInput
);
551 Status
= NtReadFile (KeyboardDeviceHandle
,
557 sizeof(KEYBOARD_INPUT_DATA
),
561 if(Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
565 if(Status
== STATUS_PENDING
)
567 NtWaitForSingleObject(KeyboardDeviceHandle
, FALSE
, NULL
);
568 Status
= Iosb
.Status
;
570 if(!NT_SUCCESS(Status
))
572 DPRINT1("Win32K: Failed to read from mouse.\n");
576 DPRINT("KeyRaw: %s %04x\n",
577 (KeyInput
.Flags
& KEY_BREAK
) ? "up" : "down",
580 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
583 if (!NT_SUCCESS(Status
))
585 DPRINT1("Win32K: Failed to read from keyboard.\n");
589 /* Set LastInputTick */
590 IntLastInputTick(TRUE
);
592 /* Update modifier state */
593 fsModifiers
= IntKeyboardGetModifiers(&KeyInput
);
597 if (KeyInput
.Flags
& KEY_BREAK
)
599 ModifierState
&= ~fsModifiers
;
600 if(fsModifiers
== MOD_ALT
)
602 if(KeyInput
.Flags
& KEY_E0
)
604 gQueueKeyStateTable
[VK_RMENU
] = 0;
608 gQueueKeyStateTable
[VK_LMENU
] = 0;
610 if (gQueueKeyStateTable
[VK_RMENU
] == 0 &&
611 gQueueKeyStateTable
[VK_LMENU
] == 0)
613 gQueueKeyStateTable
[VK_MENU
] = 0;
619 ModifierState
|= fsModifiers
;
621 if (ModifierState
== fsModifiers
&&
622 (fsModifiers
== MOD_ALT
|| fsModifiers
== MOD_WIN
))
624 /* First send out special notifications
625 * (For alt, the message that turns on accelerator
626 * display, not sure what for win. Both TODO though.)
629 if(fsModifiers
== MOD_ALT
)
631 if(KeyInput
.Flags
& KEY_E0
)
633 gQueueKeyStateTable
[VK_RMENU
] = 0x80;
637 gQueueKeyStateTable
[VK_LMENU
] = 0x80;
641 gQueueKeyStateTable
[VK_MENU
] = 0x80;
644 /* Read the next key before sending this one */
647 Status
= NtReadFile (KeyboardDeviceHandle
,
653 sizeof(KEYBOARD_INPUT_DATA
),
656 DPRINT("KeyRaw: %s %04x\n",
657 (NextKeyInput
.Flags
& KEY_BREAK
) ? "up":"down",
658 NextKeyInput
.MakeCode
);
660 if (Status
== STATUS_ALERTED
&& !InputThreadsRunning
)
664 while ((!(NextKeyInput
.Flags
& KEY_BREAK
)) &&
665 NextKeyInput
.MakeCode
== KeyInput
.MakeCode
);
666 /* ^ Ignore repeats, they'll be KEY_MAKE and the same
667 * code. I'm not caring about the counting, not sure
668 * if that matters. I think not.
671 /* If the ModifierState is now empty again, send a
672 * special notification and eat both keypresses
675 fsNextModifiers
= IntKeyboardGetModifiers(&NextKeyInput
);
678 ModifierState
^= fsNextModifiers
;
680 if (ModifierState
== 0)
682 if (fsModifiers
== MOD_WIN
)
683 IntKeyboardSendWinKeyMsg();
684 else if (fsModifiers
== MOD_ALT
)
686 gQueueKeyStateTable
[VK_MENU
] = 0;
689 gQueueKeyStateTable
[VK_LMENU
] = 0;
693 gQueueKeyStateTable
[VK_RMENU
] = 0;
695 co_IntKeyboardSendAltKeyMsg();
705 for (;NumKeys
;memcpy(&KeyInput
, &NextKeyInput
, sizeof(KeyInput
)),
710 IntKeyboardUpdateLeds(KeyboardDeviceHandle
,
714 /* While we are working, we set up lParam. The format is:
715 * 0-15: The number of times this key has autorepeated
716 * 16-23: The keyboard scancode
717 * 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
718 * Note that E1 is only used for PAUSE (E1-1D-45) and
719 * E0-45 happens not to be anything.
720 * 29: Alt is pressed ('Context code')
721 * 30: Previous state, if the key was down before this message
722 * This is a cheap way to ignore autorepeat keys
723 * 31: 1 if the key is being pressed
726 /* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
727 * and it's the same key as the last one, increase the repeat
731 if (!(KeyInput
.Flags
& KEY_BREAK
))
733 if (((KeyInput
.Flags
& (KEY_E0
| KEY_E1
)) == LastFlags
) &&
734 (KeyInput
.MakeCode
== LastMakeCode
))
742 LastFlags
= KeyInput
.Flags
& (KEY_E0
| KEY_E1
);
743 LastMakeCode
= KeyInput
.MakeCode
;
749 LastMakeCode
= 0; /* Should never match */
750 lParam
|= (1 << 30) | (1 << 31);
753 lParam
|= RepeatCount
;
755 lParam
|= (KeyInput
.MakeCode
& 0xff) << 16;
757 if (KeyInput
.Flags
& KEY_E0
)
760 if (ModifierState
& MOD_ALT
)
764 if (!(KeyInput
.Flags
& KEY_BREAK
))
765 msg
.message
= WM_SYSKEYDOWN
;
767 msg
.message
= WM_SYSKEYUP
;
771 if (!(KeyInput
.Flags
& KEY_BREAK
))
772 msg
.message
= WM_KEYDOWN
;
774 msg
.message
= WM_KEYUP
;
777 /* Find the target thread whose locale is in effect */
778 FocusQueue
= IntGetFocusMessageQueue();
780 /* This might cause us to lose hot keys, which are important
781 * (ctrl-alt-del secure attention sequence). Not sure if it
788 msg
.hwnd
= FocusQueue
->FocusWindow
;
790 FocusThread
= FocusQueue
->Thread
;
792 if (!(FocusThread
&& FocusThread
->Tcb
.Win32Thread
&&
793 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
))
796 /* This function uses lParam to fill wParam according to the
797 * keyboard layout in use.
799 W32kKeyProcessMessage(&msg
,
800 ((PTHREADINFO
)FocusThread
->Tcb
.Win32Thread
)->KeyboardLayout
->KBTables
,
801 KeyInput
.Flags
& KEY_E0
? 0xE0 :
802 (KeyInput
.Flags
& KEY_E1
? 0xE1 : 0));
804 if (GetHotKey(ModifierState
,
810 if (!(KeyInput
.Flags
& KEY_BREAK
))
812 DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd
, id
);
813 MsqPostHotKeyMessage (Thread
,
816 MAKELPARAM((WORD
)ModifierState
,
819 continue; /* Eat key up motion too */
823 * Post a keyboard message.
825 co_MsqPostKeyboardMessage(msg
.message
,msg
.wParam
,msg
.lParam
);
830 DPRINT( "KeyboardInput Thread Stopped...\n" );
840 KeInitializeEvent(&InputThreadsStart
, NotificationEvent
, FALSE
);
842 /* Initialize the default keyboard layout */
843 if(!UserInitDefaultKeyboardLayout())
845 DPRINT1("Failed to initialize default keyboard layout!\n");
848 Status
= PsCreateSystemThread(&KeyboardThreadHandle
,
855 if (!NT_SUCCESS(Status
))
857 DPRINT1("Win32K: Failed to create keyboard thread.\n");
860 Status
= PsCreateSystemThread(&MouseThreadHandle
,
867 if (!NT_SUCCESS(Status
))
869 DPRINT1("Win32K: Failed to create mouse thread.\n");
872 InputThreadsRunning
= TRUE
;
873 KeSetEvent(&InputThreadsStart
, IO_NO_INCREMENT
, FALSE
);
875 return STATUS_SUCCESS
;
879 CleanupInputImp(VOID
)
881 return(STATUS_SUCCESS
);
888 POINT pt
) // Just like the User call.
895 IntBlockInput(PTHREADINFO W32Thread
, BOOL BlockIt
)
897 PTHREADINFO OldBlock
;
900 if(!W32Thread
->Desktop
|| (W32Thread
->IsExiting
&& BlockIt
))
903 * fail blocking if exiting the thread
910 * FIXME - check access rights of the window station
911 * e.g. services running in the service window station cannot block input
913 if(!ThreadHasInputAccess(W32Thread
) ||
914 !IntIsActiveDesktop(W32Thread
->Desktop
))
916 SetLastWin32Error(ERROR_ACCESS_DENIED
);
920 ASSERT(W32Thread
->Desktop
);
921 OldBlock
= W32Thread
->Desktop
->BlockInputThread
;
924 if(OldBlock
!= W32Thread
)
926 SetLastWin32Error(ERROR_ACCESS_DENIED
);
929 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
930 return OldBlock
== NULL
;
933 W32Thread
->Desktop
->BlockInputThread
= (BlockIt
? W32Thread
: NULL
);
934 return OldBlock
== NULL
;
942 DECLARE_RETURN(BOOLEAN
);
944 DPRINT("Enter NtUserBlockInput\n");
945 UserEnterExclusive();
947 RETURN( IntBlockInput(PsGetCurrentThreadWin32Thread(), BlockIt
));
950 DPRINT("Leave NtUserBlockInput, ret=%i\n",_ret_
);
956 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject
, BOOL Swap
)
958 PSYSTEM_CURSORINFO CurInfo
;
961 CurInfo
= IntGetSysCursorInfo(WinStaObject
);
962 res
= CurInfo
->SwapButtons
;
963 CurInfo
->SwapButtons
= Swap
;
968 IntMouseInput(MOUSEINPUT
*mi
)
970 const UINT SwapBtnMsg
[2][2] =
973 WM_LBUTTONDOWN
, WM_RBUTTONDOWN
975 {WM_LBUTTONUP
, WM_RBUTTONUP
}
977 const WPARAM SwapBtn
[2] =
979 MK_LBUTTON
, MK_RBUTTON
981 POINT MousePos
= {0}, OrgPos
;
982 PSYSTEM_CURSORINFO CurInfo
;
983 PWINSTATION_OBJECT WinSta
;
984 BOOL DoMove
, SwapButtons
;
987 BITMAPOBJ
*BitmapObj
;
990 PWINDOW_OBJECT DesktopWindow
;
996 /* FIXME - get the screen dc from the window station or desktop */
997 if(!(hDC
= IntGetScreenDC()))
1006 WinSta
= PsGetCurrentProcessWin32Process()->WindowStation
;
1008 /* FIXME - ugly hack but as long as we're using this dumb callback from the
1009 mouse class driver, we can't access the window station from the calling
1011 WinSta
= InputWindowStation
;
1016 CurInfo
= IntGetSysCursorInfo(WinSta
);
1020 LARGE_INTEGER LargeTickCount
;
1021 KeQueryTickCount(&LargeTickCount
);
1022 mi
->time
= MsqCalculateMessageTime(&LargeTickCount
);
1025 SwapButtons
= CurInfo
->SwapButtons
;
1028 IntGetCursorLocation(WinSta
, &MousePos
);
1029 OrgPos
.x
= MousePos
.x
;
1030 OrgPos
.y
= MousePos
.y
;
1032 if(mi
->dwFlags
& MOUSEEVENTF_MOVE
)
1034 if(mi
->dwFlags
& MOUSEEVENTF_ABSOLUTE
)
1036 MousePos
.x
= mi
->dx
;
1037 MousePos
.y
= mi
->dy
;
1041 MousePos
.x
+= mi
->dx
;
1042 MousePos
.y
+= mi
->dy
;
1045 DesktopWindow
= IntGetWindowObject(WinSta
->ActiveDesktop
->DesktopWindow
);
1049 if(MousePos
.x
>= DesktopWindow
->Wnd
->ClientRect
.right
)
1050 MousePos
.x
= DesktopWindow
->Wnd
->ClientRect
.right
- 1;
1051 if(MousePos
.y
>= DesktopWindow
->Wnd
->ClientRect
.bottom
)
1052 MousePos
.y
= DesktopWindow
->Wnd
->ClientRect
.bottom
- 1;
1053 UserDereferenceObject(DesktopWindow
);
1061 if(CurInfo
->CursorClipInfo
.IsClipped
)
1063 /* The mouse cursor needs to be clipped */
1065 if(MousePos
.x
>= (LONG
)CurInfo
->CursorClipInfo
.Right
)
1066 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Right
;
1067 if(MousePos
.x
< (LONG
)CurInfo
->CursorClipInfo
.Left
)
1068 MousePos
.x
= (LONG
)CurInfo
->CursorClipInfo
.Left
;
1069 if(MousePos
.y
>= (LONG
)CurInfo
->CursorClipInfo
.Bottom
)
1070 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Bottom
;
1071 if(MousePos
.y
< (LONG
)CurInfo
->CursorClipInfo
.Top
)
1072 MousePos
.y
= (LONG
)CurInfo
->CursorClipInfo
.Top
;
1075 DoMove
= (MousePos
.x
!= OrgPos
.x
|| MousePos
.y
!= OrgPos
.y
);
1080 dc
= DC_LockDc(hDC
);
1083 hBitmap
= dc
->w
.hBitmap
;
1086 BitmapObj
= BITMAPOBJ_LockBitmap(hBitmap
);
1089 SurfObj
= &BitmapObj
->SurfObj
;
1091 if (CurInfo
->ShowingCursor
)
1093 IntEngMovePointer(SurfObj
, MousePos
.x
, MousePos
.y
, &(GDIDEV(SurfObj
)->Pointer
.Exclude
));
1095 /* Only now, update the info in the GDIDEVICE, so EngMovePointer can
1096 * use the old values to move the pointer image */
1097 GDIDEV(SurfObj
)->Pointer
.Pos
.x
= MousePos
.x
;
1098 GDIDEV(SurfObj
)->Pointer
.Pos
.y
= MousePos
.y
;
1100 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1106 * Insert the messages into the system queue
1109 Msg
.wParam
= CurInfo
->ButtonsDown
;
1110 Msg
.lParam
= MAKELPARAM(MousePos
.x
, MousePos
.y
);
1113 if (gQueueKeyStateTable
[VK_SHIFT
] & 0xc0)
1115 Msg
.wParam
|= MK_SHIFT
;
1118 if (gQueueKeyStateTable
[VK_CONTROL
] & 0xc0)
1120 Msg
.wParam
|= MK_CONTROL
;
1125 Msg
.message
= WM_MOUSEMOVE
;
1126 MsqInsertSystemMessage(&Msg
);
1130 if(mi
->dwFlags
& MOUSEEVENTF_LEFTDOWN
)
1132 gQueueKeyStateTable
[VK_LBUTTON
] |= 0xc0;
1133 Msg
.message
= SwapBtnMsg
[0][SwapButtons
];
1134 CurInfo
->ButtonsDown
|= SwapBtn
[SwapButtons
];
1135 MsqInsertSystemMessage(&Msg
);
1137 else if(mi
->dwFlags
& MOUSEEVENTF_LEFTUP
)
1139 gQueueKeyStateTable
[VK_LBUTTON
] &= ~0x80;
1140 Msg
.message
= SwapBtnMsg
[1][SwapButtons
];
1141 CurInfo
->ButtonsDown
&= ~SwapBtn
[SwapButtons
];
1142 MsqInsertSystemMessage(&Msg
);
1144 if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEDOWN
)
1146 gQueueKeyStateTable
[VK_MBUTTON
] |= 0xc0;
1147 Msg
.message
= WM_MBUTTONDOWN
;
1148 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
1149 MsqInsertSystemMessage(&Msg
);
1151 else if(mi
->dwFlags
& MOUSEEVENTF_MIDDLEUP
)
1153 gQueueKeyStateTable
[VK_MBUTTON
] &= ~0x80;
1154 Msg
.message
= WM_MBUTTONUP
;
1155 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
1156 MsqInsertSystemMessage(&Msg
);
1158 if(mi
->dwFlags
& MOUSEEVENTF_RIGHTDOWN
)
1160 gQueueKeyStateTable
[VK_RBUTTON
] |= 0xc0;
1161 Msg
.message
= SwapBtnMsg
[0][!SwapButtons
];
1162 CurInfo
->ButtonsDown
|= SwapBtn
[!SwapButtons
];
1163 MsqInsertSystemMessage(&Msg
);
1165 else if(mi
->dwFlags
& MOUSEEVENTF_RIGHTUP
)
1167 gQueueKeyStateTable
[VK_RBUTTON
] &= ~0x80;
1168 Msg
.message
= SwapBtnMsg
[1][!SwapButtons
];
1169 CurInfo
->ButtonsDown
&= ~SwapBtn
[!SwapButtons
];
1170 MsqInsertSystemMessage(&Msg
);
1173 if((mi
->dwFlags
& (MOUSEEVENTF_XDOWN
| MOUSEEVENTF_XUP
)) &&
1174 (mi
->dwFlags
& MOUSEEVENTF_WHEEL
))
1176 /* fail because both types of events use the mouseData field */
1180 if(mi
->dwFlags
& MOUSEEVENTF_XDOWN
)
1182 Msg
.message
= WM_XBUTTONDOWN
;
1183 if(mi
->mouseData
& XBUTTON1
)
1185 gQueueKeyStateTable
[VK_XBUTTON1
] |= 0xc0;
1186 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1187 CurInfo
->ButtonsDown
|= XBUTTON1
;
1188 MsqInsertSystemMessage(&Msg
);
1190 if(mi
->mouseData
& XBUTTON2
)
1192 gQueueKeyStateTable
[VK_XBUTTON2
] |= 0xc0;
1193 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1194 CurInfo
->ButtonsDown
|= XBUTTON2
;
1195 MsqInsertSystemMessage(&Msg
);
1198 else if(mi
->dwFlags
& MOUSEEVENTF_XUP
)
1200 Msg
.message
= WM_XBUTTONUP
;
1201 if(mi
->mouseData
& XBUTTON1
)
1203 gQueueKeyStateTable
[VK_XBUTTON1
] &= ~0x80;
1204 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON1
);
1205 CurInfo
->ButtonsDown
&= ~XBUTTON1
;
1206 MsqInsertSystemMessage(&Msg
);
1208 if(mi
->mouseData
& XBUTTON2
)
1210 gQueueKeyStateTable
[VK_XBUTTON2
] &= ~0x80;
1211 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, XBUTTON2
);
1212 CurInfo
->ButtonsDown
&= ~XBUTTON2
;
1213 MsqInsertSystemMessage(&Msg
);
1216 if(mi
->dwFlags
& MOUSEEVENTF_WHEEL
)
1218 Msg
.message
= WM_MOUSEWHEEL
;
1219 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, mi
->mouseData
);
1220 MsqInsertSystemMessage(&Msg
);
1227 IntKeyboardInput(KEYBDINPUT
*ki
)
1239 PTHREADINFO W32Thread
;
1241 DECLARE_RETURN(UINT
);
1243 DPRINT("Enter NtUserSendInput\n");
1244 UserEnterExclusive();
1246 W32Thread
= PsGetCurrentThreadWin32Thread();
1249 if(!W32Thread
->Desktop
)
1254 if(!nInputs
|| !pInput
|| (cbSize
!= sizeof(INPUT
)))
1256 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1261 * FIXME - check access rights of the window station
1262 * e.g. services running in the service window station cannot block input
1264 if(!ThreadHasInputAccess(W32Thread
) ||
1265 !IntIsActiveDesktop(W32Thread
->Desktop
))
1267 SetLastWin32Error(ERROR_ACCESS_DENIED
);
1277 Status
= MmCopyFromCaller(&SafeInput
, pInput
++, sizeof(INPUT
));
1278 if(!NT_SUCCESS(Status
))
1280 SetLastNtError(Status
);
1284 switch(SafeInput
.type
)
1287 if(IntMouseInput(&SafeInput
.mi
))
1292 case INPUT_KEYBOARD
:
1293 if(IntKeyboardInput(&SafeInput
.ki
))
1298 case INPUT_HARDWARE
:
1303 DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput
.type
);
1313 DPRINT("Leave NtUserSendInput, ret=%i\n",_ret_
);