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