fixed bugs and completed SetCursorPos() and ClipCursor()
[reactos.git] / reactos / subsys / win32k / eng / mouse.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: mouse.c,v 1.32 2003/08/24 23:52:29 weiden Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * PURPOSE: Mouse
23 * FILE: subsys/win32k/eng/mouse.c
24 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * REVISION HISTORY:
26 * 06-06-2001 CSH Created
27 */
28 /* INCLUDES ******************************************************************/
29
30 #include <windows.h>
31 #include <ddk/ntddk.h>
32 #include <ddk/ntddmou.h>
33 #include <win32k/dc.h>
34 #include "objects.h"
35 #include "include/msgqueue.h"
36 #include "include/object.h"
37 #include "include/winsta.h"
38 #include <include/mouse.h>
39
40 #define NDEBUG
41 #include <debug.h>
42
43
44 #define GETSYSCURSOR(x) ((x) - OCR_NORMAL)
45
46 /* GLOBALS *******************************************************************/
47
48 //static BOOLEAN SafetySwitch = FALSE;
49 //static BOOLEAN SafetySwitch2 = FALSE;
50 //static BOOLEAN MouseEnabled = FALSE;
51 //static LONG mouse_x, mouse_y;
52 //static LONG mouse_width = 0, mouse_height = 0;
53 static ULONG PointerStatus;
54
55 static UCHAR DefaultCursor[256] = {
56 0x3F, 0xFF, 0xFF, 0xFF,
57 0x1F, 0xFF, 0xFF, 0xFF,
58 0x0F, 0xFF, 0xFF, 0xFF,
59 0x07, 0xFF, 0xFF, 0xFF,
60 0x03, 0xFF, 0xFF, 0xFF,
61 0x01, 0xFF, 0xFF, 0xFF,
62 0x00, 0xFF, 0xFF, 0xFF,
63 0x00, 0x7F, 0xFF, 0xFF,
64 0x00, 0x3F, 0xFF, 0xFF,
65 0x00, 0x1F, 0xFF, 0xFF,
66 0x00, 0x0F, 0xFF, 0xFF,
67 0x00, 0xFF, 0xFF, 0xFF,
68 0x00, 0xFF, 0xFF, 0xFF,
69 0x18, 0x7F, 0xFF, 0xFF,
70 0x38, 0x7F, 0xFF, 0xFF,
71 0x7C, 0x3F, 0xFF, 0xFF,
72 0xFC, 0x3F, 0xFF, 0xFF,
73 0xFE, 0x1F, 0xFF, 0xFF,
74 0xFE, 0x1F, 0xFF, 0xFF,
75 0xFF, 0x3F, 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,
84 0xFF, 0xFF, 0xFF, 0xFF,
85 0xFF, 0xFF, 0xFF, 0xFF,
86 0xFF, 0xFF, 0xFF, 0xFF,
87 0xFF, 0xFF, 0xFF, 0xFF,
88
89 0x00, 0x00, 0x00, 0x00,
90 0x40, 0x00, 0x00, 0x00,
91 0x60, 0x00, 0x00, 0x00,
92 0x70, 0x00, 0x00, 0x00,
93 0x78, 0x00, 0x00, 0x00,
94 0x7C, 0x00, 0x00, 0x00,
95 0x7E, 0x00, 0x00, 0x00,
96 0x7F, 0x00, 0x00, 0x00,
97 0x7F, 0x80, 0x00, 0x00,
98 0x7F, 0xC0, 0x00, 0x00,
99 0x7E, 0x00, 0x00, 0x00,
100 0x76, 0x00, 0x00, 0x00,
101 0x76, 0x00, 0x00, 0x00,
102 0x43, 0x00, 0x00, 0x00,
103 0x03, 0x00, 0x00, 0x00,
104 0x01, 0x80, 0x00, 0x00,
105 0x01, 0x80, 0x00, 0x00,
106 0x00, 0xC0, 0x00, 0x00,
107 0x00, 0xC0, 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,
117 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00};
121
122 /* FUNCTIONS *****************************************************************/
123
124 BOOL FASTCALL
125 CheckClipCursor(LONG *x, LONG *y, PSYSTEM_CURSORINFO CurInfo)
126 {
127 if(CurInfo->CursorClipInfo.IsClipped)
128 {
129 if(*x > CurInfo->CursorClipInfo.Right)
130 *x = CurInfo->CursorClipInfo.Right;
131 if(*x < CurInfo->CursorClipInfo.Left)
132 *x = CurInfo->CursorClipInfo.Left;
133 if(*y > CurInfo->CursorClipInfo.Bottom)
134 *y = CurInfo->CursorClipInfo.Bottom;
135 if(*y < CurInfo->CursorClipInfo.Top)
136 *y = CurInfo->CursorClipInfo.Top;
137 return TRUE;
138 }
139 return TRUE;
140 }
141
142 INT STDCALL
143 MouseSafetyOnDrawStart(PSURFOBJ SurfObj, PSURFGDI SurfGDI, LONG HazardX1,
144 LONG HazardY1, LONG HazardX2, LONG HazardY2)
145 /*
146 * FUNCTION: Notify the mouse driver that drawing is about to begin in
147 * a rectangle on a particular surface.
148 */
149 {
150 RECTL MouseRect;
151 LONG tmp;
152 PSYSTEM_CURSORINFO CurInfo;
153 PSYSCURSOR SysCursor;
154 BOOL MouseEnabled = FALSE;
155
156
157 /* Mouse is not allowed to move if GDI is busy drawing */
158
159 if(IntGetWindowStationObject(InputWindowStation))
160 {
161 CurInfo = &InputWindowStation->SystemCursor;
162
163 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
164 MouseEnabled = CurInfo->Enabled && SysCursor->hCursor;
165 }
166 else
167 return FALSE;
168
169 CurInfo->SafetySwitch2 = TRUE;
170
171 if (SurfObj == NULL)
172 {
173 ObDereferenceObject(InputWindowStation);
174 return(FALSE);
175 }
176
177
178 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
179 {
180 ObDereferenceObject(InputWindowStation);
181 return(FALSE);
182 }
183
184 if (SPS_ACCEPT_NOEXCLUDE == PointerStatus)
185 {
186 /* Hardware cursor, no need to remove it */
187 ObDereferenceObject(InputWindowStation);
188 return(FALSE);
189 }
190
191 if (HazardX1 > HazardX2)
192 {
193 tmp = HazardX2; HazardX2 = HazardX1; HazardX1 = tmp;
194 }
195 if (HazardY1 > HazardY2)
196 {
197 tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
198 }
199
200 if (((CurInfo->x + SysCursor->cx) >= HazardX1) && (CurInfo->x <= HazardX2) &&
201 ((CurInfo->y + SysCursor->cy) >= HazardY1) && (CurInfo->y <= HazardY2))
202 {
203 /* Mouse is not allowed to move if GDI is busy drawing */
204 CurInfo->SafetySwitch = TRUE;
205 SurfGDI->MovePointer(SurfObj, -1, -1, &MouseRect);
206 }
207
208 ObDereferenceObject(InputWindowStation);
209 return(TRUE);
210 }
211
212 INT FASTCALL
213 MouseSafetyOnDrawEnd(PSURFOBJ SurfObj, PSURFGDI SurfGDI)
214 /*
215 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
216 */
217 {
218 RECTL MouseRect;
219 PSYSTEM_CURSORINFO CurInfo;
220 PSYSCURSOR SysCursor;
221 BOOL MouseEnabled = FALSE;
222
223 if(IntGetWindowStationObject(InputWindowStation))
224 {
225 CurInfo = &InputWindowStation->SystemCursor;
226 }
227 else
228 return FALSE;
229
230 if(SurfObj == NULL)
231 {
232 CurInfo->SafetySwitch2 = FALSE;
233 ObDereferenceObject(InputWindowStation);
234 return FALSE;
235 }
236
237 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
238 MouseEnabled = CurInfo->Enabled && SysCursor->hCursor;
239
240 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
241 {
242 CurInfo->SafetySwitch2 = FALSE;
243 ObDereferenceObject(InputWindowStation);
244 return(FALSE);
245 }
246
247 if (SPS_ACCEPT_NOEXCLUDE == PointerStatus)
248 {
249 /* Hardware cursor, it wasn't removed so need to restore it */
250 CurInfo->SafetySwitch2 = FALSE;
251 ObDereferenceObject(InputWindowStation);
252 return(FALSE);
253 }
254
255 if (CurInfo->SafetySwitch)
256 {
257 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
258 CurInfo->SafetySwitch = FALSE;
259 }
260
261 CurInfo->SafetySwitch2 = FALSE;
262 ObDereferenceObject(InputWindowStation);
263 return(TRUE);
264 }
265
266 BOOL FASTCALL
267 MouseMoveCursor(LONG X, LONG Y)
268 {
269 HDC hDC;
270 PDC dc;
271 RECTL MouseRect;
272 BOOL res = FALSE;
273 PSURFOBJ SurfObj;
274 PSURFGDI SurfGDI;
275 PSYSTEM_CURSORINFO CurInfo;
276 MSG Msg;
277 LARGE_INTEGER LargeTickCount;
278 ULONG TickCount;
279
280 hDC = IntGetScreenDC();
281
282 if(!hDC || !InputWindowStation)
283 return FALSE;
284
285 if(IntGetWindowStationObject(InputWindowStation))
286 {
287 dc = DC_LockDc(hDC);
288 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
289 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
290 DC_UnlockDc( hDC );
291 CurInfo = &InputWindowStation->SystemCursor;
292 CheckClipCursor(&X, &X, CurInfo);
293 if((X != CurInfo->x) || (Y != CurInfo->y))
294 {
295 /* send MOUSEMOVE message */
296 KeQueryTickCount(&LargeTickCount);
297 TickCount = LargeTickCount.u.LowPart;
298 Msg.wParam = 0;
299 Msg.lParam = MAKELPARAM(X, Y);
300 Msg.message = WM_MOUSEMOVE;
301 Msg.time = TickCount;
302 Msg.pt.x = X;
303 Msg.pt.y = Y;
304 MsqInsertSystemMessage(&Msg);
305 /* move cursor */
306 CurInfo->x = X;
307 CurInfo->y = Y;
308 if(!CurInfo->SafetySwitch && !CurInfo->SafetySwitch2 && CurInfo->Enabled)
309 {
310 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
311 }
312 res = TRUE;
313 }
314
315 ObDereferenceObject(InputWindowStation);
316 return res;
317 }
318 else
319 return FALSE;
320 }
321
322 VOID /* STDCALL */
323 MouseGDICallBack(PMOUSE_INPUT_DATA Data, ULONG InputCount)
324 /*
325 * FUNCTION: Call by the mouse driver when input events occur.
326 */
327 {
328 ULONG i;
329 PSYSTEM_CURSORINFO CurInfo;
330 PSYSCURSOR SysCursor;
331 BOOL MouseEnabled = FALSE;
332 LONG mouse_ox, mouse_oy;
333 LONG mouse_cx = 0, mouse_cy = 0;
334 HDC hDC;
335 PDC dc;
336 PSURFOBJ SurfObj;
337 PSURFGDI SurfGDI;
338 RECTL MouseRect;
339 MSG Msg;
340 LARGE_INTEGER LargeTickCount;
341 ULONG TickCount;
342 static ULONG ButtonsDown = 0;
343
344 hDC = IntGetScreenDC();
345
346 if(!hDC || !InputWindowStation)
347 return;
348
349 if(IntGetWindowStationObject(InputWindowStation))
350 {
351 CurInfo = &InputWindowStation->SystemCursor;
352 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
353 MouseEnabled = CurInfo->Enabled;
354 mouse_ox = CurInfo->x;
355 mouse_oy = CurInfo->y;
356 }
357 else
358 return;
359
360 KeQueryTickCount(&LargeTickCount);
361 TickCount = LargeTickCount.u.LowPart;
362
363 dc = DC_LockDc(hDC);
364 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
365 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
366 DC_UnlockDc( hDC );
367
368 /* Compile the total mouse movement change and dispatch button events. */
369 for (i = 0; i < InputCount; i++)
370 {
371 mouse_cx += Data[i].LastX;
372 mouse_cy += Data[i].LastY;
373
374 Msg.wParam = ButtonsDown;
375 Msg.lParam = MAKELPARAM(CurInfo->x + mouse_cx, CurInfo->y + mouse_cy);
376 Msg.message = WM_MOUSEMOVE;
377 Msg.time = TickCount;
378 Msg.pt.x = CurInfo->x + mouse_cx;
379 Msg.pt.y = CurInfo->y + mouse_cy;
380
381 CheckClipCursor(&Msg.pt.x, &Msg.pt.y, CurInfo);
382
383 if ((0 != Data[i].LastX) || (0 != Data[i].LastY))
384 {
385 MsqInsertSystemMessage(&Msg);
386 }
387
388 if (Data[i].ButtonFlags != 0)
389 {
390 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_DOWN) > 0)
391 {
392 Msg.wParam = MK_LBUTTON;
393 Msg.message = WM_LBUTTONDOWN;
394 }
395 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN) > 0)
396 {
397 Msg.wParam = MK_MBUTTON;
398 Msg.message = WM_MBUTTONDOWN;
399 }
400 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN) > 0)
401 {
402 Msg.wParam = MK_RBUTTON;
403 Msg.message = WM_RBUTTONDOWN;
404 }
405
406 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_UP) > 0)
407 {
408 Msg.wParam = MK_LBUTTON;
409 Msg.message = WM_LBUTTONUP;
410 }
411 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_UP) > 0)
412 {
413 Msg.wParam = MK_MBUTTON;
414 Msg.message = WM_MBUTTONUP;
415 }
416 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_UP) > 0)
417 {
418 Msg.wParam = MK_RBUTTON;
419 Msg.message = WM_RBUTTONUP;
420 }
421
422 MsqInsertSystemMessage(&Msg);
423 }
424 }
425
426 /* If the mouse moved then move the pointer. */
427 if ((mouse_cx != 0 || mouse_cy != 0) && MouseEnabled)
428 {
429 CurInfo->x += mouse_cx;
430 CurInfo->y += mouse_cy;
431
432 CurInfo->x = max(CurInfo->x, 0);
433 CurInfo->y = max(CurInfo->y, 0);
434 CurInfo->x = min(CurInfo->x, SurfObj->sizlBitmap.cx - 20);
435 CurInfo->y = min(CurInfo->y, SurfObj->sizlBitmap.cy - 20);
436
437 CheckClipCursor(&CurInfo->x, &CurInfo->y, CurInfo);
438
439 if (!CurInfo->SafetySwitch && !CurInfo->SafetySwitch2 &&
440 ((mouse_ox != CurInfo->x) || (mouse_oy != CurInfo->y)))
441 {
442 SurfGDI->MovePointer(SurfObj, CurInfo->x, CurInfo->y, &MouseRect);
443 }
444 }
445
446 ObDereferenceObject(InputWindowStation);
447 }
448
449 VOID FASTCALL
450 EnableMouse(HDC hDisplayDC)
451 {
452 PDC dc;
453 PSURFOBJ SurfObj;
454 PSURFGDI SurfGDI;
455 HBITMAP hMouseSurf;
456 PSURFOBJ MouseSurf;
457 SIZEL MouseSize;
458 RECTL MouseRect;
459 PSYSTEM_CURSORINFO CurInfo;
460 PSYSCURSOR SysCursor;
461
462 if( hDisplayDC && InputWindowStation)
463 {
464 if(!IntGetWindowStationObject(InputWindowStation))
465 {
466 InputWindowStation->SystemCursor.Enabled = FALSE;
467 return;
468 }
469 CurInfo = &InputWindowStation->SystemCursor;
470 SysCursor = &CurInfo->SystemCursors[CurInfo->CurrentCursor];
471
472 dc = DC_LockDc(hDisplayDC);
473 SurfObj = (PSURFOBJ)AccessUserObject((ULONG) dc->Surface);
474 SurfGDI = (PSURFGDI)AccessInternalObject((ULONG) dc->Surface);
475 DC_UnlockDc( hDisplayDC );
476
477 /* Tell the display driver to set the pointer shape. */
478 #if 1
479 CurInfo->x = SurfObj->sizlBitmap.cx / 2;
480 CurInfo->y = SurfObj->sizlBitmap.cy / 2;
481 #else
482 CurInfo->x = 320;
483 CurInfo->y = 240;
484 #endif
485
486 /* Create the default mouse cursor. */
487 MouseSize.cx = SysCursor->cx;
488 MouseSize.cy = SysCursor->cy * 2;
489 hMouseSurf = EngCreateBitmap(MouseSize, 4, BMF_1BPP, BMF_TOPDOWN, DefaultCursor);
490 MouseSurf = (PSURFOBJ)AccessUserObject((ULONG) hMouseSurf);
491
492 DbgPrint("Setting Cursor up at 0x%x, 0x%x\n", CurInfo->x, CurInfo->y);
493 CheckClipCursor(&CurInfo->x,
494 &CurInfo->y,
495 CurInfo);
496
497 PointerStatus = SurfGDI->SetPointerShape(SurfObj, MouseSurf, NULL, NULL,
498 0, 0,
499 CurInfo->x,
500 CurInfo->y,
501 &MouseRect,
502 SPS_CHANGE);
503
504 InputWindowStation->SystemCursor.Enabled = (SPS_ACCEPT_EXCLUDE == PointerStatus ||
505 SPS_ACCEPT_NOEXCLUDE == PointerStatus);
506
507 EngDeleteSurface(hMouseSurf);
508 ObDereferenceObject(InputWindowStation);
509
510 }
511 else
512 {
513 if(IntGetWindowStationObject(InputWindowStation))
514 {
515 InputWindowStation->SystemCursor.Enabled = FALSE;
516 InputWindowStation->SystemCursor.CursorClipInfo.IsClipped = FALSE;
517 ObDereferenceObject(InputWindowStation);
518 return;
519 }
520 }
521 }
522 /* EOF */