/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+ * 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
#include <windows.h>
#include <ddk/ntddk.h>
#include <ddk/ntddmou.h>
+#include <win32k/win32k.h>
#include <win32k/dc.h>
#include "objects.h"
#include "include/msgqueue.h"
#include "include/object.h"
#include "include/winsta.h"
+#include <include/mouse.h>
#define NDEBUG
#include <debug.h>
+
+#define GETSYSCURSOR(x) ((x) - OCR_NORMAL)
+
/* GLOBALS *******************************************************************/
-static BOOLEAN SafetySwitch = FALSE;
-static BOOLEAN SafetySwitch2 = FALSE;
-static BOOLEAN MouseEnabled = FALSE;
-static LONG mouse_x, mouse_y;
-static UINT mouse_width = 0, mouse_height = 0;
static ULONG PointerStatus;
static UCHAR DefaultCursor[256] = {
/* FUNCTIONS *****************************************************************/
-INT
+BOOL FASTCALL
+IntCheckClipCursor(LONG *x, LONG *y, PSYSTEM_CURSORINFO CurInfo)
+{
+ if(CurInfo->CursorClipInfo.IsClipped)
+ {
+ if(*x > CurInfo->CursorClipInfo.Right)
+ *x = CurInfo->CursorClipInfo.Right;
+ if(*x < CurInfo->CursorClipInfo.Left)
+ *x = CurInfo->CursorClipInfo.Left;
+ if(*y > CurInfo->CursorClipInfo.Bottom)
+ *y = CurInfo->CursorClipInfo.Bottom;
+ if(*y < CurInfo->CursorClipInfo.Top)
+ *y = CurInfo->CursorClipInfo.Top;
+ return TRUE;
+ }
+ return TRUE;
+}
+
+BOOL FASTCALL
+IntDetectDblClick(PSYSTEM_CURSORINFO CurInfo, DWORD TickCount)
+{
+ LONG dX, dY;
+ BOOL res = ((TickCount - CurInfo->LastBtnDown) < CurInfo->DblClickSpeed);
+ if(res)
+ {
+ /* check if the second click is within the DblClickWidth and DblClickHeight values */
+ dX = CurInfo->LastBtnDownX - CurInfo->x;
+ dY = CurInfo->LastBtnDownY - CurInfo->y;
+ if(dX < 0) dX = -dX;
+ if(dY < 0) dY = -dY;
+
+ res = (dX <= CurInfo->DblClickWidth) &&
+ (dY <= CurInfo->DblClickHeight);
+
+ if(res)
+ {
+ CurInfo->LastBtnDown = 0; /* prevent sending 2 or more DBLCLK messages */
+ CurInfo->LastBtnDownX = CurInfo->x;
+ CurInfo->LastBtnDownY = CurInfo->y;
+ }
+ else
+ {
+ CurInfo->LastBtnDown = TickCount;
+ CurInfo->LastBtnDownX = CurInfo->x;
+ CurInfo->LastBtnDownY = CurInfo->y;
+ }
+ }
+ else
+ {
+ CurInfo->LastBtnDown = TickCount;
+ CurInfo->LastBtnDownX = CurInfo->x;
+ CurInfo->LastBtnDownY = CurInfo->y;
+ }
+ return res;
+}
+
+BOOL FASTCALL
+IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
+{
+ BOOL res = WinStaObject->SystemCursor.SwapButtons;
+ WinStaObject->SystemCursor.SwapButtons = Swap;
+ return res;
+}
+
+INT STDCALL
MouseSafetyOnDrawStart(PSURFOBJ SurfObj, PSURFGDI SurfGDI, LONG HazardX1,
LONG HazardY1, LONG HazardX2, LONG HazardY2)
/*
{
RECTL MouseRect;
LONG tmp;
+ PSYSTEM_CURSORINFO CurInfo;
+ PSYSCURSOR SysCursor;
+ BOOL MouseEnabled = FALSE;
/* Mouse is not allowed to move if GDI is busy drawing */
- SafetySwitch2 = TRUE;
-
+
+ if(IntGetWindowStationObject(InputWindowStation))
+ {
+ CurInfo = &InputWindowStation->SystemCursor;
+
+ SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
+ MouseEnabled = CurInfo->Enabled && SysCursor->hCursor;
+ }
+ else
+ return FALSE;
+
+ CurInfo->SafetySwitch2 = TRUE;
+
if (SurfObj == NULL)
{
+ ObDereferenceObject(InputWindowStation);
return(FALSE);
}
+
if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
{
+ ObDereferenceObject(InputWindowStation);
return(FALSE);
}
if (SPS_ACCEPT_NOEXCLUDE == PointerStatus)
{
/* Hardware cursor, no need to remove it */
+ ObDereferenceObject(InputWindowStation);
return(FALSE);
}
tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
}
- if (((mouse_x + mouse_width) >= HazardX1) && (mouse_x <= HazardX2) &&
- ((mouse_y + mouse_height) >= HazardY1) && (mouse_y <= HazardY2))
+ if (((CurInfo->x + SysCursor->cx) >= HazardX1) && (CurInfo->x <= HazardX2) &&
+ ((CurInfo->y + SysCursor->cy) >= HazardY1) && (CurInfo->y <= HazardY2))
{
- SafetySwitch = TRUE;
+ /* Mouse is not allowed to move if GDI is busy drawing */
+ ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
+ CurInfo->SafetySwitch = TRUE;
SurfGDI->MovePointer(SurfObj, -1, -1, &MouseRect);
+ ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
}
-
+
+ ObDereferenceObject(InputWindowStation);
return(TRUE);
}
-INT
+INT FASTCALL
MouseSafetyOnDrawEnd(PSURFOBJ SurfObj, PSURFGDI SurfGDI)
/*
* FUNCTION: Notify the mouse driver that drawing has finished on a surface.
*/
{
RECTL MouseRect;
-
- if (SurfObj == NULL)
- {
- SafetySwitch2 = FALSE;
- return(FALSE);
- }
+ PSYSTEM_CURSORINFO CurInfo;
+ PSYSCURSOR SysCursor;
+ BOOL MouseEnabled = FALSE;
+
+ if(IntGetWindowStationObject(InputWindowStation))
+ {
+ CurInfo = &InputWindowStation->SystemCursor;
+ }
+ else
+ return FALSE;
+
+ if(SurfObj == NULL)
+ {
+ CurInfo->SafetySwitch2 = FALSE;
+ ObDereferenceObject(InputWindowStation);
+ return FALSE;
+ }
+
+ SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
+ MouseEnabled = CurInfo->Enabled && SysCursor->hCursor;
if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
{
- SafetySwitch2 = FALSE;
+ CurInfo->SafetySwitch2 = FALSE;
+ ObDereferenceObject(InputWindowStation);
return(FALSE);
}
if (SPS_ACCEPT_NOEXCLUDE == PointerStatus)
{
/* Hardware cursor, it wasn't removed so need to restore it */
- SafetySwitch2 = FALSE;
+ CurInfo->SafetySwitch2 = FALSE;
+ ObDereferenceObject(InputWindowStation);
return(FALSE);
}
- if (SafetySwitch)
+ if (CurInfo->SafetySwitch)
{
- SurfGDI->MovePointer(SurfObj, mouse_x, mouse_y, &MouseRect);
- SafetySwitch = FALSE;
+ ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
+ SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
+ CurInfo->SafetySwitch = FALSE;
+ ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
}
-
- SafetySwitch2 = FALSE;
-
+
+ CurInfo->SafetySwitch2 = FALSE;
+ ObDereferenceObject(InputWindowStation);
return(TRUE);
}
-VOID
+BOOL FASTCALL
+MouseMoveCursor(LONG X, LONG Y)
+{
+ HDC hDC;
+ PDC dc;
+ RECTL MouseRect;
+ BOOL res = FALSE;
+ PSURFOBJ SurfObj;
+ PSURFGDI SurfGDI;
+ PSYSTEM_CURSORINFO CurInfo;
+ MSG Msg;
+ LARGE_INTEGER LargeTickCount;
+ ULONG TickCount;
+ static ULONG ButtonsDown = 0;
+
+ if(!InputWindowStation)
+ return FALSE;
+
+ if(IntGetWindowStationObject(InputWindowStation))
+ {
+ CurInfo = &InputWindowStation->SystemCursor;
+ if(!CurInfo->Enabled)
+ {
+ ObDereferenceObject(InputWindowStation);
+ return FALSE;
+ }
+ hDC = IntGetScreenDC();
+ if(!hDC)
+ {
+ ObDereferenceObject(InputWindowStation);
+ return FALSE;
+ }
+ dc = DC_LockDc(hDC);
+ SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
+ SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
+ DC_UnlockDc( hDC );
+ IntCheckClipCursor(&X, &Y, CurInfo);
+ if((X != CurInfo->x) || (Y != CurInfo->y))
+ {
+ /* send MOUSEMOVE message */
+ KeQueryTickCount(&LargeTickCount);
+ TickCount = LargeTickCount.u.LowPart;
+ Msg.wParam = ButtonsDown;
+ Msg.lParam = MAKELPARAM(X, Y);
+ Msg.message = WM_MOUSEMOVE;
+ Msg.time = TickCount;
+ Msg.pt.x = X;
+ Msg.pt.y = Y;
+ MsqInsertSystemMessage(&Msg, TRUE);
+ /* move cursor */
+ CurInfo->x = X;
+ CurInfo->y = Y;
+ if(CurInfo->Enabled)
+ {
+ ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
+ SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
+ ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
+ }
+ res = TRUE;
+ }
+
+ ObDereferenceObject(InputWindowStation);
+ return res;
+ }
+ else
+ return FALSE;
+}
+
+VOID /* STDCALL */
MouseGDICallBack(PMOUSE_INPUT_DATA Data, ULONG InputCount)
/*
* FUNCTION: Call by the mouse driver when input events occur.
*/
{
ULONG i;
+ PSYSTEM_CURSORINFO CurInfo;
+ PSYSCURSOR SysCursor;
+ BOOL MouseEnabled = FALSE;
+ BOOL MouseMoveAdded = FALSE;
+ LONG mouse_ox, mouse_oy;
LONG mouse_cx = 0, mouse_cy = 0;
- HDC hDC = W32kGetScreenDC();
+ HDC hDC;
PDC dc;
PSURFOBJ SurfObj;
PSURFGDI SurfGDI;
LARGE_INTEGER LargeTickCount;
ULONG TickCount;
static ULONG ButtonsDown = 0;
+
+ hDC = IntGetScreenDC();
+
+ if(!hDC || !InputWindowStation)
+ return;
- KeQueryTickCount(&LargeTickCount);
- TickCount = LargeTickCount.u.LowPart;
-
- if (hDC == 0)
+ if(IntGetWindowStationObject(InputWindowStation))
{
- return;
+ CurInfo = &InputWindowStation->SystemCursor;
+ SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
+ MouseEnabled = CurInfo->Enabled;
+ if(!MouseEnabled)
+ {
+ ObDereferenceObject(InputWindowStation);
+ return;
+ }
+ mouse_ox = CurInfo->x;
+ mouse_oy = CurInfo->y;
}
+ else
+ return;
- dc = DC_HandleToPtr(hDC);
+ dc = DC_LockDc(hDC);
SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
- DC_ReleasePtr( hDC );
+ DC_UnlockDc( hDC );
/* Compile the total mouse movement change and dispatch button events. */
for (i = 0; i < InputCount; i++)
{
mouse_cx += Data[i].LastX;
mouse_cy += Data[i].LastY;
+
+ CurInfo->x += Data[i].LastX;
+ CurInfo->y += Data[i].LastY;
+
+ CurInfo->x = max(CurInfo->x, 0);
+ CurInfo->y = max(CurInfo->y, 0);
+ CurInfo->x = min(CurInfo->x, SurfObj->sizlBitmap.cx - 1);
+ CurInfo->y = min(CurInfo->y, SurfObj->sizlBitmap.cy - 1);
+
+ IntCheckClipCursor(&CurInfo->x, &CurInfo->y, CurInfo);
+
+ KeQueryTickCount(&LargeTickCount);
+ TickCount = LargeTickCount.u.LowPart;
Msg.wParam = ButtonsDown;
- Msg.lParam = MAKELPARAM(mouse_x + mouse_cx, mouse_y + mouse_cy);
+ Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
Msg.message = WM_MOUSEMOVE;
Msg.time = TickCount;
- Msg.pt.x = mouse_x + mouse_cx;
- Msg.pt.y = mouse_y + mouse_cy;
- if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
- {
- MsqInsertSystemMessage(&Msg);
- }
-
+ Msg.pt.x = CurInfo->x;
+ Msg.pt.y = CurInfo->y;
+
+ MouseMoveAdded = FALSE;
+
if (Data[i].ButtonFlags != 0)
{
+
if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_DOWN) > 0)
{
- Msg.wParam = MK_LBUTTON;
- Msg.message = WM_LBUTTONDOWN;
+ /* insert WM_MOUSEMOVE messages before Button down messages */
+ if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
+ {
+ MsqInsertSystemMessage(&Msg, FALSE);
+ MouseMoveAdded = TRUE;
+ }
+ Msg.wParam = CurInfo->SwapButtons ? MK_RBUTTON : MK_LBUTTON;
+ if(IntDetectDblClick(CurInfo, TickCount))
+ Msg.message = CurInfo->SwapButtons ? WM_RBUTTONDBLCLK : WM_LBUTTONDBLCLK;
+ else
+ Msg.message = CurInfo->SwapButtons ? WM_RBUTTONDOWN : WM_LBUTTONDOWN;
}
if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN) > 0)
{
+ /* insert WM_MOUSEMOVE messages before Button down messages */
+ if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
+ {
+ MsqInsertSystemMessage(&Msg, FALSE);
+ MouseMoveAdded = TRUE;
+ }
Msg.wParam = MK_MBUTTON;
- Msg.message = WM_MBUTTONDOWN;
+ if(IntDetectDblClick(CurInfo, TickCount))
+ Msg.message = WM_MBUTTONDBLCLK;
+ else
+ Msg.message = WM_MBUTTONDOWN;
}
if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN) > 0)
{
- Msg.wParam = MK_RBUTTON;
- Msg.message = WM_RBUTTONDOWN;
+ /* insert WM_MOUSEMOVE messages before Button down messages */
+ if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
+ {
+ MsqInsertSystemMessage(&Msg, FALSE);
+ MouseMoveAdded = TRUE;
+ }
+ Msg.wParam = CurInfo->SwapButtons ? MK_LBUTTON : MK_RBUTTON;
+ if(IntDetectDblClick(CurInfo, TickCount))
+ Msg.message = CurInfo->SwapButtons ? WM_LBUTTONDBLCLK : WM_RBUTTONDBLCLK;
+ else
+ Msg.message = CurInfo->SwapButtons ? WM_LBUTTONDOWN : WM_RBUTTONDOWN;
}
if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_UP) > 0)
{
- Msg.wParam = MK_LBUTTON;
- Msg.message = WM_LBUTTONUP;
+ Msg.wParam = CurInfo->SwapButtons ? MK_RBUTTON : MK_LBUTTON;
+ Msg.message = CurInfo->SwapButtons ? WM_RBUTTONUP : WM_LBUTTONUP;
}
if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_UP) > 0)
{
}
if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_UP) > 0)
{
- Msg.wParam = MK_RBUTTON;
- Msg.message = WM_RBUTTONUP;
+ Msg.wParam = CurInfo->SwapButtons ? MK_LBUTTON : MK_RBUTTON;
+ Msg.message = CurInfo->SwapButtons ? WM_LBUTTONUP : WM_RBUTTONUP;
}
- MsqInsertSystemMessage(&Msg);
+ MsqInsertSystemMessage(&Msg, FALSE);
+
+ /* insert WM_MOUSEMOVE messages after Button up messages */
+ if(!MouseMoveAdded && ((0 != Data[i].LastX) || (0 != Data[i].LastY)))
+ {
+ Msg.wParam = ButtonsDown;
+ Msg.message = WM_MOUSEMOVE;
+ MsqInsertSystemMessage(&Msg, FALSE);
+ MouseMoveAdded = TRUE;
+ }
}
}
/* If the mouse moved then move the pointer. */
if ((mouse_cx != 0 || mouse_cy != 0) && MouseEnabled)
{
- mouse_x += mouse_cx;
- mouse_y += mouse_cy;
-
- mouse_x = max(mouse_x, 0);
- mouse_y = max(mouse_y, 0);
- mouse_x = min(mouse_x, 620);
- mouse_y = min(mouse_y, 460);
- if (SafetySwitch == FALSE && SafetySwitch2 == FALSE)
+ if(!MouseMoveAdded)
{
- SurfGDI->MovePointer(SurfObj, mouse_x, mouse_y, &MouseRect);
+ KeQueryTickCount(&LargeTickCount);
+ TickCount = LargeTickCount.u.LowPart;
+ Msg.wParam = ButtonsDown;
+ Msg.message = WM_MOUSEMOVE;
+ Msg.pt.x = CurInfo->x;
+ Msg.pt.y = CurInfo->y;
+ Msg.time = TickCount;
+ Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
+ MsqInsertSystemMessage(&Msg, TRUE);
+ }
+
+ if (!CurInfo->SafetySwitch && !CurInfo->SafetySwitch2 &&
+ ((mouse_ox != CurInfo->x) || (mouse_oy != CurInfo->y)))
+ {
+ ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
+ SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
+ ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
}
}
+
+ ObDereferenceObject(InputWindowStation);
}
-VOID
+VOID FASTCALL
EnableMouse(HDC hDisplayDC)
{
PDC dc;
PSURFOBJ MouseSurf;
SIZEL MouseSize;
RECTL MouseRect;
+ PSYSTEM_CURSORINFO CurInfo;
+ PSYSCURSOR SysCursor;
- if( hDisplayDC )
+ if( hDisplayDC && InputWindowStation)
{
- dc = DC_HandleToPtr(hDisplayDC);
+ if(!IntGetWindowStationObject(InputWindowStation))
+ {
+ InputWindowStation->SystemCursor.Enabled = FALSE;
+ return;
+ }
+
+ CurInfo = &InputWindowStation->SystemCursor;
+ SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
+
+ dc = DC_LockDc(hDisplayDC);
SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
- DC_ReleasePtr( hDisplayDC );
+ DC_UnlockDc( hDisplayDC );
+
+ /* Tell the display driver to set the pointer shape. */
+ CurInfo->x = SurfObj->sizlBitmap.cx / 2;
+ CurInfo->y = SurfObj->sizlBitmap.cy / 2;
/* Create the default mouse cursor. */
- mouse_width = 32;
- mouse_height = 32;
- MouseSize.cx = 32;
- MouseSize.cy = 64;
+ MouseSize.cx = SysCursor->cx;
+ MouseSize.cy = SysCursor->cy * 2;
hMouseSurf = EngCreateBitmap(MouseSize, 4, BMF_1BPP, BMF_TOPDOWN, DefaultCursor);
MouseSurf = (PSURFOBJ)AccessUserObject((ULONG) hMouseSurf);
- /* Tell the display driver to set the pointer shape. */
-#if 0
- mouse_x = SurfObj->sizlBitmap.cx / 2;
- mouse_y = SurfObj->sizlBitmap.cy / 2;
-#else
- mouse_x = 320;
- mouse_y = 240;
-#endif
+ DPRINT("Setting Cursor up at 0x%x, 0x%x\n", CurInfo->x, CurInfo->y);
+ IntCheckClipCursor(&CurInfo->x,
+ &CurInfo->y,
+ CurInfo);
+
PointerStatus = SurfGDI->SetPointerShape(SurfObj, MouseSurf, NULL, NULL,
- 0, 0, mouse_x, mouse_y, &MouseRect,
+ SysCursor->hx,
+ SysCursor->hy,
+ CurInfo->x,
+ CurInfo->y,
+ &MouseRect,
SPS_CHANGE);
- MouseEnabled = (SPS_ACCEPT_EXCLUDE == PointerStatus ||
- SPS_ACCEPT_NOEXCLUDE == PointerStatus);
+ InputWindowStation->SystemCursor.Enabled = (SPS_ACCEPT_EXCLUDE == PointerStatus ||
+ SPS_ACCEPT_NOEXCLUDE == PointerStatus);
EngDeleteSurface(hMouseSurf);
+ ObDereferenceObject(InputWindowStation);
+
}
else
{
- MouseEnabled = FALSE;
+ if(IntGetWindowStationObject(InputWindowStation))
+ {
+ InputWindowStation->SystemCursor.Enabled = FALSE;
+ InputWindowStation->SystemCursor.CursorClipInfo.IsClipped = FALSE;
+ ObDereferenceObject(InputWindowStation);
+ return;
+ }
}
}
-
+/* EOF */