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