Improved mouse button handling
[reactos.git] / reactos / subsys / win32k / eng / mouse.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 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.19 2003/03/09 15:00:51 jfilby 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
37 #define NDEBUG
38 #include <debug.h>
39
40 /* GLOBALS *******************************************************************/
41
42 static BOOLEAN SafetySwitch = FALSE;
43 static BOOLEAN SafetySwitch2 = FALSE;
44 static BOOLEAN MouseEnabled = FALSE;
45 static LONG mouse_x, mouse_y;
46 static UINT mouse_width = 0, mouse_height = 0;
47
48 static UCHAR DefaultCursor[256] = {
49 0x00, 0x00, 0x00, 0x00,
50 0x00, 0x00, 0x00, 0x00,
51 0x00, 0x00, 0x00, 0x00,
52 0x00, 0x00, 0x00, 0x00,
53 0x00, 0x00, 0x00, 0x00,
54 0x00, 0x00, 0x00, 0x00,
55 0x00, 0x00, 0x00, 0x00,
56 0x00, 0x00, 0x00, 0x00,
57 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0x00,
60 0x00, 0x00, 0x00, 0x00,
61 0x00, 0x00, 0x00, 0x00,
62 0x00, 0xC0, 0x00, 0x00,
63 0x00, 0xC0, 0x00, 0x00,
64 0x01, 0x80, 0x00, 0x00,
65 0x01, 0x80, 0x00, 0x00,
66 0x03, 0x00, 0x00, 0x00,
67 0x43, 0x00, 0x00, 0x00,
68 0x66, 0x00, 0x00, 0x00,
69 0x76, 0x00, 0x00, 0x00,
70 0x7E, 0x00, 0x00, 0x00,
71 0x7F, 0xC0, 0x00, 0x00,
72 0x7F, 0x80, 0x00, 0x00,
73 0x7F, 0x00, 0x00, 0x00,
74 0x7E, 0x00, 0x00, 0x00,
75 0x7C, 0x00, 0x00, 0x00,
76 0x78, 0x00, 0x00, 0x00,
77 0x70, 0x00, 0x00, 0x00,
78 0x60, 0x00, 0x00, 0x00,
79 0x40, 0x00, 0x00, 0x00,
80 0x00, 0x00, 0x00, 0x00,
81
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 0xFF, 0xFF, 0xFF, 0xFF,
89 0xFF, 0xFF, 0xFF, 0xFF,
90 0xFF, 0xFF, 0xFF, 0xFF,
91 0xFF, 0xFF, 0xFF, 0xFF,
92 0xFF, 0xFF, 0xFF, 0xFF,
93 0xFF, 0xFF, 0xFF, 0xFF,
94 0xFF, 0x3F, 0xFF, 0xFF,
95 0xFE, 0x1F, 0xFF, 0xFF,
96 0xFE, 0x1F, 0xFF, 0xFF,
97 0xFC, 0x3F, 0xFF, 0xFF,
98 0x7C, 0x3F, 0xFF, 0xFF,
99 0x38, 0x7F, 0xFF, 0xFF,
100 0x18, 0x7F, 0xFF, 0xFF,
101 0x00, 0xFF, 0xFF, 0xFF,
102 0x00, 0xFF, 0xFF, 0xFF,
103 0x00, 0x0F, 0xFF, 0xFF,
104 0x00, 0x1F, 0xFF, 0xFF,
105 0x00, 0x3F, 0xFF, 0xFF,
106 0x00, 0x7F, 0xFF, 0xFF,
107 0x00, 0xFF, 0xFF, 0xFF,
108 0x01, 0xFF, 0xFF, 0xFF,
109 0x03, 0xFF, 0xFF, 0xFF,
110 0x07, 0xFF, 0xFF, 0xFF,
111 0x0F, 0xFF, 0xFF, 0xFF,
112 0x1F, 0xFF, 0xFF, 0xFF,
113 0x3F, 0xFF, 0xFF, 0xFF};
114
115 /* FUNCTIONS *****************************************************************/
116
117 INT
118 MouseSafetyOnDrawStart(PSURFOBJ SurfObj, PSURFGDI SurfGDI, LONG HazardX1,
119 LONG HazardY1, LONG HazardX2, LONG HazardY2)
120 /*
121 * FUNCTION: Notify the mouse driver that drawing is about to begin in
122 * a rectangle on a particular surface.
123 */
124 {
125 RECTL MouseRect;
126 LONG tmp;
127
128 /* Mouse is not allowed to move if GDI is busy drawing */
129 SafetySwitch2 = TRUE;
130
131 if (SurfObj == NULL)
132 {
133 return(FALSE);
134 }
135
136 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
137 {
138 return(FALSE);
139 }
140
141 if (HazardX1 > HazardX2)
142 {
143 tmp = HazardX2; HazardX2 = HazardX1; HazardX1 = tmp;
144 }
145 if (HazardY1 > HazardY2)
146 {
147 tmp = HazardY2; HazardY2 = HazardY1; HazardY1 = tmp;
148 }
149
150 if (((mouse_x + mouse_width) >= HazardX1) && (mouse_x <= HazardX2) &&
151 ((mouse_y + mouse_height) >= HazardY1) && (mouse_y <= HazardY2))
152 {
153 SafetySwitch = TRUE;
154 SurfGDI->MovePointer(SurfObj, -1, -1, &MouseRect);
155 }
156
157 return(TRUE);
158 }
159
160 INT
161 MouseSafetyOnDrawEnd(PSURFOBJ SurfObj, PSURFGDI SurfGDI)
162 /*
163 * FUNCTION: Notify the mouse driver that drawing has finished on a surface.
164 */
165 {
166 RECTL MouseRect;
167
168 if (SurfObj == NULL)
169 {
170 return(FALSE);
171 }
172
173 if (SurfObj->iType != STYPE_DEVICE || MouseEnabled == FALSE)
174 {
175 return(FALSE);
176 }
177
178 if (SafetySwitch)
179 {
180 SurfGDI->MovePointer(SurfObj, mouse_x, mouse_y, &MouseRect);
181 SafetySwitch = FALSE;
182 }
183
184 SafetySwitch2 = FALSE;
185
186 return(TRUE);
187 }
188
189 VOID
190 MouseGDICallBack(PMOUSE_INPUT_DATA Data, ULONG InputCount)
191 /*
192 * FUNCTION: Call by the mouse driver when input events occur.
193 */
194 {
195 ULONG i;
196 LONG mouse_cx = 0, mouse_cy = 0;
197 HDC hDC = W32kGetScreenDC();
198 PDC dc;
199 PSURFOBJ SurfObj;
200 PSURFGDI SurfGDI;
201 RECTL MouseRect;
202 MSG Msg;
203 ULONG j;
204 LARGE_INTEGER LargeTickCount;
205 ULONG TickCount;
206 static ULONG ButtonsDown = 0;
207 const UINT MouseButtonDownMessage[3] =
208 {WM_RBUTTONDOWN, WM_MBUTTONDOWN, WM_LBUTTONDOWN};
209 const UINT MouseButtonUpMessage[3] =
210 {WM_RBUTTONUP, WM_MBUTTONUP, WM_LBUTTONUP};
211 const ULONG MouseButtonFlag[3] = {MK_RBUTTON, MK_MBUTTON, MK_LBUTTON};
212
213 KeQueryTickCount(&LargeTickCount);
214 TickCount = LargeTickCount.u.LowPart;
215
216 if (hDC == 0)
217 {
218 return;
219 }
220
221 dc = DC_HandleToPtr(hDC);
222 SurfObj = (PSURFOBJ)AccessUserObject(dc->Surface);
223 SurfGDI = (PSURFGDI)AccessInternalObject(dc->Surface);
224 DC_ReleasePtr( hDC );
225
226 /* Compile the total mouse movement change and dispatch button events. */
227 for (i = 0; i < InputCount; i++)
228 {
229 mouse_cx += Data[i].LastX;
230 mouse_cy += Data[i].LastY;
231
232 Msg.wParam = ButtonsDown;
233 Msg.lParam = MAKELPARAM(mouse_x + mouse_cx, mouse_y + mouse_cy);
234 Msg.message = WM_MOUSEMOVE;
235 Msg.time = TickCount;
236 Msg.pt.x = mouse_x + mouse_cx;
237 Msg.pt.y = mouse_y + mouse_cy;
238 if ((mouse_cx > 0) || (mouse_cy > 0))
239 {
240 MsqInsertSystemMessage(&Msg);
241 }
242
243 if (Data[i].ButtonFlags != 0)
244 {
245 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_DOWN) > 0)
246 {
247 Msg.wParam = MK_LBUTTON;
248 Msg.message = WM_LBUTTONDOWN;
249 }
250 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_DOWN) > 0)
251 {
252 Msg.wParam = MK_MBUTTON;
253 Msg.message = WM_MBUTTONDOWN;
254 }
255 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_DOWN) > 0)
256 {
257 Msg.wParam = MK_RBUTTON;
258 Msg.message = WM_RBUTTONDOWN;
259 }
260
261 if ((Data[i].ButtonFlags & MOUSE_LEFT_BUTTON_UP) > 0)
262 {
263 Msg.wParam = MK_LBUTTON;
264 Msg.message = WM_LBUTTONUP;
265 }
266 if ((Data[i].ButtonFlags & MOUSE_MIDDLE_BUTTON_UP) > 0)
267 {
268 Msg.wParam = MK_MBUTTON;
269 Msg.message = WM_MBUTTONUP;
270 }
271 if ((Data[i].ButtonFlags & MOUSE_RIGHT_BUTTON_UP) > 0)
272 {
273 Msg.wParam = MK_RBUTTON;
274 Msg.message = WM_RBUTTONUP;
275 }
276
277 MsqInsertSystemMessage(&Msg);
278 }
279 }
280
281 /* If the mouse moved then move the pointer. */
282 if ((mouse_cx != 0 || mouse_cy != 0) && MouseEnabled)
283 {
284 mouse_x += mouse_cx;
285 mouse_y += mouse_cy;
286
287 mouse_x = max(mouse_x, 0);
288 mouse_y = max(mouse_y, 0);
289 mouse_x = min(mouse_x, 620);
290 mouse_y = min(mouse_y, 460);
291
292 if (SafetySwitch == FALSE && SafetySwitch2 == FALSE)
293 {
294 SurfGDI->MovePointer(SurfObj, mouse_x, mouse_y, &MouseRect);
295 }
296 }
297 }
298
299 VOID
300 EnableMouse(HDC hDisplayDC)
301 {
302 PDC dc;
303 PSURFOBJ SurfObj;
304 PSURFGDI SurfGDI;
305 HBITMAP hMouseSurf;
306 PSURFOBJ MouseSurf;
307 SIZEL MouseSize;
308 RECTL MouseRect;
309
310 dc = DC_HandleToPtr(hDisplayDC);
311 if( dc ){
312 SurfObj = (PSURFOBJ)AccessUserObject(dc->Surface);
313 SurfGDI = (PSURFGDI)AccessInternalObject(dc->Surface);
314 DC_ReleasePtr( hDisplayDC );
315
316 /* Create the default mouse cursor. */
317 mouse_width = 32;
318 mouse_height = 32;
319 MouseSize.cx = 32;
320 MouseSize.cy = 64;
321 hMouseSurf = EngCreateBitmap(MouseSize, 4, BMF_1BPP, 0, DefaultCursor);
322 MouseSurf = (PSURFOBJ)AccessUserObject(hMouseSurf);
323
324 /* Tell the display driver to set the pointer shape. */
325 SurfGDI->SetPointerShape(SurfObj, MouseSurf, NULL, NULL, 0, 0, 320, 240,
326 &MouseRect, 0);
327
328 mouse_x = 320;
329 mouse_y = 240;
330 MouseEnabled = TRUE;
331 }
332 else{
333 MouseEnabled = FALSE;
334 }
335 }
336