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 * PROJECT: ReactOS kernel
23 * FILE: subsys/win32k/eng/mouse.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 06-06-2001 CSH Created
28 /* INCLUDES ******************************************************************/
31 #include <ddk/ntddk.h>
32 #include <ddk/ntddmou.h>
33 #include <win32k/win32k.h>
34 #include <win32k/dc.h>
36 #include "include/msgqueue.h"
37 #include "include/object.h"
38 #include "include/winsta.h"
39 #include <include/mouse.h>
45 #define GETSYSCURSOR(x) ((x) - OCR_NORMAL)
47 /* GLOBALS *******************************************************************/
49 static ULONG PointerStatus;
51 static UCHAR DefaultCursor[256] = {
52 0x3F, 0xFF, 0xFF, 0xFF,
53 0x1F, 0xFF, 0xFF, 0xFF,
54 0x0F, 0xFF, 0xFF, 0xFF,
55 0x07, 0xFF, 0xFF, 0xFF,
56 0x03, 0xFF, 0xFF, 0xFF,
57 0x01, 0xFF, 0xFF, 0xFF,
58 0x00, 0xFF, 0xFF, 0xFF,
59 0x00, 0x7F, 0xFF, 0xFF,
60 0x00, 0x3F, 0xFF, 0xFF,
61 0x00, 0x1F, 0xFF, 0xFF,
62 0x00, 0x0F, 0xFF, 0xFF,
63 0x00, 0xFF, 0xFF, 0xFF,
64 0x00, 0xFF, 0xFF, 0xFF,
65 0x18, 0x7F, 0xFF, 0xFF,
66 0x38, 0x7F, 0xFF, 0xFF,
67 0x7C, 0x3F, 0xFF, 0xFF,
68 0xFC, 0x3F, 0xFF, 0xFF,
69 0xFE, 0x1F, 0xFF, 0xFF,
70 0xFE, 0x1F, 0xFF, 0xFF,
71 0xFF, 0x3F, 0xFF, 0xFF,
72 0xFF, 0xFF, 0xFF, 0xFF,
73 0xFF, 0xFF, 0xFF, 0xFF,
74 0xFF, 0xFF, 0xFF, 0xFF,
75 0xFF, 0xFF, 0xFF, 0xFF,
76 0xFF, 0xFF, 0xFF, 0xFF,
77 0xFF, 0xFF, 0xFF, 0xFF,
78 0xFF, 0xFF, 0xFF, 0xFF,
79 0xFF, 0xFF, 0xFF, 0xFF,
80 0xFF, 0xFF, 0xFF, 0xFF,
81 0xFF, 0xFF, 0xFF, 0xFF,
82 0xFF, 0xFF, 0xFF, 0xFF,
83 0xFF, 0xFF, 0xFF, 0xFF,
85 0x00, 0x00, 0x00, 0x00,
86 0x40, 0x00, 0x00, 0x00,
87 0x60, 0x00, 0x00, 0x00,
88 0x70, 0x00, 0x00, 0x00,
89 0x78, 0x00, 0x00, 0x00,
90 0x7C, 0x00, 0x00, 0x00,
91 0x7E, 0x00, 0x00, 0x00,
92 0x7F, 0x00, 0x00, 0x00,
93 0x7F, 0x80, 0x00, 0x00,
94 0x7F, 0xC0, 0x00, 0x00,
95 0x7E, 0x00, 0x00, 0x00,
96 0x76, 0x00, 0x00, 0x00,
97 0x76, 0x00, 0x00, 0x00,
98 0x43, 0x00, 0x00, 0x00,
99 0x03, 0x00, 0x00, 0x00,
100 0x01, 0x80, 0x00, 0x00,
101 0x01, 0x80, 0x00, 0x00,
102 0x00, 0xC0, 0x00, 0x00,
103 0x00, 0xC0, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00,
113 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00};
118 /* FUNCTIONS *****************************************************************/
121 IntCheckClipCursor(LONG *x, LONG *y, PSYSTEM_CURSORINFO CurInfo)
123 if(CurInfo->CursorClipInfo.IsClipped)
125 if(*x > CurInfo->CursorClipInfo.Right)
126 *x = CurInfo->CursorClipInfo.Right;
127 if(*x < CurInfo->CursorClipInfo.Left)
128 *x = CurInfo->CursorClipInfo.Left;
129 if(*y > CurInfo->CursorClipInfo.Bottom)
130 *y = CurInfo->CursorClipInfo.Bottom;
131 if(*y < CurInfo->CursorClipInfo.Top)
132 *y = CurInfo->CursorClipInfo.Top;
139 IntDetectDblClick(PSYSTEM_CURSORINFO CurInfo, DWORD TickCount)
142 BOOL res = ((TickCount - CurInfo->LastBtnDown) < CurInfo->DblClickSpeed);
145 /* check if the second click is within the DblClickWidth and DblClickHeight values */
146 dX = CurInfo->LastBtnDownX - CurInfo->x;
147 dY = CurInfo->LastBtnDownY - CurInfo->y;
151 res = (dX <= CurInfo->DblClickWidth) &&
152 (dY <= CurInfo->DblClickHeight);
156 CurInfo->LastBtnDown = 0; /* prevent sending 2 or more DBLCLK messages */
157 CurInfo->LastBtnDownX = CurInfo->x;
158 CurInfo->LastBtnDownY = CurInfo->y;
162 CurInfo->LastBtnDown = TickCount;
163 CurInfo->LastBtnDownX = CurInfo->x;
164 CurInfo->LastBtnDownY = CurInfo->y;
169 CurInfo->LastBtnDown = TickCount;
170 CurInfo->LastBtnDownX = CurInfo->x;
171 CurInfo->LastBtnDownY = CurInfo->y;
177 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject, BOOL Swap)
179 BOOL res = WinStaObject->SystemCursor.SwapButtons;
180 WinStaObject->SystemCursor.SwapButtons = Swap;
185 MouseSafetyOnDrawStart(PSURFOBJ SurfObj, PSURFGDI SurfGDI, LONG HazardX1,
186 LONG HazardY1, LONG HazardX2, LONG HazardY2)
188 * FUNCTION: Notify the mouse driver that drawing is about to begin in
189 * a rectangle on a particular surface.
194 PSYSTEM_CURSORINFO CurInfo;
195 PSYSCURSOR SysCursor;
196 BOOL MouseEnabled = FALSE;
199 /* Mouse is not allowed to move if GDI is busy drawing */
201 if(IntGetWindowStationObject(InputWindowStation))
203 CurInfo = &InputWindowStation->SystemCursor;
205 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
206 MouseEnabled = CurInfo->Enabled && SysCursor->hCursor;
211 CurInfo->SafetySwitch2 = TRUE;
215 ObDereferenceObject(InputWindowStation);
220 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
222 ObDereferenceObject(InputWindowStation);
226 if (SPS_ACCEPT_NOEXCLUDE == PointerStatus)
228 /* Hardware cursor, no need to remove it */
229 ObDereferenceObject(InputWindowStation);
233 if (HazardX1 > HazardX2)
235 tmp = HazardX2; HazardX2 = HazardX1; HazardX1 = tmp;
237 if (HazardY1 > HazardY2)
239 tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
242 if (((CurInfo->x + SysCursor->cx) >= HazardX1) && (CurInfo->x <= HazardX2) &&
243 ((CurInfo->y + SysCursor->cy) >= HazardY1) && (CurInfo->y <= HazardY2))
245 /* Mouse is not allowed to move if GDI is busy drawing */
246 ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
247 CurInfo->SafetySwitch = TRUE;
248 SurfGDI->MovePointer(SurfObj, -1, -1, &MouseRect);
249 ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
252 ObDereferenceObject(InputWindowStation);
257 MouseSafetyOnDrawEnd(PSURFOBJ SurfObj, PSURFGDI SurfGDI)
259 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
263 PSYSTEM_CURSORINFO CurInfo;
264 PSYSCURSOR SysCursor;
265 BOOL MouseEnabled = FALSE;
267 if(IntGetWindowStationObject(InputWindowStation))
269 CurInfo = &InputWindowStation->SystemCursor;
276 CurInfo->SafetySwitch2 = FALSE;
277 ObDereferenceObject(InputWindowStation);
281 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
282 MouseEnabled = CurInfo->Enabled && SysCursor->hCursor;
284 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
286 CurInfo->SafetySwitch2 = FALSE;
287 ObDereferenceObject(InputWindowStation);
291 if (SPS_ACCEPT_NOEXCLUDE == PointerStatus)
293 /* Hardware cursor, it wasn't removed so need to restore it */
294 CurInfo->SafetySwitch2 = FALSE;
295 ObDereferenceObject(InputWindowStation);
299 if (CurInfo->SafetySwitch)
301 ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
302 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
303 CurInfo->SafetySwitch = FALSE;
304 ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
307 CurInfo->SafetySwitch2 = FALSE;
308 ObDereferenceObject(InputWindowStation);
313 MouseMoveCursor(LONG X, LONG Y)
321 PSYSTEM_CURSORINFO CurInfo;
323 LARGE_INTEGER LargeTickCount;
325 static ULONG ButtonsDown = 0;
327 if(!InputWindowStation)
330 if(IntGetWindowStationObject(InputWindowStation))
332 CurInfo = &InputWindowStation->SystemCursor;
333 if(!CurInfo->Enabled)
335 ObDereferenceObject(InputWindowStation);
338 hDC = IntGetScreenDC();
341 ObDereferenceObject(InputWindowStation);
345 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
346 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
348 IntCheckClipCursor(&X, &Y, CurInfo);
349 if((X != CurInfo->x) || (Y != CurInfo->y))
351 /* send MOUSEMOVE message */
352 KeQueryTickCount(&LargeTickCount);
353 TickCount = LargeTickCount.u.LowPart;
354 Msg.wParam = ButtonsDown;
355 Msg.lParam = MAKELPARAM(X, Y);
356 Msg.message = WM_MOUSEMOVE;
357 Msg.time = TickCount;
360 MsqInsertSystemMessage(&Msg, TRUE);
366 ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
367 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
368 ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
373 ObDereferenceObject(InputWindowStation);
381 MouseGDICallBack(PMOUSE_INPUT_DATA Data, ULONG InputCount)
383 * FUNCTION: Call by the mouse driver when input events occur.
387 PSYSTEM_CURSORINFO CurInfo;
388 PSYSCURSOR SysCursor;
389 BOOL MouseEnabled = FALSE;
390 BOOL MouseMoveAdded = FALSE;
391 LONG mouse_ox, mouse_oy;
392 LONG mouse_cx = 0, mouse_cy = 0;
399 LARGE_INTEGER LargeTickCount;
401 static ULONG ButtonsDown = 0;
403 hDC = IntGetScreenDC();
405 if(!hDC || !InputWindowStation)
408 if(IntGetWindowStationObject(InputWindowStation))
410 CurInfo = &InputWindowStation->SystemCursor;
411 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
412 MouseEnabled = CurInfo->Enabled;
415 ObDereferenceObject(InputWindowStation);
418 mouse_ox = CurInfo->x;
419 mouse_oy = CurInfo->y;
425 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
426 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
429 /* Compile the total mouse movement change and dispatch button events. */
430 for (i = 0; i < InputCount; i++)
432 mouse_cx += Data[i].LastX;
433 mouse_cy += Data[i].LastY;
435 CurInfo->x += Data[i].LastX;
436 CurInfo->y += Data[i].LastY;
438 CurInfo->x = max(CurInfo->x, 0);
439 CurInfo->y = max(CurInfo->y, 0);
440 CurInfo->x = min(CurInfo->x, SurfObj->sizlBitmap.cx - 1);
441 CurInfo->y = min(CurInfo->y, SurfObj->sizlBitmap.cy - 1);
443 IntCheckClipCursor(&CurInfo->x, &CurInfo->y, CurInfo);
445 KeQueryTickCount(&LargeTickCount);
446 TickCount = LargeTickCount.u.LowPart;
448 Msg.wParam = ButtonsDown;
449 Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
450 Msg.message = WM_MOUSEMOVE;
451 Msg.time = TickCount;
452 Msg.pt.x = CurInfo->x;
453 Msg.pt.y = CurInfo->y;
455 MouseMoveAdded = FALSE;
457 if (Data[i].ButtonFlags != 0)
460 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_DOWN) > 0)
462 /* insert WM_MOUSEMOVE messages before Button down messages */
463 if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
465 MsqInsertSystemMessage(&Msg, FALSE);
466 MouseMoveAdded = TRUE;
468 Msg.wParam = CurInfo->SwapButtons ? MK_RBUTTON : MK_LBUTTON;
469 if(IntDetectDblClick(CurInfo, TickCount))
470 Msg.message = CurInfo->SwapButtons ? WM_RBUTTONDBLCLK : WM_LBUTTONDBLCLK;
472 Msg.message = CurInfo->SwapButtons ? WM_RBUTTONDOWN : WM_LBUTTONDOWN;
474 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN) > 0)
476 /* insert WM_MOUSEMOVE messages before Button down messages */
477 if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
479 MsqInsertSystemMessage(&Msg, FALSE);
480 MouseMoveAdded = TRUE;
482 Msg.wParam = MK_MBUTTON;
483 if(IntDetectDblClick(CurInfo, TickCount))
484 Msg.message = WM_MBUTTONDBLCLK;
486 Msg.message = WM_MBUTTONDOWN;
488 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN) > 0)
490 /* insert WM_MOUSEMOVE messages before Button down messages */
491 if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
493 MsqInsertSystemMessage(&Msg, FALSE);
494 MouseMoveAdded = TRUE;
496 Msg.wParam = CurInfo->SwapButtons ? MK_LBUTTON : MK_RBUTTON;
497 if(IntDetectDblClick(CurInfo, TickCount))
498 Msg.message = CurInfo->SwapButtons ? WM_LBUTTONDBLCLK : WM_RBUTTONDBLCLK;
500 Msg.message = CurInfo->SwapButtons ? WM_LBUTTONDOWN : WM_RBUTTONDOWN;
503 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_UP) > 0)
505 Msg.wParam = CurInfo->SwapButtons ? MK_RBUTTON : MK_LBUTTON;
506 Msg.message = CurInfo->SwapButtons ? WM_RBUTTONUP : WM_LBUTTONUP;
508 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_UP) > 0)
510 Msg.wParam = MK_MBUTTON;
511 Msg.message = WM_MBUTTONUP;
513 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_UP) > 0)
515 Msg.wParam = CurInfo->SwapButtons ? MK_LBUTTON : MK_RBUTTON;
516 Msg.message = CurInfo->SwapButtons ? WM_LBUTTONUP : WM_RBUTTONUP;
519 MsqInsertSystemMessage(&Msg, FALSE);
521 /* insert WM_MOUSEMOVE messages after Button up messages */
522 if(!MouseMoveAdded && ((0 != Data[i].LastX) || (0 != Data[i].LastY)))
524 Msg.wParam = ButtonsDown;
525 Msg.message = WM_MOUSEMOVE;
526 MsqInsertSystemMessage(&Msg, FALSE);
527 MouseMoveAdded = TRUE;
532 /* If the mouse moved then move the pointer. */
533 if ((mouse_cx != 0 || mouse_cy != 0) && MouseEnabled)
538 KeQueryTickCount(&LargeTickCount);
539 TickCount = LargeTickCount.u.LowPart;
540 Msg.wParam = ButtonsDown;
541 Msg.message = WM_MOUSEMOVE;
542 Msg.pt.x = CurInfo->x;
543 Msg.pt.y = CurInfo->y;
544 Msg.time = TickCount;
545 Msg.lParam = MAKELPARAM(CurInfo->x, CurInfo->y);
546 MsqInsertSystemMessage(&Msg, TRUE);
549 if (!CurInfo->SafetySwitch && !CurInfo->SafetySwitch2 &&
550 ((mouse_ox != CurInfo->x) || (mouse_oy != CurInfo->y)))
552 ExAcquireFastMutexUnsafe(&CurInfo->CursorMutex);
553 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
554 ExReleaseFastMutexUnsafe(&CurInfo->CursorMutex);
558 ObDereferenceObject(InputWindowStation);
562 EnableMouse(HDC hDisplayDC)
571 PSYSTEM_CURSORINFO CurInfo;
572 PSYSCURSOR SysCursor;
574 if( hDisplayDC && InputWindowStation)
576 if(!IntGetWindowStationObject(InputWindowStation))
578 InputWindowStation->SystemCursor.Enabled = FALSE;
582 CurInfo = &InputWindowStation->SystemCursor;
583 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
585 dc = DC_LockDc(hDisplayDC);
586 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
587 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
588 DC_UnlockDc( hDisplayDC );
590 /* Tell the display driver to set the pointer shape. */
591 CurInfo->x = SurfObj->sizlBitmap.cx / 2;
592 CurInfo->y = SurfObj->sizlBitmap.cy / 2;
594 /* Create the default mouse cursor. */
595 MouseSize.cx = SysCursor->cx;
596 MouseSize.cy = SysCursor->cy * 2;
597 hMouseSurf = EngCreateBitmap(MouseSize, 4, BMF_1BPP, BMF_TOPDOWN, DefaultCursor);
598 MouseSurf = (PSURFOBJ)AccessUserObject((ULONG) hMouseSurf);
600 DPRINT("Setting Cursor up at 0x%x, 0x%x\n", CurInfo->x, CurInfo->y);
601 IntCheckClipCursor(&CurInfo->x,
605 PointerStatus = SurfGDI->SetPointerShape(SurfObj, MouseSurf, NULL, NULL,
613 InputWindowStation->SystemCursor.Enabled = (SPS_ACCEPT_EXCLUDE == PointerStatus ||
614 SPS_ACCEPT_NOEXCLUDE == PointerStatus);
616 EngDeleteSurface(hMouseSurf);
617 ObDereferenceObject(InputWindowStation);
622 if(IntGetWindowStationObject(InputWindowStation))
624 InputWindowStation->SystemCursor.Enabled = FALSE;
625 InputWindowStation->SystemCursor.CursorClipInfo.IsClipped = FALSE;
626 ObDereferenceObject(InputWindowStation);