Added an unknown VxD error code.
[wine] / dlls / dinput / mouse / main.c
1 /*              DirectInput Mouse device
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  *
6  */
7
8 #include "config.h"
9 #include <string.h>
10 #ifdef HAVE_SYS_ERRNO_H
11 # include <sys/errno.h>
12 #endif
13
14 #include "debugtools.h"
15 #include "input.h"
16 #include "user.h"
17 #include "winbase.h"
18 #include "wingdi.h"
19 #include "winerror.h"
20 #include "windef.h"
21 #include "mouse.h"
22 #include "winuser.h"
23 #include "dinput.h"
24
25 #include "dinput_private.h"
26 #include "device_private.h"
27
28 #define MOUSE_HACK
29
30 DEFAULT_DEBUG_CHANNEL(dinput);
31
32 /* Wine mouse driver object instances */
33 #define WINE_MOUSE_X_AXIS_INSTANCE 0x0001
34 #define WINE_MOUSE_Y_AXIS_INSTANCE 0x0002
35 #define WINE_MOUSE_L_BUTTON_INSTANCE 0x0004
36 #define WINE_MOUSE_R_BUTTON_INSTANCE 0x0008
37 #define WINE_MOUSE_M_BUTTON_INSTANCE 0x0010
38
39 /* ------------------------------- */
40 /* Wine mouse internal data format */
41 /* ------------------------------- */
42
43 /* Constants used to access the offset array */
44 #define WINE_MOUSE_X_POSITION 0
45 #define WINE_MOUSE_Y_POSITION 1
46 #define WINE_MOUSE_L_POSITION 2
47 #define WINE_MOUSE_R_POSITION 3
48 #define WINE_MOUSE_M_POSITION 4
49
50 typedef struct {
51   LONG lX;
52   LONG lY;
53   BYTE rgbButtons[4];
54 } Wine_InternalMouseData;
55
56 #define WINE_INTERNALMOUSE_NUM_OBJS 5
57
58 static DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = {
59   { &GUID_XAxis,   FIELD_OFFSET(Wine_InternalMouseData, lX),
60       DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
61   { &GUID_YAxis,   FIELD_OFFSET(Wine_InternalMouseData, lY),
62       DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
63   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0,
64       DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
65   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1,
66       DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
67   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2,
68       DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }
69 };
70
71 static DIDATAFORMAT Wine_InternalMouseFormat = {
72   0, /* dwSize - unused */
73   0, /* dwObjsize - unused */
74   0, /* dwFlags - unused */
75   sizeof(Wine_InternalMouseData),
76   WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */
77   Wine_InternalMouseObjectFormat
78 };
79
80 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt;
81 static ICOM_VTABLE(IDirectInputDevice7A) SysMouse7Avt;
82 typedef struct SysMouseAImpl SysMouseAImpl;
83
84 typedef enum {
85   WARP_NEEDED,  /* Warping is needed */
86   WARP_STARTED, /* Warping has been done, waiting for the warp event */
87   WARP_DONE     /* Warping has been done */
88 } WARP_STATUS;
89
90 struct SysMouseAImpl
91 {
92         /* IDirectInputDevice2AImpl */
93         ICOM_VFIELD(IDirectInputDevice2A);
94         DWORD                           ref;
95         GUID                            guid;
96
97         IDirectInputAImpl *dinput;
98         
99         /* The current data format and the conversion between internal
100            and external data formats */
101         LPDIDATAFORMAT                  df;
102         DataFormat                     *wine_df;
103         int                             offset_array[5];
104         
105         /* SysMouseAImpl */
106         BYTE                            absolute;
107         /* Previous position for relative moves */
108         LONG                            prevX, prevY;
109         LPMOUSE_EVENT_PROC              prev_handler;
110         HWND                            win;
111         DWORD                           dwCoopLevel;
112         POINT                           mapped_center;
113         DWORD                           win_centerX, win_centerY;
114         LPDIDEVICEOBJECTDATA            data_queue;
115         int                             queue_head, queue_tail, queue_len;
116         WARP_STATUS                     need_warp;
117         int                             acquired;
118         HANDLE                          hEvent;
119         CRITICAL_SECTION                crit;
120
121         /* This is for mouse reporting. */
122         Wine_InternalMouseData          m_state;
123 };
124
125 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
126   0x9e573ed8,
127   0x7734,
128   0x11d2,
129   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
130 };
131
132 /* FIXME: This is ugly and not thread safe :/ */
133 static IDirectInputDevice2A* current_lock = NULL;
134
135
136 static BOOL mousedev_enum_device(DWORD dwDevType, DWORD dwFlags, LPCDIDEVICEINSTANCEA lpddi)
137 {
138   if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_MOUSE)) {
139     TRACE("Enumerating the Mouse device\n");
140
141     /* Return mouse */
142     lpddi->guidInstance = GUID_SysMouse;/* DInput's GUID */
143     lpddi->guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
144     lpddi->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
145     strcpy(lpddi->tszInstanceName, "Mouse");
146     strcpy(lpddi->tszProductName, "Wine Mouse");
147
148     return TRUE;
149   }
150
151   return FALSE;
152 }
153
154 static SysMouseAImpl *alloc_device(REFGUID rguid, ICOM_VTABLE(IDirectInputDevice2A) *mvt, IDirectInputAImpl *dinput)
155 {
156     int offset_array[5] = {
157       FIELD_OFFSET(Wine_InternalMouseData, lX),
158       FIELD_OFFSET(Wine_InternalMouseData, lY),
159       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0,
160       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1,
161       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2
162     };
163     SysMouseAImpl* newDevice;
164     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
165     newDevice->ref = 1;
166     ICOM_VTBL(newDevice) = mvt;
167     InitializeCriticalSection(&(newDevice->crit));
168     memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
169     
170     /* Per default, Wine uses its internal data format */
171     newDevice->df = &Wine_InternalMouseFormat;
172     memcpy(newDevice->offset_array, offset_array, 5 * sizeof(int));
173     newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
174     newDevice->wine_df->size = 0;
175     newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize;
176     newDevice->wine_df->dt = NULL;
177     newDevice->dinput = dinput;
178
179     return newDevice;
180 }
181
182 static HRESULT mousedev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
183 {
184   if ((IsEqualGUID(&GUID_SysMouse,rguid)) ||             /* Generic Mouse */
185       (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
186     if ((riid == NULL) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid))) {
187       *pdev=(IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput);
188     
189       TRACE("Creating a Mouse device (%p)\n", *pdev);
190       return DI_OK;
191     }else if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
192       *pdev=(IDirectInputDeviceA*) alloc_device(rguid, (ICOM_VTABLE(IDirectInputDevice2A) *) &SysMouse7Avt, dinput);
193     
194       TRACE("Creating a Mouse DInput7A device (%p)\n", *pdev);
195       return DI_OK;
196     } else
197       return DIERR_NOINTERFACE;
198   }
199
200   return DIERR_DEVICENOTREG;
201 }
202
203 static dinput_device mousedev = {
204   100,
205   mousedev_enum_device,
206   mousedev_create_device
207 };
208
209 DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); }
210
211 /******************************************************************************
212  *      SysMouseA (DInput Mouse support)
213  */
214
215 /******************************************************************************
216   *     Release : release the mouse buffer.
217   */
218 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
219 {
220         ICOM_THIS(SysMouseAImpl,iface);
221
222         This->ref--;
223         if (This->ref)
224                 return This->ref;
225
226         /* Free the data queue */
227         if (This->data_queue != NULL)
228           HeapFree(GetProcessHeap(),0,This->data_queue);
229
230         /* Install the previous event handler (in case of releasing an acquired
231            mouse device) */
232         if (This->prev_handler != NULL)
233           MOUSE_Enable(This->prev_handler);
234         DeleteCriticalSection(&(This->crit));
235
236         /* Free the DataFormat */
237         if (This->df != &(Wine_InternalMouseFormat)) {
238           HeapFree(GetProcessHeap(), 0, This->df->rgodf);
239           HeapFree(GetProcessHeap(), 0, This->df);
240         }
241         
242         HeapFree(GetProcessHeap(),0,This);
243         return 0;
244 }
245
246
247 /******************************************************************************
248   *     SetCooperativeLevel : store the window in which we will do our
249   *   grabbing.
250   */
251 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
252         LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
253 )
254 {
255   ICOM_THIS(SysMouseAImpl,iface);
256
257   TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
258
259   if (TRACE_ON(dinput))
260     _dump_cooperativelevel_DI(dwflags);
261
262   /* Store the window which asks for the mouse */
263   if (!hwnd)
264     hwnd = GetDesktopWindow();
265   This->win = hwnd;
266   This->dwCoopLevel = dwflags;
267   
268   return 0;
269 }
270
271
272 /******************************************************************************
273   *     SetDataFormat : the application can choose the format of the data
274   *   the device driver sends back with GetDeviceState.
275   *
276   *   For the moment, only the "standard" configuration (c_dfDIMouse) is supported
277   *   in absolute and relative mode.
278   */
279 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
280         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
281 )
282 {
283   ICOM_THIS(SysMouseAImpl,iface);
284   int i;
285   
286   TRACE("(this=%p,%p)\n",This,df);
287
288   TRACE("(df.dwSize=%ld)\n",df->dwSize);
289   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
290   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
291   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
292   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
293
294   for (i=0;i<df->dwNumObjs;i++) {
295
296     TRACE("df.rgodf[%d].guid %s (%p)\n",i, debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
297     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
298     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
299     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
300   }
301
302   /* Check if the mouse is in absolute or relative mode */
303   if (df->dwFlags == DIDF_ABSAXIS)
304     This->absolute = 1;
305   else if (df->dwFlags == DIDF_RELAXIS)
306     This->absolute = 0;
307   else
308     ERR("Neither absolute nor relative flag set\n");
309
310   /* Store the new data format */
311   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
312   memcpy(This->df, df, df->dwSize);
313   This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
314   memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
315
316   /* Prepare all the data-conversion filters */
317   This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array);
318   
319   return 0;
320 }
321   
322 /* Our private mouse event handler */
323 static void WINAPI dinput_mouse_event( DWORD dwFlags, DWORD dx, DWORD dy,
324                                       DWORD cButtons, DWORD dwExtraInfo )
325 {
326   long posX = -1, posY = -1;
327   DWORD keyState, xtime, extra;
328   SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
329   
330   EnterCriticalSection(&(This->crit));
331   /* Mouse moved -> send event if asked */
332   if (This->hEvent)
333     SetEvent(This->hEvent);
334   
335   if (   !IsBadReadPtr( (LPVOID)dwExtraInfo, sizeof(WINE_MOUSEEVENT) )
336       && ((WINE_MOUSEEVENT *)dwExtraInfo)->magic == WINE_MOUSEEVENT_MAGIC ) {
337     WINE_MOUSEEVENT *wme = (WINE_MOUSEEVENT *)dwExtraInfo;
338     keyState = wme->keyState;
339     xtime = wme->time;
340     extra = (DWORD)wme->hWnd;
341     
342     if (dwFlags & MOUSEEVENTF_MOVE) {
343       if (dwFlags & MOUSEEVENTF_ABSOLUTE) {
344         posX = (dx * GetSystemMetrics(SM_CXSCREEN)) >> 16;
345         posY = (dy * GetSystemMetrics(SM_CYSCREEN)) >> 16;
346
347         if (This->absolute) {
348           if (posX != This->prevX)
349             GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX, xtime, 0);
350           if (posY != This->prevY)
351             GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY, xtime, 0);
352         } else {
353           /* Now, warp handling */
354           if ((This->need_warp == WARP_STARTED) &&
355               (posX == This->mapped_center.x) && (posY == This->mapped_center.y)) {
356             /* Warp has been done... */
357             This->need_warp = WARP_DONE;
358             goto end;
359           }
360                   
361           /* Relative mouse input with absolute mouse event : the real fun starts here... */
362           if ((This->need_warp == WARP_NEEDED) ||
363               (This->need_warp == WARP_STARTED)) {
364             if (posX != This->prevX)
365               GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX - This->prevX, xtime, (This->dinput->evsequence)++);
366             if (posY != This->prevY)
367               GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY - This->prevY, xtime, (This->dinput->evsequence)++);
368           } else {
369             /* This is the first time the event handler has been called after a
370                GetData of GetState. */
371             if (posX != This->mapped_center.x) {
372               GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX - This->mapped_center.x, xtime, (This->dinput->evsequence)++);
373               This->need_warp = WARP_NEEDED;
374             }
375             
376             if (posY != This->mapped_center.y) {
377               GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY - This->mapped_center.y, xtime, (This->dinput->evsequence)++);
378               This->need_warp = WARP_NEEDED;
379             }
380           }
381         }
382
383         This->prevX = posX;
384         This->prevY = posY;
385         
386         if (This->absolute) {
387           This->m_state.lX = posX;
388           This->m_state.lY = posY;
389         } else {
390           This->m_state.lX = posX - This->mapped_center.x;
391           This->m_state.lY = posY - This->mapped_center.y;
392         }
393       } else {
394         /* Mouse reporting is in relative mode */
395         posX = (long) dx;
396         posY = (long) dy;
397
398         if (This->absolute) {
399           long aposX, aposY;
400           
401           aposX = This->m_state.lX + posX;
402           if (aposX < 0)
403             aposX = 0;
404           if (aposX >= GetSystemMetrics(SM_CXSCREEN))
405             aposX = GetSystemMetrics(SM_CXSCREEN);
406           
407           aposY = This->m_state.lY + posY;
408           if (aposY < 0)
409             aposY = 0;
410           if (aposY >= GetSystemMetrics(SM_CYSCREEN))
411             aposY = GetSystemMetrics(SM_CYSCREEN);
412           
413           if (posX != 0)
414             GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], aposX, xtime, (This->dinput->evsequence)++);
415           if (posY != 0)
416             GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], aposY, xtime, (This->dinput->evsequence)++);
417
418           This->m_state.lX = aposX;
419           This->m_state.lY = aposY;
420         } else {
421           if (posX != 0)
422             GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX, xtime, (This->dinput->evsequence)++);
423           if (posY != 0)
424             GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY, xtime, (This->dinput->evsequence)++);
425
426           This->m_state.lX = posX;
427           This->m_state.lY = posY;
428         }
429       }
430     }
431   } else {
432     ERR("Mouse event not supported...\n");
433     goto end;
434   }
435
436   if (TRACE_ON(dinput)) {
437     if (dwFlags & MOUSEEVENTF_MOVE)
438       TRACE(" %ld %ld (%s)", posX, posY,
439             (dwFlags & MOUSEEVENTF_ABSOLUTE ? "abs" : "rel"));
440     
441     if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) DPRINTF(" LD ");
442     if ( dwFlags & MOUSEEVENTF_LEFTUP )   DPRINTF(" LU ");
443
444     if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) DPRINTF(" RD ");
445     if ( dwFlags & MOUSEEVENTF_RIGHTUP )   DPRINTF(" RU ");
446
447     if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) DPRINTF(" MD ");
448     if ( dwFlags & MOUSEEVENTF_MIDDLEUP )   DPRINTF(" MU ");
449
450     if (!(This->absolute)) DPRINTF(" W=%d ", This->need_warp);
451     
452     DPRINTF("\n");
453   }
454
455   
456   if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) {
457     GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF, xtime, (This->dinput->evsequence)++);
458     This->m_state.rgbButtons[0] = 0xFF;
459   }
460   if ( dwFlags & MOUSEEVENTF_LEFTUP ) {
461     GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00, xtime, (This->dinput->evsequence)++);
462     This->m_state.rgbButtons[0] = 0x00;
463   }
464   if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) {
465     GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF, xtime, (This->dinput->evsequence)++);
466     This->m_state.rgbButtons[1] = 0xFF;
467   }
468   if ( dwFlags & MOUSEEVENTF_RIGHTUP ) {
469     GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00, xtime, (This->dinput->evsequence)++);
470     This->m_state.rgbButtons[1] = 0x00;
471   }
472   if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) {
473     GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF, xtime, (This->dinput->evsequence)++);
474     This->m_state.rgbButtons[2] = 0xFF;
475   }
476   if ( dwFlags & MOUSEEVENTF_MIDDLEUP ) {
477     GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00, xtime, (This->dinput->evsequence)++);
478     This->m_state.rgbButtons[2] = 0x00;
479   }
480
481   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
482         This->m_state.lX, This->m_state.lY,
483         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
484
485 end:
486   if (This->dwCoopLevel & DISCL_NONEXCLUSIVE)
487   { /* pass the events down to previous handlers (e.g. win32 input) */
488     if (This->prev_handler)
489         This->prev_handler(dwFlags, dx, dy, cButtons, dwExtraInfo);
490   }
491   LeaveCriticalSection(&(This->crit));
492 }
493
494
495 /******************************************************************************
496   *     Acquire : gets exclusive control of the mouse
497   */
498 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
499 {
500   ICOM_THIS(SysMouseAImpl,iface);
501   RECT  rect;
502   
503   TRACE("(this=%p)\n",This);
504
505   if (This->acquired == 0) {
506     POINT point;
507     
508     /* This stores the current mouse handler. */
509     This->prev_handler = mouse_event;
510     
511     /* Store (in a global variable) the current lock */
512     current_lock = (IDirectInputDevice2A*)This;
513
514     /* Init the mouse state */
515     if (This->absolute) {
516       GetCursorPos( &point );
517       This->m_state.lX = point.x;
518       This->m_state.lY = point.y;
519       This->prevX = point.x;
520       This->prevY = point.y;
521     } else {
522       This->m_state.lX = 0;
523       This->m_state.lY = 0;
524     }
525     This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
526     This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
527     This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
528
529     /* Install our own mouse event handler */
530     MOUSE_Enable(dinput_mouse_event);
531     
532     /* Get the window dimension and find the center */
533     GetWindowRect(This->win, &rect);
534     This->win_centerX = (rect.right  - rect.left) / 2;
535     This->win_centerY = (rect.bottom - rect.top ) / 2;
536
537     /* Warp the mouse to the center of the window */
538     if (This->absolute == 0) {
539       This->mapped_center.x = This->win_centerX;
540       This->mapped_center.y = This->win_centerY;
541       MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
542       TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); 
543       SetCursorPos( This->mapped_center.x, This->mapped_center.y );
544 #ifdef MOUSE_HACK
545       This->need_warp = WARP_DONE;
546 #else
547       This->need_warp = WARP_STARTED;
548 #endif
549     }
550
551     This->acquired = 1;
552   }
553   return DI_OK;
554 }
555
556 /******************************************************************************
557   *     Unacquire : frees the mouse
558   */
559 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
560 {
561     ICOM_THIS(SysMouseAImpl,iface);
562
563     TRACE("(this=%p)\n",This);
564
565     if (This->acquired)
566     {
567         /* Reinstall previous mouse event handler */
568         MOUSE_Enable(This->prev_handler);
569         This->prev_handler = NULL;
570   
571         /* No more locks */
572         current_lock = NULL;
573
574         /* Unacquire device */
575         This->acquired = 0;
576     }
577     else
578         ERR("Unacquiring a not-acquired device !!!\n");
579   
580     return DI_OK;
581 }
582
583 /******************************************************************************
584   *     GetDeviceState : returns the "state" of the mouse.
585   *
586   *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
587   *   supported.
588   */
589 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
590         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
591 ) {
592   ICOM_THIS(SysMouseAImpl,iface);
593   
594   EnterCriticalSection(&(This->crit));
595   TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
596   
597   /* Copy the current mouse state */
598   fill_DataFormat(ptr, &(This->m_state), This->wine_df);
599   
600   /* Initialize the buffer when in relative mode */
601   if (This->absolute == 0) {
602     This->m_state.lX = 0;
603     This->m_state.lY = 0;
604   }
605
606   /* Check if we need to do a mouse warping */
607   if (This->need_warp == WARP_NEEDED) {
608     This->mapped_center.x = This->win_centerX;
609     This->mapped_center.y = This->win_centerY;
610     MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
611     TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); 
612     SetCursorPos( This->mapped_center.x, This->mapped_center.y );
613
614 #ifdef MOUSE_HACK
615     This->need_warp = WARP_DONE;
616 #else
617     This->need_warp = WARP_STARTED;
618 #endif
619   }
620
621   LeaveCriticalSection(&(This->crit));
622   
623   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
624         This->m_state.lX, This->m_state.lY,
625         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
626   
627   return 0;
628 }
629
630 /******************************************************************************
631   *     GetDeviceState : gets buffered input data.
632   */
633 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
634                                               DWORD dodsize,
635                                               LPDIDEVICEOBJECTDATA dod,
636                                               LPDWORD entries,
637                                               DWORD flags
638 ) {
639   ICOM_THIS(SysMouseAImpl,iface);
640   DWORD len, nqtail;
641   
642   EnterCriticalSection(&(This->crit));
643   TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
644
645   len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
646       + (This->queue_head - This->queue_tail);
647   if (len > *entries) len = *entries;
648
649   if (dod == NULL) {
650     *entries = len;
651     nqtail = This->queue_tail + len;
652     while (nqtail >= This->queue_len) nqtail -= This->queue_len;
653   } else {
654     if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
655       ERR("Wrong structure size !\n");
656       LeaveCriticalSection(&(This->crit));
657       return DIERR_INVALIDPARAM;
658     }
659
660     if (len)
661         TRACE("Application retrieving %ld event(s).\n", len); 
662
663     *entries = 0;
664     nqtail = This->queue_tail;
665     while (len) {
666       DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
667                  - nqtail;
668       if (span > len) span = len;
669       /* Copy the buffered data into the application queue */
670       memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
671       /* Advance position */
672       nqtail += span;
673       if (nqtail >= This->queue_len) nqtail -= This->queue_len;
674       *entries += span;
675       len -= span;
676     }
677   }
678   if (!(flags & DIGDD_PEEK))
679     This->queue_tail = nqtail;
680
681   LeaveCriticalSection(&(This->crit));
682
683   /* Check if we need to do a mouse warping */
684   if (This->need_warp == WARP_NEEDED) {
685     This->mapped_center.x = This->win_centerX;
686     This->mapped_center.y = This->win_centerY;
687     MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
688     TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); 
689     SetCursorPos( This->mapped_center.x, This->mapped_center.y );
690
691 #ifdef MOUSE_HACK
692     This->need_warp = WARP_DONE;
693 #else
694     This->need_warp = WARP_STARTED;
695 #endif
696   }
697   return 0;
698 }
699
700 /******************************************************************************
701   *     SetProperty : change input device properties
702   */
703 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
704                                             REFGUID rguid,
705                                             LPCDIPROPHEADER ph)
706 {
707   ICOM_THIS(SysMouseAImpl,iface);
708
709   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
710   
711   if (!HIWORD(rguid)) {
712     switch ((DWORD)rguid) {
713     case (DWORD) DIPROP_BUFFERSIZE: {
714       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
715       
716       TRACE("buffersize = %ld\n",pd->dwData);
717
718       This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
719                                                           pd->dwData * sizeof(DIDEVICEOBJECTDATA));
720       This->queue_head = 0;
721       This->queue_tail = 0;
722       This->queue_len  = pd->dwData;
723       break;
724     }
725     case (DWORD) DIPROP_AXISMODE: {
726       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
727       This->absolute = !(pd->dwData);
728       TRACE("absolute mode: %d\n", This->absolute);
729       break;
730     }
731     default:
732       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
733       break;
734     }
735   }
736   
737   return 0;
738 }
739
740 /******************************************************************************
741   *     GetProperty : get input device properties
742   */
743 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE2A iface,
744                                                 REFGUID rguid,
745                                                 LPDIPROPHEADER pdiph)
746 {
747   ICOM_THIS(SysMouseAImpl,iface);
748
749   TRACE("(this=%p,%s,%p): stub!\n",
750         iface, debugstr_guid(rguid), pdiph);
751
752   if (TRACE_ON(dinput))
753     _dump_DIPROPHEADER(pdiph);
754   
755   if (!HIWORD(rguid)) {
756     switch ((DWORD)rguid) {
757     case (DWORD) DIPROP_BUFFERSIZE: {
758       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
759       
760       TRACE(" return buffersize = %d\n",This->queue_len);
761       pd->dwData = This->queue_len;
762       break;
763     }
764
765     case (DWORD) DIPROP_RANGE: {
766       LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
767
768       if ((pdiph->dwHow == DIPH_BYID) &&
769           ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
770            (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
771         /* Querying the range of either the X or the Y axis.  As I do
772            not know the range, do as if the range where
773            unrestricted...*/
774         pr->lMin = DIPROPRANGE_NOMIN;
775         pr->lMax = DIPROPRANGE_NOMAX;
776       }
777       
778       break;
779     }
780       
781     default:
782       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
783       break;
784     }
785   }
786   
787   
788   return DI_OK;
789 }
790
791
792
793 /******************************************************************************
794   *     SetEventNotification : specifies event to be sent on state change
795   */
796 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
797                                                          HANDLE hnd) {
798   ICOM_THIS(SysMouseAImpl,iface);
799
800   TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
801
802   This->hEvent = hnd;
803
804   return DI_OK;
805 }
806
807 /******************************************************************************
808   *     GetCapabilities : get the device capablitites
809   */
810 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
811         LPDIRECTINPUTDEVICE2A iface,
812         LPDIDEVCAPS lpDIDevCaps)
813 {
814   ICOM_THIS(SysMouseAImpl,iface);
815
816   TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
817
818   if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
819     lpDIDevCaps->dwFlags = DIDC_ATTACHED;
820     lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
821     lpDIDevCaps->dwAxes = 2;
822     lpDIDevCaps->dwButtons = 3;
823     lpDIDevCaps->dwPOVs = 0;
824     lpDIDevCaps->dwFFSamplePeriod = 0;
825     lpDIDevCaps->dwFFMinTimeResolution = 0;
826     lpDIDevCaps->dwFirmwareRevision = 100;
827     lpDIDevCaps->dwHardwareRevision = 100;
828     lpDIDevCaps->dwFFDriverVersion = 0;
829   } else {
830     /* DirectX 3.0 */
831     FIXME("DirectX 3.0 not supported....\n");
832   }
833   
834   return DI_OK;
835 }
836
837
838 /******************************************************************************
839   *     EnumObjects : enumerate the different buttons and axis...
840   */
841 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
842         LPDIRECTINPUTDEVICE2A iface,
843         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
844         LPVOID lpvRef,
845         DWORD dwFlags)
846 {
847   ICOM_THIS(SysMouseAImpl,iface);
848   DIDEVICEOBJECTINSTANCEA ddoi;
849   
850   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
851   if (TRACE_ON(dinput)) {
852     DPRINTF("  - flags = ");
853     _dump_EnumObjects_flags(dwFlags);
854     DPRINTF("\n");
855   }
856
857   /* Only the fields till dwFFMaxForce are relevant */
858   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
859     
860   /* In a mouse, we have : two relative axis and three buttons */
861   if ((dwFlags == DIDFT_ALL) ||
862       (dwFlags & DIDFT_AXIS)) {
863     /* X axis */
864     ddoi.guidType = GUID_XAxis;
865     ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
866     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
867     strcpy(ddoi.tszName, "X-Axis");
868     _dump_OBJECTINSTANCEA(&ddoi);
869     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
870     
871     /* Y axis */
872     ddoi.guidType = GUID_YAxis;
873     ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
874     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
875     strcpy(ddoi.tszName, "Y-Axis");
876     _dump_OBJECTINSTANCEA(&ddoi);
877     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
878   }
879
880   if ((dwFlags == DIDFT_ALL) ||
881       (dwFlags & DIDFT_BUTTON)) {
882     ddoi.guidType = GUID_Button;
883
884     /* Left button */
885     ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
886     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
887     strcpy(ddoi.tszName, "Left-Button");
888     _dump_OBJECTINSTANCEA(&ddoi);
889     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
890
891     /* Right button */
892     ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
893     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
894     strcpy(ddoi.tszName, "Right-Button");
895     _dump_OBJECTINSTANCEA(&ddoi);
896     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
897
898     /* Middle button */
899     ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
900     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
901     strcpy(ddoi.tszName, "Middle-Button");
902     _dump_OBJECTINSTANCEA(&ddoi);
903     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
904   }
905
906   return DI_OK;
907 }
908
909
910 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt = 
911 {
912         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
913         IDirectInputDevice2AImpl_QueryInterface,
914         IDirectInputDevice2AImpl_AddRef,
915         SysMouseAImpl_Release,
916         SysMouseAImpl_GetCapabilities,
917         SysMouseAImpl_EnumObjects,
918         SysMouseAImpl_GetProperty,
919         SysMouseAImpl_SetProperty,
920         SysMouseAImpl_Acquire,
921         SysMouseAImpl_Unacquire,
922         SysMouseAImpl_GetDeviceState,
923         SysMouseAImpl_GetDeviceData,
924         SysMouseAImpl_SetDataFormat,
925         SysMouseAImpl_SetEventNotification,
926         SysMouseAImpl_SetCooperativeLevel,
927         IDirectInputDevice2AImpl_GetObjectInfo,
928         IDirectInputDevice2AImpl_GetDeviceInfo,
929         IDirectInputDevice2AImpl_RunControlPanel,
930         IDirectInputDevice2AImpl_Initialize,
931         IDirectInputDevice2AImpl_CreateEffect,
932         IDirectInputDevice2AImpl_EnumEffects,
933         IDirectInputDevice2AImpl_GetEffectInfo,
934         IDirectInputDevice2AImpl_GetForceFeedbackState,
935         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
936         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
937         IDirectInputDevice2AImpl_Escape,
938         IDirectInputDevice2AImpl_Poll,
939         IDirectInputDevice2AImpl_SendDeviceData,
940 };
941
942 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
943 # define XCAST(fun)     (typeof(SysMouse7Avt.fun))
944 #else
945 # define XCAST(fun)     (void*)
946 #endif
947
948 static ICOM_VTABLE(IDirectInputDevice7A) SysMouse7Avt = 
949 {
950         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
951         XCAST(QueryInterface)IDirectInputDevice2AImpl_QueryInterface,
952         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
953         XCAST(Release)SysMouseAImpl_Release,
954         XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities,
955         XCAST(EnumObjects)SysMouseAImpl_EnumObjects,
956         XCAST(GetProperty)SysMouseAImpl_GetProperty,
957         XCAST(SetProperty)SysMouseAImpl_SetProperty,
958         XCAST(Acquire)SysMouseAImpl_Acquire,
959         XCAST(Unacquire)SysMouseAImpl_Unacquire,
960         XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState,
961         XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData,
962         XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat,
963         XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification,
964         XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel,
965         XCAST(GetObjectInfo)IDirectInputDevice2AImpl_GetObjectInfo,
966         XCAST(GetDeviceInfo)IDirectInputDevice2AImpl_GetDeviceInfo,
967         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
968         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
969         XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
970         XCAST(EnumEffects)IDirectInputDevice2AImpl_EnumEffects,
971         XCAST(GetEffectInfo)IDirectInputDevice2AImpl_GetEffectInfo,
972         XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
973         XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
974         XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
975         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
976         XCAST(Poll)IDirectInputDevice2AImpl_Poll,
977         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
978         IDirectInputDevice7AImpl_EnumEffectsInFile,
979         IDirectInputDevice7AImpl_WriteEffectToFile
980 };
981
982 #undef XCAST