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