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.
19 /* $Id: mouse.c,v 1.47 2003/12/07 19:29:33 weiden Exp $
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/desktop.h"
40 #include "include/window.h"
41 #include "include/cursoricon.h"
42 #include "include/callback.h"
43 #include <include/mouse.h>
48 #define GETSYSCURSOR(x) ((x) - OCR_NORMAL)
50 /* FUNCTIONS *****************************************************************/
53 IntCheckClipCursor(LONG
*x
, LONG
*y
, PSYSTEM_CURSORINFO CurInfo
)
55 if(CurInfo
->CursorClipInfo
.IsClipped
)
57 if(*x
> CurInfo
->CursorClipInfo
.Right
)
58 *x
= CurInfo
->CursorClipInfo
.Right
;
59 if(*x
< CurInfo
->CursorClipInfo
.Left
)
60 *x
= CurInfo
->CursorClipInfo
.Left
;
61 if(*y
> CurInfo
->CursorClipInfo
.Bottom
)
62 *y
= CurInfo
->CursorClipInfo
.Bottom
;
63 if(*y
< CurInfo
->CursorClipInfo
.Top
)
64 *y
= CurInfo
->CursorClipInfo
.Top
;
71 IntDetectDblClick(PSYSTEM_CURSORINFO CurInfo
, DWORD TickCount
)
74 BOOL res
= ((TickCount
- CurInfo
->LastBtnDown
) < CurInfo
->DblClickSpeed
);
77 /* check if the second click is within the DblClickWidth and DblClickHeight values */
78 dX
= CurInfo
->LastBtnDownX
- CurInfo
->x
;
79 dY
= CurInfo
->LastBtnDownY
- CurInfo
->y
;
83 res
= (dX
<= CurInfo
->DblClickWidth
) &&
84 (dY
<= CurInfo
->DblClickHeight
);
88 CurInfo
->LastBtnDown
= 0; /* prevent sending 2 or more DBLCLK messages */
89 CurInfo
->LastBtnDownX
= CurInfo
->x
;
90 CurInfo
->LastBtnDownY
= CurInfo
->y
;
94 CurInfo
->LastBtnDown
= TickCount
;
95 CurInfo
->LastBtnDownX
= CurInfo
->x
;
96 CurInfo
->LastBtnDownY
= CurInfo
->y
;
101 CurInfo
->LastBtnDown
= TickCount
;
102 CurInfo
->LastBtnDownX
= CurInfo
->x
;
103 CurInfo
->LastBtnDownY
= CurInfo
->y
;
109 IntSwapMouseButton(PWINSTATION_OBJECT WinStaObject
, BOOL Swap
)
111 BOOL res
= WinStaObject
->SystemCursor
.SwapButtons
;
112 WinStaObject
->SystemCursor
.SwapButtons
= Swap
;
117 MouseSafetyOnDrawStart(PSURFOBJ SurfObj
, PSURFGDI SurfGDI
, LONG HazardX1
,
118 LONG HazardY1
, LONG HazardX2
, LONG HazardY2
)
120 * FUNCTION: Notify the mouse driver that drawing is about to begin in
121 * a rectangle on a particular surface.
126 PSYSTEM_CURSORINFO CurInfo
;
127 BOOL MouseEnabled
= FALSE
;
128 PCURICON_OBJECT Cursor
;
131 /* Mouse is not allowed to move if GDI is busy drawing */
133 if(IntGetWindowStationObject(InputWindowStation
))
135 CurInfo
= &InputWindowStation
->SystemCursor
;
137 MouseEnabled
= CurInfo
->Enabled
&& CurInfo
->ShowingCursor
;
142 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
143 CurInfo
->SafetySwitch2
= TRUE
;
144 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
148 ObDereferenceObject(InputWindowStation
);
153 if (SurfObj
->iType
!= STYPE_DEVICE
|| MouseEnabled
== FALSE
)
155 ObDereferenceObject(InputWindowStation
);
159 if (SPS_ACCEPT_NOEXCLUDE
== SurfGDI
->PointerStatus
)
161 /* Hardware cursor, no need to remove it */
162 ObDereferenceObject(InputWindowStation
);
166 if(!(Cursor
= CurInfo
->CurrentCursorObject
))
168 ObDereferenceObject(InputWindowStation
);
172 if (HazardX1
> HazardX2
)
174 tmp
= HazardX2
; HazardX2
= HazardX1
; HazardX1
= tmp
;
176 if (HazardY1
> HazardY2
)
178 tmp
= HazardY2
; HazardY2
= HazardY1
; HazardY1
= tmp
;
181 if (CurInfo
->x
- (INT
) Cursor
->IconInfo
.xHotspot
+ Cursor
->Size
.cx
>= HazardX1
182 && CurInfo
->x
- (INT
) Cursor
->IconInfo
.xHotspot
<= HazardX2
183 && CurInfo
->y
- (INT
) Cursor
->IconInfo
.yHotspot
+ Cursor
->Size
.cy
>= HazardY1
184 && CurInfo
->y
- (INT
) Cursor
->IconInfo
.yHotspot
<= HazardY2
)
186 /* Mouse is not allowed to move if GDI is busy drawing */
187 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
188 CurInfo
->SafetySwitch
= TRUE
;
189 SurfGDI
->MovePointer(SurfObj
, -1, -1, &MouseRect
);
190 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
193 ObDereferenceObject(InputWindowStation
);
198 MouseSafetyOnDrawEnd(PSURFOBJ SurfObj
, PSURFGDI SurfGDI
)
200 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
204 PSYSTEM_CURSORINFO CurInfo
;
205 BOOL MouseEnabled
= FALSE
;
207 if(IntGetWindowStationObject(InputWindowStation
))
209 CurInfo
= &InputWindowStation
->SystemCursor
;
216 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
217 CurInfo
->SafetySwitch2
= FALSE
;
218 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
219 ObDereferenceObject(InputWindowStation
);
223 MouseEnabled
= CurInfo
->Enabled
&& CurInfo
->ShowingCursor
;
225 if (SurfObj
->iType
!= STYPE_DEVICE
|| MouseEnabled
== FALSE
)
227 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
228 CurInfo
->SafetySwitch2
= FALSE
;
229 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
230 ObDereferenceObject(InputWindowStation
);
234 if (SPS_ACCEPT_NOEXCLUDE
== SurfGDI
->PointerStatus
)
236 /* Hardware cursor, it wasn't removed so need to restore it */
237 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
238 CurInfo
->SafetySwitch2
= FALSE
;
239 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
240 ObDereferenceObject(InputWindowStation
);
244 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
245 if (CurInfo
->SafetySwitch
)
247 SurfGDI
->MovePointer(SurfObj
, CurInfo
->x
, CurInfo
->y
, &MouseRect
);
248 CurInfo
->SafetySwitch
= FALSE
;
249 CurInfo
->SafetySwitch2
= FALSE
;
253 CurInfo
->SafetySwitch2
= FALSE
;
255 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
256 ObDereferenceObject(InputWindowStation
);
261 MouseMoveCursor(LONG X
, LONG Y
)
269 PSYSTEM_CURSORINFO CurInfo
;
271 LARGE_INTEGER LargeTickCount
;
274 if(!InputWindowStation
)
277 if(IntGetWindowStationObject(InputWindowStation
))
279 CurInfo
= &InputWindowStation
->SystemCursor
;
280 if(!CurInfo
->Enabled
)
282 ObDereferenceObject(InputWindowStation
);
285 hDC
= IntGetScreenDC();
288 ObDereferenceObject(InputWindowStation
);
292 SurfObj
= (PSURFOBJ
)AccessUserObject((ULONG
) dc
->Surface
);
293 SurfGDI
= (PSURFGDI
)AccessInternalObject((ULONG
) dc
->Surface
);
295 IntCheckClipCursor(&X
, &Y
, CurInfo
);
296 if((X
!= CurInfo
->x
) || (Y
!= CurInfo
->y
))
298 /* send MOUSEMOVE message */
299 KeQueryTickCount(&LargeTickCount
);
300 TickCount
= LargeTickCount
.u
.LowPart
;
301 Msg
.wParam
= CurInfo
->ButtonsDown
;
302 Msg
.lParam
= MAKELPARAM(X
, Y
);
303 Msg
.message
= WM_MOUSEMOVE
;
304 Msg
.time
= TickCount
;
307 MsqInsertSystemMessage(&Msg
, TRUE
);
313 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
314 SurfGDI
->MovePointer(SurfObj
, CurInfo
->x
, CurInfo
->y
, &MouseRect
);
315 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
320 ObDereferenceObject(InputWindowStation
);
328 MouseGDICallBack(PMOUSE_INPUT_DATA Data
, ULONG InputCount
)
330 * FUNCTION: Call by the mouse driver when input events occur.
334 PSYSTEM_CURSORINFO CurInfo
;
335 BOOL MouseEnabled
= FALSE
;
336 BOOL MouseMoveAdded
= FALSE
;
338 LONG mouse_ox
, mouse_oy
;
339 LONG mouse_cx
= 0, mouse_cy
= 0;
348 LARGE_INTEGER LargeTickCount
;
351 hDC
= IntGetScreenDC();
353 if(!hDC
|| !InputWindowStation
)
356 if(IntGetWindowStationObject(InputWindowStation
))
358 CurInfo
= &InputWindowStation
->SystemCursor
;
359 MouseEnabled
= CurInfo
->Enabled
;
362 ObDereferenceObject(InputWindowStation
);
365 mouse_ox
= CurInfo
->x
;
366 mouse_oy
= CurInfo
->y
;
372 SurfObj
= (PSURFOBJ
)AccessUserObject((ULONG
) dc
->Surface
);
373 SurfGDI
= (PSURFGDI
)AccessInternalObject((ULONG
) dc
->Surface
);
376 /* Compile the total mouse movement change and dispatch button events. */
377 for (i
= 0; i
< InputCount
; i
++)
379 mouse_cx
+= Data
[i
].LastX
;
380 mouse_cy
+= Data
[i
].LastY
;
382 CurInfo
->x
+= Data
[i
].LastX
;
383 CurInfo
->y
+= Data
[i
].LastY
;
385 CurInfo
->x
= max(CurInfo
->x
, 0);
386 CurInfo
->y
= max(CurInfo
->y
, 0);
387 CurInfo
->x
= min(CurInfo
->x
, SurfObj
->sizlBitmap
.cx
- 1);
388 CurInfo
->y
= min(CurInfo
->y
, SurfObj
->sizlBitmap
.cy
- 1);
390 IntCheckClipCursor(&CurInfo
->x
, &CurInfo
->y
, CurInfo
);
392 KeQueryTickCount(&LargeTickCount
);
393 TickCount
= LargeTickCount
.u
.LowPart
;
395 Msg
.wParam
= CurInfo
->ButtonsDown
;
396 Msg
.lParam
= MAKELPARAM(CurInfo
->x
, CurInfo
->y
);
397 Msg
.message
= WM_MOUSEMOVE
;
398 Msg
.time
= TickCount
;
399 Msg
.pt
.x
= CurInfo
->x
;
400 Msg
.pt
.y
= CurInfo
->y
;
402 MouseMoveAdded
= FALSE
;
404 //PrintInputData(i, Data[i]);
406 if (Data
[i
].ButtonFlags
!= 0)
409 if ((Data
[i
].ButtonFlags
& MOUSE_LEFT_BUTTON_DOWN
) > 0)
411 /* insert WM_MOUSEMOVE messages before Button down messages */
412 if ((0 != Data
[i
].LastX
) || (0 != Data
[i
].LastY
))
414 MsqInsertSystemMessage(&Msg
, FALSE
);
415 MouseMoveAdded
= TRUE
;
417 CurInfo
->ButtonsDown
|= CurInfo
->SwapButtons
? MK_RBUTTON
: MK_LBUTTON
;
418 if(IntDetectDblClick(CurInfo
, TickCount
))
419 Msg
.message
= CurInfo
->SwapButtons
? WM_RBUTTONDBLCLK
: WM_LBUTTONDBLCLK
;
421 Msg
.message
= CurInfo
->SwapButtons
? WM_RBUTTONDOWN
: WM_LBUTTONDOWN
;
423 if ((Data
[i
].ButtonFlags
& MOUSE_MIDDLE_BUTTON_DOWN
) > 0)
425 /* insert WM_MOUSEMOVE messages before Button down messages */
426 if ((0 != Data
[i
].LastX
) || (0 != Data
[i
].LastY
))
428 MsqInsertSystemMessage(&Msg
, FALSE
);
429 MouseMoveAdded
= TRUE
;
431 CurInfo
->ButtonsDown
|= MK_MBUTTON
;
432 if(IntDetectDblClick(CurInfo
, TickCount
))
433 Msg
.message
= WM_MBUTTONDBLCLK
;
435 Msg
.message
= WM_MBUTTONDOWN
;
437 if ((Data
[i
].ButtonFlags
& MOUSE_RIGHT_BUTTON_DOWN
) > 0)
439 /* insert WM_MOUSEMOVE messages before Button down messages */
440 if ((0 != Data
[i
].LastX
) || (0 != Data
[i
].LastY
))
442 MsqInsertSystemMessage(&Msg
, FALSE
);
443 MouseMoveAdded
= TRUE
;
445 CurInfo
->ButtonsDown
|= CurInfo
->SwapButtons
? MK_LBUTTON
: MK_RBUTTON
;
446 if(IntDetectDblClick(CurInfo
, TickCount
))
447 Msg
.message
= CurInfo
->SwapButtons
? WM_LBUTTONDBLCLK
: WM_RBUTTONDBLCLK
;
449 Msg
.message
= CurInfo
->SwapButtons
? WM_LBUTTONDOWN
: WM_RBUTTONDOWN
;
452 if ((Data
[i
].ButtonFlags
& MOUSE_BUTTON_4_DOWN
) > 0)
454 /* insert WM_MOUSEMOVE messages before Button down messages */
455 if ((0 != Data
[i
].LastX
) || (0 != Data
[i
].LastY
))
457 MsqInsertSystemMessage(&Msg
, FALSE
);
458 MouseMoveAdded
= TRUE
;
460 CurInfo
->ButtonsDown
|= MK_XBUTTON1
;
461 if(IntDetectDblClick(CurInfo
, TickCount
))
463 Msg
.message
= WM_XBUTTONDBLCLK
;
467 Msg
.message
= WM_XBUTTONDOWN
;
469 if ((Data
[i
].ButtonFlags
& MOUSE_BUTTON_5_DOWN
) > 0)
471 /* insert WM_MOUSEMOVE messages before Button down messages */
472 if ((0 != Data
[i
].LastX
) || (0 != Data
[i
].LastY
))
474 MsqInsertSystemMessage(&Msg
, FALSE
);
475 MouseMoveAdded
= TRUE
;
477 CurInfo
->ButtonsDown
|= MK_XBUTTON2
;
478 if(IntDetectDblClick(CurInfo
, TickCount
))
480 Msg
.message
= WM_XBUTTONDBLCLK
;
484 Msg
.message
= WM_XBUTTONDOWN
;
487 if ((Data
[i
].ButtonFlags
& MOUSE_LEFT_BUTTON_UP
) > 0)
489 CurInfo
->ButtonsDown
&= CurInfo
->SwapButtons
? ~MK_RBUTTON
: ~MK_LBUTTON
;
490 Msg
.message
= CurInfo
->SwapButtons
? WM_RBUTTONUP
: WM_LBUTTONUP
;
492 if ((Data
[i
].ButtonFlags
& MOUSE_MIDDLE_BUTTON_UP
) > 0)
494 CurInfo
->ButtonsDown
&= ~MK_MBUTTON
;
495 Msg
.message
= WM_MBUTTONUP
;
497 if ((Data
[i
].ButtonFlags
& MOUSE_RIGHT_BUTTON_UP
) > 0)
499 CurInfo
->ButtonsDown
&= CurInfo
->SwapButtons
? ~MK_LBUTTON
: ~MK_RBUTTON
;
500 Msg
.message
= CurInfo
->SwapButtons
? WM_LBUTTONUP
: WM_RBUTTONUP
;
502 if ((Data
[i
].ButtonFlags
& MOUSE_BUTTON_4_UP
) > 0)
504 CurInfo
->ButtonsDown
&= ~MK_XBUTTON1
;
505 Msg
.message
= WM_XBUTTONUP
;
507 if ((Data
[i
].ButtonFlags
& MOUSE_BUTTON_5_UP
) > 0)
509 CurInfo
->ButtonsDown
&= ~MK_XBUTTON2
;
510 Msg
.message
= WM_XBUTTONUP
;
512 if ((Data
[i
].ButtonFlags
& MOUSE_WHEEL
) > 0)
514 dScroll
+= (LONG
)Data
[i
].ButtonData
;
517 if (Data
[i
].ButtonFlags
!= MOUSE_WHEEL
)
519 Moved
= (0 != mouse_cx
) || (0 != mouse_cy
);
520 if(Moved
&& MouseEnabled
)
522 if (!CurInfo
->SafetySwitch
&& !CurInfo
->SafetySwitch2
&&
523 ((mouse_ox
!= CurInfo
->x
) || (mouse_oy
!= CurInfo
->y
)))
525 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
526 SurfGDI
->MovePointer(SurfObj
, CurInfo
->x
, CurInfo
->y
, &MouseRect
);
527 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
533 Msg
.wParam
= CurInfo
->ButtonsDown
;
534 MsqInsertSystemMessage(&Msg
, FALSE
);
536 /* insert WM_MOUSEMOVE messages after Button up messages */
537 if(!MouseMoveAdded
&& Moved
)
539 Msg
.message
= WM_MOUSEMOVE
;
540 MsqInsertSystemMessage(&Msg
, FALSE
);
541 MouseMoveAdded
= TRUE
;
547 KeQueryTickCount(&LargeTickCount
);
548 TickCount
= LargeTickCount
.u
.LowPart
;
550 /* If the mouse moved then move the pointer. */
551 if ((mouse_cx
!= 0 || mouse_cy
!= 0) && MouseEnabled
)
556 Msg
.wParam
= CurInfo
->ButtonsDown
;
557 Msg
.message
= WM_MOUSEMOVE
;
558 Msg
.pt
.x
= CurInfo
->x
;
559 Msg
.pt
.y
= CurInfo
->y
;
560 Msg
.time
= TickCount
;
561 Msg
.lParam
= MAKELPARAM(CurInfo
->x
, CurInfo
->y
);
562 MsqInsertSystemMessage(&Msg
, TRUE
);
565 if (!CurInfo
->SafetySwitch
&& !CurInfo
->SafetySwitch2
&&
566 ((mouse_ox
!= CurInfo
->x
) || (mouse_oy
!= CurInfo
->y
)))
568 ExAcquireFastMutexUnsafe(&CurInfo
->CursorMutex
);
569 SurfGDI
->MovePointer(SurfObj
, CurInfo
->x
, CurInfo
->y
, &MouseRect
);
570 ExReleaseFastMutexUnsafe(&CurInfo
->CursorMutex
);
574 /* send WM_MOUSEWHEEL message */
575 if(dScroll
&& MouseEnabled
)
577 Msg
.message
= WM_MOUSEWHEEL
;
578 Msg
.wParam
= MAKEWPARAM(CurInfo
->ButtonsDown
, dScroll
);
579 Msg
.lParam
= MAKELPARAM(CurInfo
->x
, CurInfo
->y
);
580 Msg
.time
= TickCount
;
581 Msg
.pt
.x
= CurInfo
->x
;
582 Msg
.pt
.y
= CurInfo
->y
;
583 MsqInsertSystemMessage(&Msg
, FALSE
);
586 ObDereferenceObject(InputWindowStation
);
590 EnableMouse(HDC hDisplayDC
)
596 if( hDisplayDC
&& InputWindowStation
)
598 if(!IntGetWindowStationObject(InputWindowStation
))
600 InputWindowStation
->SystemCursor
.Enabled
= FALSE
;
603 IntSetCursor(InputWindowStation
, NULL
, TRUE
);
605 dc
= DC_LockDc(hDisplayDC
);
606 SurfObj
= (PSURFOBJ
)AccessUserObject((ULONG
) dc
->Surface
);
607 SurfGDI
= (PSURFGDI
)AccessInternalObject((ULONG
) dc
->Surface
);
608 DC_UnlockDc( hDisplayDC
);
610 InputWindowStation
->SystemCursor
.Enabled
= (SPS_ACCEPT_EXCLUDE
== SurfGDI
->PointerStatus
||
611 SPS_ACCEPT_NOEXCLUDE
== SurfGDI
->PointerStatus
);
613 /* Move the cursor to the screen center */
614 DPRINT("Setting Cursor up at 0x%x, 0x%x\n", SurfObj
->sizlBitmap
.cx
/ 2, SurfObj
->sizlBitmap
.cy
/ 2);
615 MouseMoveCursor(SurfObj
->sizlBitmap
.cx
/ 2, SurfObj
->sizlBitmap
.cy
/ 2);
617 ObDereferenceObject(InputWindowStation
);
621 if(IntGetWindowStationObject(InputWindowStation
))
623 IntSetCursor(InputWindowStation
, NULL
, TRUE
);
624 InputWindowStation
->SystemCursor
.Enabled
= FALSE
;
625 InputWindowStation
->SystemCursor
.CursorClipInfo
.IsClipped
= FALSE
;
626 ObDereferenceObject(InputWindowStation
);