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