Better implementation of GetCalendarInfo{A,W}, not perfect.
[wine] / dlls / dinput / mouse / main.c
1 /*              DirectInput Mouse device
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include <string.h>
23 #ifdef HAVE_SYS_ERRNO_H
24 # include <sys/errno.h>
25 #endif
26
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "dinput.h"
32
33 #include "dinput_private.h"
34 #include "device_private.h"
35 #include "wine/debug.h"
36
37 #define MOUSE_HACK
38
39 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
40
41 /* Wine mouse driver object instances */
42 #define WINE_MOUSE_X_AXIS_INSTANCE 0x0001
43 #define WINE_MOUSE_Y_AXIS_INSTANCE 0x0002
44 #define WINE_MOUSE_L_BUTTON_INSTANCE 0x0004
45 #define WINE_MOUSE_R_BUTTON_INSTANCE 0x0008
46 #define WINE_MOUSE_M_BUTTON_INSTANCE 0x0010
47
48 /* ------------------------------- */
49 /* Wine mouse internal data format */
50 /* ------------------------------- */
51
52 /* Constants used to access the offset array */
53 #define WINE_MOUSE_X_POSITION 0
54 #define WINE_MOUSE_Y_POSITION 1
55 #define WINE_MOUSE_L_POSITION 2
56 #define WINE_MOUSE_R_POSITION 3
57 #define WINE_MOUSE_M_POSITION 4
58
59 typedef struct {
60   LONG lX;
61   LONG lY;
62   BYTE rgbButtons[4];
63 } Wine_InternalMouseData;
64
65 #define WINE_INTERNALMOUSE_NUM_OBJS 5
66
67 static DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = {
68   { &GUID_XAxis,   FIELD_OFFSET(Wine_InternalMouseData, lX),
69       DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
70   { &GUID_YAxis,   FIELD_OFFSET(Wine_InternalMouseData, lY),
71       DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
72   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0,
73       DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
74   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1,
75       DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
76   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2,
77       DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }
78 };
79
80 static DIDATAFORMAT Wine_InternalMouseFormat = {
81   0, /* dwSize - unused */
82   0, /* dwObjsize - unused */
83   0, /* dwFlags - unused */
84   sizeof(Wine_InternalMouseData),
85   WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */
86   Wine_InternalMouseObjectFormat
87 };
88
89 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt;
90 static ICOM_VTABLE(IDirectInputDevice7A) SysMouse7Avt;
91 typedef struct SysMouseAImpl SysMouseAImpl;
92
93 typedef enum {
94   WARP_NEEDED,  /* Warping is needed */
95   WARP_STARTED, /* Warping has been done, waiting for the warp event */
96   WARP_DONE     /* Warping has been done */
97 } WARP_STATUS;
98
99 struct SysMouseAImpl
100 {
101         /* IDirectInputDevice2AImpl */
102         ICOM_VFIELD(IDirectInputDevice2A);
103         DWORD                           ref;
104         GUID                            guid;
105
106         IDirectInputAImpl *dinput;
107         
108         /* The current data format and the conversion between internal
109            and external data formats */
110         LPDIDATAFORMAT                  df;
111         DataFormat                     *wine_df;
112         int                             offset_array[5];
113         
114         /* SysMouseAImpl */
115         BYTE                            absolute;
116         /* Previous position for relative moves */
117         LONG                            prevX, prevY;
118         HHOOK                           hook;
119         HWND                            win;
120         DWORD                           dwCoopLevel;
121         POINT                           mapped_center;
122         DWORD                           win_centerX, win_centerY;
123         LPDIDEVICEOBJECTDATA            data_queue;
124         int                             queue_head, queue_tail, queue_len;
125         /* warping: whether we need to move mouse back to middle once we
126          * reach window borders (for e.g. shooters, "surface movement" games) */
127         WARP_STATUS                     need_warp;
128         int                             acquired;
129         HANDLE                          hEvent;
130         CRITICAL_SECTION                crit;
131
132         /* This is for mouse reporting. */
133         Wine_InternalMouseData          m_state;
134 };
135
136 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
137   0x9e573ed8,
138   0x7734,
139   0x11d2,
140   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
141 };
142
143 /* FIXME: This is ugly and not thread safe :/ */
144 static IDirectInputDevice2A* current_lock = NULL;
145
146
147 static BOOL mousedev_enum_device(DWORD dwDevType, DWORD dwFlags, LPCDIDEVICEINSTANCEA lpddi)
148 {
149   if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_MOUSE)) {
150     TRACE("Enumerating the mouse device\n");
151
152     /* Return mouse */
153     lpddi->guidInstance = GUID_SysMouse;/* DInput's GUID */
154     lpddi->guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
155     lpddi->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
156     strcpy(lpddi->tszInstanceName, "Mouse");
157     strcpy(lpddi->tszProductName, "Wine Mouse");
158
159     return TRUE;
160   }
161
162   return FALSE;
163 }
164
165 static SysMouseAImpl *alloc_device(REFGUID rguid, ICOM_VTABLE(IDirectInputDevice2A) *mvt, IDirectInputAImpl *dinput)
166 {
167     int offset_array[5] = {
168       FIELD_OFFSET(Wine_InternalMouseData, lX),
169       FIELD_OFFSET(Wine_InternalMouseData, lY),
170       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0,
171       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1,
172       FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2
173     };
174     SysMouseAImpl* newDevice;
175     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
176     newDevice->ref = 1;
177     ICOM_VTBL(newDevice) = mvt;
178     InitializeCriticalSection(&(newDevice->crit));
179     memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
180     
181     /* Per default, Wine uses its internal data format */
182     newDevice->df = &Wine_InternalMouseFormat;
183     memcpy(newDevice->offset_array, offset_array, 5 * sizeof(int));
184     newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
185     newDevice->wine_df->size = 0;
186     newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize;
187     newDevice->wine_df->dt = NULL;
188     newDevice->dinput = dinput;
189
190     return newDevice;
191 }
192
193 static HRESULT mousedev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
194 {
195   if ((IsEqualGUID(&GUID_SysMouse,rguid)) ||             /* Generic Mouse */
196       (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
197     if ((riid == NULL) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid))) {
198       *pdev=(IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput);
199     
200       TRACE("Creating a Mouse device (%p)\n", *pdev);
201       return DI_OK;
202     }else if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
203       *pdev=(IDirectInputDeviceA*) alloc_device(rguid, (ICOM_VTABLE(IDirectInputDevice2A) *) &SysMouse7Avt, dinput);
204     
205       TRACE("Creating a Mouse DInput7A device (%p)\n", *pdev);
206       return DI_OK;
207     } else
208       return DIERR_NOINTERFACE;
209   }
210
211   return DIERR_DEVICENOTREG;
212 }
213
214 static dinput_device mousedev = {
215   100,
216   mousedev_enum_device,
217   mousedev_create_device
218 };
219
220 DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); }
221
222 /******************************************************************************
223  *      SysMouseA (DInput Mouse support)
224  */
225
226 /******************************************************************************
227   *     Release : release the mouse buffer.
228   */
229 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
230 {
231         ICOM_THIS(SysMouseAImpl,iface);
232
233         This->ref--;
234         if (This->ref)
235                 return This->ref;
236
237         /* Free the data queue */
238         if (This->data_queue != NULL)
239           HeapFree(GetProcessHeap(),0,This->data_queue);
240
241         if (This->hook) UnhookWindowsHookEx( This->hook );
242         DeleteCriticalSection(&(This->crit));
243
244         /* Free the DataFormat */
245         if (This->df != &(Wine_InternalMouseFormat)) {
246           HeapFree(GetProcessHeap(), 0, This->df->rgodf);
247           HeapFree(GetProcessHeap(), 0, This->df);
248         }
249         
250         HeapFree(GetProcessHeap(),0,This);
251         return 0;
252 }
253
254
255 /******************************************************************************
256   *     SetCooperativeLevel : store the window in which we will do our
257   *   grabbing.
258   */
259 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
260         LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
261 )
262 {
263   ICOM_THIS(SysMouseAImpl,iface);
264
265   TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
266
267   if (TRACE_ON(dinput))
268     _dump_cooperativelevel_DI(dwflags);
269
270   /* Store the window which asks for the mouse */
271   if (!hwnd)
272     hwnd = GetDesktopWindow();
273   This->win = hwnd;
274   This->dwCoopLevel = dwflags;
275   
276   return 0;
277 }
278
279
280 /******************************************************************************
281   *     SetDataFormat : the application can choose the format of the data
282   *   the device driver sends back with GetDeviceState.
283   *
284   *   For the moment, only the "standard" configuration (c_dfDIMouse) is supported
285   *   in absolute and relative mode.
286   */
287 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
288         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
289 )
290 {
291   ICOM_THIS(SysMouseAImpl,iface);
292   int i;
293   
294   TRACE("(this=%p,%p)\n",This,df);
295
296   TRACE("(df.dwSize=%ld)\n",df->dwSize);
297   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
298   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
299   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
300   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
301
302   for (i=0;i<df->dwNumObjs;i++) {
303
304     TRACE("df.rgodf[%d].guid %s (%p)\n",i, debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
305     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
306     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
307     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
308   }
309
310   /* Check if the mouse is in absolute or relative mode */
311   if (df->dwFlags == DIDF_ABSAXIS)
312     This->absolute = 1;
313   else if (df->dwFlags == DIDF_RELAXIS)
314     This->absolute = 0;
315   else
316     ERR("Neither absolute nor relative flag set\n");
317
318   /* Store the new data format */
319   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
320   memcpy(This->df, df, df->dwSize);
321   This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
322   memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
323
324   /* Prepare all the data-conversion filters */
325   This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array);
326   
327   return 0;
328 }
329   
330 /* low-level mouse hook */
331 static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam )
332 {
333     LRESULT ret;
334     MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
335     SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
336
337     if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam );
338
339     EnterCriticalSection(&(This->crit));
340     /* Mouse moved -> send event if asked */
341     if (This->hEvent)
342         SetEvent(This->hEvent);
343
344     if (wparam == WM_MOUSEMOVE) {
345         if (This->absolute) {
346           if (hook->pt.x != This->prevX)
347             GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0);
348           if (hook->pt.y != This->prevY)
349             GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0);
350         } else {
351           /* Now, warp handling */
352           if ((This->need_warp == WARP_STARTED) &&
353               (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) {
354             /* Warp has been done... */
355             This->need_warp = WARP_DONE;
356             goto end;
357           }
358                   
359           /* Relative mouse input with absolute mouse event : the real fun starts here... */
360           if ((This->need_warp == WARP_NEEDED) ||
361               (This->need_warp == WARP_STARTED)) {
362             if (hook->pt.x != This->prevX)
363               GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, hook->time, (This->dinput->evsequence)++);
364             if (hook->pt.y != This->prevY)
365               GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, hook->time, (This->dinput->evsequence)++);
366           } else {
367             /* This is the first time the event handler has been called after a
368                GetDeviceData or GetDeviceState. */
369             if (hook->pt.x != This->mapped_center.x) {
370               GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, hook->time, (This->dinput->evsequence)++);
371               This->need_warp = WARP_NEEDED;
372             }
373             
374             if (hook->pt.y != This->mapped_center.y) {
375               GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, hook->time, (This->dinput->evsequence)++);
376               This->need_warp = WARP_NEEDED;
377             }
378           }
379         }
380
381         This->prevX = hook->pt.x;
382         This->prevY = hook->pt.y;
383         
384         if (This->absolute) {
385           This->m_state.lX = hook->pt.x;
386           This->m_state.lY = hook->pt.y;
387         } else {
388           This->m_state.lX = hook->pt.x - This->mapped_center.x;
389           This->m_state.lY = hook->pt.y - This->mapped_center.y;
390         }
391     }
392
393     TRACE(" msg %x pt %ld %ld (W=%d)\n",
394           wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp );
395
396     switch(wparam)
397     {
398     case WM_LBUTTONDOWN:
399         GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF,
400                   hook->time, This->dinput->evsequence++);
401         This->m_state.rgbButtons[0] = 0xFF;
402         break;
403     case WM_LBUTTONUP:
404         GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00,
405                   hook->time, This->dinput->evsequence++);
406         This->m_state.rgbButtons[0] = 0x00;
407         break;
408     case WM_RBUTTONDOWN:
409         GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF,
410                   hook->time, This->dinput->evsequence++);
411         This->m_state.rgbButtons[1] = 0xFF;
412         break;
413     case WM_RBUTTONUP:
414         GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00,
415                   hook->time, This->dinput->evsequence++);
416         This->m_state.rgbButtons[1] = 0x00;
417         break;
418     case WM_MBUTTONDOWN:
419         GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF,
420                   hook->time, This->dinput->evsequence++);
421         This->m_state.rgbButtons[2] = 0xFF;
422         break;
423     case WM_MBUTTONUP:
424         GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00,
425                   hook->time, This->dinput->evsequence++);
426         This->m_state.rgbButtons[2] = 0x00;
427         break;
428     }
429
430   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
431         This->m_state.lX, This->m_state.lY,
432         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
433
434 end:
435   if (This->dwCoopLevel & DISCL_NONEXCLUSIVE)
436   { /* pass the events down to previous handlers (e.g. win32 input) */
437       ret = CallNextHookEx( This->hook, code, wparam, lparam );
438   }
439   else ret = 1;  /* ignore message */
440   LeaveCriticalSection(&(This->crit));
441   return ret;
442 }
443
444
445 /******************************************************************************
446   *     Acquire : gets exclusive control of the mouse
447   */
448 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
449 {
450   ICOM_THIS(SysMouseAImpl,iface);
451   RECT  rect;
452   
453   TRACE("(this=%p)\n",This);
454
455   if (This->acquired == 0) {
456     POINT point;
457
458     /* Store (in a global variable) the current lock */
459     current_lock = (IDirectInputDevice2A*)This;
460
461     /* Init the mouse state */
462     if (This->absolute) {
463       GetCursorPos( &point );
464       This->m_state.lX = point.x;
465       This->m_state.lY = point.y;
466       This->prevX = point.x;
467       This->prevY = point.y;
468     } else {
469       This->m_state.lX = 0;
470       This->m_state.lY = 0;
471     }
472     This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
473     This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
474     This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
475
476     /* Install our mouse hook */
477     This->hook = SetWindowsHookExW( WH_MOUSE_LL, dinput_mouse_hook, 0, 0 );
478
479     /* Get the window dimension and find the center */
480     GetWindowRect(This->win, &rect);
481     This->win_centerX = (rect.right  - rect.left) / 2;
482     This->win_centerY = (rect.bottom - rect.top ) / 2;
483
484     /* Warp the mouse to the center of the window */
485     if (This->absolute == 0) {
486       This->mapped_center.x = This->win_centerX;
487       This->mapped_center.y = This->win_centerY;
488       MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
489       TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); 
490       SetCursorPos( This->mapped_center.x, This->mapped_center.y );
491 #ifdef MOUSE_HACK
492       This->need_warp = WARP_DONE;
493 #else
494       This->need_warp = WARP_STARTED;
495 #endif
496     }
497
498     This->acquired = 1;
499   }
500   return DI_OK;
501 }
502
503 /******************************************************************************
504   *     Unacquire : frees the mouse
505   */
506 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
507 {
508     ICOM_THIS(SysMouseAImpl,iface);
509
510     TRACE("(this=%p)\n",This);
511
512     if (This->acquired)
513     {
514         /* Reinstall previous mouse event handler */
515         if (This->hook) UnhookWindowsHookEx( This->hook );
516         This->hook = 0;
517
518         /* No more locks */
519         current_lock = NULL;
520
521         /* Unacquire device */
522         This->acquired = 0;
523     }
524     else
525         ERR("Unacquiring a not-acquired device !!!\n");
526   
527     return DI_OK;
528 }
529
530 /******************************************************************************
531   *     GetDeviceState : returns the "state" of the mouse.
532   *
533   *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
534   *   supported.
535   */
536 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
537         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
538 ) {
539   ICOM_THIS(SysMouseAImpl,iface);
540   
541   EnterCriticalSection(&(This->crit));
542   TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
543   
544   /* Copy the current mouse state */
545   fill_DataFormat(ptr, &(This->m_state), This->wine_df);
546   
547   /* Initialize the buffer when in relative mode */
548   if (This->absolute == 0) {
549     This->m_state.lX = 0;
550     This->m_state.lY = 0;
551   }
552
553   /* Check if we need to do a mouse warping */
554   if (This->need_warp == WARP_NEEDED) {
555     This->mapped_center.x = This->win_centerX;
556     This->mapped_center.y = This->win_centerY;
557     MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
558     TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); 
559     SetCursorPos( This->mapped_center.x, This->mapped_center.y );
560
561 #ifdef MOUSE_HACK
562     This->need_warp = WARP_DONE;
563 #else
564     This->need_warp = WARP_STARTED;
565 #endif
566   }
567
568   LeaveCriticalSection(&(This->crit));
569   
570   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
571         This->m_state.lX, This->m_state.lY,
572         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
573   
574   return 0;
575 }
576
577 /******************************************************************************
578   *     GetDeviceState : gets buffered input data.
579   */
580 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
581                                               DWORD dodsize,
582                                               LPDIDEVICEOBJECTDATA dod,
583                                               LPDWORD entries,
584                                               DWORD flags
585 ) {
586   ICOM_THIS(SysMouseAImpl,iface);
587   DWORD len, nqtail;
588   
589   EnterCriticalSection(&(This->crit));
590   TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
591
592   len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
593       + (This->queue_head - This->queue_tail);
594   if (len > *entries) len = *entries;
595
596   if (dod == NULL) {
597     *entries = len;
598     nqtail = This->queue_tail + len;
599     while (nqtail >= This->queue_len) nqtail -= This->queue_len;
600   } else {
601     if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
602       ERR("Wrong structure size !\n");
603       LeaveCriticalSection(&(This->crit));
604       return DIERR_INVALIDPARAM;
605     }
606
607     if (len)
608         TRACE("Application retrieving %ld event(s).\n", len); 
609
610     *entries = 0;
611     nqtail = This->queue_tail;
612     while (len) {
613       DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
614                  - nqtail;
615       if (span > len) span = len;
616       /* Copy the buffered data into the application queue */
617       memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
618       /* Advance position */
619       nqtail += span;
620       if (nqtail >= This->queue_len) nqtail -= This->queue_len;
621       *entries += span;
622       len -= span;
623     }
624   }
625   if (!(flags & DIGDD_PEEK))
626     This->queue_tail = nqtail;
627
628   LeaveCriticalSection(&(This->crit));
629
630   /* Check if we need to do a mouse warping */
631   if (This->need_warp == WARP_NEEDED) {
632     This->mapped_center.x = This->win_centerX;
633     This->mapped_center.y = This->win_centerY;
634     MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
635     TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); 
636     SetCursorPos( This->mapped_center.x, This->mapped_center.y );
637
638 #ifdef MOUSE_HACK
639     This->need_warp = WARP_DONE;
640 #else
641     This->need_warp = WARP_STARTED;
642 #endif
643   }
644   return 0;
645 }
646
647 /******************************************************************************
648   *     SetProperty : change input device properties
649   */
650 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
651                                             REFGUID rguid,
652                                             LPCDIPROPHEADER ph)
653 {
654   ICOM_THIS(SysMouseAImpl,iface);
655
656   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
657   
658   if (!HIWORD(rguid)) {
659     switch ((DWORD)rguid) {
660     case (DWORD) DIPROP_BUFFERSIZE: {
661       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
662       
663       TRACE("buffersize = %ld\n",pd->dwData);
664
665       This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
666                                                           pd->dwData * sizeof(DIDEVICEOBJECTDATA));
667       This->queue_head = 0;
668       This->queue_tail = 0;
669       This->queue_len  = pd->dwData;
670       break;
671     }
672     case (DWORD) DIPROP_AXISMODE: {
673       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
674       This->absolute = !(pd->dwData);
675       TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative");
676       break;
677     }
678     default:
679       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
680       break;
681     }
682   }
683   
684   return 0;
685 }
686
687 /******************************************************************************
688   *     GetProperty : get input device properties
689   */
690 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE2A iface,
691                                                 REFGUID rguid,
692                                                 LPDIPROPHEADER pdiph)
693 {
694   ICOM_THIS(SysMouseAImpl,iface);
695
696   TRACE("(this=%p,%s,%p): stub!\n",
697         iface, debugstr_guid(rguid), pdiph);
698
699   if (TRACE_ON(dinput))
700     _dump_DIPROPHEADER(pdiph);
701   
702   if (!HIWORD(rguid)) {
703     switch ((DWORD)rguid) {
704     case (DWORD) DIPROP_BUFFERSIZE: {
705       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
706       
707       TRACE(" return buffersize = %d\n",This->queue_len);
708       pd->dwData = This->queue_len;
709       break;
710     }
711
712     case (DWORD) DIPROP_RANGE: {
713       LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
714
715       if ((pdiph->dwHow == DIPH_BYID) &&
716           ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
717            (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
718         /* Querying the range of either the X or the Y axis.  As I do
719            not know the range, do as if the range were
720            unrestricted...*/
721         pr->lMin = DIPROPRANGE_NOMIN;
722         pr->lMax = DIPROPRANGE_NOMAX;
723       }
724       
725       break;
726     }
727       
728     default:
729       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
730       break;
731     }
732   }
733   
734   
735   return DI_OK;
736 }
737
738
739
740 /******************************************************************************
741   *     SetEventNotification : specifies event to be sent on state change
742   */
743 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
744                                                          HANDLE hnd) {
745   ICOM_THIS(SysMouseAImpl,iface);
746
747   TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
748
749   This->hEvent = hnd;
750
751   return DI_OK;
752 }
753
754 /******************************************************************************
755   *     GetCapabilities : get the device capablitites
756   */
757 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
758         LPDIRECTINPUTDEVICE2A iface,
759         LPDIDEVCAPS lpDIDevCaps)
760 {
761   ICOM_THIS(SysMouseAImpl,iface);
762
763   TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
764
765   if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
766     lpDIDevCaps->dwFlags = DIDC_ATTACHED;
767     lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
768     lpDIDevCaps->dwAxes = 2;
769     lpDIDevCaps->dwButtons = 3;
770     lpDIDevCaps->dwPOVs = 0;
771     lpDIDevCaps->dwFFSamplePeriod = 0;
772     lpDIDevCaps->dwFFMinTimeResolution = 0;
773     lpDIDevCaps->dwFirmwareRevision = 100;
774     lpDIDevCaps->dwHardwareRevision = 100;
775     lpDIDevCaps->dwFFDriverVersion = 0;
776   } else {
777     /* DirectX 3.0 */
778     FIXME("DirectX 3.0 not supported....\n");
779   }
780   
781   return DI_OK;
782 }
783
784
785 /******************************************************************************
786   *     EnumObjects : enumerate the different buttons and axis...
787   */
788 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
789         LPDIRECTINPUTDEVICE2A iface,
790         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
791         LPVOID lpvRef,
792         DWORD dwFlags)
793 {
794   ICOM_THIS(SysMouseAImpl,iface);
795   DIDEVICEOBJECTINSTANCEA ddoi;
796   
797   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
798   if (TRACE_ON(dinput)) {
799     DPRINTF("  - flags = ");
800     _dump_EnumObjects_flags(dwFlags);
801     DPRINTF("\n");
802   }
803
804   /* Only the fields till dwFFMaxForce are relevant */
805   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
806     
807   /* In a mouse, we have : two relative axis and three buttons */
808   if ((dwFlags == DIDFT_ALL) ||
809       (dwFlags & DIDFT_AXIS)) {
810     /* X axis */
811     ddoi.guidType = GUID_XAxis;
812     ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
813     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
814     strcpy(ddoi.tszName, "X-Axis");
815     _dump_OBJECTINSTANCEA(&ddoi);
816     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
817     
818     /* Y axis */
819     ddoi.guidType = GUID_YAxis;
820     ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
821     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
822     strcpy(ddoi.tszName, "Y-Axis");
823     _dump_OBJECTINSTANCEA(&ddoi);
824     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
825   }
826
827   if ((dwFlags == DIDFT_ALL) ||
828       (dwFlags & DIDFT_BUTTON)) {
829     ddoi.guidType = GUID_Button;
830
831     /* Left button */
832     ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
833     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
834     strcpy(ddoi.tszName, "Left-Button");
835     _dump_OBJECTINSTANCEA(&ddoi);
836     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
837
838     /* Right button */
839     ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
840     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
841     strcpy(ddoi.tszName, "Right-Button");
842     _dump_OBJECTINSTANCEA(&ddoi);
843     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
844
845     /* Middle button */
846     ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
847     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
848     strcpy(ddoi.tszName, "Middle-Button");
849     _dump_OBJECTINSTANCEA(&ddoi);
850     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
851   }
852
853   return DI_OK;
854 }
855
856
857 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt = 
858 {
859         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
860         IDirectInputDevice2AImpl_QueryInterface,
861         IDirectInputDevice2AImpl_AddRef,
862         SysMouseAImpl_Release,
863         SysMouseAImpl_GetCapabilities,
864         SysMouseAImpl_EnumObjects,
865         SysMouseAImpl_GetProperty,
866         SysMouseAImpl_SetProperty,
867         SysMouseAImpl_Acquire,
868         SysMouseAImpl_Unacquire,
869         SysMouseAImpl_GetDeviceState,
870         SysMouseAImpl_GetDeviceData,
871         SysMouseAImpl_SetDataFormat,
872         SysMouseAImpl_SetEventNotification,
873         SysMouseAImpl_SetCooperativeLevel,
874         IDirectInputDevice2AImpl_GetObjectInfo,
875         IDirectInputDevice2AImpl_GetDeviceInfo,
876         IDirectInputDevice2AImpl_RunControlPanel,
877         IDirectInputDevice2AImpl_Initialize,
878         IDirectInputDevice2AImpl_CreateEffect,
879         IDirectInputDevice2AImpl_EnumEffects,
880         IDirectInputDevice2AImpl_GetEffectInfo,
881         IDirectInputDevice2AImpl_GetForceFeedbackState,
882         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
883         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
884         IDirectInputDevice2AImpl_Escape,
885         IDirectInputDevice2AImpl_Poll,
886         IDirectInputDevice2AImpl_SendDeviceData,
887 };
888
889 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
890 # define XCAST(fun)     (typeof(SysMouse7Avt.fun))
891 #else
892 # define XCAST(fun)     (void*)
893 #endif
894
895 static ICOM_VTABLE(IDirectInputDevice7A) SysMouse7Avt = 
896 {
897         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
898         XCAST(QueryInterface)IDirectInputDevice2AImpl_QueryInterface,
899         XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
900         XCAST(Release)SysMouseAImpl_Release,
901         XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities,
902         XCAST(EnumObjects)SysMouseAImpl_EnumObjects,
903         XCAST(GetProperty)SysMouseAImpl_GetProperty,
904         XCAST(SetProperty)SysMouseAImpl_SetProperty,
905         XCAST(Acquire)SysMouseAImpl_Acquire,
906         XCAST(Unacquire)SysMouseAImpl_Unacquire,
907         XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState,
908         XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData,
909         XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat,
910         XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification,
911         XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel,
912         XCAST(GetObjectInfo)IDirectInputDevice2AImpl_GetObjectInfo,
913         XCAST(GetDeviceInfo)IDirectInputDevice2AImpl_GetDeviceInfo,
914         XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
915         XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
916         XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
917         XCAST(EnumEffects)IDirectInputDevice2AImpl_EnumEffects,
918         XCAST(GetEffectInfo)IDirectInputDevice2AImpl_GetEffectInfo,
919         XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
920         XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
921         XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
922         XCAST(Escape)IDirectInputDevice2AImpl_Escape,
923         XCAST(Poll)IDirectInputDevice2AImpl_Poll,
924         XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
925         IDirectInputDevice7AImpl_EnumEffectsInFile,
926         IDirectInputDevice7AImpl_WriteEffectToFile
927 };
928
929 #undef XCAST