reactos/reactos/subsys/win32k/ntuser/input.c

1143 lines
28 KiB
C
Raw Normal View History

/*
* 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.
*/
/* $Id$
*
* 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 ******************************************************************/
#include <w32k.h>
#include <rosrtl/string.h>
#include <ddk/ntddkbd.h>
/* GLOBALS *******************************************************************/
static HANDLE MouseDeviceHandle;
static HANDLE MouseThreadHandle;
static CLIENT_ID MouseThreadId;
static HANDLE KeyboardThreadHandle;
static CLIENT_ID KeyboardThreadId;
static HANDLE KeyboardDeviceHandle;
static KEVENT InputThreadsStart;
static BOOLEAN InputThreadsRunning = FALSE;
PUSER_MESSAGE_QUEUE pmPrimitiveMessageQueue = 0;
/* FUNCTIONS *****************************************************************/
#define ClearMouseInput(mi) \
mi.dx = 0; \
mi.dy = 0; \
mi.mouseData = 0; \
mi.dwFlags = 0;
#define SendMouseEvent(mi) \
if(mi.dx != 0 || mi.dy != 0) \
mi.dwFlags |= MOUSEEVENTF_MOVE; \
if(mi.dwFlags) \
IntMouseInput(&mi); \
ClearMouseInput(mi);
VOID FASTCALL
ProcessMouseInputData(PMOUSE_INPUT_DATA Data, ULONG InputCount)
{
PMOUSE_INPUT_DATA mid;
MOUSEINPUT mi;
ULONG i;
ClearMouseInput(mi);
mi.time = 0;
mi.dwExtraInfo = 0;
for(i = 0; i < InputCount; i++)
{
mid = (Data + i);
mi.dx += mid->LastX;
mi.dy += mid->LastY;
if(mid->ButtonFlags)
{
if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_DOWN)
{
mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_LEFT_BUTTON_UP)
{
mi.dwFlags |= MOUSEEVENTF_LEFTUP;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN)
{
mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_MIDDLE_BUTTON_UP)
{
mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN)
{
mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_RIGHT_BUTTON_UP)
{
mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_BUTTON_4_DOWN)
{
mi.mouseData |= XBUTTON1;
mi.dwFlags |= MOUSEEVENTF_XDOWN;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_BUTTON_4_UP)
{
mi.mouseData |= XBUTTON1;
mi.dwFlags |= MOUSEEVENTF_XUP;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_BUTTON_5_DOWN)
{
mi.mouseData |= XBUTTON2;
mi.dwFlags |= MOUSEEVENTF_XDOWN;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_BUTTON_5_UP)
{
mi.mouseData |= XBUTTON2;
mi.dwFlags |= MOUSEEVENTF_XUP;
SendMouseEvent(mi);
}
if(mid->ButtonFlags & MOUSE_WHEEL)
{
mi.mouseData = mid->ButtonData;
mi.dwFlags |= MOUSEEVENTF_WHEEL;
SendMouseEvent(mi);
}
}
}
SendMouseEvent(mi);
}
VOID STDCALL
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");
ProcessMouseInputData(&MouseInput, Iosb.Information / sizeof(MOUSE_INPUT_DATA));
}
DPRINT("Mouse Input Thread Stopped...\n");
}
}
/* Returns a value that indicates if the key is a modifier key, and
* which one.
*/
STATIC UINT STDCALL
IntKeyboardGetModifiers(KEYBOARD_INPUT_DATA *InputData)
{
if (InputData->Flags & KEY_E1)
return 0;
if (!(InputData->Flags & KEY_E0))
{
switch (InputData->MakeCode)
{
case 0x2a: /* left shift */
case 0x36: /* right shift */
return MOD_SHIFT;
case 0x1d: /* left control */
return MOD_CONTROL;
case 0x38: /* left alt */
return MOD_ALT;
default:
return 0;
}
}
else
{
switch (InputData->MakeCode)
{
case 0x1d: /* right control */
return MOD_CONTROL;
case 0x38: /* right alt */
return MOD_ALT;
case 0x5b: /* left gui (windows) */
case 0x5c: /* right gui (windows) */
return MOD_WIN;
default:
return 0;
}
}
}
/* Asks the keyboard driver to send a small table that shows which
* lights should connect with which scancodes
*/
STATIC NTSTATUS STDCALL
IntKeyboardGetIndicatorTrans(HANDLE KeyboardDeviceHandle,
PKEYBOARD_INDICATOR_TRANSLATION *IndicatorTrans)
{
NTSTATUS Status;
DWORD Size = 0;
IO_STATUS_BLOCK Block;
PKEYBOARD_INDICATOR_TRANSLATION Ret;
Size = sizeof(KEYBOARD_INDICATOR_TRANSLATION);
Ret = ExAllocatePoolWithTag(PagedPool,
Size,
TAG_KEYBOARD);
while (Ret)
{
Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
NULL,
NULL,
NULL,
&Block,
IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION,
NULL, 0,
Ret, Size);
if (Status != STATUS_BUFFER_TOO_SMALL)
break;
ExFreePool(Ret);
Size += sizeof(KEYBOARD_INDICATOR_TRANSLATION);
Ret = ExAllocatePoolWithTag(PagedPool,
Size,
TAG_KEYBOARD);
}
if (!Ret)
return STATUS_INSUFFICIENT_RESOURCES;
if (Status != STATUS_SUCCESS)
{
ExFreePool(Ret);
return Status;
}
*IndicatorTrans = Ret;
return Status;
}
/* Sends the keyboard commands to turn on/off the lights.
*/
STATIC NTSTATUS STDCALL
IntKeyboardUpdateLeds(HANDLE KeyboardDeviceHandle,
PKEYBOARD_INPUT_DATA KeyInput,
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans)
{
NTSTATUS Status;
UINT Count;
static KEYBOARD_INDICATOR_PARAMETERS Indicators;
IO_STATUS_BLOCK Block;
if (!IndicatorTrans)
return STATUS_NOT_SUPPORTED;
if (KeyInput->Flags & (KEY_E0 | KEY_E1 | KEY_BREAK))
return STATUS_SUCCESS;
for (Count = 0; Count < IndicatorTrans->NumberOfIndicatorKeys; Count++)
{
if (KeyInput->MakeCode == IndicatorTrans->IndicatorList[Count].MakeCode)
{
Indicators.LedFlags ^=
IndicatorTrans->IndicatorList[Count].IndicatorFlags;
/* Update the lights on the hardware */
Status = NtDeviceIoControlFile(KeyboardDeviceHandle,
NULL,
NULL,
NULL,
&Block,
IOCTL_KEYBOARD_SET_INDICATORS,
&Indicators, sizeof(Indicators),
NULL, 0);
return Status;
}
}
return STATUS_SUCCESS;
}
STATIC VOID STDCALL
IntKeyboardSendWinKeyMsg()
{
PWINDOW_OBJECT Window;
MSG Mesg;
NTSTATUS Status;
Status = ObmReferenceObjectByHandle(InputWindowStation->HandleTable,
InputWindowStation->ShellWindow,
otWindow,
(PVOID *)&Window);
if (!NT_SUCCESS(Status))
{
DPRINT1("Couldn't find window to send Windows key message!\n");
return;
}
Mesg.hwnd = InputWindowStation->ShellWindow;
Mesg.message = WM_SYSCOMMAND;
Mesg.wParam = SC_TASKLIST;
Mesg.lParam = 0;
/* The QS_HOTKEY is just a guess */
MsqPostMessage(Window->MessageQueue, &Mesg, FALSE, QS_HOTKEY);
ObmDereferenceObject(Window);
}
STATIC VOID STDCALL
IntKeyboardSendAltKeyMsg()
{
MsqPostKeyboardMessage(WM_SYSCOMMAND,SC_KEYMENU,0);
}
STATIC VOID STDCALL
KeyboardThreadMain(PVOID StartContext)
{
UNICODE_STRING KeyboardDeviceName;
OBJECT_ATTRIBUTES KeyboardObjectAttributes;
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
MSG msg;
PUSER_MESSAGE_QUEUE FocusQueue;
struct _ETHREAD *FocusThread;
PKEYBOARD_INDICATOR_TRANSLATION IndicatorTrans = NULL;
UINT ModifierState = 0;
USHORT LastMakeCode = 0;
USHORT LastFlags = 0;
UINT RepeatCount = 0;
RtlRosInitUnicodeStringFromLiteral(&KeyboardDeviceName, L"\\??\\Keyboard");
InitializeObjectAttributes(&KeyboardObjectAttributes,
&KeyboardDeviceName,
0,
NULL,
NULL);
Status = NtOpenFile(&KeyboardDeviceHandle,
FILE_ALL_ACCESS,
&KeyboardObjectAttributes,
&Iosb,
0,
FILE_SYNCHRONOUS_IO_ALERT);
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to open keyboard.\n");
return; //(Status);
}
IntKeyboardGetIndicatorTrans(KeyboardDeviceHandle,
&IndicatorTrans);
for (;;)
{
/*
* Wait to start input.
*/
DPRINT( "Keyboard Input Thread Waiting for start event\n" );
Status = KeWaitForSingleObject(&InputThreadsStart,
0,
KernelMode,
TRUE,
NULL);
DPRINT( "Keyboard Input Thread Starting...\n" );
/*
* Receive and process keyboard input.
*/
while (InputThreadsRunning)
{
KEY_EVENT_RECORD KeyEvent;
BOOLEAN NumKeys = 1;
KEYBOARD_INPUT_DATA KeyInput;
KEYBOARD_INPUT_DATA NextKeyInput;
LPARAM lParam = 0;
UINT fsModifiers, fsNextModifiers;
struct _ETHREAD *Thread;
HWND hWnd;
int id;
Status = NtReadFile (KeyboardDeviceHandle,
NULL,
NULL,
NULL,
&Iosb,
&KeyInput,
sizeof(KEYBOARD_INPUT_DATA),
NULL,
NULL);
DPRINT("KeyRaw: %s %04x\n",
(KeyInput.Flags & KEY_BREAK) ? "up" : "down",
KeyInput.MakeCode );
if (Status == STATUS_ALERTED && !InputThreadsRunning)
break;
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to read from keyboard.\n");
return; //(Status);
}
/* Update modifier state */
fsModifiers = IntKeyboardGetModifiers(&KeyInput);
if (fsModifiers)
{
if (KeyInput.Flags & KEY_BREAK)
{
ModifierState &= ~fsModifiers;
}
else
{
ModifierState |= fsModifiers;
if (ModifierState == fsModifiers &&
(fsModifiers == MOD_ALT || fsModifiers == MOD_WIN))
{
/* First send out special notifications
* (For alt, the message that turns on accelerator
* display, not sure what for win. Both TODO though.)
*/
/* Read the next key before sending this one */
do
{
Status = NtReadFile (KeyboardDeviceHandle,
NULL,
NULL,
NULL,
&Iosb,
&NextKeyInput,
sizeof(KEYBOARD_INPUT_DATA),
NULL,
NULL);
DPRINT("KeyRaw: %s %04x\n",
(NextKeyInput.Flags & KEY_BREAK) ? "up":"down",
NextKeyInput.MakeCode );
if (Status == STATUS_ALERTED && !InputThreadsRunning)
goto KeyboardEscape;
} while ((!(NextKeyInput.Flags & KEY_BREAK)) &&
NextKeyInput.MakeCode == KeyInput.MakeCode);
/* ^ Ignore repeats, they'll be KEY_MAKE and the same
* code. I'm not caring about the counting, not sure
* if that matters. I think not.
*/
/* If the ModifierState is now empty again, send a
* special notification and eat both keypresses
*/
fsNextModifiers = IntKeyboardGetModifiers(&NextKeyInput);
if (fsNextModifiers)
ModifierState ^= fsNextModifiers;
if (ModifierState == 0)
{
if (fsModifiers == MOD_WIN)
IntKeyboardSendWinKeyMsg();
else if (fsModifiers == MOD_ALT)
IntKeyboardSendAltKeyMsg();
continue;
}
NumKeys = 2;
}
}
}
for (;NumKeys;memcpy(&KeyInput, &NextKeyInput, sizeof(KeyInput)),
NumKeys--)
{
lParam = 0;
IntKeyboardUpdateLeds(KeyboardDeviceHandle,
&KeyInput,
IndicatorTrans);
/* While we are working, we set up lParam. The format is:
* 0-15: The number of times this key has autorepeated
* 16-23: The keyboard scancode
* 24: Set if it's and extended key (I assume KEY_E0 | KEY_E1)
* Note that E1 is only used for PAUSE (E1-1D-45) and
* E0-45 happens not to be anything.
* 29: Alt is pressed ('Context code')
* 30: Previous state, if the key was down before this message
* This is a cheap way to ignore autorepeat keys
* 31: 1 if the key is being pressed
*/
/* If it's a KEY_MAKE (which is 0, so test using !KEY_BREAK)
* and it's the same key as the last one, increase the repeat
* count.
*/
if (!(KeyInput.Flags & KEY_BREAK))
{
if (((KeyInput.Flags & (KEY_E0 | KEY_E1)) == LastFlags) &&
(KeyInput.MakeCode == LastMakeCode))
{
RepeatCount++;
lParam |= (1 << 30);
}
else
{
RepeatCount = 0;
LastFlags = KeyInput.Flags & (KEY_E0 | KEY_E1);
LastMakeCode = KeyInput.MakeCode;
}
}
else
{
LastFlags = 0;
LastMakeCode = 0; /* Should never match */
lParam |= (1 << 30) | (1 << 31);
}
lParam |= RepeatCount;
lParam |= (KeyInput.MakeCode & 0xff) << 16;
if (KeyInput.Flags & (KEY_E0 | KEY_E1))
lParam |= (1 << 24);
if (ModifierState & MOD_ALT)
{
lParam |= (1 << 29);
if (!(KeyInput.Flags & KEY_BREAK))
msg.message = WM_SYSKEYDOWN;
else
msg.message = WM_SYSKEYUP;
}
else
{
if (!(KeyInput.Flags & KEY_BREAK))
msg.message = WM_KEYDOWN;
else
msg.message = WM_KEYUP;
}
/* Find the target thread whose locale is in effect */
if (!IntGetScreenDC())
FocusQueue = W32kGetPrimitiveMessageQueue();
else
FocusQueue = IntGetFocusMessageQueue();
/* This might cause us to lose hot keys, which are important
* (ctrl-alt-del secure attention sequence). Not sure if it
* can happen though.
*/
if (!FocusQueue) continue;
msg.lParam = lParam;
msg.hwnd = FocusQueue->FocusWindow;
FocusThread = FocusQueue->Thread;
if (!(FocusThread && FocusThread->Tcb.Win32Thread &&
FocusThread->Tcb.Win32Thread->KeyboardLayout))
continue;
/* This function uses lParam to fill wParam according to the
* keyboard layout in use.
*/
W32kKeyProcessMessage(&msg,
FocusThread->Tcb.Win32Thread->KeyboardLayout);
if (GetHotKey(InputWindowStation,
ModifierState,
msg.wParam,
&Thread,
&hWnd,
&id))
{
if (KeyEvent.bKeyDown)
{
DPRINT("Hot key pressed (hWnd %lx, id %d)\n", hWnd, id);
MsqPostHotKeyMessage (Thread,
hWnd,
(WPARAM)id,
MAKELPARAM((WORD)ModifierState,
(WORD)msg.wParam));
}
continue; /* Eat key up motion too */
}
/*
* Post a keyboard message.
*/
MsqPostKeyboardMessage(msg.message,msg.wParam,msg.lParam);
}
}
KeyboardEscape:
DPRINT( "KeyboardInput Thread Stopped...\n" );
}
}
NTSTATUS STDCALL
NtUserAcquireOrReleaseInputOwnership(BOOLEAN Release)
{
if (Release && InputThreadsRunning && !pmPrimitiveMessageQueue)
{
DPRINT( "Releasing input: PM = %08x\n", pmPrimitiveMessageQueue );
KeClearEvent(&InputThreadsStart);
InputThreadsRunning = FALSE;
NtAlertThread(KeyboardThreadHandle);
}
else if (!Release && !InputThreadsRunning)
{
InputThreadsRunning = TRUE;
KeSetEvent(&InputThreadsStart, IO_NO_INCREMENT, FALSE);
}
return(STATUS_SUCCESS);
}
NTSTATUS FASTCALL
InitInputImpl(VOID)
{
NTSTATUS Status;
KeInitializeEvent(&InputThreadsStart, NotificationEvent, FALSE);
Status = PsCreateSystemThread(&KeyboardThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&KeyboardThreadId,
KeyboardThreadMain,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to create keyboard thread.\n");
}
/* Initialize the default keyboard layout */
(VOID)W32kGetDefaultKeyLayout();
Status = PsCreateSystemThread(&MouseThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&MouseThreadId,
MouseThreadMain,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Win32K: Failed to create mouse thread.\n");
}
return STATUS_SUCCESS;
}
NTSTATUS FASTCALL
CleanupInputImp(VOID)
{
return(STATUS_SUCCESS);
}
BOOL
STDCALL
NtUserDragDetect(
HWND hWnd,
LONG x,
LONG y)
{
UNIMPLEMENTED
return 0;
}
BOOL FASTCALL
IntBlockInput(PW32THREAD W32Thread, BOOL BlockIt)
{
PW32THREAD OldBlock;
ASSERT(W32Thread);
if(!W32Thread->Desktop || (W32Thread->IsExiting && BlockIt))
{
/*
* 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);
}
BOOL FASTCALL
IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
{
PSYSTEM_CURSORINFO CurInfo;
BOOL res;
CurInfo = IntGetSysCursorInfo(WinStaObject);
res = CurInfo->SwapButtons;
CurInfo->SwapButtons = Swap;
return res;
}
BOOL FASTCALL
IntMouseInput(MOUSEINPUT *mi)
{
const UINT SwapBtnMsg[2][2] = {{WM_LBUTTONDOWN, WM_RBUTTONDOWN},
{WM_LBUTTONUP, WM_RBUTTONUP}};
const WPARAM SwapBtn[2] = {MK_LBUTTON, MK_RBUTTON};
POINT MousePos, OrgPos;
PSYSTEM_CURSORINFO CurInfo;
PWINSTATION_OBJECT WinSta;
BOOL DoMove, SwapButtons;
MSG Msg;
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
HBITMAP hBitmap;
BITMAPOBJ *BitmapObj;
SURFOBJ *SurfObj;
PDC dc;
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
PWINDOW_OBJECT DesktopWindow;
NTSTATUS Status;
#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);
CurInfo = IntGetSysCursorInfo(WinSta);
if(!mi->time)
{
LARGE_INTEGER LargeTickCount;
KeQueryTickCount(&LargeTickCount);
mi->time = LargeTickCount.u.LowPart;
}
SwapButtons = CurInfo->SwapButtons;
DoMove = FALSE;
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
ExAcquireFastMutex(&CurInfo->CursorMutex);
IntGetCursorLocation(WinSta, &MousePos);
OrgPos.x = MousePos.x;
OrgPos.y = MousePos.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;
}
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
Status = ObmReferenceObjectByHandle(WinSta->HandleTable,
WinSta->ActiveDesktop->DesktopWindow, otWindow, (PVOID*)&DesktopWindow);
if (NT_SUCCESS(Status))
{
if(MousePos.x >= DesktopWindow->ClientRect.right)
MousePos.x = DesktopWindow->ClientRect.right - 1;
if(MousePos.y >= DesktopWindow->ClientRect.bottom)
MousePos.y = DesktopWindow->ClientRect.bottom - 1;
ObmDereferenceObject(DesktopWindow);
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
}
if(MousePos.x < 0)
MousePos.x = 0;
if(MousePos.y < 0)
MousePos.y = 0;
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;
}
DoMove = (MousePos.x != OrgPos.x || MousePos.y != OrgPos.y);
}
ExReleaseFastMutex(&CurInfo->CursorMutex);
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
if (DoMove)
{
dc = DC_LockDc(hDC);
if (dc)
{
hBitmap = dc->w.hBitmap;
DC_UnlockDc(hDC);
BitmapObj = BITMAPOBJ_LockBitmap(hBitmap);
if (BitmapObj)
{
SurfObj = &BitmapObj->SurfObj;
if (GDIDEV(SurfObj)->Pointer.MovePointer)
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
{
GDIDEV(SurfObj)->Pointer.MovePointer(SurfObj, MousePos.x, MousePos.y, &(GDIDEV(SurfObj)->Pointer.Exclude));
} else {
EngMovePointer(SurfObj, MousePos.x, MousePos.y, &(GDIDEV(SurfObj)->Pointer.Exclude));
}
/* Only now, update the info in the GDIDEVICE, so EngMovePointer can
* use the old values to move the pointer image */
GDIDEV(SurfObj)->Pointer.Pos.x = MousePos.x;
GDIDEV(SurfObj)->Pointer.Pos.y = MousePos.y;
[Sorry for too many changes in one patch, but it's nearly impossible to separate it without breaking the functionality] - Remove the eng/brush.h header and all occurrences of BRUSHINST. - Remove eng/nls.c and make the NLS functions forward exports to ntoskrnl. - Remove DDBITMAP definition. - Overall cleanup of eng/xlate.c. - Stop processing if exact match is found in ClosestColorMatch. - Move SURFGDI->PointerStatus to GDIDEVICE structure. - Remove the GDIDEVICE->DriverLock. - Replace BITMAP by SURFOBJ in BITMAPOBJ structure and added two new members (Flags and Hooks). - Replace function pointers to driver functions in SURFGDI with flHooks variable specifying the bitmask of hooked functions. - Added two new macros: GDIDEV and GDIDEVFUNCS. - Fixed locking in NtGdiGetBitmapBits. - Removed IntCopyBitmap and replaced it's usage by BITMAPOBJ_CopyBitmap. - Fixed setting of SURFOBJ->pvBits and SURFOBJ->pvScan0 in EngCreateBitmap for bottom-up surfaces. - Fix DPRINTs. - Remove unused definitions from eng/objects.h. - Call IntEngBitBlt instead of EngBitBlt from EngCopyBits. - Correctly set the SURFOBJ->hsurf field. - Merge Engine surface handling with the GDI one and remove DC->Surface, SURFGDI, BitmapToSurf. - Support for bottom-up mouse cursors in the Eng* cursor emulation routines. - Fix locking in error cases of NtGdiRestoreDC (get Primitives demo to start). - Fix BitmapFormat to return 0 for unknown bit depth. - Move code from EngCreateBitmap to IntCreateBitmap and use this function in EngCreateBitmap, NtGdiCreateBitmap and DIB_CreateDIBSection. - New implementation of NtGdiGetDIBits. svn path=/trunk/; revision=9977
2004-07-03 13:55:37 +00:00
BITMAPOBJ_UnlockBitmap(hBitmap);
}
}
}
/*
* 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;
}
BOOL FASTCALL
IntKeyboardInput(KEYBDINPUT *ki)
{
return FALSE;
}
UINT
STDCALL
NtUserSendInput(
UINT nInputs,
LPINPUT pInput,
INT cbSize)
{
PW32THREAD W32Thread;
UINT cnt;
W32Thread = PsGetWin32Thread();
ASSERT(W32Thread);
if(!W32Thread->Desktop)
{
return 0;
}
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) ||
!IntIsActiveDesktop(W32Thread->Desktop))
{
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;
}
/* EOF */