Fix subclassing to support nested messages.
[wine] / dlls / dinput / mouse.c
1 /*              DirectInput Mouse device
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winerror.h"
33 #include "dinput.h"
34
35 #include "dinput_private.h"
36 #include "device_private.h"
37 #include "wine/debug.h"
38 #include "wine/unicode.h"
39
40 #define MOUSE_HACK
41
42 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
43
44 /* Wine mouse driver object instances */
45 #define WINE_MOUSE_X_AXIS_INSTANCE 0x0001
46 #define WINE_MOUSE_Y_AXIS_INSTANCE 0x0002
47 #define WINE_MOUSE_Z_AXIS_INSTANCE 0x0004
48 #define WINE_MOUSE_L_BUTTON_INSTANCE 0x0008
49 #define WINE_MOUSE_R_BUTTON_INSTANCE 0x0010
50 #define WINE_MOUSE_M_BUTTON_INSTANCE 0x0020
51
52 /* ------------------------------- */
53 /* Wine mouse internal data format */
54 /* ------------------------------- */
55
56 /* Constants used to access the offset array */
57 #define WINE_MOUSE_X_POSITION 0
58 #define WINE_MOUSE_Y_POSITION 1
59 #define WINE_MOUSE_Z_POSITION 2
60 #define WINE_MOUSE_L_POSITION 3
61 #define WINE_MOUSE_R_POSITION 4
62 #define WINE_MOUSE_M_POSITION 5
63
64 typedef struct {
65   LONG lX;
66   LONG lY;
67   LONG lZ;
68   BYTE rgbButtons[4];
69 } Wine_InternalMouseData;
70
71 #define WINE_INTERNALMOUSE_NUM_OBJS 6
72
73 static DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = {
74   { &GUID_XAxis,   FIELD_OFFSET(Wine_InternalMouseData, lX),
75       DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
76   { &GUID_YAxis,   FIELD_OFFSET(Wine_InternalMouseData, lY),
77       DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
78   { &GUID_ZAxis,   FIELD_OFFSET(Wine_InternalMouseData, lZ),
79       DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
80   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0,
81       DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
82   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1,
83       DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
84   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2,
85       DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }
86 };
87
88 static DIDATAFORMAT Wine_InternalMouseFormat = {
89   0, /* dwSize - unused */
90   0, /* dwObjsize - unused */
91   0, /* dwFlags - unused */
92   sizeof(Wine_InternalMouseData),
93   WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */
94   Wine_InternalMouseObjectFormat
95 };
96
97 static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt;
98 static ICOM_VTABLE(IDirectInputDevice8W) SysMouseWvt;
99
100 typedef struct SysMouseImpl SysMouseImpl;
101
102 typedef enum {
103   WARP_NEEDED,  /* Warping is needed */
104   WARP_STARTED, /* Warping has been done, waiting for the warp event */
105   WARP_DONE     /* Warping has been done */
106 } WARP_STATUS;
107
108 struct SysMouseImpl
109 {
110         LPVOID                          lpVtbl;
111         DWORD                           ref;
112         GUID                            guid;
113
114         IDirectInputImpl               *dinput;
115
116         /* The current data format and the conversion between internal
117            and external data formats */
118         LPDIDATAFORMAT                  df;
119         DataFormat                     *wine_df;
120         int                             offset_array[WINE_INTERNALMOUSE_NUM_OBJS];
121
122         /* SysMouseAImpl */
123         BYTE                            absolute;
124         /* Previous position for relative moves */
125         LONG                            prevX, prevY;
126         HHOOK                           hook;
127         HWND                            win;
128         DWORD                           dwCoopLevel;
129         POINT                           mapped_center;
130         DWORD                           win_centerX, win_centerY;
131         LPDIDEVICEOBJECTDATA            data_queue;
132         int                             queue_head, queue_tail, queue_len;
133         /* warping: whether we need to move mouse back to middle once we
134          * reach window borders (for e.g. shooters, "surface movement" games) */
135         WARP_STATUS                     need_warp;
136         int                             acquired;
137         HANDLE                          hEvent;
138         CRITICAL_SECTION                crit;
139
140         /* This is for mouse reporting. */
141         Wine_InternalMouseData          m_state;
142 };
143
144 /* FIXME: This is ugly and not thread safe :/ */
145 static IDirectInputDevice8A* current_lock = NULL;
146
147 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
148   0x9e573ed8,
149   0x7734,
150   0x11d2,
151   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
152 };
153
154 static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, int version) {
155     DWORD dwSize;
156     DIDEVICEINSTANCEA ddi;
157     
158     dwSize = lpddi->dwSize;
159
160     TRACE("%ld %p\n", dwSize, lpddi);
161     
162     memset(lpddi, 0, dwSize);
163     memset(&ddi, 0, sizeof(ddi));
164
165     ddi.dwSize = dwSize;
166     ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */
167     ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
168     if (version >= 8)
169         ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
170     else
171         ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
172     strcpy(ddi.tszInstanceName, "Mouse");
173     strcpy(ddi.tszProductName, "Wine Mouse");
174
175     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
176 }
177
178 static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, int version) {
179     DWORD dwSize;
180     DIDEVICEINSTANCEW ddi;
181     
182     dwSize = lpddi->dwSize;
183
184     TRACE("%ld %p\n", dwSize, lpddi);
185     
186     memset(lpddi, 0, dwSize);
187     memset(&ddi, 0, sizeof(ddi));
188
189     ddi.dwSize = dwSize;
190     ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */
191     ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
192     if (version >= 8)
193         ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
194     else
195         ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
196     MultiByteToWideChar(CP_ACP, 0, "Mouse", -1, ddi.tszInstanceName, MAX_PATH);
197     MultiByteToWideChar(CP_ACP, 0, "Wine Mouse", -1, ddi.tszProductName, MAX_PATH);
198
199     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
200 }
201
202 static BOOL mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, int version)
203 {
204   if ((dwDevType == 0) ||
205       ((dwDevType == DIDEVTYPE_MOUSE) && (version < 8)) ||
206       ((dwDevType == DI8DEVTYPE_MOUSE) && (version >= 8))) {
207     TRACE("Enumerating the mouse device\n");
208
209     fill_mouse_dideviceinstanceA(lpddi, version);
210
211     return TRUE;
212   }
213
214   return FALSE;
215 }
216
217 static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, int version)
218 {
219   if ((dwDevType == 0) ||
220       ((dwDevType == DIDEVTYPE_MOUSE) && (version < 8)) ||
221       ((dwDevType == DI8DEVTYPE_MOUSE) && (version >= 8))) {
222     TRACE("Enumerating the mouse device\n");
223
224     fill_mouse_dideviceinstanceW(lpddi, version);
225
226     return TRUE;
227   }
228
229   return FALSE;
230 }
231
232 static SysMouseImpl *alloc_device(REFGUID rguid, LPVOID mvt, IDirectInputImpl *dinput)
233 {
234     int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = {
235       FIELD_OFFSET(Wine_InternalMouseData, lX),
236       FIELD_OFFSET(Wine_InternalMouseData, lY),
237       FIELD_OFFSET(Wine_InternalMouseData, lZ),
238       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0,
239       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1,
240       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2
241     };
242     SysMouseImpl* newDevice;
243     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl));
244     newDevice->ref = 1;
245     newDevice->lpVtbl = mvt;
246     InitializeCriticalSection(&(newDevice->crit));
247     memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
248
249     /* Per default, Wine uses its internal data format */
250     newDevice->df = &Wine_InternalMouseFormat;
251     memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int));
252     newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
253     newDevice->wine_df->size = 0;
254     newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize;
255     newDevice->wine_df->dt = NULL;
256     newDevice->dinput = dinput;
257
258     return newDevice;
259 }
260
261 static HRESULT mousedev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
262 {
263   if ((IsEqualGUID(&GUID_SysMouse,rguid)) ||             /* Generic Mouse */
264       (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
265     if ((riid == NULL) ||
266         IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
267         IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
268         IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
269         IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
270       *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput);
271       TRACE("Creating a Mouse device (%p)\n", *pdev);
272       return DI_OK;
273     } else
274       return DIERR_NOINTERFACE;
275   }
276
277   return DIERR_DEVICENOTREG;
278 }
279
280 static HRESULT mousedev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
281 {
282   if ((IsEqualGUID(&GUID_SysMouse,rguid)) ||             /* Generic Mouse */
283       (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
284     if ((riid == NULL) ||
285         IsEqualGUID(&IID_IDirectInputDeviceW,riid) ||
286         IsEqualGUID(&IID_IDirectInputDevice2W,riid) ||
287         IsEqualGUID(&IID_IDirectInputDevice7W,riid) ||
288         IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
289       *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &SysMouseWvt, dinput);
290       TRACE("Creating a Mouse device (%p)\n", *pdev);
291       return DI_OK;
292     } else
293       return DIERR_NOINTERFACE;
294   }
295
296   return DIERR_DEVICENOTREG;
297 }
298 static dinput_device mousedev = {
299   100,
300   mousedev_enum_deviceA,
301   mousedev_enum_deviceW,
302   mousedev_create_deviceA,
303   mousedev_create_deviceW
304 };
305
306 DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); }
307
308 /******************************************************************************
309  *      SysMouseA (DInput Mouse support)
310  */
311
312 /******************************************************************************
313   *     Release : release the mouse buffer.
314   */
315 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
316 {
317         ICOM_THIS(SysMouseImpl,iface);
318
319         This->ref--;
320         if (This->ref)
321                 return This->ref;
322
323         /* Free the data queue */
324         if (This->data_queue != NULL)
325           HeapFree(GetProcessHeap(),0,This->data_queue);
326
327         if (This->hook) {
328           UnhookWindowsHookEx( This->hook );
329           if (This->dwCoopLevel & DISCL_EXCLUSIVE)
330             ShowCursor(TRUE); /* show cursor */
331         }
332         DeleteCriticalSection(&(This->crit));
333
334         /* Free the DataFormat */
335         if (This->df != &(Wine_InternalMouseFormat)) {
336           HeapFree(GetProcessHeap(), 0, This->df->rgodf);
337           HeapFree(GetProcessHeap(), 0, This->df);
338         }
339
340         HeapFree(GetProcessHeap(),0,This);
341         return DI_OK;
342 }
343
344
345 /******************************************************************************
346   *     SetCooperativeLevel : store the window in which we will do our
347   *   grabbing.
348   */
349 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
350         LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags
351 )
352 {
353   ICOM_THIS(SysMouseImpl,iface);
354
355   TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
356
357   if (TRACE_ON(dinput)) {
358       TRACE(" cooperative level : ");
359       _dump_cooperativelevel_DI(dwflags);
360   }
361
362   /* Store the window which asks for the mouse */
363   if (!hwnd)
364     hwnd = GetDesktopWindow();
365   This->win = hwnd;
366   This->dwCoopLevel = dwflags;
367
368   return DI_OK;
369 }
370
371
372 /******************************************************************************
373   *     SetDataFormat : the application can choose the format of the data
374   *   the device driver sends back with GetDeviceState.
375   *
376   *   For the moment, only the "standard" configuration (c_dfDIMouse) is supported
377   *   in absolute and relative mode.
378   */
379 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
380         LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
381 )
382 {
383   ICOM_THIS(SysMouseImpl,iface);
384   int i;
385
386   TRACE("(this=%p,%p)\n",This,df);
387
388   TRACE("(df.dwSize=%ld)\n",df->dwSize);
389   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
390   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
391   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
392   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
393
394   for (i=0;i<df->dwNumObjs;i++) {
395
396     TRACE("df.rgodf[%d].guid %s (%p)\n",i, debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
397     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
398     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
399     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
400   }
401
402   /* Tests under windows show that a call to SetDataFormat always sets the mouse
403      in relative mode whatever the dwFlags value (DIDF_ABSAXIS/DIDF_RELAXIS).
404      To switch in absolute mode, SetProperty must be used. */
405   This->absolute = 0;
406
407   /* Store the new data format */
408   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
409   memcpy(This->df, df, df->dwSize);
410   This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
411   memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
412
413   /* Prepare all the data-conversion filters */
414   This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array);
415
416   return DI_OK;
417 }
418
419 /* low-level mouse hook */
420 static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam )
421 {
422     LRESULT ret;
423     MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
424     SysMouseImpl* This = (SysMouseImpl*) current_lock;
425     DWORD dwCoop;
426     static long last_event = 0;
427     int wdata;
428
429     if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam );
430
431     EnterCriticalSection(&(This->crit));
432     dwCoop = This->dwCoopLevel;
433
434     /* Only allow mouse events every 10 ms.
435      * This is to allow the cursor to start acceleration before
436      * the warps happen. But if it involves a mouse button event we
437      * allow it since we don't want to loose the clicks.
438      */
439     if (((GetCurrentTime() - last_event) < 10)
440         && wparam == WM_MOUSEMOVE)
441       goto end;
442     else last_event = GetCurrentTime();
443
444     /* Mouse moved -> send event if asked */
445     if (This->hEvent)
446         SetEvent(This->hEvent);
447
448     if (wparam == WM_MOUSEMOVE) {
449         if (This->absolute) {
450           if (hook->pt.x != This->prevX)
451             GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0);
452           if (hook->pt.y != This->prevY)
453             GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0);
454         } else {
455           /* Now, warp handling */
456           if ((This->need_warp == WARP_STARTED) &&
457               (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) {
458             /* Warp has been done... */
459             This->need_warp = WARP_DONE;
460             goto end;
461           }
462
463           /* Relative mouse input with absolute mouse event : the real fun starts here... */
464           if ((This->need_warp == WARP_NEEDED) ||
465               (This->need_warp == WARP_STARTED)) {
466             if (hook->pt.x != This->prevX)
467               GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, hook->time, (This->dinput->evsequence)++);
468             if (hook->pt.y != This->prevY)
469               GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, hook->time, (This->dinput->evsequence)++);
470           } else {
471             /* This is the first time the event handler has been called after a
472                GetDeviceData or GetDeviceState. */
473             if (hook->pt.x != This->mapped_center.x) {
474               GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, hook->time, (This->dinput->evsequence)++);
475               This->need_warp = WARP_NEEDED;
476             }
477
478             if (hook->pt.y != This->mapped_center.y) {
479               GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, hook->time, (This->dinput->evsequence)++);
480               This->need_warp = WARP_NEEDED;
481             }
482           }
483         }
484
485         This->prevX = hook->pt.x;
486         This->prevY = hook->pt.y;
487
488         if (This->absolute) {
489           This->m_state.lX = hook->pt.x;
490           This->m_state.lY = hook->pt.y;
491         } else {
492           This->m_state.lX = hook->pt.x - This->mapped_center.x;
493           This->m_state.lY = hook->pt.y - This->mapped_center.y;
494         }
495     }
496
497     TRACE(" msg %x pt %ld %ld (W=%d)\n",
498           wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp );
499
500     switch(wparam)
501     {
502     case WM_LBUTTONDOWN:
503         GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF,
504                   hook->time, This->dinput->evsequence++);
505         This->m_state.rgbButtons[0] = 0xFF;
506         break;
507     case WM_LBUTTONUP:
508         GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00,
509                   hook->time, This->dinput->evsequence++);
510         This->m_state.rgbButtons[0] = 0x00;
511         break;
512     case WM_RBUTTONDOWN:
513         GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF,
514                   hook->time, This->dinput->evsequence++);
515         This->m_state.rgbButtons[1] = 0xFF;
516         break;
517     case WM_RBUTTONUP:
518         GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00,
519                   hook->time, This->dinput->evsequence++);
520         This->m_state.rgbButtons[1] = 0x00;
521         break;
522     case WM_MBUTTONDOWN:
523         GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF,
524                   hook->time, This->dinput->evsequence++);
525         This->m_state.rgbButtons[2] = 0xFF;
526         break;
527     case WM_MBUTTONUP:
528         GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00,
529                   hook->time, This->dinput->evsequence++);
530         This->m_state.rgbButtons[2] = 0x00;
531         break;
532     case WM_MOUSEWHEEL:
533         wdata = (short)HIWORD(hook->mouseData);
534         GEN_EVENT(This->offset_array[WINE_MOUSE_Z_POSITION], wdata,
535                   hook->time, This->dinput->evsequence++);
536         This->m_state.lZ += wdata;
537         break;
538     }
539
540   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
541         This->m_state.lX, This->m_state.lY,
542         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
543
544 end:
545   LeaveCriticalSection(&(This->crit));
546
547   if (dwCoop & DISCL_NONEXCLUSIVE)
548   { /* pass the events down to previous handlers (e.g. win32 input) */
549       ret = CallNextHookEx( This->hook, code, wparam, lparam );
550   }
551   else ret = 1;  /* ignore message */
552   return ret;
553 }
554
555
556 static void dinput_window_check(SysMouseImpl* This)
557 {
558   RECT rect;
559   DWORD centerX, centerY;
560
561   /* make sure the window hasn't moved */
562   GetWindowRect(This->win, &rect);
563   centerX = (rect.right  - rect.left) / 2;
564   centerY = (rect.bottom - rect.top ) / 2;
565   if (This->win_centerX != centerX || This->win_centerY != centerY) {
566     This->win_centerX = centerX;
567     This->win_centerY = centerY;
568   }
569   This->mapped_center.x = This->win_centerX;
570   This->mapped_center.y = This->win_centerY;
571   MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
572 }
573
574
575 /******************************************************************************
576   *     Acquire : gets exclusive control of the mouse
577   */
578 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
579 {
580   ICOM_THIS(SysMouseImpl,iface);
581   RECT  rect;
582
583   TRACE("(this=%p)\n",This);
584
585   if (This->acquired == 0) {
586     POINT point;
587
588     /* Store (in a global variable) the current lock */
589     current_lock = (IDirectInputDevice8A*)This;
590
591     /* Init the mouse state */
592     if (This->absolute) {
593       GetCursorPos( &point );
594       This->m_state.lX = point.x;
595       This->m_state.lY = point.y;
596       This->prevX = point.x;
597       This->prevY = point.y;
598     } else {
599       This->m_state.lX = 0;
600       This->m_state.lY = 0;
601     }
602     This->m_state.lZ = 0;
603     This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
604     This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
605     This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
606
607     /* Install our mouse hook */
608     if (This->dwCoopLevel & DISCL_EXCLUSIVE)
609       ShowCursor(FALSE); /* hide cursor */
610     This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 );
611
612     /* Get the window dimension and find the center */
613     GetWindowRect(This->win, &rect);
614     This->win_centerX = (rect.right  - rect.left) / 2;
615     This->win_centerY = (rect.bottom - rect.top ) / 2;
616
617     /* Warp the mouse to the center of the window */
618     if (This->absolute == 0) {
619       This->mapped_center.x = This->win_centerX;
620       This->mapped_center.y = This->win_centerY;
621       MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
622       TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
623       SetCursorPos( This->mapped_center.x, This->mapped_center.y );
624 #ifdef MOUSE_HACK
625       This->need_warp = WARP_DONE;
626 #else
627       This->need_warp = WARP_STARTED;
628 #endif
629     }
630
631     This->acquired = 1;
632     return DI_OK;
633   }
634   return S_FALSE;
635 }
636
637 /******************************************************************************
638   *     Unacquire : frees the mouse
639   */
640 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
641 {
642     ICOM_THIS(SysMouseImpl,iface);
643
644     TRACE("(this=%p)\n",This);
645
646     if (This->acquired)
647     {
648         /* Reinstall previous mouse event handler */
649         if (This->hook) {
650           UnhookWindowsHookEx( This->hook );
651           This->hook = 0;
652           if (This->dwCoopLevel & DISCL_EXCLUSIVE)
653             ShowCursor(TRUE); /* show cursor */
654         }
655
656         /* No more locks */
657         current_lock = NULL;
658
659         /* Unacquire device */
660         This->acquired = 0;
661     }
662     else
663         return DI_NOEFFECT;
664         
665     return DI_OK;
666 }
667
668 /******************************************************************************
669   *     GetDeviceState : returns the "state" of the mouse.
670   *
671   *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
672   *   supported.
673   */
674 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
675         LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
676 ) {
677   ICOM_THIS(SysMouseImpl,iface);
678
679   EnterCriticalSection(&(This->crit));
680   TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
681
682   /* Copy the current mouse state */
683   fill_DataFormat(ptr, &(This->m_state), This->wine_df);
684
685   /* Initialize the buffer when in relative mode */
686   if (This->absolute == 0) {
687     This->m_state.lX = 0;
688     This->m_state.lY = 0;
689     This->m_state.lZ = 0;
690   }
691
692   /* Check if we need to do a mouse warping */
693   if (This->need_warp == WARP_NEEDED) {
694     dinput_window_check(This);
695     TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
696     SetCursorPos( This->mapped_center.x, This->mapped_center.y );
697
698 #ifdef MOUSE_HACK
699     This->need_warp = WARP_DONE;
700 #else
701     This->need_warp = WARP_STARTED;
702 #endif
703   }
704
705   LeaveCriticalSection(&(This->crit));
706
707   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
708         This->m_state.lX, This->m_state.lY,
709         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
710
711   return DI_OK;
712 }
713
714 /******************************************************************************
715   *     GetDeviceState : gets buffered input data.
716   */
717 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
718                                               DWORD dodsize,
719                                               LPDIDEVICEOBJECTDATA dod,
720                                               LPDWORD entries,
721                                               DWORD flags
722 ) {
723   ICOM_THIS(SysMouseImpl,iface);
724   DWORD len, nqtail;
725
726   TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
727
728   if (This->acquired == 0) {
729       WARN(" application tries to get data from an unacquired device !\n");
730       return DIERR_NOTACQUIRED;
731   }
732   
733   EnterCriticalSection(&(This->crit));
734
735   len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
736       + (This->queue_head - This->queue_tail);
737   if (len > *entries) len = *entries;
738
739   if (dod == NULL) {
740     if (len)
741         TRACE("Application discarding %ld event(s).\n", len);
742
743     *entries = len;
744     nqtail = This->queue_tail + len;
745     while (nqtail >= This->queue_len) nqtail -= This->queue_len;
746   } else {
747     if (dodsize < sizeof(DIDEVICEOBJECTDATA)) {
748       ERR("Wrong structure size !\n");
749       LeaveCriticalSection(&(This->crit));
750       return DIERR_INVALIDPARAM;
751     }
752
753     if (len)
754         TRACE("Application retrieving %ld event(s).\n", len);
755
756     *entries = 0;
757     nqtail = This->queue_tail;
758     while (len) {
759       DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
760                  - nqtail;
761       if (span > len) span = len;
762       /* Copy the buffered data into the application queue */
763       memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
764       /* Advance position */
765       nqtail += span;
766       if (nqtail >= This->queue_len) nqtail -= This->queue_len;
767       *entries += span;
768       len -= span;
769     }
770   }
771   if (!(flags & DIGDD_PEEK))
772     This->queue_tail = nqtail;
773
774   LeaveCriticalSection(&(This->crit));
775
776   /* Check if we need to do a mouse warping */
777   if (This->need_warp == WARP_NEEDED) {
778     dinput_window_check(This);
779     TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
780     SetCursorPos( This->mapped_center.x, This->mapped_center.y );
781
782 #ifdef MOUSE_HACK
783     This->need_warp = WARP_DONE;
784 #else
785     This->need_warp = WARP_STARTED;
786 #endif
787   }
788   return DI_OK;
789 }
790
791 /******************************************************************************
792   *     SetProperty : change input device properties
793   */
794 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
795                                             REFGUID rguid,
796                                             LPCDIPROPHEADER ph)
797 {
798   ICOM_THIS(SysMouseImpl,iface);
799
800   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
801
802   if (!HIWORD(rguid)) {
803     switch ((DWORD)rguid) {
804     case (DWORD) DIPROP_BUFFERSIZE: {
805       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
806
807       TRACE("buffersize = %ld\n",pd->dwData);
808
809       This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
810                                                           pd->dwData * sizeof(DIDEVICEOBJECTDATA));
811       This->queue_head = 0;
812       This->queue_tail = 0;
813       This->queue_len  = pd->dwData;
814       break;
815     }
816     case (DWORD) DIPROP_AXISMODE: {
817       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
818       This->absolute = !(pd->dwData);
819       TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative");
820       break;
821     }
822     default:
823       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
824       break;
825     }
826   }
827
828   return DI_OK;
829 }
830
831 /******************************************************************************
832   *     GetProperty : get input device properties
833   */
834 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
835                                                 REFGUID rguid,
836                                                 LPDIPROPHEADER pdiph)
837 {
838   ICOM_THIS(SysMouseImpl,iface);
839
840   TRACE("(this=%p,%s,%p): stub!\n",
841         iface, debugstr_guid(rguid), pdiph);
842
843   if (TRACE_ON(dinput))
844     _dump_DIPROPHEADER(pdiph);
845
846   if (!HIWORD(rguid)) {
847     switch ((DWORD)rguid) {
848     case (DWORD) DIPROP_BUFFERSIZE: {
849       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
850
851       TRACE(" return buffersize = %d\n",This->queue_len);
852       pd->dwData = This->queue_len;
853       break;
854     }
855
856     case (DWORD) DIPROP_GRANULARITY: {
857       LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph;
858
859       /* We'll just assume that the app asks about the Z axis */
860       pr->dwData = WHEEL_DELTA;
861
862       break;
863     }
864
865     case (DWORD) DIPROP_RANGE: {
866       LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
867
868       if ((pdiph->dwHow == DIPH_BYID) &&
869           ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
870            (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
871         /* Querying the range of either the X or the Y axis.  As I do
872            not know the range, do as if the range were
873            unrestricted...*/
874         pr->lMin = DIPROPRANGE_NOMIN;
875         pr->lMax = DIPROPRANGE_NOMAX;
876       }
877
878       break;
879     }
880
881     default:
882       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
883       break;
884     }
885   }
886
887
888   return DI_OK;
889 }
890
891
892
893 /******************************************************************************
894   *     SetEventNotification : specifies event to be sent on state change
895   */
896 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface,
897                                                          HANDLE hnd) {
898   ICOM_THIS(SysMouseImpl,iface);
899
900   TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
901
902   This->hEvent = hnd;
903
904   return DI_OK;
905 }
906
907 /******************************************************************************
908   *     GetCapabilities : get the device capablitites
909   */
910 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
911         LPDIRECTINPUTDEVICE8A iface,
912         LPDIDEVCAPS lpDIDevCaps)
913 {
914   ICOM_THIS(SysMouseImpl,iface);
915
916   TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
917
918   if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
919     lpDIDevCaps->dwFlags = DIDC_ATTACHED;
920     if (This->dinput->version >= 8)
921         lpDIDevCaps->dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
922     else
923         lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
924     lpDIDevCaps->dwAxes = 3;
925     lpDIDevCaps->dwButtons = 3;
926     lpDIDevCaps->dwPOVs = 0;
927     lpDIDevCaps->dwFFSamplePeriod = 0;
928     lpDIDevCaps->dwFFMinTimeResolution = 0;
929     lpDIDevCaps->dwFirmwareRevision = 100;
930     lpDIDevCaps->dwHardwareRevision = 100;
931     lpDIDevCaps->dwFFDriverVersion = 0;
932   } else {
933     /* DirectX 3.0 */
934     FIXME("DirectX 3.0 not supported....\n");
935   }
936
937   return DI_OK;
938 }
939
940
941 /******************************************************************************
942   *     EnumObjects : enumerate the different buttons and axis...
943   */
944 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
945         LPDIRECTINPUTDEVICE8A iface,
946         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
947         LPVOID lpvRef,
948         DWORD dwFlags)
949 {
950   ICOM_THIS(SysMouseImpl,iface);
951   DIDEVICEOBJECTINSTANCEA ddoi;
952
953   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
954   if (TRACE_ON(dinput)) {
955     TRACE("  - flags = ");
956     _dump_EnumObjects_flags(dwFlags);
957     TRACE("\n");
958   }
959
960   /* Only the fields till dwFFMaxForce are relevant */
961   memset(&ddoi, 0, sizeof(ddoi));
962   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
963
964   /* In a mouse, we have : two relative axis and three buttons */
965   if ((dwFlags == DIDFT_ALL) ||
966       (dwFlags & DIDFT_AXIS)) {
967     /* X axis */
968     ddoi.guidType = GUID_XAxis;
969     ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
970     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
971     strcpy(ddoi.tszName, "X-Axis");
972     _dump_OBJECTINSTANCEA(&ddoi);
973     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
974
975     /* Y axis */
976     ddoi.guidType = GUID_YAxis;
977     ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
978     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
979     strcpy(ddoi.tszName, "Y-Axis");
980     _dump_OBJECTINSTANCEA(&ddoi);
981     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
982
983     /* Z axis */
984     ddoi.guidType = GUID_ZAxis;
985     ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION];
986     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS;
987     strcpy(ddoi.tszName, "Z-Axis");
988     _dump_OBJECTINSTANCEA(&ddoi);
989     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
990   }
991
992   if ((dwFlags == DIDFT_ALL) ||
993       (dwFlags & DIDFT_BUTTON)) {
994     ddoi.guidType = GUID_Button;
995
996     /* Left button */
997     ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
998     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
999     strcpy(ddoi.tszName, "Left-Button");
1000     _dump_OBJECTINSTANCEA(&ddoi);
1001     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1002
1003     /* Right button */
1004     ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
1005     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1006     strcpy(ddoi.tszName, "Right-Button");
1007     _dump_OBJECTINSTANCEA(&ddoi);
1008     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1009
1010     /* Middle button */
1011     ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
1012     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1013     strcpy(ddoi.tszName, "Middle-Button");
1014     _dump_OBJECTINSTANCEA(&ddoi);
1015     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1016   }
1017
1018   return DI_OK;
1019 }
1020
1021 static HRESULT WINAPI SysMouseWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef,DWORD dwFlags)
1022 {
1023   ICOM_THIS(SysMouseImpl,iface);
1024
1025   device_enumobjects_AtoWcb_data data;
1026
1027   data.lpCallBack = lpCallback;
1028   data.lpvRef = lpvRef;
1029
1030   return SysMouseAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags);
1031 }
1032
1033 /******************************************************************************
1034   *     GetDeviceInfo : get information about a device's identity
1035   */
1036 static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo(
1037         LPDIRECTINPUTDEVICE8A iface,
1038         LPDIDEVICEINSTANCEA pdidi)
1039 {
1040     ICOM_THIS(SysMouseImpl,iface);
1041     TRACE("(this=%p,%p)\n", This, pdidi);
1042
1043     if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) {
1044         WARN(" dinput3 not supporte yet...\n");
1045         return DI_OK;
1046     }
1047
1048     fill_mouse_dideviceinstanceA(pdidi, This->dinput->version);
1049     
1050     return DI_OK;
1051 }
1052
1053 static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi)
1054 {
1055     ICOM_THIS(SysMouseImpl,iface);
1056     TRACE("(this=%p,%p)\n", This, pdidi);
1057
1058     if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) {
1059         WARN(" dinput3 not supporte yet...\n");
1060         return DI_OK;
1061     }
1062
1063     fill_mouse_dideviceinstanceW(pdidi, This->dinput->version);
1064     
1065     return DI_OK;
1066 }
1067
1068
1069 static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt =
1070 {
1071         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1072         IDirectInputDevice2AImpl_QueryInterface,
1073         IDirectInputDevice2AImpl_AddRef,
1074         SysMouseAImpl_Release,
1075         SysMouseAImpl_GetCapabilities,
1076         SysMouseAImpl_EnumObjects,
1077         SysMouseAImpl_GetProperty,
1078         SysMouseAImpl_SetProperty,
1079         SysMouseAImpl_Acquire,
1080         SysMouseAImpl_Unacquire,
1081         SysMouseAImpl_GetDeviceState,
1082         SysMouseAImpl_GetDeviceData,
1083         SysMouseAImpl_SetDataFormat,
1084         SysMouseAImpl_SetEventNotification,
1085         SysMouseAImpl_SetCooperativeLevel,
1086         IDirectInputDevice2AImpl_GetObjectInfo,
1087         SysMouseAImpl_GetDeviceInfo,
1088         IDirectInputDevice2AImpl_RunControlPanel,
1089         IDirectInputDevice2AImpl_Initialize,
1090         IDirectInputDevice2AImpl_CreateEffect,
1091         IDirectInputDevice2AImpl_EnumEffects,
1092         IDirectInputDevice2AImpl_GetEffectInfo,
1093         IDirectInputDevice2AImpl_GetForceFeedbackState,
1094         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1095         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1096         IDirectInputDevice2AImpl_Escape,
1097         IDirectInputDevice2AImpl_Poll,
1098         IDirectInputDevice2AImpl_SendDeviceData,
1099         IDirectInputDevice7AImpl_EnumEffectsInFile,
1100         IDirectInputDevice7AImpl_WriteEffectToFile,
1101         IDirectInputDevice8AImpl_BuildActionMap,
1102         IDirectInputDevice8AImpl_SetActionMap,
1103         IDirectInputDevice8AImpl_GetImageInfo
1104 };
1105
1106 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
1107 # define XCAST(fun)     (typeof(SysMouseWvt.fun))
1108 #else
1109 # define XCAST(fun)     (void*)
1110 #endif
1111
1112 static ICOM_VTABLE(IDirectInputDevice8W) SysMouseWvt =
1113 {
1114         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1115         IDirectInputDevice2WImpl_QueryInterface,
1116         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
1117         XCAST(Release)SysMouseAImpl_Release,
1118         XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities,
1119         SysMouseWImpl_EnumObjects,
1120         XCAST(GetProperty)SysMouseAImpl_GetProperty,
1121         XCAST(SetProperty)SysMouseAImpl_SetProperty,
1122         XCAST(Acquire)SysMouseAImpl_Acquire,
1123         XCAST(Unacquire)SysMouseAImpl_Unacquire,
1124         XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState,
1125         XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData,
1126         XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat,
1127         XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification,
1128         XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel,
1129         IDirectInputDevice2WImpl_GetObjectInfo,
1130         SysMouseWImpl_GetDeviceInfo,
1131         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
1132         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
1133         XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
1134         IDirectInputDevice2WImpl_EnumEffects,
1135         IDirectInputDevice2WImpl_GetEffectInfo,
1136         XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
1137         XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1138         XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1139         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
1140         XCAST(Poll)IDirectInputDevice2AImpl_Poll,
1141         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
1142         IDirectInputDevice7WImpl_EnumEffectsInFile,
1143         IDirectInputDevice7WImpl_WriteEffectToFile,
1144         IDirectInputDevice8WImpl_BuildActionMap,
1145         IDirectInputDevice8WImpl_SetActionMap,
1146         IDirectInputDevice8WImpl_GetImageInfo
1147 };
1148 #undef XCAST