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