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