Moved the 16 bit driver functions callout into the dir.
[wine] / windows / dinput.c
1 /*              DirectInput
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  *
6  */
7 /* Status:
8  *
9  * - Tomb Raider 2 Demo:
10  *   Playable using keyboard only.
11  * - WingCommander Prophecy Demo:
12  *   Doesn't get Input Focus.
13  * 
14  * - Fallout : works great in X and DGA mode
15  *
16  * FIXME: The keyboard handling needs to (and will) be merged into keyboard.c
17  *        (The current implementation is currently only a proof of concept and
18  *         an utter mess.)
19  */
20
21 #include "config.h"
22 #include <string.h>
23 #include <time.h>
24 #include <unistd.h>
25 #include <assert.h>
26 #ifdef HAVE_SYS_SIGNAL_H
27 # include <sys/signal.h>
28 #endif
29 #include <sys/time.h>
30 #include <sys/fcntl.h>
31 #include <sys/ioctl.h>
32 #include <errno.h>
33 #ifdef HAVE_SYS_ERRNO_H
34 # include <sys/errno.h>
35 #endif
36 #ifdef HAVE_LINUX_JOYSTICK_H
37 # include <linux/joystick.h>
38 # define JOYDEV "/dev/js0"
39 #endif
40 #include "wine/obj_base.h"
41 #include "debugtools.h"
42 #include "dinput.h"
43 #include "display.h"
44 #include "input.h"
45 #include "keyboard.h"
46 #include "message.h"
47 #include "mouse.h"
48 #include "sysmetrics.h"
49 #include "winbase.h"
50 #include "winerror.h"
51 #include "winuser.h"
52
53 DEFAULT_DEBUG_CHANNEL(dinput)
54
55
56 extern BYTE InputKeyStateTable[256];
57 extern int min_keycode, max_keycode;
58 extern WORD keyc2vkey[256];
59
60 static ICOM_VTABLE(IDirectInputA) ddiavt;
61 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt;
62 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt;
63
64 typedef struct IDirectInputAImpl IDirectInputAImpl;
65 typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl;
66 typedef struct SysKeyboardAImpl SysKeyboardAImpl;
67 typedef struct SysMouseAImpl SysMouseAImpl;
68
69 struct IDirectInputDevice2AImpl
70 {
71         ICOM_VFIELD(IDirectInputDevice2A);
72         DWORD                           ref;
73         GUID                            guid;
74 };
75
76 struct SysKeyboardAImpl
77 {
78         /* IDirectInputDevice2AImpl */
79         ICOM_VFIELD(IDirectInputDevice2A);
80         DWORD                           ref;
81         GUID                            guid;
82         /* SysKeyboardAImpl */
83         BYTE                            keystate[256];
84         KEYBOARD_CONFIG                 initial_config;
85         int                             acquired;
86 };
87
88 #ifdef HAVE_LINUX_22_JOYSTICK_API
89 typedef struct JoystickAImpl JoystickAImpl;
90 static ICOM_VTABLE(IDirectInputDevice2A) JoystickAvt;
91 struct JoystickAImpl
92 {
93         /* IDirectInputDevice2AImpl */
94         ICOM_VFIELD(IDirectInputDevice2A);
95         DWORD                           ref;
96         GUID                            guid;
97
98         /* joystick private */
99         int                             joyfd;
100         LPDIDATAFORMAT                  df;
101         HANDLE                          hEvent;
102         LONG                            lMin,lMax,deadzone;
103         LPDIDEVICEOBJECTDATA            data_queue;
104         int                             queue_pos, queue_len;
105         DIJOYSTATE                      js;
106 };
107 #endif
108
109 struct SysMouseAImpl
110 {
111         /* IDirectInputDevice2AImpl */
112         ICOM_VFIELD(IDirectInputDevice2A);
113         DWORD                           ref;
114         GUID                            guid;
115
116         LPDIDATAFORMAT                  df;
117         /* SysMouseAImpl */
118         BYTE                            absolute;
119         /* Previous position for relative moves */
120         LONG                            prevX, prevY;
121         LPMOUSE_EVENT_PROC              prev_handler;
122         HWND                            win;
123         DWORD                           win_centerX, win_centerY;
124         LPDIDEVICEOBJECTDATA            data_queue;
125         int                             queue_pos, queue_len;
126         int                             need_warp;
127         int                             acquired;
128         HANDLE                          hEvent;
129         CRITICAL_SECTION                crit;
130
131         /* This is for mouse reporting. */
132         struct DIMOUSESTATE2            m_state;
133 };
134
135 static int evsequence=0;
136
137
138 /* UIDs for Wine "drivers".
139    When enumerating each device supporting DInput, they have two UIDs :
140     - the 'windows' UID
141     - a vendor UID */
142 #ifdef HAVE_LINUX_22_JOYSTICK_API
143 static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
144   0x9e573ed9,
145   0x7734,
146   0x11d2,
147   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
148 };
149 #endif
150 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
151   0x9e573ed8,
152   0x7734,
153   0x11d2,
154   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
155 };
156 static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
157   0x0ab8648a,
158   0x7735,
159   0x11d2,
160   {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41}
161 };
162
163 /* FIXME: This is ugly and not thread safe :/ */
164 static IDirectInputDevice2A* current_lock = NULL;
165
166 /******************************************************************************
167  *      Various debugging tools
168  */
169 static void _dump_cooperativelevel(DWORD dwFlags) {
170   int   i;
171   const struct {
172     DWORD       mask;
173     char        *name;
174   } flags[] = {
175 #define FE(x) { x, #x},
176     FE(DISCL_BACKGROUND)
177     FE(DISCL_EXCLUSIVE)
178     FE(DISCL_FOREGROUND)
179     FE(DISCL_NONEXCLUSIVE)
180   };
181   for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
182     if (flags[i].mask & dwFlags)
183       DPRINTF("%s ",flags[i].name);
184   DPRINTF("\n");
185 }
186
187 struct IDirectInputAImpl
188 {
189         ICOM_VFIELD(IDirectInputA);
190         DWORD                   ref;
191 };
192
193 /******************************************************************************
194  *      DirectInputCreate32A
195  */
196 HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
197 {
198         IDirectInputAImpl* This;
199         TRACE("(0x%08lx,%04lx,%p,%p)\n",
200                 (DWORD)hinst,dwVersion,ppDI,punkOuter
201         );
202         This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
203         This->ref = 1;
204         ICOM_VTBL(This) = &ddiavt;
205         *ppDI=(IDirectInputA*)This;
206         return 0;
207 }
208 /******************************************************************************
209  *      IDirectInputA_EnumDevices
210  */
211 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
212         LPDIRECTINPUTA iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
213         LPVOID pvRef, DWORD dwFlags
214 )
215 {
216         ICOM_THIS(IDirectInputAImpl,iface);
217         DIDEVICEINSTANCEA devInstance;
218         int ret;
219
220         TRACE("(this=%p,0x%04lx,%p,%p,%04lx)\n", This, dwDevType, lpCallback, pvRef, dwFlags);
221
222         devInstance.dwSize = sizeof(DIDEVICEINSTANCEA);
223         if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
224                 /* Return keyboard */
225                 devInstance.guidInstance = GUID_SysKeyboard;/* DInput's GUID */
226                 devInstance.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
227                 devInstance.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
228                 strcpy(devInstance.tszInstanceName, "Keyboard");
229                 strcpy(devInstance.tszProductName, "Wine Keyboard");
230
231                 ret = lpCallback(&devInstance, pvRef);
232                 TRACE("Keyboard registered\n");
233                 if (ret == DIENUM_STOP)
234                         return 0;
235         }
236   
237         if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_MOUSE)) {
238                 /* Return mouse */
239                 devInstance.guidInstance = GUID_SysMouse;/* DInput's GUID */
240                 devInstance.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
241                 devInstance.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
242                 strcpy(devInstance.tszInstanceName, "Mouse");
243                 strcpy(devInstance.tszProductName, "Wine Mouse");
244
245                 ret = lpCallback(&devInstance, pvRef);
246                 TRACE("Mouse registered\n");
247                 if (ret == DIENUM_STOP)
248                         return 0;
249         }
250         if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_JOYSTICK)) {
251                 /* check whether we have a joystick */
252 #ifdef HAVE_LINUX_22_JOYSTICK_API
253                 if (    (access(JOYDEV,O_RDONLY)!=-1)           ||
254                         (errno!=ENODEV && errno!=ENOENT)
255                 ) {
256                     /* Return joystick */
257                     devInstance.guidInstance    = GUID_Joystick;
258                     devInstance.guidProduct     = DInput_Wine_Joystick_GUID;
259                     /* we only support traditional joysticks for now */
260                     devInstance.dwDevType       = DIDEVTYPE_JOYSTICK | DIDEVTYPEJOYSTICK_TRADITIONAL;
261                     strcpy(devInstance.tszInstanceName, "Joystick");
262                     /* ioctl JSIOCGNAME(len) */
263                     strcpy(devInstance.tszProductName,  "Wine Joystick");
264
265                     ret = lpCallback(&devInstance,pvRef);
266                     TRACE("Joystick registered\n");
267                     if (ret == DIENUM_STOP)
268                             return 0;
269                 }
270 #endif
271         }
272         return 0;
273 }
274
275 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUTA iface)
276 {
277         ICOM_THIS(IDirectInputAImpl,iface);
278         return ++(This->ref);
279 }
280
281 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUTA iface)
282 {
283         ICOM_THIS(IDirectInputAImpl,iface);
284         if (!(--This->ref)) {
285                 HeapFree(GetProcessHeap(),0,This);
286                 return 0;
287         }
288         return This->ref;
289 }
290
291 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(
292         LPDIRECTINPUTA iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev,
293         LPUNKNOWN punk
294 ) {
295         ICOM_THIS(IDirectInputAImpl,iface);
296         char    xbuf[50];
297         
298         WINE_StringFromCLSID(rguid,xbuf);
299         TRACE("(this=%p,%s,%p,%p)\n",This,xbuf,pdev,punk);
300         if ((!memcmp(&GUID_SysKeyboard,rguid,sizeof(GUID_SysKeyboard))) ||          /* Generic Keyboard */
301             (!memcmp(&DInput_Wine_Keyboard_GUID,rguid,sizeof(GUID_SysKeyboard)))) { /* Wine Keyboard */
302                 SysKeyboardAImpl* newDevice;
303                 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardAImpl));
304                 newDevice->ref = 1;
305                 ICOM_VTBL(newDevice) = &SysKeyboardAvt;
306                 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
307                 memset(newDevice->keystate,0,256);
308                 *pdev=(IDirectInputDeviceA*)newDevice;
309                 return DI_OK;
310         }
311         if ((!memcmp(&GUID_SysMouse,rguid,sizeof(GUID_SysMouse))) ||             /* Generic Mouse */
312             (!memcmp(&DInput_Wine_Mouse_GUID,rguid,sizeof(GUID_SysMouse)))) { /* Wine Mouse */
313                 SysMouseAImpl* newDevice;
314                 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
315                 newDevice->ref = 1;
316                 ICOM_VTBL(newDevice) = &SysMouseAvt;
317                 InitializeCriticalSection(&(newDevice->crit));
318                 MakeCriticalSectionGlobal(&(newDevice->crit));
319                 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
320                 *pdev=(IDirectInputDeviceA*)newDevice;
321                 return DI_OK;
322         }
323 #ifdef HAVE_LINUX_22_JOYSTICK_API
324         if ((!memcmp(&GUID_Joystick,rguid,sizeof(GUID_Joystick))) ||
325             (!memcmp(&DInput_Wine_Joystick_GUID,rguid,sizeof(GUID_Joystick)))) {
326                 JoystickAImpl* newDevice;
327                 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickAImpl));
328                 newDevice->ref          = 1;
329                 ICOM_VTBL(newDevice)    = &JoystickAvt;
330                 newDevice->joyfd        = -1;
331                 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
332                 *pdev=(IDirectInputDeviceA*)newDevice;
333                 return DI_OK;
334         }
335 #endif
336         return E_FAIL;
337 }
338
339 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(
340         LPDIRECTINPUTA iface,REFIID riid,LPVOID *ppobj
341 ) {
342         ICOM_THIS(IDirectInputAImpl,iface);
343         char    xbuf[50];
344
345         WINE_StringFromCLSID(riid,xbuf);
346         TRACE("(this=%p,%s,%p)\n",This,xbuf,ppobj);
347         if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
348                 IDirectInputA_AddRef(iface);
349                 *ppobj = This;
350                 return 0;
351         }
352         if (!memcmp(&IID_IDirectInputA,riid,sizeof(*riid))) {
353                 IDirectInputA_AddRef(iface);
354                 *ppobj = This;
355                 return 0;
356         }
357         return E_FAIL;
358 }
359
360 static HRESULT WINAPI IDirectInputAImpl_Initialize(
361         LPDIRECTINPUTA iface,HINSTANCE hinst,DWORD x
362 ) {
363         return DIERR_ALREADYINITIALIZED;
364 }
365
366 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUTA iface,
367                                                         REFGUID rguid) {
368   ICOM_THIS(IDirectInputAImpl,iface);
369   char xbuf[50];
370   
371   WINE_StringFromCLSID(rguid,xbuf);
372   FIXME("(%p)->(%s): stub\n",This,xbuf);
373   
374   return DI_OK;
375 }
376
377 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUTA iface,
378                                                         HWND hwndOwner,
379                                                         DWORD dwFlags) {
380   ICOM_THIS(IDirectInputAImpl,iface);
381   FIXME("(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags);
382   
383   return DI_OK;
384 }
385
386 static ICOM_VTABLE(IDirectInputA) ddiavt = 
387 {
388         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
389         IDirectInputAImpl_QueryInterface,
390         IDirectInputAImpl_AddRef,
391         IDirectInputAImpl_Release,
392         IDirectInputAImpl_CreateDevice,
393         IDirectInputAImpl_EnumDevices,
394         IDirectInputAImpl_GetDeviceStatus,
395         IDirectInputAImpl_RunControlPanel,
396         IDirectInputAImpl_Initialize
397 };
398
399 /******************************************************************************
400  *      IDirectInputDeviceA
401  */
402
403 static HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
404         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
405 ) {
406         /*
407         int i;
408         TRACE(dinput,"(this=%p,%p)\n",This,df);
409
410         TRACE(dinput,"df.dwSize=%ld\n",df->dwSize);
411         TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
412         TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
413         TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
414         TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
415
416         for (i=0;i<df->dwNumObjs;i++) {
417                 char    xbuf[50];
418
419                 if (df->rgodf[i].pguid)
420                         WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
421                 else
422                         strcpy(xbuf,"<no guid>");
423                 TRACE(dinput,"df.rgodf[%d].guid %s\n",i,xbuf);
424                 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
425                 TRACE(dinput,"dwType 0x%02lx,dwInstance %ld\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
426                 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
427         }
428         */
429         return 0;
430 }
431
432 static HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
433         LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
434 ) {
435         ICOM_THIS(IDirectInputDevice2AImpl,iface);
436         TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
437         if (TRACE_ON(dinput))
438           _dump_cooperativelevel(dwflags);
439         return 0;
440 }
441
442 static HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
443         LPDIRECTINPUTDEVICE2A iface,HANDLE hnd
444 ) {
445         ICOM_THIS(IDirectInputDevice2AImpl,iface);
446         FIXME("(this=%p,0x%08lx): stub\n",This,(DWORD)hnd);
447         return 0;
448 }
449
450 static ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE2A iface)
451 {
452         ICOM_THIS(IDirectInputDevice2AImpl,iface);
453         This->ref--;
454         if (This->ref)
455                 return This->ref;
456         HeapFree(GetProcessHeap(),0,This);
457         return 0;
458 }
459
460 static HRESULT WINAPI SysKeyboardAImpl_SetProperty(
461         LPDIRECTINPUTDEVICE2A iface,REFGUID rguid,LPCDIPROPHEADER ph
462 )
463 {
464         ICOM_THIS(SysKeyboardAImpl,iface);
465         char                    xbuf[50];
466
467         if (HIWORD(rguid))
468                 WINE_StringFromCLSID(rguid,xbuf);
469         else
470                 sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
471         TRACE("(this=%p,%s,%p)\n",This,xbuf,ph);
472         TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
473             ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
474         if (!HIWORD(rguid)) {
475                 switch ((DWORD)rguid) {
476                 case (DWORD) DIPROP_BUFFERSIZE: {
477                         LPCDIPROPDWORD  pd = (LPCDIPROPDWORD)ph;
478
479                         TRACE("(buffersize=%ld)\n",pd->dwData);
480                         break;
481                 }
482                 default:
483                         WARN("Unknown type %ld\n",(DWORD)rguid);
484                         break;
485                 }
486         }
487         return 0;
488 }
489
490 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(
491         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
492 )
493 {
494         return KEYBOARD_Driver->pGetDIState(len, ptr)?DI_OK:E_FAIL;
495 }
496
497 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData(
498         LPDIRECTINPUTDEVICE2A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
499         LPDWORD entries,DWORD flags
500 )
501 {
502         ICOM_THIS(SysKeyboardAImpl,iface);
503         HRESULT ret;
504         int     i;
505
506         TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
507               This,dodsize,dod,entries,entries?*entries:0,flags);
508
509         ret=KEYBOARD_Driver->pGetDIData(
510                 This->keystate, dodsize, dod, entries, flags)?DI_OK:E_FAIL;
511         for (i=0;i<*entries;i++) {
512                 dod[i].dwTimeStamp = GetTickCount();
513                 dod[i].dwSequence = evsequence++;
514         }
515         return ret;
516 }
517
518 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
519 {
520         ICOM_THIS(SysKeyboardAImpl,iface);
521         
522         TRACE("(this=%p)\n",This);
523         
524         if (This->acquired == 0) {
525           KEYBOARD_CONFIG no_auto;
526           
527           /* Save the original config */
528           KEYBOARD_Driver->pGetKeyboardConfig(&(This->initial_config));
529           
530           /* Now, remove auto-repeat */
531           no_auto.auto_repeat = FALSE;
532           KEYBOARD_Driver->pSetKeyboardConfig(&no_auto, WINE_KEYBOARD_CONFIG_AUTO_REPEAT);
533
534           This->acquired = 1;
535         }
536         
537         return DI_OK;
538 }
539
540 static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
541 {
542         ICOM_THIS(SysKeyboardAImpl,iface);
543         TRACE("(this=%p)\n",This);
544
545         if (This->acquired == 1) {
546           /* Restore the original configuration */
547           KEYBOARD_Driver->pSetKeyboardConfig(&(This->initial_config), 0xFFFFFFFF);
548           This->acquired = 0;
549         } else {
550           ERR("Unacquiring a not-acquired device !!!\n");
551         }
552
553         return DI_OK;
554 }
555
556 static HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
557         LPDIRECTINPUTDEVICE2A iface,REFIID riid,LPVOID *ppobj
558 )
559 {
560         ICOM_THIS(IDirectInputDevice2AImpl,iface);
561         char    xbuf[50];
562
563         WINE_StringFromCLSID(riid,xbuf);
564         TRACE("(this=%p,%s,%p)\n",This,xbuf,ppobj);
565         if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
566                 IDirectInputDevice2_AddRef(iface);
567                 *ppobj = This;
568                 return 0;
569         }
570         if (!memcmp(&IID_IDirectInputDeviceA,riid,sizeof(*riid))) {
571                 IDirectInputDevice2_AddRef(iface);
572                 *ppobj = This;
573                 return 0;
574         }
575         if (!memcmp(&IID_IDirectInputDevice2A,riid,sizeof(*riid))) {
576                 IDirectInputDevice2_AddRef(iface);
577                 *ppobj = This;
578                 return 0;
579         }
580         return E_FAIL;
581 }
582
583 static ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
584         LPDIRECTINPUTDEVICE2A iface)
585 {
586         ICOM_THIS(IDirectInputDevice2AImpl,iface);
587         return ++This->ref;
588 }
589
590 static HRESULT WINAPI IDirectInputDevice2AImpl_GetCapabilities(
591         LPDIRECTINPUTDEVICE2A iface,
592         LPDIDEVCAPS lpDIDevCaps)
593 {
594         lpDIDevCaps->dwFlags = DIDC_ATTACHED;
595         FIXME("stub!\n");
596         return DI_OK;
597 }
598
599 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
600         LPDIRECTINPUTDEVICE2A iface,
601         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
602         LPVOID lpvRef,
603         DWORD dwFlags)
604 {
605         FIXME("stub!\n");
606 #if 0
607         if (lpCallback)
608                 lpCallback(NULL, lpvRef);
609 #endif
610         return DI_OK;
611 }
612         
613 static HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
614         LPDIRECTINPUTDEVICE2A iface,
615         REFGUID rguid,
616         LPDIPROPHEADER pdiph)
617 {
618         FIXME("stub!\n");
619         return DI_OK;
620 }
621
622 static HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
623         LPDIRECTINPUTDEVICE2A iface,
624         LPDIDEVICEOBJECTINSTANCEA pdidoi,
625         DWORD dwObj,
626         DWORD dwHow)
627 {
628         FIXME("stub!\n");
629         return DI_OK;
630 }
631         
632 static HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
633         LPDIRECTINPUTDEVICE2A iface,
634         LPDIDEVICEINSTANCEA pdidi)
635 {
636         FIXME("stub!\n");
637         return DI_OK;
638 }
639         
640 static HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
641         LPDIRECTINPUTDEVICE2A iface,
642         HWND hwndOwner,
643         DWORD dwFlags)
644 {
645         FIXME("stub!\n");
646         return DI_OK;
647 }
648         
649 static HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
650         LPDIRECTINPUTDEVICE2A iface,
651         HINSTANCE hinst,
652         DWORD dwVersion,
653         REFGUID rguid)
654 {
655         FIXME("stub!\n");
656         return DI_OK;
657 }
658         
659 /******************************************************************************
660  *      IDirectInputDevice2A
661  */
662
663 static HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
664         LPDIRECTINPUTDEVICE2A iface,
665         REFGUID rguid,
666         LPCDIEFFECT lpeff,
667         LPDIRECTINPUTEFFECT *ppdef,
668         LPUNKNOWN pUnkOuter)
669 {
670         FIXME("stub!\n");
671         return DI_OK;
672 }
673
674 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
675         LPDIRECTINPUTDEVICE2A iface,
676         LPDIENUMEFFECTSCALLBACKA lpCallback,
677         LPVOID lpvRef,
678         DWORD dwFlags)
679 {
680         FIXME("stub!\n");
681         if (lpCallback)
682                 lpCallback(NULL, lpvRef);
683         return DI_OK;
684 }
685
686 static HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
687         LPDIRECTINPUTDEVICE2A iface,
688         LPDIEFFECTINFOA lpdei,
689         REFGUID rguid)
690 {
691         FIXME("stub!\n");
692         return DI_OK;
693 }
694
695 static HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
696         LPDIRECTINPUTDEVICE2A iface,
697         LPDWORD pdwOut)
698 {
699         FIXME("stub!\n");
700         return DI_OK;
701 }
702
703 static HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
704         LPDIRECTINPUTDEVICE2A iface,
705         DWORD dwFlags)
706 {
707         FIXME("stub!\n");
708         return DI_OK;
709 }
710
711 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
712         LPDIRECTINPUTDEVICE2A iface,
713         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
714         LPVOID lpvRef,
715         DWORD dwFlags)
716 {
717         FIXME("stub!\n");
718         if (lpCallback)
719                 lpCallback(NULL, lpvRef);
720         return DI_OK;
721 }
722
723 static HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
724         LPDIRECTINPUTDEVICE2A iface,
725         LPDIEFFESCAPE lpDIEEsc)
726 {
727         FIXME("stub!\n");
728         return DI_OK;
729 }
730
731 static HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
732         LPDIRECTINPUTDEVICE2A iface)
733 {
734         FIXME("stub!\n");
735         return DI_OK;
736 }
737
738 static HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
739         LPDIRECTINPUTDEVICE2A iface,
740         DWORD cbObjectData,
741         LPDIDEVICEOBJECTDATA rgdod,
742         LPDWORD pdwInOut,
743         DWORD dwFlags)
744 {
745         FIXME("stub!\n");
746         return DI_OK;
747 }
748
749 /******************************************************************************
750  *      SysMouseA (DInput Mouse support)
751  */
752
753 /******************************************************************************
754   *     Release : release the mouse buffer.
755   */
756 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
757 {
758         ICOM_THIS(SysMouseAImpl,iface);
759
760         This->ref--;
761         if (This->ref)
762                 return This->ref;
763
764         /* Free the data queue */
765         if (This->data_queue != NULL)
766           HeapFree(GetProcessHeap(),0,This->data_queue);
767
768         /* Install the previous event handler (in case of releasing an aquired
769            mouse device) */
770         if (This->prev_handler != NULL)
771           MOUSE_Enable(This->prev_handler);
772         DeleteCriticalSection(&(This->crit));
773         
774         HeapFree(GetProcessHeap(),0,This);
775         return 0;
776 }
777
778
779 /******************************************************************************
780   *     SetCooperativeLevel : store the window in which we will do our
781   *   grabbing.
782   */
783 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
784         LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
785 )
786 {
787   ICOM_THIS(SysMouseAImpl,iface);
788
789   TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
790
791   if (TRACE_ON(dinput))
792     _dump_cooperativelevel(dwflags);
793
794   /* Store the window which asks for the mouse */
795   This->win = hwnd;
796   
797   return 0;
798 }
799
800
801 /******************************************************************************
802   *     SetDataFormat : the application can choose the format of the data
803   *   the device driver sends back with GetDeviceState.
804   *
805   *   For the moment, only the "standard" configuration (c_dfDIMouse) is supported
806   *   in absolute and relative mode.
807   */
808 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
809         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
810 )
811 {
812   ICOM_THIS(SysMouseAImpl,iface);
813   int i;
814   
815   TRACE("(this=%p,%p)\n",This,df);
816
817   TRACE("(df.dwSize=%ld)\n",df->dwSize);
818   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
819   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
820   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
821   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
822
823   for (i=0;i<df->dwNumObjs;i++) {
824     char        xbuf[50];
825     
826     if (df->rgodf[i].pguid)
827       WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
828     else
829       strcpy(xbuf,"<no guid>");
830     TRACE("df.rgodf[%d].guid %s (%p)\n",i,xbuf, df->rgodf[i].pguid);
831     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
832     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
833     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
834   }
835
836   /* Check size of data format to prevent crashes if the applications
837      sends a smaller buffer */
838   if ((df->dwDataSize != sizeof(struct DIMOUSESTATE)) &&
839       (df->dwDataSize != sizeof(struct DIMOUSESTATE2))) {
840     FIXME("non-standard mouse configuration not supported yet.");
841     return DIERR_INVALIDPARAM;
842   }
843   
844   /* For the moment, ignore these fields and return always as if
845      c_dfDIMouse was passed as format... */
846
847   /* Check if the mouse is in absolute or relative mode */
848   if (df->dwFlags == DIDF_ABSAXIS)
849     This->absolute = 1;
850   else if (df->dwFlags == DIDF_RELAXIS)
851     This->absolute = 0;
852   else
853     ERR("Neither absolute nor relative flag set.");
854   
855   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize+(df->dwNumObjs*df->dwObjSize));
856   memcpy(This->df,df,df->dwSize+(df->dwNumObjs*df->dwObjSize));
857   return 0;
858 }
859
860 #define GEN_EVENT(offset,data,xtime,seq)                        \
861 {                                                               \
862   if (This->queue_pos < This->queue_len) {                      \
863     This->data_queue[This->queue_pos].dwOfs = offset;           \
864     This->data_queue[This->queue_pos].dwData = data;            \
865     This->data_queue[This->queue_pos].dwTimeStamp = xtime;      \
866     This->data_queue[This->queue_pos].dwSequence = seq;         \
867     This->queue_pos++;                                          \
868   }                                                             \
869 }
870
871   
872 /* Our private mouse event handler */
873 static void WINAPI dinput_mouse_event( DWORD dwFlags, DWORD dx, DWORD dy,
874                                       DWORD cButtons, DWORD dwExtraInfo )
875 {
876   DWORD posX, posY, keyState, xtime, extra;
877   SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
878   
879   EnterCriticalSection(&(This->crit));
880   /* Mouse moved -> send event if asked */
881   if (This->hEvent)
882     SetEvent(This->hEvent);
883   
884   if (   !IsBadReadPtr( (LPVOID)dwExtraInfo, sizeof(WINE_MOUSEEVENT) )
885       && ((WINE_MOUSEEVENT *)dwExtraInfo)->magic == WINE_MOUSEEVENT_MAGIC ) {
886     WINE_MOUSEEVENT *wme = (WINE_MOUSEEVENT *)dwExtraInfo;
887     keyState = wme->keyState;
888     xtime = wme->time;
889     extra = (DWORD)wme->hWnd;
890     
891     if ((dwFlags & MOUSEEVENTF_MOVE) &&
892         (dwFlags & MOUSEEVENTF_ABSOLUTE)) {
893       posX = (dx * GetSystemMetrics(SM_CXSCREEN)) >> 16;
894       posY = (dy * GetSystemMetrics(SM_CYSCREEN)) >> 16;
895     } else {
896       posX = This->prevX;
897       posY = This->prevY;
898     }
899   } else {
900     ERR("Mouse event not supported...\n");
901     LeaveCriticalSection(&(This->crit));
902     return ;
903   }
904
905   TRACE(" %ld %ld ", posX, posY);
906
907   if ( dwFlags & MOUSEEVENTF_MOVE ) {
908     if (This->absolute) {
909       if (posX != This->prevX)
910         GEN_EVENT(DIMOFS_X, posX, xtime, 0);
911       if (posY != This->prevY)
912         GEN_EVENT(DIMOFS_Y, posY, xtime, 0);
913     } else {
914       /* Relative mouse input : the real fun starts here... */
915       if (This->need_warp) {
916         if (posX != This->prevX)
917           GEN_EVENT(DIMOFS_X, posX - This->prevX, xtime, evsequence++);
918         if (posY != This->prevY)
919           GEN_EVENT(DIMOFS_Y, posY - This->prevY, xtime, evsequence++);
920       } else {
921         /* This is the first time the event handler has been called after a
922            GetData of GetState. */
923         if (posX != This->win_centerX) {
924           GEN_EVENT(DIMOFS_X, posX - This->win_centerX, xtime, evsequence++);
925           This->need_warp = 1;
926         }
927           
928         if (posY != This->win_centerY) {
929           GEN_EVENT(DIMOFS_Y, posY - This->win_centerY, xtime, evsequence++);
930           This->need_warp = 1;
931         }
932       }
933     }
934   }
935   if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) {
936     if (TRACE_ON(dinput))
937       DPRINTF(" LD ");
938
939     GEN_EVENT(DIMOFS_BUTTON0, 0xFF, xtime, evsequence++);
940     This->m_state.rgbButtons[0] = 0xFF;
941   }
942   if ( dwFlags & MOUSEEVENTF_LEFTUP ) {
943     if (TRACE_ON(dinput))
944       DPRINTF(" LU ");
945
946     GEN_EVENT(DIMOFS_BUTTON0, 0x00, xtime, evsequence++);
947     This->m_state.rgbButtons[0] = 0x00;
948   }
949   if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) {
950     if (TRACE_ON(dinput))
951       DPRINTF(" RD ");
952
953     GEN_EVENT(DIMOFS_BUTTON1, 0xFF, xtime, evsequence++);
954     This->m_state.rgbButtons[1] = 0xFF;
955   }
956   if ( dwFlags & MOUSEEVENTF_RIGHTUP ) {
957     if (TRACE_ON(dinput))
958       DPRINTF(" RU ");
959
960     GEN_EVENT(DIMOFS_BUTTON1, 0x00, xtime, evsequence++);
961     This->m_state.rgbButtons[1] = 0x00;
962   }
963   if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) {
964     if (TRACE_ON(dinput))
965       DPRINTF(" MD ");
966
967     GEN_EVENT(DIMOFS_BUTTON2, 0xFF, xtime, evsequence++);
968     This->m_state.rgbButtons[2] = 0xFF;
969   }
970   if ( dwFlags & MOUSEEVENTF_MIDDLEUP ) {
971     if (TRACE_ON(dinput))
972       DPRINTF(" MU ");
973
974     GEN_EVENT(DIMOFS_BUTTON2, 0x00, xtime, evsequence++);
975     This->m_state.rgbButtons[2] = 0x00;
976   }
977   if (TRACE_ON(dinput))
978     DPRINTF("\n");
979   
980   This->prevX = posX;
981   This->prevY = posY;
982
983   if (This->absolute) {
984     This->m_state.lX = posX;
985     This->m_state.lY = posY;
986   } else {
987     This->m_state.lX = posX - This->win_centerX;
988     This->m_state.lY = posY - This->win_centerY;
989   }
990   
991   LeaveCriticalSection(&(This->crit));
992
993 }
994
995
996 /******************************************************************************
997   *     Acquire : gets exclusive control of the mouse
998   */
999 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
1000 {
1001   ICOM_THIS(SysMouseAImpl,iface);
1002   RECT  rect;
1003   
1004   TRACE("(this=%p)\n",This);
1005
1006   if (This->acquired == 0) {
1007     POINT       point;
1008     int i;
1009     
1010     /* This stores the current mouse handler. */
1011     This->prev_handler = mouse_event;
1012     
1013     /* Store (in a global variable) the current lock */
1014     current_lock = (IDirectInputDevice2A*)This;
1015
1016     /* Init the mouse state */
1017     This->m_state.lX = PosX;
1018     This->m_state.lY = PosY;
1019     This->m_state.lZ = 0;
1020     This->m_state.rgbButtons[0] = (MouseButtonsStates[0] ? 0xFF : 0x00);
1021     This->m_state.rgbButtons[1] = (MouseButtonsStates[1] ? 0xFF : 0x00);
1022     This->m_state.rgbButtons[2] = (MouseButtonsStates[2] ? 0xFF : 0x00);
1023     for (i = 0; i < 8; i++) 
1024       This->m_state.rgbButtons[i] = 0x00;
1025
1026     /* Install our own mouse event handler */
1027     MOUSE_Enable(dinput_mouse_event);
1028     
1029     /* Get the window dimension and find the center */
1030     GetWindowRect(This->win, &rect);
1031     This->win_centerX = (rect.right  - rect.left) / 2;
1032     This->win_centerY = (rect.bottom - rect.top ) / 2;
1033
1034     /* Warp the mouse to the center of the window */
1035     TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1036     point.x = This->win_centerX;
1037     point.y = This->win_centerY;
1038     MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1039     DISPLAY_MoveCursor(point.x, point.y);
1040
1041     This->acquired = 1;
1042   }
1043   return 0;
1044 }
1045
1046 /******************************************************************************
1047   *     Unacquire : frees the mouse
1048   */
1049 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
1050 {
1051   ICOM_THIS(SysMouseAImpl,iface);
1052
1053   TRACE("(this=%p)\n",This);
1054
1055   /* Reinstall previous mouse event handler */
1056   MOUSE_Enable(This->prev_handler);
1057   This->prev_handler = NULL;
1058   
1059   /* No more locks */
1060   current_lock = NULL;
1061
1062   /* Unacquire device */
1063   This->acquired = 0;
1064   
1065   return 0;
1066 }
1067
1068 /******************************************************************************
1069   *     GetDeviceState : returns the "state" of the mouse.
1070   *
1071   *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
1072   *   supported.
1073   */
1074 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
1075         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
1076 ) {
1077   ICOM_THIS(SysMouseAImpl,iface);
1078   
1079   EnterCriticalSection(&(This->crit));
1080   TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
1081   
1082   /* Check if the buffer is big enough */
1083   if ((len != sizeof(struct DIMOUSESTATE)) &&
1084       (len != sizeof(struct DIMOUSESTATE2))) {
1085     FIXME("unsupported state structure.");
1086     LeaveCriticalSection(&(This->crit));
1087     return DIERR_INVALIDPARAM;
1088   }
1089
1090   /* Copy the current mouse state */
1091   memcpy(ptr, &(This->m_state), len);
1092   
1093   /* Check if we need to do a mouse warping */
1094   if (This->need_warp) {
1095     POINT point;
1096
1097     TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1098     point.x = This->win_centerX;
1099     point.y = This->win_centerY;
1100     MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1101     DISPLAY_MoveCursor(point.x, point.y);
1102
1103     This->need_warp = 0;
1104   }
1105
1106   LeaveCriticalSection(&(This->crit));
1107   
1108   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
1109         This->m_state.lX, This->m_state.lY,
1110         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
1111   
1112   return 0;
1113 }
1114
1115 /******************************************************************************
1116   *     GetDeviceState : gets buffered input data.
1117   */
1118 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
1119                                               DWORD dodsize,
1120                                               LPDIDEVICEOBJECTDATA dod,
1121                                               LPDWORD entries,
1122                                               DWORD flags
1123 ) {
1124   ICOM_THIS(SysMouseAImpl,iface);
1125   
1126   EnterCriticalSection(&(This->crit));
1127   TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
1128
1129   if (flags & DIGDD_PEEK)
1130     FIXME("DIGDD_PEEK\n");
1131
1132   if (dod == NULL) {
1133     *entries = This->queue_pos;
1134     This->queue_pos = 0;
1135   } else {
1136     /* Check for buffer overflow */
1137     if (This->queue_pos > *entries) {
1138       WARN("Buffer overflow not handled properly yet...\n");
1139       This->queue_pos = *entries;
1140     }
1141     if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
1142       ERR("Wrong structure size !\n");
1143       LeaveCriticalSection(&(This->crit));
1144       return DIERR_INVALIDPARAM;
1145     }
1146
1147     if (This->queue_pos)
1148         TRACE("Application retrieving %d event(s).\n", This->queue_pos); 
1149     
1150     /* Copy the buffered data into the application queue */
1151     memcpy(dod, This->data_queue, This->queue_pos * dodsize);
1152     *entries = This->queue_pos;
1153
1154     /* Reset the event queue */
1155     This->queue_pos = 0;
1156   }
1157   LeaveCriticalSection(&(This->crit));
1158   
1159 #if 0 /* FIXME: seems to create motion events, which fire back at us. */
1160   /* Check if we need to do a mouse warping */
1161   if (This->need_warp) {
1162     POINT point;
1163
1164     TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1165     point.x = This->win_centerX;
1166     point.y = This->win_centerY;
1167     MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1168
1169     DISPLAY_MoveCursor(point.x, point.y);
1170
1171     This->need_warp = 0;
1172   }
1173 #endif
1174   return 0;
1175 }
1176
1177 /******************************************************************************
1178   *     SetProperty : change input device properties
1179   */
1180 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
1181                                             REFGUID rguid,
1182                                             LPCDIPROPHEADER ph)
1183 {
1184   ICOM_THIS(SysMouseAImpl,iface);
1185   char  xbuf[50];
1186
1187   if (HIWORD(rguid))
1188     WINE_StringFromCLSID(rguid,xbuf);
1189   else
1190     sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
1191
1192   TRACE("(this=%p,%s,%p)\n",This,xbuf,ph);
1193   
1194   if (!HIWORD(rguid)) {
1195     switch ((DWORD)rguid) {
1196     case (DWORD) DIPROP_BUFFERSIZE: {
1197       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1198       
1199       TRACE("buffersize = %ld\n",pd->dwData);
1200
1201       This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
1202                                                           pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1203       This->queue_pos  = 0;
1204       This->queue_len  = pd->dwData;
1205       break;
1206     }
1207     default:
1208       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,xbuf);
1209       break;
1210     }
1211   }
1212   
1213   return 0;
1214 }
1215
1216 /******************************************************************************
1217   *     SetEventNotification : specifies event to be sent on state change
1218   */
1219 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
1220                                                          HANDLE hnd) {
1221   ICOM_THIS(SysMouseAImpl,iface);
1222
1223   TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
1224
1225   This->hEvent = hnd;
1226
1227   return DI_OK;
1228 }
1229
1230 #ifdef HAVE_LINUX_22_JOYSTICK_API
1231 /******************************************************************************
1232  *      Joystick
1233  */
1234 static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
1235 {
1236         ICOM_THIS(JoystickAImpl,iface);
1237
1238         This->ref--;
1239         if (This->ref)
1240                 return This->ref;
1241         HeapFree(GetProcessHeap(),0,This);
1242         return 0;
1243 }
1244
1245 /******************************************************************************
1246   *   SetDataFormat : the application can choose the format of the data
1247   *   the device driver sends back with GetDeviceState.
1248   */
1249 static HRESULT WINAPI JoystickAImpl_SetDataFormat(
1250         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
1251 )
1252 {
1253   ICOM_THIS(JoystickAImpl,iface);
1254   int i;
1255   
1256   TRACE("(this=%p,%p)\n",This,df);
1257
1258   TRACE("(df.dwSize=%ld)\n",df->dwSize);
1259   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
1260   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
1261   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
1262   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
1263
1264   for (i=0;i<df->dwNumObjs;i++) {
1265     char        xbuf[50];
1266     
1267     if (df->rgodf[i].pguid)
1268       WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
1269     else
1270       strcpy(xbuf,"<no guid>");
1271     TRACE("df.rgodf[%d].guid %s (%p)\n",i,xbuf, df->rgodf[i].pguid);
1272     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
1273     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
1274     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
1275   }
1276   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize+(df->dwNumObjs*df->dwObjSize));
1277   memcpy(This->df,df,df->dwSize+(df->dwNumObjs*df->dwObjSize));
1278   return 0;
1279 }
1280
1281 /******************************************************************************
1282   *     Acquire : gets exclusive control of the joystick
1283   */
1284 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
1285 {
1286     ICOM_THIS(JoystickAImpl,iface);
1287   
1288     TRACE("(this=%p)\n",This);
1289     if (This->joyfd!=-1)
1290         return 0;
1291     This->joyfd=open(JOYDEV,O_RDONLY);
1292     if (This->joyfd==-1)
1293         return DIERR_NOTFOUND;
1294     return 0;
1295 }
1296
1297 /******************************************************************************
1298   *     Unacquire : frees the joystick
1299   */
1300 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
1301 {
1302     ICOM_THIS(JoystickAImpl,iface);
1303
1304     TRACE("(this=%p)\n",This);
1305     if (This->joyfd!=-1) {
1306         close(This->joyfd);
1307         This->joyfd = -1;
1308     }
1309     return 0;
1310 }
1311
1312 #define map_axis(val) ((val+32768)*(This->lMax-This->lMin)/65536+This->lMin)
1313
1314 static void joy_polldev(JoystickAImpl *This) {
1315     struct timeval tv;
1316     fd_set      readfds;
1317     struct      js_event jse;
1318
1319     if (This->joyfd==-1)
1320         return;
1321     while (1) {
1322         memset(&tv,0,sizeof(tv));
1323         FD_ZERO(&readfds);FD_SET(This->joyfd,&readfds);
1324         if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv))
1325             return;
1326         /* we have one event, so we can read */
1327         if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
1328             return;
1329         }
1330         TRACE("js_event: type 0x%x, number %d, value %d\n",jse.type,jse.number,jse.value);
1331         if (jse.type & JS_EVENT_BUTTON) {
1332             GEN_EVENT(DIJOFS_BUTTON(jse.number),jse.value?0x80:0x00,jse.time,evsequence++);
1333             This->js.rgbButtons[jse.number] = jse.value?0x80:0x00;
1334         }
1335         if (jse.type & JS_EVENT_AXIS) {
1336             switch (jse.number) {
1337             case 0:
1338                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1339                 This->js.lX = map_axis(jse.value);
1340                 break;
1341             case 1:
1342                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1343                 This->js.lY = map_axis(jse.value);
1344                 break;
1345             case 2:
1346                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1347                 This->js.lZ = map_axis(jse.value);
1348                 break;
1349             default:
1350                 FIXME("more then 3 axes (%d) not handled!\n",jse.number);
1351                 break;
1352             }
1353         }
1354     }
1355 }
1356
1357 /******************************************************************************
1358   *     GetDeviceState : returns the "state" of the joystick.
1359   *
1360   */
1361 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
1362         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
1363 ) {
1364     ICOM_THIS(JoystickAImpl,iface);
1365   
1366     joy_polldev(This);
1367     TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr);
1368     if (len != sizeof(DIJOYSTATE)) {
1369         FIXME("len %ld is not sizeof(DIJOYSTATE), unsupported format.\n",len);
1370     }
1371     memcpy(ptr,&(This->js),len);
1372     This->queue_pos = 0;
1373     return 0;
1374 }
1375
1376 /******************************************************************************
1377   *     GetDeviceState : gets buffered input data.
1378   */
1379 static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
1380                                               DWORD dodsize,
1381                                               LPDIDEVICEOBJECTDATA dod,
1382                                               LPDWORD entries,
1383                                               DWORD flags
1384 ) {
1385   ICOM_THIS(JoystickAImpl,iface);
1386   
1387   FIXME("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx),STUB!\n",This,dodsize,*entries,flags);
1388
1389   joy_polldev(This);
1390   if (flags & DIGDD_PEEK)
1391     FIXME("DIGDD_PEEK\n");
1392
1393   if (dod == NULL) {
1394   } else {
1395   }
1396   return 0;
1397 }
1398
1399 /******************************************************************************
1400   *     SetProperty : change input device properties
1401   */
1402 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
1403                                             REFGUID rguid,
1404                                             LPCDIPROPHEADER ph)
1405 {
1406   ICOM_THIS(JoystickAImpl,iface);
1407   char  xbuf[50];
1408
1409   if (HIWORD(rguid))
1410     WINE_StringFromCLSID(rguid,xbuf);
1411   else
1412     sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
1413
1414   FIXME("(this=%p,%s,%p)\n",This,xbuf,ph);
1415   FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow);
1416   
1417   if (!HIWORD(rguid)) {
1418     switch ((DWORD)rguid) {
1419     case (DWORD) DIPROP_BUFFERSIZE: {
1420       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1421
1422       FIXME("buffersize = %ld\n",pd->dwData);
1423       break;
1424     }
1425     case (DWORD)DIPROP_RANGE: {
1426       LPCDIPROPRANGE    pr = (LPCDIPROPRANGE)ph;
1427
1428       FIXME("proprange(%ld,%ld)\n",pr->lMin,pr->lMax);
1429       This->lMin = pr->lMin;
1430       This->lMax = pr->lMax;
1431       break;
1432     }
1433     case (DWORD)DIPROP_DEADZONE: {
1434       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1435
1436       FIXME("deadzone(%ld)\n",pd->dwData);
1437       This->deadzone = pd->dwData;
1438       break;
1439     }
1440     default:
1441       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,xbuf);
1442       break;
1443     }
1444   }
1445   return 0;
1446 }
1447
1448 /******************************************************************************
1449   *     SetEventNotification : specifies event to be sent on state change
1450   */
1451 static HRESULT WINAPI JoystickAImpl_SetEventNotification(
1452         LPDIRECTINPUTDEVICE2A iface, HANDLE hnd
1453 ) {
1454     ICOM_THIS(JoystickAImpl,iface);
1455
1456     TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
1457     This->hEvent = hnd;
1458     return DI_OK;
1459 }
1460
1461 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
1462         LPDIRECTINPUTDEVICE2A iface,
1463         LPDIDEVCAPS lpDIDevCaps)
1464 {
1465     ICOM_THIS(JoystickAImpl,iface);
1466     BYTE        axes,buttons;
1467     int         xfd = This->joyfd;
1468
1469     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
1470     if (xfd==-1)
1471         xfd = open(JOYDEV,O_RDONLY);
1472     lpDIDevCaps->dwFlags        = DIDC_ATTACHED;
1473     lpDIDevCaps->dwDevType      = DIDEVTYPE_JOYSTICK;
1474 #ifdef JSIOCGAXES
1475     if (-1==ioctl(xfd,JSIOCGAXES,&axes))
1476         axes = 2;
1477     lpDIDevCaps->dwAxes = axes;
1478 #endif
1479 #ifdef JSIOCGBUTTONS
1480     if (-1==ioctl(xfd,JSIOCGAXES,&buttons))
1481         buttons = 2;
1482     lpDIDevCaps->dwButtons = buttons;
1483 #endif
1484     if (xfd!=This->joyfd)
1485         close(xfd);
1486     return DI_OK;
1487 }
1488 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE2A iface) {
1489     ICOM_THIS(JoystickAImpl,iface);
1490     TRACE("(),stub!\n");
1491
1492     joy_polldev(This);
1493     return DI_OK;
1494 }
1495 #endif
1496
1497 /****************************************************************************/
1498 /****************************************************************************/
1499
1500 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt = 
1501 {
1502         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1503         IDirectInputDevice2AImpl_QueryInterface,
1504         IDirectInputDevice2AImpl_AddRef,
1505         IDirectInputDevice2AImpl_Release,
1506         IDirectInputDevice2AImpl_GetCapabilities,
1507         IDirectInputDevice2AImpl_EnumObjects,
1508         IDirectInputDevice2AImpl_GetProperty,
1509         SysKeyboardAImpl_SetProperty,
1510         SysKeyboardAImpl_Acquire,
1511         SysKeyboardAImpl_Unacquire,
1512         SysKeyboardAImpl_GetDeviceState,
1513         SysKeyboardAImpl_GetDeviceData,
1514         IDirectInputDevice2AImpl_SetDataFormat,
1515         IDirectInputDevice2AImpl_SetEventNotification,
1516         IDirectInputDevice2AImpl_SetCooperativeLevel,
1517         IDirectInputDevice2AImpl_GetObjectInfo,
1518         IDirectInputDevice2AImpl_GetDeviceInfo,
1519         IDirectInputDevice2AImpl_RunControlPanel,
1520         IDirectInputDevice2AImpl_Initialize,
1521         IDirectInputDevice2AImpl_CreateEffect,
1522         IDirectInputDevice2AImpl_EnumEffects,
1523         IDirectInputDevice2AImpl_GetEffectInfo,
1524         IDirectInputDevice2AImpl_GetForceFeedbackState,
1525         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1526         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1527         IDirectInputDevice2AImpl_Escape,
1528         IDirectInputDevice2AImpl_Poll,
1529         IDirectInputDevice2AImpl_SendDeviceData,
1530 };
1531
1532 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt = 
1533 {
1534         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1535         IDirectInputDevice2AImpl_QueryInterface,
1536         IDirectInputDevice2AImpl_AddRef,
1537         SysMouseAImpl_Release,
1538         IDirectInputDevice2AImpl_GetCapabilities,
1539         IDirectInputDevice2AImpl_EnumObjects,
1540         IDirectInputDevice2AImpl_GetProperty,
1541         SysMouseAImpl_SetProperty,
1542         SysMouseAImpl_Acquire,
1543         SysMouseAImpl_Unacquire,
1544         SysMouseAImpl_GetDeviceState,
1545         SysMouseAImpl_GetDeviceData,
1546         SysMouseAImpl_SetDataFormat,
1547         SysMouseAImpl_SetEventNotification,
1548         SysMouseAImpl_SetCooperativeLevel,
1549         IDirectInputDevice2AImpl_GetObjectInfo,
1550         IDirectInputDevice2AImpl_GetDeviceInfo,
1551         IDirectInputDevice2AImpl_RunControlPanel,
1552         IDirectInputDevice2AImpl_Initialize,
1553         IDirectInputDevice2AImpl_CreateEffect,
1554         IDirectInputDevice2AImpl_EnumEffects,
1555         IDirectInputDevice2AImpl_GetEffectInfo,
1556         IDirectInputDevice2AImpl_GetForceFeedbackState,
1557         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1558         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1559         IDirectInputDevice2AImpl_Escape,
1560         IDirectInputDevice2AImpl_Poll,
1561         IDirectInputDevice2AImpl_SendDeviceData,
1562 };
1563
1564 #ifdef HAVE_LINUX_22_JOYSTICK_API
1565 static ICOM_VTABLE(IDirectInputDevice2A) JoystickAvt = 
1566 {
1567         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1568         IDirectInputDevice2AImpl_QueryInterface,
1569         IDirectInputDevice2AImpl_AddRef,
1570         JoystickAImpl_Release,
1571         JoystickAImpl_GetCapabilities,
1572         IDirectInputDevice2AImpl_EnumObjects,
1573         IDirectInputDevice2AImpl_GetProperty,
1574         JoystickAImpl_SetProperty,
1575         JoystickAImpl_Acquire,
1576         JoystickAImpl_Unacquire,
1577         JoystickAImpl_GetDeviceState,
1578         JoystickAImpl_GetDeviceData,
1579         JoystickAImpl_SetDataFormat,
1580         JoystickAImpl_SetEventNotification,
1581         IDirectInputDevice2AImpl_SetCooperativeLevel,
1582         IDirectInputDevice2AImpl_GetObjectInfo,
1583         IDirectInputDevice2AImpl_GetDeviceInfo,
1584         IDirectInputDevice2AImpl_RunControlPanel,
1585         IDirectInputDevice2AImpl_Initialize,
1586         IDirectInputDevice2AImpl_CreateEffect,
1587         IDirectInputDevice2AImpl_EnumEffects,
1588         IDirectInputDevice2AImpl_GetEffectInfo,
1589         IDirectInputDevice2AImpl_GetForceFeedbackState,
1590         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1591         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1592         IDirectInputDevice2AImpl_Escape,
1593         JoystickAImpl_Poll,
1594         IDirectInputDevice2AImpl_SendDeviceData,
1595 };
1596 #endif