2003-05-18 17:16:18 +00:00
|
|
|
/*
|
|
|
|
* ReactOS W32 Subsystem
|
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
2004-05-14 23:57:32 +00:00
|
|
|
/* $Id: input.c,v 1.33 2004/05/14 23:57:32 weiden Exp $
|
2002-01-14 01:11:58 +00:00
|
|
|
*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* PURPOSE: Window classes
|
|
|
|
* FILE: subsys/win32k/ntuser/class.c
|
|
|
|
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
|
|
* REVISION HISTORY:
|
|
|
|
* 06-06-2001 CSH Created
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
2004-05-10 17:07:20 +00:00
|
|
|
#include <w32k.h>
|
|
|
|
|
2003-11-17 02:12:52 +00:00
|
|
|
#include <rosrtl/string.h>
|
2002-01-14 01:11:58 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
2004-02-07 15:39:14 +00:00
|
|
|
#define ENABLEMOUSEGDICALLBACK 1
|
|
|
|
|
2002-09-17 23:43:29 +00:00
|
|
|
static HANDLE MouseDeviceHandle;
|
2004-02-07 15:39:14 +00:00
|
|
|
#if !ENABLEMOUSEGDICALLBACK
|
2003-12-14 14:05:47 +00:00
|
|
|
static HANDLE MouseThreadHandle;
|
|
|
|
static CLIENT_ID MouseThreadId;
|
2004-02-07 15:39:14 +00:00
|
|
|
#endif
|
2002-01-14 01:11:58 +00:00
|
|
|
static HANDLE KeyboardThreadHandle;
|
|
|
|
static CLIENT_ID KeyboardThreadId;
|
|
|
|
static HANDLE KeyboardDeviceHandle;
|
|
|
|
static KEVENT InputThreadsStart;
|
|
|
|
static BOOLEAN InputThreadsRunning = FALSE;
|
2003-10-09 06:13:05 +00:00
|
|
|
PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue = 0;
|
2002-01-14 01:11:58 +00:00
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2004-02-07 15:39:14 +00:00
|
|
|
#if !ENABLEMOUSEGDICALLBACK
|
2003-12-14 14:05:47 +00:00
|
|
|
VOID STDCALL_FUNC STATIC
|
|
|
|
MouseThreadMain(PVOID StartContext)
|
|
|
|
{
|
|
|
|
UNICODE_STRING MouseDeviceName;
|
|
|
|
OBJECT_ATTRIBUTES MouseObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
RtlRosInitUnicodeStringFromLiteral(&MouseDeviceName, L"\\??\\Mouse"); /* FIXME - does win use the same? */
|
|
|
|
InitializeObjectAttributes(&MouseObjectAttributes,
|
|
|
|
&MouseDeviceName,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&MouseDeviceHandle,
|
|
|
|
FILE_ALL_ACCESS,
|
|
|
|
&MouseObjectAttributes,
|
|
|
|
&Iosb,
|
|
|
|
0,
|
|
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Win32K: Failed to open mouse.\n");
|
|
|
|
return; //(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Wait to start input.
|
|
|
|
*/
|
|
|
|
DPRINT("Mouse Input Thread Waiting for start event\n");
|
|
|
|
Status = KeWaitForSingleObject(&InputThreadsStart,
|
|
|
|
0,
|
|
|
|
KernelMode,
|
|
|
|
TRUE,
|
|
|
|
NULL);
|
|
|
|
DPRINT("Mouse Input Thread Starting...\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Receive and process keyboard input.
|
|
|
|
*/
|
|
|
|
while(InputThreadsRunning)
|
|
|
|
{
|
|
|
|
MOUSE_INPUT_DATA MouseInput;
|
|
|
|
Status = NtReadFile(MouseDeviceHandle,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&Iosb,
|
|
|
|
&MouseInput,
|
|
|
|
sizeof(MOUSE_INPUT_DATA),
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
if(Status == STATUS_ALERTED && !InputThreadsRunning)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
NtWaitForSingleObject(MouseDeviceHandle, FALSE, NULL);
|
|
|
|
Status = Iosb.Status;
|
|
|
|
}
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Win32K: Failed to read from mouse.\n");
|
|
|
|
return; //(Status);
|
|
|
|
}
|
|
|
|
DPRINT("MouseEvent\n");
|
|
|
|
|
|
|
|
MouseGDICallBack(&MouseInput, sizeof(MOUSE_INPUT_DATA));
|
|
|
|
}
|
|
|
|
DPRINT("Mouse Input Thread Stopped...\n");
|
|
|
|
}
|
|
|
|
}
|
2004-02-07 15:39:14 +00:00
|
|
|
#endif
|
2003-12-14 14:05:47 +00:00
|
|
|
|
2004-02-10 18:11:12 +00:00
|
|
|
STATIC VOID STDCALL
|
2002-01-14 01:11:58 +00:00
|
|
|
KeyboardThreadMain(PVOID StartContext)
|
|
|
|
{
|
|
|
|
UNICODE_STRING KeyboardDeviceName;
|
|
|
|
OBJECT_ATTRIBUTES KeyboardObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
NTSTATUS Status;
|
2003-11-24 00:22:53 +00:00
|
|
|
MSG msg;
|
|
|
|
PUSER_MESSAGE_QUEUE FocusQueue;
|
|
|
|
struct _ETHREAD *FocusThread;
|
|
|
|
|
2003-11-17 02:12:52 +00:00
|
|
|
RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
|
2002-01-14 01:11:58 +00:00
|
|
|
InitializeObjectAttributes(&KeyboardObjectAttributes,
|
|
|
|
&KeyboardDeviceName,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
Status = NtOpenFile(&KeyboardDeviceHandle,
|
|
|
|
FILE_ALL_ACCESS,
|
|
|
|
&KeyboardObjectAttributes,
|
|
|
|
&Iosb,
|
|
|
|
0,
|
2002-10-31 00:03:31 +00:00
|
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
2002-01-14 01:11:58 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-09-30 22:04:24 +00:00
|
|
|
DPRINT1("Win32K: Failed to open keyboard.\n");
|
2003-08-11 21:10:49 +00:00
|
|
|
return; //(Status);
|
2002-01-14 01:11:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Wait to start input.
|
|
|
|
*/
|
2003-12-14 14:05:47 +00:00
|
|
|
DPRINT( "Keyboard Input Thread Waiting for start event\n" );
|
2002-01-14 01:11:58 +00:00
|
|
|
Status = KeWaitForSingleObject(&InputThreadsStart,
|
|
|
|
0,
|
2003-12-14 14:05:47 +00:00
|
|
|
KernelMode,
|
2002-01-14 01:11:58 +00:00
|
|
|
TRUE,
|
|
|
|
NULL);
|
2003-12-14 14:05:47 +00:00
|
|
|
DPRINT( "Keyboard Input Thread Starting...\n" );
|
2003-07-05 16:04:01 +00:00
|
|
|
|
2002-01-14 01:11:58 +00:00
|
|
|
/*
|
|
|
|
* Receive and process keyboard input.
|
|
|
|
*/
|
|
|
|
while (InputThreadsRunning)
|
|
|
|
{
|
|
|
|
KEY_EVENT_RECORD KeyEvent;
|
2003-10-09 06:13:05 +00:00
|
|
|
LPARAM lParam = 0;
|
2003-11-03 18:52:21 +00:00
|
|
|
UINT fsModifiers;
|
|
|
|
struct _ETHREAD *Thread;
|
|
|
|
HWND hWnd;
|
|
|
|
int id;
|
2003-11-02 16:33:51 +00:00
|
|
|
|
|
|
|
Status = NtReadFile (KeyboardDeviceHandle,
|
2002-01-14 01:11:58 +00:00
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&Iosb,
|
|
|
|
&KeyEvent,
|
|
|
|
sizeof(KEY_EVENT_RECORD),
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2003-11-02 16:33:51 +00:00
|
|
|
DPRINT( "KeyRaw: %s %04x\n",
|
|
|
|
KeyEvent.bKeyDown ? "down" : "up",
|
|
|
|
KeyEvent.wVirtualScanCode );
|
2003-07-29 23:03:01 +00:00
|
|
|
|
2002-01-14 01:11:58 +00:00
|
|
|
if (Status == STATUS_ALERTED && !InputThreadsRunning)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-09-30 22:04:24 +00:00
|
|
|
DPRINT1("Win32K: Failed to read from keyboard.\n");
|
2003-08-11 21:10:49 +00:00
|
|
|
return; //(Status);
|
2002-01-14 01:11:58 +00:00
|
|
|
}
|
2003-11-02 16:33:51 +00:00
|
|
|
|
|
|
|
DPRINT( "Key: %s\n", KeyEvent.bKeyDown ? "down" : "up" );
|
2003-07-05 16:04:01 +00:00
|
|
|
|
2003-11-03 18:52:21 +00:00
|
|
|
fsModifiers = 0;
|
|
|
|
if (KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
|
|
|
|
fsModifiers |= MOD_ALT;
|
|
|
|
|
|
|
|
if (KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
|
|
|
|
fsModifiers |= MOD_CONTROL;
|
|
|
|
|
|
|
|
if (KeyEvent.dwControlKeyState & SHIFT_PRESSED)
|
|
|
|
fsModifiers |= MOD_SHIFT;
|
|
|
|
|
|
|
|
/* FIXME: Support MOD_WIN */
|
|
|
|
|
2003-11-24 00:22:53 +00:00
|
|
|
lParam = KeyEvent.wRepeatCount |
|
|
|
|
((KeyEvent.wVirtualScanCode << 16) & 0x00FF0000) | 0x40000000;
|
|
|
|
|
|
|
|
/* Bit 24 indicates if this is an extended key */
|
|
|
|
if (KeyEvent.dwControlKeyState & ENHANCED_KEY)
|
|
|
|
{
|
|
|
|
lParam |= (1 << 24);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fsModifiers & MOD_ALT)
|
|
|
|
{
|
|
|
|
/* Context mode. 1 if ALT if pressed while the key is pressed */
|
|
|
|
lParam |= (1 << 29);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(KeyEvent.bKeyDown && (fsModifiers & MOD_ALT))
|
|
|
|
msg.message = WM_SYSKEYDOWN;
|
|
|
|
else if(KeyEvent.bKeyDown)
|
|
|
|
msg.message = WM_KEYDOWN;
|
|
|
|
else if(fsModifiers & MOD_ALT)
|
|
|
|
msg.message = WM_SYSKEYUP;
|
|
|
|
else
|
|
|
|
msg.message = WM_KEYUP;
|
|
|
|
|
|
|
|
/* Find the target thread whose locale is in effect */
|
2003-11-30 20:03:47 +00:00
|
|
|
if (!IntGetScreenDC())
|
|
|
|
{
|
|
|
|
FocusQueue = W32kGetPrimitiveMessageQueue();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FocusQueue = IntGetFocusMessageQueue();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!FocusQueue) continue;
|
2003-11-24 00:22:53 +00:00
|
|
|
|
|
|
|
msg.wParam = KeyEvent.wVirtualKeyCode;
|
|
|
|
msg.lParam = lParam;
|
2003-11-30 20:03:47 +00:00
|
|
|
msg.hwnd = FocusQueue->FocusWindow;
|
2003-11-24 00:22:53 +00:00
|
|
|
|
|
|
|
FocusThread = FocusQueue->Thread;
|
|
|
|
|
|
|
|
if (FocusThread && FocusThread->Win32Thread &&
|
|
|
|
FocusThread->Win32Thread->KeyboardLayout)
|
|
|
|
{
|
|
|
|
W32kKeyProcessMessage(&msg,
|
|
|
|
FocusThread->Win32Thread->KeyboardLayout);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
|
2003-11-11 22:17:18 +00:00
|
|
|
if (GetHotKey(InputWindowStation,
|
2003-11-24 00:22:53 +00:00
|
|
|
fsModifiers,
|
|
|
|
msg.wParam,
|
2003-11-03 18:52:21 +00:00
|
|
|
&Thread,
|
|
|
|
&hWnd,
|
|
|
|
&id))
|
|
|
|
{
|
|
|
|
if (KeyEvent.bKeyDown)
|
|
|
|
{
|
|
|
|
DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
|
|
|
|
MsqPostHotKeyMessage (Thread,
|
|
|
|
hWnd,
|
|
|
|
(WPARAM)id,
|
2003-11-24 00:22:53 +00:00
|
|
|
MAKELPARAM((WORD)fsModifiers,
|
|
|
|
(WORD)msg.wParam));
|
2003-11-02 16:33:51 +00:00
|
|
|
}
|
2002-01-14 01:11:58 +00:00
|
|
|
}
|
2003-11-24 00:22:53 +00:00
|
|
|
else
|
2002-01-14 01:11:58 +00:00
|
|
|
{
|
2003-11-24 00:22:53 +00:00
|
|
|
/*
|
|
|
|
* Post a keyboard message.
|
|
|
|
*/
|
|
|
|
MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
|
2002-01-14 01:11:58 +00:00
|
|
|
}
|
|
|
|
}
|
2003-12-14 14:05:47 +00:00
|
|
|
DPRINT( "KeyboardInput Thread Stopped...\n" );
|
2002-01-14 01:11:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-11-03 18:52:21 +00:00
|
|
|
|
2002-01-14 01:11:58 +00:00
|
|
|
NTSTATUS STDCALL
|
|
|
|
NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
|
|
|
|
{
|
2003-10-09 06:13:05 +00:00
|
|
|
if (Release && InputThreadsRunning && !pmPrimitiveMessageQueue)
|
2002-01-14 01:11:58 +00:00
|
|
|
{
|
2003-11-24 16:19:58 +00:00
|
|
|
DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue );
|
2002-01-14 01:11:58 +00:00
|
|
|
KeClearEvent(&InputThreadsStart);
|
|
|
|
InputThreadsRunning = FALSE;
|
2003-10-09 06:13:05 +00:00
|
|
|
|
2002-01-14 01:11:58 +00:00
|
|
|
NtAlertThread(KeyboardThreadHandle);
|
|
|
|
}
|
|
|
|
else if (!Release && !InputThreadsRunning)
|
|
|
|
{
|
|
|
|
InputThreadsRunning = TRUE;
|
|
|
|
KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
|
|
|
|
}
|
2003-10-09 06:13:05 +00:00
|
|
|
|
2002-01-14 01:11:58 +00:00
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2003-05-18 17:16:18 +00:00
|
|
|
NTSTATUS FASTCALL
|
2002-01-14 01:11:58 +00:00
|
|
|
InitInputImpl(VOID)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2003-12-14 14:05:47 +00:00
|
|
|
#if ENABLEMOUSEGDICALLBACK
|
2002-09-17 23:43:29 +00:00
|
|
|
UNICODE_STRING MouseDeviceName;
|
|
|
|
OBJECT_ATTRIBUTES MouseObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
PIRP Irp;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
GDI_INFORMATION GdiInfo;
|
|
|
|
KEVENT IoEvent;
|
|
|
|
PIO_STACK_LOCATION StackPtr;
|
2003-12-14 14:05:47 +00:00
|
|
|
#endif
|
2002-01-14 01:11:58 +00:00
|
|
|
|
|
|
|
KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
|
|
|
|
|
|
|
|
Status = PsCreateSystemThread(&KeyboardThreadHandle,
|
|
|
|
THREAD_ALL_ACCESS,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&KeyboardThreadId,
|
|
|
|
KeyboardThreadMain,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2003-12-14 14:05:47 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Win32K: Failed to create keyboard thread.\n");
|
|
|
|
}
|
2002-09-17 23:43:29 +00:00
|
|
|
|
2003-12-14 14:05:47 +00:00
|
|
|
/* Initialize the default keyboard layout */
|
|
|
|
(VOID)W32kGetDefaultKeyLayout();
|
|
|
|
|
|
|
|
#if ENABLEMOUSEGDICALLBACK
|
2002-09-17 23:43:29 +00:00
|
|
|
/*
|
|
|
|
* Connect to the mouse class driver.
|
2003-09-30 22:04:24 +00:00
|
|
|
* Failures here don't result in a failure return, the system must be
|
|
|
|
* able to operate without mouse
|
2002-09-17 23:43:29 +00:00
|
|
|
*/
|
2003-11-17 02:12:52 +00:00
|
|
|
RtlRosInitUnicodeStringFromLiteral(&MouseDeviceName, L"\\??\\MouseClass");
|
2002-09-17 23:43:29 +00:00
|
|
|
InitializeObjectAttributes(&MouseObjectAttributes,
|
|
|
|
&MouseDeviceName,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2004-02-07 15:39:14 +00:00
|
|
|
Status = ZwOpenFile(&MouseDeviceHandle,
|
2002-09-17 23:43:29 +00:00
|
|
|
FILE_ALL_ACCESS,
|
|
|
|
&MouseObjectAttributes,
|
|
|
|
&Iosb,
|
|
|
|
0,
|
2004-02-07 15:39:14 +00:00
|
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
2002-09-17 23:43:29 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-09-30 22:04:24 +00:00
|
|
|
DPRINT1("Win32K: Failed to open mouse.\n");
|
|
|
|
return STATUS_SUCCESS;
|
2002-09-17 23:43:29 +00:00
|
|
|
}
|
|
|
|
Status = ObReferenceObjectByHandle(MouseDeviceHandle,
|
|
|
|
FILE_READ_DATA | FILE_WRITE_DATA,
|
|
|
|
IoFileObjectType,
|
|
|
|
KernelMode,
|
|
|
|
(PVOID *) &FileObject,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2004-02-07 15:39:14 +00:00
|
|
|
DPRINT1("Win32K: Failed to reference mouse file object. (0x%X)\n", Status);
|
|
|
|
ZwClose(MouseDeviceHandle);
|
2003-09-30 22:04:24 +00:00
|
|
|
return STATUS_SUCCESS;
|
2002-09-17 23:43:29 +00:00
|
|
|
}
|
|
|
|
KeInitializeEvent(&IoEvent, FALSE, NotificationEvent);
|
|
|
|
GdiInfo.CallBack = MouseGDICallBack;
|
|
|
|
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
|
|
|
|
FileObject->DeviceObject,
|
|
|
|
&GdiInfo,
|
|
|
|
sizeof(GdiInfo),
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
TRUE,
|
|
|
|
&FileObject->Event,
|
|
|
|
&Iosb);
|
2003-05-22 00:47:04 +00:00
|
|
|
|
|
|
|
//trigger FileObject/Event dereferencing
|
|
|
|
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
|
|
|
|
2002-09-17 23:43:29 +00:00
|
|
|
StackPtr = IoGetNextIrpStackLocation(Irp);
|
|
|
|
StackPtr->FileObject = FileObject;
|
|
|
|
StackPtr->DeviceObject = FileObject->DeviceObject;
|
|
|
|
StackPtr->Parameters.DeviceIoControl.InputBufferLength = sizeof(GdiInfo);
|
|
|
|
StackPtr->Parameters.DeviceIoControl.OutputBufferLength = 0;
|
|
|
|
|
|
|
|
Status = IoCallDriver(FileObject->DeviceObject, Irp);
|
|
|
|
if (Status == STATUS_PENDING)
|
|
|
|
{
|
|
|
|
KeWaitForSingleObject(&FileObject->Event, Executive, KernelMode, FALSE,
|
|
|
|
NULL);
|
|
|
|
Status = Iosb.Status;
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2003-09-30 22:04:24 +00:00
|
|
|
DPRINT1("Win32K: Failed to connect to mouse driver.\n");
|
|
|
|
ObDereferenceObject(&FileObject);
|
|
|
|
NtClose(MouseDeviceHandle);
|
|
|
|
return STATUS_SUCCESS;
|
2002-09-17 23:43:29 +00:00
|
|
|
}
|
2004-02-07 15:39:14 +00:00
|
|
|
#else
|
|
|
|
Status = PsCreateSystemThread(&MouseThreadHandle,
|
|
|
|
THREAD_ALL_ACCESS,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
&MouseThreadId,
|
|
|
|
MouseThreadMain,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Win32K: Failed to create mouse thread.\n");
|
|
|
|
}
|
2003-12-14 14:05:47 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
2002-01-14 01:11:58 +00:00
|
|
|
}
|
|
|
|
|
2003-05-18 17:16:18 +00:00
|
|
|
NTSTATUS FASTCALL
|
2002-01-14 01:11:58 +00:00
|
|
|
CleanupInputImp(VOID)
|
|
|
|
{
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2003-08-04 16:55:36 +00:00
|
|
|
BOOL
|
|
|
|
STDCALL
|
|
|
|
NtUserDragDetect(
|
|
|
|
HWND hWnd,
|
|
|
|
LONG x,
|
|
|
|
LONG y)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-04-29 20:26:35 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntBlockInput(PW32THREAD W32Thread, BOOL BlockIt)
|
|
|
|
{
|
|
|
|
PW32THREAD OldBlock;
|
|
|
|
ASSERT(W32Thread);
|
|
|
|
|
2004-04-29 20:41:03 +00:00
|
|
|
if(!W32Thread->Desktop || (W32Thread->IsExiting && BlockIt))
|
2004-04-29 20:26:35 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* fail blocking if exiting the thread
|
|
|
|
*/
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME - check access rights of the window station
|
|
|
|
* e.g. services running in the service window station cannot block input
|
|
|
|
*/
|
|
|
|
if(!ThreadHasInputAccess(W32Thread) ||
|
|
|
|
!IntIsActiveDesktop(W32Thread->Desktop))
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(W32Thread->Desktop);
|
|
|
|
OldBlock = W32Thread->Desktop->BlockInputThread;
|
|
|
|
if(OldBlock)
|
|
|
|
{
|
|
|
|
if(OldBlock != W32Thread)
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
|
|
|
|
return OldBlock == NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
W32Thread->Desktop->BlockInputThread = (BlockIt ? W32Thread : NULL);
|
|
|
|
return OldBlock == NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
STDCALL
|
|
|
|
NtUserBlockInput(
|
|
|
|
BOOL BlockIt)
|
|
|
|
{
|
|
|
|
return IntBlockInput(PsGetWin32Thread(), BlockIt);
|
|
|
|
}
|
|
|
|
|
2004-04-30 22:18:00 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
|
|
|
|
{
|
2004-05-14 23:57:32 +00:00
|
|
|
PSYSTEM_CURSORINFO CurInfo;
|
|
|
|
BOOL res;
|
|
|
|
|
|
|
|
CurInfo = IntGetSysCursorInfo(WinStaObject);
|
|
|
|
res = CurInfo->SwapButtons;
|
|
|
|
CurInfo->SwapButtons = Swap;
|
2004-04-30 22:18:00 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2004-04-29 20:26:35 +00:00
|
|
|
BOOL FASTCALL
|
|
|
|
IntMouseInput(MOUSEINPUT *mi)
|
|
|
|
{
|
2004-04-30 22:18:00 +00:00
|
|
|
const UINT SwapBtnMsg[2][2] = {{WM_LBUTTONDOWN, WM_RBUTTONDOWN},
|
|
|
|
{WM_LBUTTONUP, WM_RBUTTONUP}};
|
|
|
|
const WPARAM SwapBtn[2] = {MK_LBUTTON, MK_RBUTTON};
|
|
|
|
POINT MousePos;
|
|
|
|
PSYSTEM_CURSORINFO CurInfo;
|
|
|
|
PWINSTATION_OBJECT WinSta;
|
|
|
|
BOOL DoMove, SwapButtons;
|
|
|
|
MSG Msg;
|
|
|
|
SURFOBJ *SurfObj;
|
|
|
|
PSURFGDI SurfGDI;
|
|
|
|
PDC dc;
|
|
|
|
RECTL PointerRect;
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
HDC hDC;
|
|
|
|
|
|
|
|
/* FIXME - get the screen dc from the window station or desktop */
|
|
|
|
if(!(hDC = IntGetScreenDC()))
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ASSERT(mi);
|
|
|
|
#if 0
|
|
|
|
WinSta = PsGetWin32Process()->WindowStation;
|
|
|
|
#else
|
|
|
|
/* FIXME - ugly hack but as long as we're using this dumb callback from the
|
|
|
|
mouse class driver, we can't access the window station from the calling
|
|
|
|
process */
|
|
|
|
WinSta = InputWindowStation;
|
|
|
|
#endif
|
|
|
|
ASSERT(WinSta);
|
|
|
|
|
2004-05-14 23:57:32 +00:00
|
|
|
CurInfo = IntGetSysCursorInfo(WinSta);
|
2004-04-30 22:18:00 +00:00
|
|
|
|
|
|
|
dc = DC_LockDc(hDC);
|
|
|
|
SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
|
|
|
|
SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
|
|
|
|
DC_UnlockDc(hDC);
|
|
|
|
ASSERT(SurfObj);
|
|
|
|
ASSERT(SurfGDI);
|
|
|
|
|
|
|
|
if(!mi->time)
|
|
|
|
{
|
|
|
|
LARGE_INTEGER LargeTickCount;
|
|
|
|
KeQueryTickCount(&LargeTickCount);
|
|
|
|
mi->time = LargeTickCount.u.LowPart;
|
|
|
|
}
|
|
|
|
|
2004-05-14 23:57:32 +00:00
|
|
|
SwapButtons = CurInfo->SwapButtons;
|
2004-04-30 22:18:00 +00:00
|
|
|
DoMove = FALSE;
|
|
|
|
ExAcquireFastMutex(&CurInfo->CursorMutex);
|
|
|
|
MousePos.x = CurInfo->x;
|
|
|
|
MousePos.y = CurInfo->y;
|
|
|
|
if(mi->dwFlags & MOUSEEVENTF_MOVE)
|
|
|
|
{
|
|
|
|
if(mi->dwFlags & MOUSEEVENTF_ABSOLUTE)
|
|
|
|
{
|
|
|
|
MousePos.x = mi->dx;
|
|
|
|
MousePos.y = mi->dy;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MousePos.x += mi->dx;
|
|
|
|
MousePos.y += mi->dy;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(MousePos.x < 0)
|
|
|
|
MousePos.x = 0;
|
|
|
|
if(MousePos.y < 0)
|
|
|
|
MousePos.y = 0;
|
|
|
|
if(MousePos.x >= SurfObj->sizlBitmap.cx)
|
|
|
|
MousePos.x = SurfObj->sizlBitmap.cx - 1;
|
|
|
|
if(MousePos.y >= SurfObj->sizlBitmap.cy)
|
|
|
|
MousePos.y = SurfObj->sizlBitmap.cy - 1;
|
|
|
|
|
2004-05-01 08:47:14 +00:00
|
|
|
if(CurInfo->CursorClipInfo.IsClipped)
|
|
|
|
{
|
|
|
|
/* The mouse cursor needs to be clipped */
|
|
|
|
|
|
|
|
if(MousePos.x >= (LONG)CurInfo->CursorClipInfo.Right)
|
|
|
|
MousePos.x = (LONG)CurInfo->CursorClipInfo.Right;
|
|
|
|
if(MousePos.x < (LONG)CurInfo->CursorClipInfo.Left)
|
|
|
|
MousePos.x = (LONG)CurInfo->CursorClipInfo.Left;
|
|
|
|
if(MousePos.y >= (LONG)CurInfo->CursorClipInfo.Bottom)
|
|
|
|
MousePos.y = (LONG)CurInfo->CursorClipInfo.Bottom;
|
|
|
|
if(MousePos.y < (LONG)CurInfo->CursorClipInfo.Top)
|
|
|
|
MousePos.y = (LONG)CurInfo->CursorClipInfo.Top;
|
|
|
|
}
|
|
|
|
|
2004-04-30 22:18:00 +00:00
|
|
|
if((DoMove = (MousePos.x != CurInfo->x || MousePos.y != CurInfo->y)))
|
|
|
|
{
|
|
|
|
CurInfo->x = MousePos.x;
|
|
|
|
CurInfo->y = MousePos.y;
|
|
|
|
if(SurfGDI->MovePointer)
|
|
|
|
{
|
|
|
|
IntLockGDIDriver(SurfGDI);
|
|
|
|
SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
|
|
|
|
IntUnLockGDIDriver(SurfGDI);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IntLockGDIDriver(SurfGDI);
|
|
|
|
EngMovePointer(SurfObj, CurInfo->x, CurInfo->y, &PointerRect);
|
|
|
|
IntUnLockGDIDriver(SurfGDI);
|
|
|
|
}
|
|
|
|
SetPointerRect(CurInfo, &PointerRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ExReleaseFastMutex(&CurInfo->CursorMutex);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert the messages into the system queue
|
|
|
|
*/
|
|
|
|
|
|
|
|
Msg.wParam = CurInfo->ButtonsDown;
|
|
|
|
Msg.lParam = MAKELPARAM(MousePos.x, MousePos.y);
|
|
|
|
Msg.pt = MousePos;
|
|
|
|
if(DoMove)
|
|
|
|
{
|
|
|
|
Msg.message = WM_MOUSEMOVE;
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
Msg.message = 0;
|
|
|
|
if(mi->dwFlags & MOUSEEVENTF_LEFTDOWN)
|
|
|
|
{
|
|
|
|
Msg.message = SwapBtnMsg[0][SwapButtons];
|
|
|
|
CurInfo->ButtonsDown |= SwapBtn[SwapButtons];
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
else if(mi->dwFlags & MOUSEEVENTF_LEFTUP)
|
|
|
|
{
|
|
|
|
Msg.message = SwapBtnMsg[1][SwapButtons];
|
|
|
|
CurInfo->ButtonsDown &= ~SwapBtn[SwapButtons];
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
if(mi->dwFlags & MOUSEEVENTF_MIDDLEDOWN)
|
|
|
|
{
|
|
|
|
Msg.message = WM_MBUTTONDOWN;
|
|
|
|
CurInfo->ButtonsDown |= MK_MBUTTON;
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
else if(mi->dwFlags & MOUSEEVENTF_MIDDLEUP)
|
|
|
|
{
|
|
|
|
Msg.message = WM_MBUTTONUP;
|
|
|
|
CurInfo->ButtonsDown &= ~MK_MBUTTON;
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
if(mi->dwFlags & MOUSEEVENTF_RIGHTDOWN)
|
|
|
|
{
|
|
|
|
Msg.message = SwapBtnMsg[0][!SwapButtons];
|
|
|
|
CurInfo->ButtonsDown |= SwapBtn[!SwapButtons];
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
else if(mi->dwFlags & MOUSEEVENTF_RIGHTUP)
|
|
|
|
{
|
|
|
|
Msg.message = SwapBtnMsg[1][!SwapButtons];
|
|
|
|
CurInfo->ButtonsDown &= ~SwapBtn[!SwapButtons];
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if((mi->dwFlags & (MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)) &&
|
|
|
|
(mi->dwFlags & MOUSEEVENTF_WHEEL))
|
|
|
|
{
|
|
|
|
/* fail because both types of events use the mouseData field */
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(mi->dwFlags & MOUSEEVENTF_XDOWN)
|
|
|
|
{
|
|
|
|
Msg.message = WM_XBUTTONDOWN;
|
|
|
|
if(mi->mouseData & XBUTTON1)
|
|
|
|
{
|
|
|
|
Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
|
|
|
|
CurInfo->ButtonsDown |= XBUTTON1;
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
if(mi->mouseData & XBUTTON2)
|
|
|
|
{
|
|
|
|
Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
|
|
|
|
CurInfo->ButtonsDown |= XBUTTON2;
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(mi->dwFlags & MOUSEEVENTF_XUP)
|
|
|
|
{
|
|
|
|
Msg.message = WM_XBUTTONUP;
|
|
|
|
if(mi->mouseData & XBUTTON1)
|
|
|
|
{
|
|
|
|
Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON1);
|
|
|
|
CurInfo->ButtonsDown &= ~XBUTTON1;
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
if(mi->mouseData & XBUTTON2)
|
|
|
|
{
|
|
|
|
Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, XBUTTON2);
|
|
|
|
CurInfo->ButtonsDown &= ~XBUTTON2;
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(mi->dwFlags & MOUSEEVENTF_WHEEL)
|
|
|
|
{
|
|
|
|
Msg.message = WM_MOUSEWHEEL;
|
|
|
|
Msg.wParam = MAKEWPARAM(CurInfo->ButtonsDown, mi->mouseData);
|
|
|
|
MsqInsertSystemMessage(&Msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
2004-04-29 20:26:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL FASTCALL
|
|
|
|
IntKeyboardInput(KEYBDINPUT *ki)
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINT
|
|
|
|
STDCALL
|
|
|
|
NtUserSendInput(
|
|
|
|
UINT nInputs,
|
|
|
|
LPINPUT pInput,
|
|
|
|
INT cbSize)
|
|
|
|
{
|
2004-04-29 20:41:03 +00:00
|
|
|
PW32THREAD W32Thread;
|
2004-04-29 20:26:35 +00:00
|
|
|
UINT cnt;
|
|
|
|
|
2004-04-29 20:41:03 +00:00
|
|
|
W32Thread = PsGetWin32Thread();
|
|
|
|
ASSERT(W32Thread);
|
|
|
|
|
|
|
|
if(!W32Thread->Desktop)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-04-29 20:26:35 +00:00
|
|
|
if(!nInputs || !pInput || (cbSize != sizeof(INPUT)))
|
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_INVALID_PARAMETER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME - check access rights of the window station
|
|
|
|
* e.g. services running in the service window station cannot block input
|
|
|
|
*/
|
|
|
|
if(!ThreadHasInputAccess(W32Thread) ||
|
2004-04-29 20:41:03 +00:00
|
|
|
!IntIsActiveDesktop(W32Thread->Desktop))
|
2004-04-29 20:26:35 +00:00
|
|
|
{
|
|
|
|
SetLastWin32Error(ERROR_ACCESS_DENIED);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cnt = 0;
|
|
|
|
while(nInputs--)
|
|
|
|
{
|
|
|
|
INPUT SafeInput;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = MmCopyFromCaller(&SafeInput, pInput++, sizeof(INPUT));
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
SetLastNtError(Status);
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(SafeInput.type)
|
|
|
|
{
|
|
|
|
case INPUT_MOUSE:
|
|
|
|
if(IntMouseInput(&SafeInput.mi))
|
|
|
|
{
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INPUT_KEYBOARD:
|
|
|
|
if(IntKeyboardInput(&SafeInput.ki))
|
|
|
|
{
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INPUT_HARDWARE:
|
|
|
|
break;
|
|
|
|
#ifndef NDEBUG
|
|
|
|
default:
|
|
|
|
DPRINT1("SendInput(): Invalid input type: 0x%x\n", SafeInput.type);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return cnt;
|
|
|
|
}
|
|
|
|
|
2002-01-14 01:11:58 +00:00
|
|
|
/* EOF */
|