wininet: Use proc instead of enum in FTPFINDNEXTW request.
[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 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
41
42 /* Wine mouse driver object instances */
43 #define WINE_MOUSE_X_AXIS_INSTANCE   0
44 #define WINE_MOUSE_Y_AXIS_INSTANCE   1
45 #define WINE_MOUSE_Z_AXIS_INSTANCE   2
46 #define WINE_MOUSE_L_BUTTON_INSTANCE 0
47 #define WINE_MOUSE_R_BUTTON_INSTANCE 1
48 #define WINE_MOUSE_M_BUTTON_INSTANCE 2
49 #define WINE_MOUSE_D_BUTTON_INSTANCE 3
50
51 /* ------------------------------- */
52 /* Wine mouse internal data format */
53 /* ------------------------------- */
54
55 /* Constants used to access the offset array */
56 #define WINE_MOUSE_X_POSITION 0
57 #define WINE_MOUSE_Y_POSITION 1
58 #define WINE_MOUSE_Z_POSITION 2
59 #define WINE_MOUSE_L_POSITION 3
60 #define WINE_MOUSE_R_POSITION 4
61 #define WINE_MOUSE_M_POSITION 5
62
63 static const IDirectInputDevice8AVtbl SysMouseAvt;
64 static const IDirectInputDevice8WVtbl SysMouseWvt;
65
66 typedef struct SysMouseImpl SysMouseImpl;
67
68 struct SysMouseImpl
69 {
70     struct IDirectInputDevice2AImpl base;
71     
72     IDirectInputImpl               *dinput;
73
74     /* SysMouseAImpl */
75     /* These are used in case of relative -> absolute transitions */
76     POINT                           org_coords;
77     POINT                           mapped_center;
78     DWORD                           win_centerX, win_centerY;
79     /* warping: whether we need to move mouse back to middle once we
80      * reach window borders (for e.g. shooters, "surface movement" games) */
81     BOOL                            need_warp;
82     DWORD                           last_warped;
83
84     /* This is for mouse reporting. */
85     DIMOUSESTATE2                   m_state;
86 };
87
88 /* FIXME: This is ugly and not thread safe :/ */
89 static IDirectInputDevice8A* current_lock = NULL;
90
91 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
92     0x9e573ed8,
93     0x7734,
94     0x11d2,
95     {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
96 };
97
98 static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version) {
99     DWORD dwSize;
100     DIDEVICEINSTANCEA ddi;
101     
102     dwSize = lpddi->dwSize;
103
104     TRACE("%d %p\n", dwSize, lpddi);
105     
106     memset(lpddi, 0, dwSize);
107     memset(&ddi, 0, sizeof(ddi));
108
109     ddi.dwSize = dwSize;
110     ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */
111     ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
112     if (version >= 0x0800)
113         ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
114     else
115         ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
116     strcpy(ddi.tszInstanceName, "Mouse");
117     strcpy(ddi.tszProductName, "Wine Mouse");
118
119     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
120 }
121
122 static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version) {
123     DWORD dwSize;
124     DIDEVICEINSTANCEW ddi;
125     
126     dwSize = lpddi->dwSize;
127
128     TRACE("%d %p\n", dwSize, lpddi);
129     
130     memset(lpddi, 0, dwSize);
131     memset(&ddi, 0, sizeof(ddi));
132
133     ddi.dwSize = dwSize;
134     ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */
135     ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
136     if (version >= 0x0800)
137         ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
138     else
139         ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
140     MultiByteToWideChar(CP_ACP, 0, "Mouse", -1, ddi.tszInstanceName, MAX_PATH);
141     MultiByteToWideChar(CP_ACP, 0, "Wine Mouse", -1, ddi.tszProductName, MAX_PATH);
142
143     memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
144 }
145
146 static BOOL mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
147 {
148     if (id != 0)
149         return FALSE;
150
151     if ((dwDevType == 0) ||
152         ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
153         (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 0x0800))) {
154         TRACE("Enumerating the mouse device\n");
155         
156         fill_mouse_dideviceinstanceA(lpddi, version);
157         
158         return TRUE;
159     }
160     
161     return FALSE;
162 }
163
164 static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
165 {
166     if (id != 0)
167         return FALSE;
168
169     if ((dwDevType == 0) ||
170         ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
171         (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 0x0800))) {
172         TRACE("Enumerating the mouse device\n");
173         
174         fill_mouse_dideviceinstanceW(lpddi, version);
175         
176         return TRUE;
177     }
178     
179     return FALSE;
180 }
181
182 static SysMouseImpl *alloc_device(REFGUID rguid, const void *mvt, IDirectInputImpl *dinput)
183 {
184     SysMouseImpl* newDevice;
185
186     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl));
187     if (!newDevice) return NULL;
188     newDevice->base.lpVtbl = mvt;
189     newDevice->base.ref = 1;
190     newDevice->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
191     memcpy(&newDevice->base.guid, rguid, sizeof(*rguid));
192     InitializeCriticalSection(&newDevice->base.crit);
193     newDevice->dinput = dinput;
194
195     newDevice->base.data_format.wine_df = &c_dfDIMouse2;
196     if (create_DataFormat(&c_dfDIMouse2, &newDevice->base.data_format) == DI_OK)
197     {
198         IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput);
199         return newDevice;
200     }
201
202     HeapFree(GetProcessHeap(), 0, newDevice);
203     return NULL;
204 }
205
206 static HRESULT mousedev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
207 {
208     if ((IsEqualGUID(&GUID_SysMouse,rguid)) ||             /* Generic Mouse */
209         (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
210         if ((riid == NULL) ||
211             IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
212             IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
213             IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
214             IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
215             *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput);
216             TRACE("Creating a Mouse device (%p)\n", *pdev);
217             if (!*pdev) return DIERR_OUTOFMEMORY;
218             return DI_OK;
219         } else
220             return DIERR_NOINTERFACE;
221     }
222     
223     return DIERR_DEVICENOTREG;
224 }
225
226 static HRESULT mousedev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
227 {
228     if ((IsEqualGUID(&GUID_SysMouse,rguid)) ||             /* Generic Mouse */
229         (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
230         if ((riid == NULL) ||
231             IsEqualGUID(&IID_IDirectInputDeviceW,riid) ||
232             IsEqualGUID(&IID_IDirectInputDevice2W,riid) ||
233             IsEqualGUID(&IID_IDirectInputDevice7W,riid) ||
234             IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
235             *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &SysMouseWvt, dinput);
236             TRACE("Creating a Mouse device (%p)\n", *pdev);
237             if (!*pdev) return DIERR_OUTOFMEMORY;
238             return DI_OK;
239         } else
240             return DIERR_NOINTERFACE;
241     }
242     
243     return DIERR_DEVICENOTREG;
244 }
245
246 const struct dinput_device mouse_device = {
247     "Wine mouse driver",
248     mousedev_enum_deviceA,
249     mousedev_enum_deviceW,
250     mousedev_create_deviceA,
251     mousedev_create_deviceW
252 };
253
254 /******************************************************************************
255  *      SysMouseA (DInput Mouse support)
256  */
257
258 /******************************************************************************
259   *     Release : release the mouse buffer.
260   */
261 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
262 {
263     SysMouseImpl *This = (SysMouseImpl *)iface;
264     ULONG ref;
265  
266     ref = InterlockedDecrement(&This->base.ref);
267     if (ref)
268         return ref;
269
270     set_dinput_hook(WH_MOUSE_LL, NULL);
271
272     /* Free the data queue */
273     HeapFree(GetProcessHeap(), 0, This->base.data_queue);
274
275     release_DataFormat(&This->base.data_format);
276
277     IDirectInput_Release((LPDIRECTINPUTDEVICE8A)This->dinput);
278     DeleteCriticalSection(&This->base.crit);
279     HeapFree(GetProcessHeap(),0,This);
280     return 0;
281 }
282
283 /* low-level mouse hook */
284 static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam )
285 {
286     MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
287     SysMouseImpl* This = (SysMouseImpl*) current_lock;
288     DWORD dwCoop;
289     int wdata;
290
291     if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam );
292
293     EnterCriticalSection(&This->base.crit);
294     dwCoop = This->base.dwCoopLevel;
295
296     switch(wparam) {
297         case WM_MOUSEMOVE:
298         {
299             POINT pt, pt1;
300
301             GetCursorPos(&pt);
302             This->m_state.lX += pt.x = hook->pt.x - pt.x;
303             This->m_state.lY += pt.y = hook->pt.y - pt.y;
304
305             if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)
306             {
307                 pt1.x = This->m_state.lX;
308                 pt1.y = This->m_state.lY;
309             } else
310                 pt1 = pt;
311
312             if (pt.x)
313                 queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_X_POSITION],
314                             pt1.x, hook->time, This->dinput->evsequence);
315             if (pt.y)
316                 queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_Y_POSITION],
317                             pt1.y, hook->time, This->dinput->evsequence);
318
319             This->need_warp = (pt.x || pt.y) && dwCoop & DISCL_EXCLUSIVE;
320             break;
321         }
322         case WM_LBUTTONDOWN:
323             queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_L_POSITION],
324                         0x80, hook->time, This->dinput->evsequence);
325             This->m_state.rgbButtons[0] = 0x80;
326             break;
327         case WM_LBUTTONUP:
328             queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_L_POSITION],
329                         0x00, hook->time, This->dinput->evsequence);
330             This->m_state.rgbButtons[0] = 0x00;
331             break;
332         case WM_RBUTTONDOWN:
333             queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_R_POSITION],
334                         0x80, hook->time, This->dinput->evsequence);
335             This->m_state.rgbButtons[1] = 0x80;
336             break;
337         case WM_RBUTTONUP:
338             queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_R_POSITION],
339                         0x00, hook->time, This->dinput->evsequence);
340             This->m_state.rgbButtons[1] = 0x00;
341             break;
342         case WM_MBUTTONDOWN:
343             queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_M_POSITION],
344                         0x80, hook->time, This->dinput->evsequence);
345             This->m_state.rgbButtons[2] = 0x80;
346             break;
347         case WM_MBUTTONUP:
348             queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_M_POSITION],
349                         0x00, hook->time, This->dinput->evsequence);
350             This->m_state.rgbButtons[2] = 0x00;
351             break;
352         case WM_MOUSEWHEEL:
353             wdata = (short)HIWORD(hook->mouseData);
354             queue_event((LPDIRECTINPUTDEVICE8A)This, This->base.data_format.offsets[WINE_MOUSE_Z_POSITION],
355                         wdata, hook->time, This->dinput->evsequence);
356             This->m_state.lZ += wdata;
357             break;
358     }
359
360     TRACE("msg %x @ (%d %d): (X: %d - Y: %d   L: %02x M: %02x R: %02x)\n",
361           wparam, hook->pt.x, hook->pt.y, This->m_state.lX, This->m_state.lY,
362           This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
363
364     This->dinput->evsequence++;
365
366     /* Mouse moved -> send event if asked */
367     if (This->base.hEvent) SetEvent(This->base.hEvent);
368
369     LeaveCriticalSection(&This->base.crit);
370     
371     /* Ignore message */
372     if (dwCoop & DISCL_EXCLUSIVE) return 1;
373
374     /* Pass the events down to previous handlers (e.g. win32 input) */
375     return CallNextHookEx( 0, code, wparam, lparam );
376 }
377
378 static BOOL dinput_window_check(SysMouseImpl* This) {
379     RECT rect;
380     DWORD centerX, centerY;
381
382     /* make sure the window hasn't moved */
383     if(!GetWindowRect(This->base.win, &rect))
384         return FALSE;
385     centerX = (rect.right  - rect.left) / 2;
386     centerY = (rect.bottom - rect.top ) / 2;
387     if (This->win_centerX != centerX || This->win_centerY != centerY) {
388         This->win_centerX = centerX;
389         This->win_centerY = centerY;
390     }
391     This->mapped_center.x = This->win_centerX;
392     This->mapped_center.y = This->win_centerY;
393     MapWindowPoints(This->base.win, HWND_DESKTOP, &This->mapped_center, 1);
394     return TRUE;
395 }
396
397
398 /******************************************************************************
399   *     Acquire : gets exclusive control of the mouse
400   */
401 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
402 {
403     SysMouseImpl *This = (SysMouseImpl *)iface;
404     RECT  rect;
405     POINT point;
406     HRESULT res;
407     
408     TRACE("(this=%p)\n",This);
409
410     if ((res = IDirectInputDevice2AImpl_Acquire(iface)) != DI_OK) return res;
411
412     /* Store (in a global variable) the current lock */
413     current_lock = (IDirectInputDevice8A*)This;
414     
415     /* Init the mouse state */
416     GetCursorPos( &point );
417     if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)
418     {
419       This->m_state.lX = point.x;
420       This->m_state.lY = point.y;
421     } else {
422       This->m_state.lX = 0;
423       This->m_state.lY = 0;
424       This->org_coords = point;
425     }
426     This->m_state.lZ = 0;
427     This->m_state.rgbButtons[0] = GetKeyState(VK_LBUTTON) & 0x80;
428     This->m_state.rgbButtons[1] = GetKeyState(VK_RBUTTON) & 0x80;
429     This->m_state.rgbButtons[2] = GetKeyState(VK_MBUTTON) & 0x80;
430     
431     /* Install our mouse hook */
432     if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
433       ShowCursor(FALSE); /* hide cursor */
434     set_dinput_hook(WH_MOUSE_LL, dinput_mouse_hook);
435     
436     /* Get the window dimension and find the center */
437     GetWindowRect(This->base.win, &rect);
438     This->win_centerX = (rect.right  - rect.left) / 2;
439     This->win_centerY = (rect.bottom - rect.top ) / 2;
440     
441     /* Warp the mouse to the center of the window */
442     if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
443     {
444       This->mapped_center.x = This->win_centerX;
445       This->mapped_center.y = This->win_centerY;
446       MapWindowPoints(This->base.win, HWND_DESKTOP, &This->mapped_center, 1);
447       TRACE("Warping mouse to %d - %d\n", This->mapped_center.x, This->mapped_center.y);
448       SetCursorPos( This->mapped_center.x, This->mapped_center.y );
449       This->last_warped = GetCurrentTime();
450
451       This->need_warp = FALSE;
452     }
453
454     return DI_OK;
455 }
456
457 /******************************************************************************
458   *     Unacquire : frees the mouse
459   */
460 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
461 {
462     SysMouseImpl *This = (SysMouseImpl *)iface;
463     HRESULT res;
464     
465     TRACE("(this=%p)\n",This);
466
467     if ((res = IDirectInputDevice2AImpl_Unacquire(iface)) != DI_OK) return res;
468
469     set_dinput_hook(WH_MOUSE_LL, NULL);
470     if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
471         ShowCursor(TRUE); /* show cursor */
472
473     /* No more locks */
474     if (current_lock == (IDirectInputDevice8A*) This)
475       current_lock = NULL;
476     else
477       ERR("this(%p) != current_lock(%p)\n", This, current_lock);
478
479     /* And put the mouse cursor back where it was at acquire time */
480     if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
481     {
482       TRACE(" warping mouse back to (%d , %d)\n", This->org_coords.x, This->org_coords.y);
483       SetCursorPos(This->org_coords.x, This->org_coords.y);
484     }
485         
486     return DI_OK;
487 }
488
489 /******************************************************************************
490   *     GetDeviceState : returns the "state" of the mouse.
491   *
492   *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
493   *   supported.
494   */
495 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
496         LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
497 ) {
498     SysMouseImpl *This = (SysMouseImpl *)iface;
499
500     if(This->base.acquired == 0) return DIERR_NOTACQUIRED;
501
502     EnterCriticalSection(&This->base.crit);
503     TRACE("(this=%p,0x%08x,%p):\n", This, len, ptr);
504     TRACE("(X: %d - Y: %d - Z: %d  L: %02x M: %02x R: %02x)\n",
505           This->m_state.lX, This->m_state.lY, This->m_state.lZ,
506           This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
507     
508     /* Copy the current mouse state */
509     fill_DataFormat(ptr, &(This->m_state), &This->base.data_format);
510     
511     /* Initialize the buffer when in relative mode */
512     if (!(This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS))
513     {
514         This->m_state.lX = 0;
515         This->m_state.lY = 0;
516         This->m_state.lZ = 0;
517     }
518
519     /* Check if we need to do a mouse warping */
520     if (This->need_warp && (GetCurrentTime() - This->last_warped > 10))
521     {
522         if(!dinput_window_check(This))
523         {
524             LeaveCriticalSection(&This->base.crit);
525             return DIERR_GENERIC;
526         }
527         TRACE("Warping mouse to %d - %d\n", This->mapped_center.x, This->mapped_center.y);
528         SetCursorPos( This->mapped_center.x, This->mapped_center.y );
529         This->last_warped = GetCurrentTime();
530
531         This->need_warp = FALSE;
532     }
533
534     LeaveCriticalSection(&This->base.crit);
535     
536     return DI_OK;
537 }
538
539 /******************************************************************************
540   *     GetDeviceData : gets buffered input data.
541   */
542 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
543         DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
544 {
545     SysMouseImpl *This = (SysMouseImpl *)iface;
546     HRESULT res;
547
548     res = IDirectInputDevice2AImpl_GetDeviceData(iface, dodsize, dod, entries, flags);
549     if (FAILED(res)) return res;
550
551     /* Check if we need to do a mouse warping */
552     if (This->need_warp && (GetCurrentTime() - This->last_warped > 10))
553     {
554         if(!dinput_window_check(This))
555             return DIERR_GENERIC;
556         TRACE("Warping mouse to %d - %d\n", This->mapped_center.x, This->mapped_center.y);
557         SetCursorPos( This->mapped_center.x, This->mapped_center.y );
558         This->last_warped = GetCurrentTime();
559
560         This->need_warp = FALSE;
561     }
562     return res;
563 }
564
565 /******************************************************************************
566   *     GetProperty : get input device properties
567   */
568 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
569                                                 REFGUID rguid,
570                                                 LPDIPROPHEADER pdiph)
571 {
572     SysMouseImpl *This = (SysMouseImpl *)iface;
573     
574     TRACE("(%p) %s,%p\n", This, debugstr_guid(rguid), pdiph);
575     _dump_DIPROPHEADER(pdiph);
576     
577     if (!HIWORD(rguid)) {
578         switch (LOWORD(rguid)) {
579             case (DWORD) DIPROP_GRANULARITY: {
580                 LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph;
581                 
582                 /* We'll just assume that the app asks about the Z axis */
583                 pr->dwData = WHEEL_DELTA;
584                 
585                 break;
586             }
587               
588             case (DWORD) DIPROP_RANGE: {
589                 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
590                 
591                 if ((pdiph->dwHow == DIPH_BYID) &&
592                     ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
593                      (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
594                     /* Querying the range of either the X or the Y axis.  As I do
595                        not know the range, do as if the range were
596                        unrestricted...*/
597                     pr->lMin = DIPROPRANGE_NOMIN;
598                     pr->lMax = DIPROPRANGE_NOMAX;
599                 }
600                 
601                 break;
602             }
603
604             default:
605                 return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph);
606         }
607     }
608     
609     return DI_OK;
610 }
611
612 /******************************************************************************
613   *     GetCapabilities : get the device capablitites
614   */
615 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
616         LPDIRECTINPUTDEVICE8A iface,
617         LPDIDEVCAPS lpDIDevCaps)
618 {
619     SysMouseImpl *This = (SysMouseImpl *)iface;
620     DIDEVCAPS devcaps;
621
622     TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
623
624     if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) {
625         WARN("invalid parameter\n");
626         return DIERR_INVALIDPARAM;
627     }
628
629     devcaps.dwSize = lpDIDevCaps->dwSize;
630     devcaps.dwFlags = DIDC_ATTACHED;
631     if (This->dinput->dwVersion >= 0x0800)
632         devcaps.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
633     else
634         devcaps.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
635     devcaps.dwAxes = 3;
636     devcaps.dwButtons = 3;
637     devcaps.dwPOVs = 0;
638     devcaps.dwFFSamplePeriod = 0;
639     devcaps.dwFFMinTimeResolution = 0;
640     devcaps.dwFirmwareRevision = 100;
641     devcaps.dwHardwareRevision = 100;
642     devcaps.dwFFDriverVersion = 0;
643
644     memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize);
645     
646     return DI_OK;
647 }
648
649
650 /******************************************************************************
651   *     EnumObjects : enumerate the different buttons and axis...
652   */
653 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
654         LPDIRECTINPUTDEVICE8A iface,
655         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
656         LPVOID lpvRef,
657         DWORD dwFlags)
658 {
659     SysMouseImpl *This = (SysMouseImpl *)iface;
660     DIDEVICEOBJECTINSTANCEA ddoi;
661     
662     TRACE("(this=%p,%p,%p,%08x)\n", This, lpCallback, lpvRef, dwFlags);
663     if (TRACE_ON(dinput)) {
664         TRACE("  - flags = ");
665         _dump_EnumObjects_flags(dwFlags);
666         TRACE("\n");
667     }
668     
669     /* Only the fields till dwFFMaxForce are relevant */
670     memset(&ddoi, 0, sizeof(ddoi));
671     ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
672     
673     /* In a mouse, we have : two relative axis and three buttons */
674     if ((dwFlags == DIDFT_ALL) ||
675         (dwFlags & DIDFT_AXIS)) {
676         /* X axis */
677         ddoi.guidType = GUID_XAxis;
678         ddoi.dwOfs = This->base.data_format.offsets[WINE_MOUSE_X_POSITION];
679         ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
680         strcpy(ddoi.tszName, "X-Axis");
681         _dump_OBJECTINSTANCEA(&ddoi);
682         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
683         
684         /* Y axis */
685         ddoi.guidType = GUID_YAxis;
686         ddoi.dwOfs = This->base.data_format.offsets[WINE_MOUSE_Y_POSITION];
687         ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
688         strcpy(ddoi.tszName, "Y-Axis");
689         _dump_OBJECTINSTANCEA(&ddoi);
690         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
691         
692         /* Z axis */
693         ddoi.guidType = GUID_ZAxis;
694         ddoi.dwOfs = This->base.data_format.offsets[WINE_MOUSE_Z_POSITION];
695         ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS;
696         strcpy(ddoi.tszName, "Z-Axis");
697         _dump_OBJECTINSTANCEA(&ddoi);
698         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
699     }
700
701     if ((dwFlags == DIDFT_ALL) ||
702         (dwFlags & DIDFT_BUTTON)) {
703         ddoi.guidType = GUID_Button;
704         
705         /* Left button */
706         ddoi.dwOfs = This->base.data_format.offsets[WINE_MOUSE_L_POSITION];
707         ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
708         strcpy(ddoi.tszName, "Left-Button");
709         _dump_OBJECTINSTANCEA(&ddoi);
710         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
711         
712         /* Right button */
713         ddoi.dwOfs = This->base.data_format.offsets[WINE_MOUSE_R_POSITION];
714         ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
715         strcpy(ddoi.tszName, "Right-Button");
716         _dump_OBJECTINSTANCEA(&ddoi);
717         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
718         
719         /* Middle button */
720         ddoi.dwOfs = This->base.data_format.offsets[WINE_MOUSE_M_POSITION];
721         ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
722         strcpy(ddoi.tszName, "Middle-Button");
723         _dump_OBJECTINSTANCEA(&ddoi);
724         if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
725     }
726     
727     return DI_OK;
728 }
729
730 static HRESULT WINAPI SysMouseWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef,DWORD dwFlags)
731 {
732     SysMouseImpl *This = (SysMouseImpl *)iface;
733     
734     device_enumobjects_AtoWcb_data data;
735     
736     data.lpCallBack = lpCallback;
737     data.lpvRef = lpvRef;
738     
739     return SysMouseAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags);
740 }
741
742 /******************************************************************************
743   *     GetDeviceInfo : get information about a device's identity
744   */
745 static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo(
746         LPDIRECTINPUTDEVICE8A iface,
747         LPDIDEVICEINSTANCEA pdidi)
748 {
749     SysMouseImpl *This = (SysMouseImpl *)iface;
750     TRACE("(this=%p,%p)\n", This, pdidi);
751
752     if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) {
753         WARN(" dinput3 not supporte yet...\n");
754         return DI_OK;
755     }
756
757     fill_mouse_dideviceinstanceA(pdidi, This->dinput->dwVersion);
758     
759     return DI_OK;
760 }
761
762 static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi)
763 {
764     SysMouseImpl *This = (SysMouseImpl *)iface;
765     TRACE("(this=%p,%p)\n", This, pdidi);
766
767     if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) {
768         WARN(" dinput3 not supporte yet...\n");
769         return DI_OK;
770     }
771
772     fill_mouse_dideviceinstanceW(pdidi, This->dinput->dwVersion);
773     
774     return DI_OK;
775 }
776
777
778 static const IDirectInputDevice8AVtbl SysMouseAvt =
779 {
780     IDirectInputDevice2AImpl_QueryInterface,
781     IDirectInputDevice2AImpl_AddRef,
782     SysMouseAImpl_Release,
783     SysMouseAImpl_GetCapabilities,
784     SysMouseAImpl_EnumObjects,
785     SysMouseAImpl_GetProperty,
786     IDirectInputDevice2AImpl_SetProperty,
787     SysMouseAImpl_Acquire,
788     SysMouseAImpl_Unacquire,
789     SysMouseAImpl_GetDeviceState,
790     SysMouseAImpl_GetDeviceData,
791     IDirectInputDevice2AImpl_SetDataFormat,
792     IDirectInputDevice2AImpl_SetEventNotification,
793     IDirectInputDevice2AImpl_SetCooperativeLevel,
794     IDirectInputDevice2AImpl_GetObjectInfo,
795     SysMouseAImpl_GetDeviceInfo,
796     IDirectInputDevice2AImpl_RunControlPanel,
797     IDirectInputDevice2AImpl_Initialize,
798     IDirectInputDevice2AImpl_CreateEffect,
799     IDirectInputDevice2AImpl_EnumEffects,
800     IDirectInputDevice2AImpl_GetEffectInfo,
801     IDirectInputDevice2AImpl_GetForceFeedbackState,
802     IDirectInputDevice2AImpl_SendForceFeedbackCommand,
803     IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
804     IDirectInputDevice2AImpl_Escape,
805     IDirectInputDevice2AImpl_Poll,
806     IDirectInputDevice2AImpl_SendDeviceData,
807     IDirectInputDevice7AImpl_EnumEffectsInFile,
808     IDirectInputDevice7AImpl_WriteEffectToFile,
809     IDirectInputDevice8AImpl_BuildActionMap,
810     IDirectInputDevice8AImpl_SetActionMap,
811     IDirectInputDevice8AImpl_GetImageInfo
812 };
813
814 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
815 # define XCAST(fun)     (typeof(SysMouseWvt.fun))
816 #else
817 # define XCAST(fun)     (void*)
818 #endif
819
820 static const IDirectInputDevice8WVtbl SysMouseWvt =
821 {
822     IDirectInputDevice2WImpl_QueryInterface,
823     XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
824     XCAST(Release)SysMouseAImpl_Release,
825     XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities,
826     SysMouseWImpl_EnumObjects,
827     XCAST(GetProperty)SysMouseAImpl_GetProperty,
828     XCAST(SetProperty)IDirectInputDevice2AImpl_SetProperty,
829     XCAST(Acquire)SysMouseAImpl_Acquire,
830     XCAST(Unacquire)SysMouseAImpl_Unacquire,
831     XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState,
832     XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData,
833     XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
834     XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
835     XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
836     IDirectInputDevice2WImpl_GetObjectInfo,
837     SysMouseWImpl_GetDeviceInfo,
838     XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
839     XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
840     XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
841     IDirectInputDevice2WImpl_EnumEffects,
842     IDirectInputDevice2WImpl_GetEffectInfo,
843     XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
844     XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
845     XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
846     XCAST(Escape)IDirectInputDevice2AImpl_Escape,
847     XCAST(Poll)IDirectInputDevice2AImpl_Poll,
848     XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
849     IDirectInputDevice7WImpl_EnumEffectsInFile,
850     IDirectInputDevice7WImpl_WriteEffectToFile,
851     IDirectInputDevice8WImpl_BuildActionMap,
852     IDirectInputDevice8WImpl_SetActionMap,
853     IDirectInputDevice8WImpl_GetImageInfo
854 };
855 #undef XCAST