Added stubs for two missing methods of DInput.
[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 <unistd.h>
24 #include <assert.h>
25 #include <sys/signal.h>
26
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "wine/obj_base.h"
30 #include "gdi.h"
31 #include "dinput.h"
32 #include "debug.h"
33 #include "message.h"
34
35 #include "mouse.h"
36 #include "ts_xlib.h"
37 #include "sysmetrics.h"
38 #include "x11drv.h"
39
40 extern BYTE InputKeyStateTable[256];
41 extern int min_keycode, max_keycode;
42 extern WORD keyc2vkey[256];
43
44 static ICOM_VTABLE(IDirectInputA) ddiavt;
45 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt;
46 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt;
47
48 typedef struct IDirectInputAImpl IDirectInputAImpl;
49 typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl;
50 typedef struct SysKeyboardAImpl SysKeyboardAImpl;
51 typedef struct SysMouseAImpl SysMouseAImpl;
52
53 struct IDirectInputDevice2AImpl
54 {
55         ICOM_VTABLE(IDirectInputDevice2A)* lpvtbl;
56         DWORD                           ref;
57         GUID                            guid;
58 };
59
60 struct SysKeyboardAImpl
61 {
62         /* IDirectInputDevice2AImpl */
63         ICOM_VTABLE(IDirectInputDevice2A)* lpvtbl;
64         DWORD                           ref;
65         GUID                            guid;
66         /* SysKeyboardAImpl */
67         BYTE                            keystate[256];
68 };
69
70 struct SysMouseAImpl
71 {
72         /* IDirectInputDevice2AImpl */
73         ICOM_VTABLE(IDirectInputDevice2A)* lpvtbl;
74         DWORD                           ref;
75         GUID                            guid;
76         /* SysMouseAImpl */
77         BYTE                            absolute;
78         /* Previous position for relative moves */
79         LONG prevX, prevY;
80         LPMOUSE_EVENT_PROC prev_handler;
81         HWND32 win;
82         int xwin;
83         DWORD win_centerX, win_centerY;
84         LPDIDEVICEOBJECTDATA data_queue;
85         int queue_pos, queue_len;
86         int need_warp;
87         int acquired;
88 };
89
90
91 /* UIDs for Wine "drivers".
92    When enumerating each device supporting DInput, they have two UIDs :
93     - the 'windows' UID
94     - a vendor UID */
95 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
96   0x9e573ed8,
97   0x7734,
98   0x11d2,
99   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
100 };
101 static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
102   0x0ab8648a,
103   0x7735,
104   0x11d2,
105   {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41}
106 };
107
108 /* FIXME: This is ugly and not thread safe :/ */
109 static IDirectInputDevice2A* current_lock = NULL;
110
111 /******************************************************************************
112  *      Various debugging tools
113  */
114 static void _dump_cooperativelevel(DWORD dwFlags) {
115   int   i;
116   const struct {
117     DWORD       mask;
118     char        *name;
119   } flags[] = {
120 #define FE(x) { x, #x},
121     FE(DISCL_BACKGROUND)
122     FE(DISCL_EXCLUSIVE)
123     FE(DISCL_FOREGROUND)
124     FE(DISCL_NONEXCLUSIVE)
125   };
126   for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
127     if (flags[i].mask & dwFlags)
128       DUMP("%s ",flags[i].name);
129   DUMP("\n");
130 }
131
132 struct IDirectInputAImpl
133 {
134         ICOM_VTABLE(IDirectInputA)* lpvtbl;
135         DWORD                   ref;
136 };
137
138 /******************************************************************************
139  *      DirectInputCreate32A
140  */
141 HRESULT WINAPI DirectInputCreate32A(HINSTANCE32 hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
142 {
143         IDirectInputAImpl* This;
144         TRACE(dinput, "(0x%08lx,%04lx,%p,%p)\n",
145                 (DWORD)hinst,dwVersion,ppDI,punkOuter
146         );
147         This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
148         This->ref = 1;
149         This->lpvtbl = &ddiavt;
150         *ppDI=(IDirectInputA*)This;
151         return 0;
152 }
153 /******************************************************************************
154  *      IDirectInputA_EnumDevices
155  */
156 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
157         LPDIRECTINPUTA iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACK32A lpCallback,
158         LPVOID pvRef, DWORD dwFlags
159 )
160 {
161   ICOM_THIS(IDirectInputAImpl,iface);
162   DIDEVICEINSTANCE32A devInstance;
163   int ret;
164
165   TRACE(dinput, "(this=%p,0x%04lx,%p,%p,%04lx)\n", This, dwDevType, lpCallback, pvRef, dwFlags);
166
167   devInstance.dwSize = sizeof(DIDEVICEINSTANCE32A);
168   
169   if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
170   /* Return keyboard */
171     devInstance.guidInstance = GUID_SysKeyboard;         /* DInput's GUID */
172     devInstance.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
173     devInstance.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
174   strcpy(devInstance.tszInstanceName, "Keyboard");
175   strcpy(devInstance.tszProductName, "Wine Keyboard");
176   
177   ret = lpCallback(&devInstance, pvRef);
178     TRACE(dinput, "Keyboard registered\n");
179   
180     if (ret == DIENUM_STOP)
181     return 0;
182   }
183   
184   if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
185   /* Return mouse */
186     devInstance.guidInstance = GUID_SysMouse;         /* DInput's GUID */
187     devInstance.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
188     devInstance.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
189   strcpy(devInstance.tszInstanceName, "Mouse");
190   strcpy(devInstance.tszProductName, "Wine Mouse");
191   
192   ret = lpCallback(&devInstance, pvRef);
193     TRACE(dinput, "Mouse registered\n");
194   }
195
196   /* Should also do joystick enumerations.... */
197   
198         return 0;
199 }
200
201 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUTA iface)
202 {
203         ICOM_THIS(IDirectInputAImpl,iface);
204         return ++(This->ref);
205 }
206
207 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUTA iface)
208 {
209         ICOM_THIS(IDirectInputAImpl,iface);
210         if (!(--This->ref)) {
211                 HeapFree(GetProcessHeap(),0,This);
212                 return 0;
213         }
214         return This->ref;
215 }
216
217 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(
218         LPDIRECTINPUTA iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev,
219         LPUNKNOWN punk
220 ) {
221         ICOM_THIS(IDirectInputAImpl,iface);
222         char    xbuf[50];
223         
224         WINE_StringFromCLSID(rguid,xbuf);
225         FIXME(dinput,"(this=%p,%s,%p,%p): stub\n",This,xbuf,pdev,punk);
226         if ((!memcmp(&GUID_SysKeyboard,rguid,sizeof(GUID_SysKeyboard))) ||          /* Generic Keyboard */
227             (!memcmp(&DInput_Wine_Keyboard_GUID,rguid,sizeof(GUID_SysKeyboard)))) { /* Wine Keyboard */
228                 SysKeyboardAImpl* newDevice;
229                 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardAImpl));
230                 newDevice->ref = 1;
231                 newDevice->lpvtbl = &SysKeyboardAvt;
232                 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
233                 memset(newDevice->keystate,0,256);
234                 *pdev=(IDirectInputDeviceA*)newDevice;
235                 return DI_OK;
236         }
237         if ((!memcmp(&GUID_SysMouse,rguid,sizeof(GUID_SysMouse))) ||             /* Generic Mouse */
238             (!memcmp(&DInput_Wine_Mouse_GUID,rguid,sizeof(GUID_SysMouse)))) { /* Wine Mouse */
239                 SysKeyboardAImpl* newDevice;
240                 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
241                 newDevice->ref = 1;
242                 newDevice->lpvtbl = &SysMouseAvt;
243                 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
244                 *pdev=(IDirectInputDeviceA*)newDevice;
245                 return DI_OK;
246         }
247         return E_FAIL;
248 }
249
250 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(
251         LPDIRECTINPUTA iface,REFIID riid,LPVOID *ppobj
252 ) {
253         ICOM_THIS(IDirectInputAImpl,iface);
254         char    xbuf[50];
255
256         WINE_StringFromCLSID(riid,xbuf);
257         TRACE(dinput,"(this=%p,%s,%p)\n",This,xbuf,ppobj);
258         if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
259                 IDirectInputA_AddRef(iface);
260                 *ppobj = This;
261                 return 0;
262         }
263         if (!memcmp(&IID_IDirectInputA,riid,sizeof(*riid))) {
264                 IDirectInputA_AddRef(iface);
265                 *ppobj = This;
266                 return 0;
267         }
268         return E_FAIL;
269 }
270
271 static HRESULT WINAPI IDirectInputAImpl_Initialize(
272         LPDIRECTINPUTA iface,HINSTANCE32 hinst,DWORD x
273 ) {
274         return DIERR_ALREADYINITIALIZED;
275 }
276
277 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUTA iface,
278                                                         REFGUID rguid) {
279   ICOM_THIS(IDirectInputAImpl,iface);
280   char xbuf[50];
281   
282   WINE_StringFromCLSID(rguid,xbuf);
283   FIXME(dinput,"(%p)->(%s): stub\n",This,xbuf);
284   
285   return DI_OK;
286 }
287
288 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUTA iface,
289                                                         HWND32 hwndOwner,
290                                                         DWORD dwFlags) {
291   ICOM_THIS(IDirectInputAImpl,iface);
292   FIXME(dinput,"(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags);
293   
294   return DI_OK;
295 }
296
297 static ICOM_VTABLE(IDirectInputA) ddiavt= {
298         IDirectInputAImpl_QueryInterface,
299         IDirectInputAImpl_AddRef,
300         IDirectInputAImpl_Release,
301         IDirectInputAImpl_CreateDevice,
302         IDirectInputAImpl_EnumDevices,
303         IDirectInputAImpl_GetDeviceStatus,
304         IDirectInputAImpl_RunControlPanel,
305         IDirectInputAImpl_Initialize
306 };
307
308 /******************************************************************************
309  *      IDirectInputDeviceA
310  */
311
312 static HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
313         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
314 ) {
315         /*
316         int i;
317         TRACE(dinput,"(this=%p,%p)\n",This,df);
318
319         TRACE(dinput,"df.dwSize=%ld\n",df->dwSize);
320         TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
321         TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
322         TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
323         TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
324
325         for (i=0;i<df->dwNumObjs;i++) {
326                 char    xbuf[50];
327
328                 if (df->rgodf[i].pguid)
329                         WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
330                 else
331                         strcpy(xbuf,"<no guid>");
332                 TRACE(dinput,"df.rgodf[%d].guid %s\n",i,xbuf);
333                 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
334                 TRACE(dinput,"dwType 0x%02lx,dwInstance %ld\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
335                 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
336         }
337         */
338         return 0;
339 }
340
341 static HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
342         LPDIRECTINPUTDEVICE2A iface,HWND32 hwnd,DWORD dwflags
343 ) {
344         ICOM_THIS(IDirectInputDevice2AImpl,iface);
345         FIXME(dinput,"(this=%p,0x%08lx,0x%08lx): stub\n",This,(DWORD)hwnd,dwflags);
346         if (TRACE_ON(dinput))
347           _dump_cooperativelevel(dwflags);
348         return 0;
349 }
350
351 static HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
352         LPDIRECTINPUTDEVICE2A iface,HANDLE32 hnd
353 ) {
354         ICOM_THIS(IDirectInputDevice2AImpl,iface);
355         FIXME(dinput,"(this=%p,0x%08lx): stub\n",This,(DWORD)hnd);
356         return 0;
357 }
358
359 static ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE2A iface)
360 {
361         ICOM_THIS(IDirectInputDevice2AImpl,iface);
362         This->ref--;
363         if (This->ref)
364                 return This->ref;
365         HeapFree(GetProcessHeap(),0,This);
366         return 0;
367 }
368
369 static HRESULT WINAPI SysKeyboardAImpl_SetProperty(
370         LPDIRECTINPUTDEVICE2A iface,REFGUID rguid,LPCDIPROPHEADER ph
371 )
372 {
373         ICOM_THIS(SysKeyboardAImpl,iface);
374         char                    xbuf[50];
375
376         if (HIWORD(rguid))
377                 WINE_StringFromCLSID(rguid,xbuf);
378         else
379                 sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
380         TRACE(dinput,"(this=%p,%s,%p)\n",This,xbuf,ph);
381         TRACE(dinput,"(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
382             ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
383         if (!HIWORD(rguid)) {
384                 switch ((DWORD)rguid) {
385                 case DIPROP_BUFFERSIZE: {
386                         LPCDIPROPDWORD  pd = (LPCDIPROPDWORD)ph;
387
388                         TRACE(dinput,"(buffersize=%ld)\n",pd->dwData);
389                         break;
390                 }
391                 default:
392                         WARN(dinput,"Unknown type %ld\n",(DWORD)rguid);
393                         break;
394                 }
395         }
396         return 0;
397 }
398
399 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(
400         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
401 )
402 {
403         if (len==256) {
404                 int keyc,vkey;
405
406                 memset(ptr,0,256);
407                 for (keyc=min_keycode;keyc<max_keycode;keyc++)
408                 {
409                     /* X keycode to virtual key */
410                     vkey = keyc2vkey[keyc] & 0xFF;
411                     /* The windows scancode is keyc-min_keycode */
412                     if (InputKeyStateTable[vkey]&0x80) {
413                         ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
414                         ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
415                     }
416                 }
417                 return 0;
418         }
419         WARN(dinput,"whoops, SysKeyboardAImpl_GetDeviceState got len %ld?\n",len);
420         return 0;
421 }
422
423 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData(
424         LPDIRECTINPUTDEVICE2A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
425         LPDWORD entries,DWORD flags
426 )
427 {
428         ICOM_THIS(SysKeyboardAImpl,iface);
429         int                     keyc,n,vkey,xentries;
430
431         TRACE(dinput,"(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
432                 This,dodsize,dod,entries,entries?*entries:0,flags);
433         EVENT_WaitNetEvent(FALSE,TRUE);
434         if (entries)
435                 xentries = *entries; 
436         else
437                 xentries = 1;
438
439         n = 0;
440
441         for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
442         {
443                     /* X keycode to virtual key */
444                     vkey = keyc2vkey[keyc] & 0xFF;
445                     if (This->keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
446                         continue;
447                 if (dod) {
448                         /* add an entry */
449                         dod[n].dwOfs            = keyc-min_keycode; /* scancode */
450                         dod[n].dwData           = InputKeyStateTable[vkey]&0x80;
451                         dod[n].dwTimeStamp      = 0; /* umm */
452                         dod[n].dwSequence       = 0; /* umm */
453                         n++;
454                 }
455                 if (!(flags & DIGDD_PEEK))
456                         This->keystate[vkey] = InputKeyStateTable[vkey]&0x80;
457                     
458         }
459         
460         if (n) fprintf(stderr,"%d entries\n",n);
461         *entries = n;
462         return 0;
463 }
464
465 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
466 {
467         ICOM_THIS(SysKeyboardAImpl,iface);
468         TRACE(dinput,"(this=%p): stub\n",This);
469         return 0;
470 }
471
472 static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
473 {
474         ICOM_THIS(SysKeyboardAImpl,iface);
475         TRACE(dinput,"(this=%p): stub\n",This);
476         return 0;
477 }
478
479 static HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
480         LPDIRECTINPUTDEVICE2A iface,REFIID riid,LPVOID *ppobj
481 )
482 {
483         ICOM_THIS(IDirectInputDevice2AImpl,iface);
484         char    xbuf[50];
485
486         WINE_StringFromCLSID(riid,xbuf);
487         TRACE(dinput,"(this=%p,%s,%p)\n",This,xbuf,ppobj);
488         if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
489                 IDirectInputDevice2_AddRef(iface);
490                 *ppobj = This;
491                 return 0;
492         }
493         if (!memcmp(&IID_IDirectInputDeviceA,riid,sizeof(*riid))) {
494                 IDirectInputDevice2_AddRef(iface);
495                 *ppobj = This;
496                 return 0;
497         }
498         if (!memcmp(&IID_IDirectInputDevice2A,riid,sizeof(*riid))) {
499                 IDirectInputDevice2_AddRef(iface);
500                 *ppobj = This;
501                 return 0;
502         }
503         return E_FAIL;
504 }
505
506 static ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
507         LPDIRECTINPUTDEVICE2A iface)
508 {
509         ICOM_THIS(IDirectInputDevice2AImpl,iface);
510         return ++This->ref;
511 }
512
513 static HRESULT WINAPI IDirectInputDevice2AImpl_GetCapabilities(
514         LPDIRECTINPUTDEVICE2A iface,
515         LPDIDEVCAPS lpDIDevCaps)
516 {
517         FIXME(dinput, "stub!\n");
518         return DI_OK;
519 }
520
521 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
522         LPDIRECTINPUTDEVICE2A iface,
523         LPDIENUMDEVICEOBJECTSCALLBACK32A lpCallback,
524         LPVOID lpvRef,
525         DWORD dwFlags)
526 {
527         FIXME(dinput, "stub!\n");
528 #if 0
529         if (lpCallback)
530                 lpCallback(NULL, lpvRef);
531 #endif
532         return DI_OK;
533 }
534         
535 static HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
536         LPDIRECTINPUTDEVICE2A iface,
537         REFGUID rguid,
538         LPDIPROPHEADER pdiph)
539 {
540         FIXME(dinput, "stub!\n");
541         return DI_OK;
542 }
543
544 static HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
545         LPDIRECTINPUTDEVICE2A iface,
546         LPDIDEVICEOBJECTINSTANCE32A pdidoi,
547         DWORD dwObj,
548         DWORD dwHow)
549 {
550         FIXME(dinput, "stub!\n");
551         return DI_OK;
552 }
553         
554 static HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
555         LPDIRECTINPUTDEVICE2A iface,
556         LPDIDEVICEINSTANCE32A pdidi)
557 {
558         FIXME(dinput, "stub!\n");
559         return DI_OK;
560 }
561         
562 static HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
563         LPDIRECTINPUTDEVICE2A iface,
564         HWND32 hwndOwner,
565         DWORD dwFlags)
566 {
567         FIXME(dinput, "stub!\n");
568         return DI_OK;
569 }
570         
571 static HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
572         LPDIRECTINPUTDEVICE2A iface,
573         HINSTANCE32 hinst,
574         DWORD dwVersion,
575         REFGUID rguid)
576 {
577         FIXME(dinput, "stub!\n");
578         return DI_OK;
579 }
580         
581 /******************************************************************************
582  *      IDirectInputDevice2A
583  */
584
585 static HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
586         LPDIRECTINPUTDEVICE2A iface,
587         REFGUID rguid,
588         LPCDIEFFECT lpeff,
589         LPDIRECTINPUTEFFECT *ppdef,
590         LPUNKNOWN pUnkOuter)
591 {
592         FIXME(dinput, "stub!\n");
593         return DI_OK;
594 }
595
596 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
597         LPDIRECTINPUTDEVICE2A iface,
598         LPDIENUMEFFECTSCALLBACKA lpCallback,
599         LPVOID lpvRef,
600         DWORD dwFlags)
601 {
602         FIXME(dinput, "stub!\n");
603         if (lpCallback)
604                 lpCallback(NULL, lpvRef);
605         return DI_OK;
606 }
607
608 static HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
609         LPDIRECTINPUTDEVICE2A iface,
610         LPDIEFFECTINFOA lpdei,
611         REFGUID rguid)
612 {
613         FIXME(dinput, "stub!\n");
614         return DI_OK;
615 }
616
617 static HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
618         LPDIRECTINPUTDEVICE2A iface,
619         LPDWORD pdwOut)
620 {
621         FIXME(dinput, "stub!\n");
622         return DI_OK;
623 }
624
625 static HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
626         LPDIRECTINPUTDEVICE2A iface,
627         DWORD dwFlags)
628 {
629         FIXME(dinput, "stub!\n");
630         return DI_OK;
631 }
632
633 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
634         LPDIRECTINPUTDEVICE2A iface,
635         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
636         LPVOID lpvRef,
637         DWORD dwFlags)
638 {
639         FIXME(dinput, "stub!\n");
640         if (lpCallback)
641                 lpCallback(NULL, lpvRef);
642         return DI_OK;
643 }
644
645 static HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
646         LPDIRECTINPUTDEVICE2A iface,
647         LPDIEFFESCAPE lpDIEEsc)
648 {
649         FIXME(dinput, "stub!\n");
650         return DI_OK;
651 }
652
653 static HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
654         LPDIRECTINPUTDEVICE2A iface)
655 {
656         FIXME(dinput, "stub!\n");
657         return DI_OK;
658 }
659
660 static HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
661         LPDIRECTINPUTDEVICE2A iface,
662         DWORD cbObjectData,
663         LPDIDEVICEOBJECTDATA rgdod,
664         LPDWORD pdwInOut,
665         DWORD dwFlags)
666 {
667         FIXME(dinput, "stub!\n");
668         return DI_OK;
669 }
670
671 /******************************************************************************
672  *      SysMouseA (DInput Mouse support)
673  */
674
675 /******************************************************************************
676   *     Release : release the mouse buffer.
677   */
678 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
679 {
680         ICOM_THIS(SysMouseAImpl,iface);
681
682         This->ref--;
683         if (This->ref)
684                 return This->ref;
685
686         /* Free the data queue */
687         if (This->data_queue != NULL)
688           HeapFree(GetProcessHeap(),0,This->data_queue);
689
690         /* Install the previous event handler (in case of releasing an aquired
691            mouse device) */
692         if (This->prev_handler != NULL)
693           MOUSE_Enable(This->prev_handler);
694         
695         HeapFree(GetProcessHeap(),0,This);
696         return 0;
697 }
698
699
700 /******************************************************************************
701   *     SetCooperativeLevel : store the window in which we will do our
702   *   grabbing.
703   */
704 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
705         LPDIRECTINPUTDEVICE2A iface,HWND32 hwnd,DWORD dwflags
706 )
707 {
708   ICOM_THIS(SysMouseAImpl,iface);
709
710   TRACE(dinput,"(this=%p,0x%08lx,0x%08lx): stub\n",This,(DWORD)hwnd,dwflags);
711
712   if (TRACE_ON(dinput))
713     _dump_cooperativelevel(dwflags);
714
715   /* Store the window which asks for the mouse */
716   This->win = hwnd;
717   
718   return 0;
719 }
720
721
722 /******************************************************************************
723   *     SetDataFormat : the application can choose the format of the data
724   *   the device driver sends back with GetDeviceState.
725   *
726   *   For the moment, only the "standard" configuration (c_dfDIMouse) is supported
727   *   in absolute and relative mode.
728   */
729 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
730         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
731 )
732 {
733   ICOM_THIS(SysMouseAImpl,iface);
734   int i;
735   
736   TRACE(dinput,"(this=%p,%p)\n",This,df);
737
738   TRACE(dinput,"(df.dwSize=%ld)\n",df->dwSize);
739   TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
740   TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
741   TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
742   TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
743
744   for (i=0;i<df->dwNumObjs;i++) {
745     char        xbuf[50];
746     
747     if (df->rgodf[i].pguid)
748       WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
749     else
750       strcpy(xbuf,"<no guid>");
751     TRACE(dinput,"df.rgodf[%d].guid %s (%p)\n",i,xbuf, df->rgodf[i].pguid);
752     TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
753     TRACE(dinput,"dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
754     TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
755   }
756
757   /* Check size of data format to prevent crashes if the applications
758      sends a smaller buffer */
759   if (df->dwDataSize != sizeof(struct DIMOUSESTATE)) {
760     FIXME(dinput, "non-standard mouse configuration not supported yet.");
761     return DIERR_INVALIDPARAM;
762   }
763   
764   /* For the moment, ignore these fields and return always as if
765      c_dfDIMouse was passed as format... */
766
767   /* Check if the mouse is in absolute or relative mode */
768   if (df->dwFlags == DIDF_ABSAXIS)
769     This->absolute = 1;
770   else 
771     This->absolute = 0;
772   
773   return 0;
774 }
775
776 #define GEN_EVENT(offset,data,time,seq)                                         \
777 {                                                                               \
778   if (This->queue_pos < This->queue_len) {                                      \
779     This->data_queue[This->queue_pos].dwOfs = offset;                           \
780     This->data_queue[This->queue_pos].dwData = data;                            \
781     This->data_queue[This->queue_pos].dwTimeStamp = time;                       \
782     This->data_queue[This->queue_pos].dwSequence = seq;                 \
783     This->queue_pos++;                                                          \
784   }                                                                             \
785   }
786   
787 /* Our private mouse event handler */
788 static void WINAPI dinput_mouse_event( DWORD dwFlags, DWORD dx, DWORD dy,
789                                       DWORD cButtons, DWORD dwExtraInfo )
790 {
791   DWORD posX, posY, keyState, time, extra;
792   SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
793   
794   if (   !IsBadReadPtr32( (LPVOID)dwExtraInfo, sizeof(WINE_MOUSEEVENT) )
795       && ((WINE_MOUSEEVENT *)dwExtraInfo)->magic == WINE_MOUSEEVENT_MAGIC ) {
796     WINE_MOUSEEVENT *wme = (WINE_MOUSEEVENT *)dwExtraInfo;
797     keyState = wme->keyState;
798     time = wme->time;
799     extra = (DWORD)wme->hWnd;
800     
801     assert( dwFlags & MOUSEEVENTF_ABSOLUTE );
802     posX = (dx * SYSMETRICS_CXSCREEN) >> 16;
803     posY = (dy * SYSMETRICS_CYSCREEN) >> 16;
804   } else {
805     ERR(dinput, "Mouse event not supported...\n");
806     return ;
807   }
808
809   TRACE(dinput, " %ld %ld ", posX, posY);
810
811   if ( dwFlags & MOUSEEVENTF_MOVE ) {
812     if (This->absolute) {
813       if (posX != This->prevX)
814         GEN_EVENT(DIMOFS_X, posX, time, 0);
815       if (posY != This->prevY)
816         GEN_EVENT(DIMOFS_Y, posY, time, 0);
817     } else {
818       /* Relative mouse input : the real fun starts here... */
819       if (This->need_warp) {
820         if (posX != This->prevX)
821           GEN_EVENT(DIMOFS_X, posX - This->prevX, time, 0);
822         if (posY != This->prevY)
823           GEN_EVENT(DIMOFS_Y, posY - This->prevY, time, 0);
824       } else {
825         /* This is the first time the event handler has been called after a
826            GetData of GetState. */
827         if (posX != This->win_centerX) {
828           GEN_EVENT(DIMOFS_X, posX - This->win_centerX, time, 0);
829           This->need_warp = 1;
830         }
831           
832         if (posY != This->win_centerY) {
833           GEN_EVENT(DIMOFS_Y, posY - This->win_centerY, time, 0);
834           This->need_warp = 1;
835         }
836       }
837     }
838   }
839   if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) {
840     if (TRACE_ON(dinput))
841       DUMP(" LD ");
842
843     GEN_EVENT(DIMOFS_BUTTON0, 0xFF, time, 0);
844   }
845   if ( dwFlags & MOUSEEVENTF_LEFTUP ) {
846     if (TRACE_ON(dinput))
847       DUMP(" LU ");
848
849     GEN_EVENT(DIMOFS_BUTTON0, 0x00, time, 0);
850   }
851   if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) {
852     if (TRACE_ON(dinput))
853       DUMP(" RD ");
854
855     GEN_EVENT(DIMOFS_BUTTON1, 0xFF, time, 0);
856   }
857   if ( dwFlags & MOUSEEVENTF_RIGHTUP ) {
858     if (TRACE_ON(dinput))
859       DUMP(" RU ");
860
861     GEN_EVENT(DIMOFS_BUTTON1, 0x00, time, 0);
862   }
863   if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) {
864     if (TRACE_ON(dinput))
865       DUMP(" MD ");
866
867     GEN_EVENT(DIMOFS_BUTTON2, 0xFF, time, 0);
868   }
869   if ( dwFlags & MOUSEEVENTF_MIDDLEUP ) {
870     if (TRACE_ON(dinput))
871       DUMP(" MU ");
872
873     GEN_EVENT(DIMOFS_BUTTON2, 0x00, time, 0);
874   }
875   if (TRACE_ON(dinput))
876     DUMP("\n");
877
878   This->prevX = posX;
879   This->prevY = posY;
880 }
881
882
883 /******************************************************************************
884   *     Acquire : gets exclusive control of the mouse
885   */
886 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
887 {
888   ICOM_THIS(SysMouseAImpl,iface);
889   RECT32        rect;
890   
891   TRACE(dinput,"(this=%p)\n",This);
892
893   if (This->acquired == 0) {
894     /* This stores the current mouse handler.
895        FIXME : need to be fixed for native USER use */
896     This->prev_handler = mouse_event;
897     
898     /* Store (in a global variable) the current lock */
899     current_lock = (IDirectInputDevice2A*)This;
900     
901     /* Install our own mouse event handler */
902     MOUSE_Enable(dinput_mouse_event);
903     
904     /* Get the window dimension and find the center */
905     GetWindowRect32(This->win, &rect);
906     This->xwin = ((X11DRV_WND_DATA *) WIN_FindWndPtr(This->win)->pDriverData)->window;
907     This->win_centerX = (rect.right  - rect.left) / 2;
908     This->win_centerY = (rect.bottom - rect.top ) / 2;
909     /* Warp the mouse to the center of the window */
910     TRACE(dinput, "Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
911     TSXWarpPointer(display, DefaultRootWindow(display),
912                    This->xwin, 0, 0, 0, 0,
913                    This->win_centerX, This->win_centerY);
914     
915     This->acquired = 1;
916   }
917   return 0;
918 }
919
920 /******************************************************************************
921   *     Unacquire : frees the mouse
922   */
923 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
924 {
925   ICOM_THIS(SysMouseAImpl,iface);
926
927   TRACE(dinput,"(this=%p)\n",This);
928
929   /* Reinstall previous mouse event handler */
930   MOUSE_Enable(This->prev_handler);
931   This->prev_handler = NULL;
932   
933   /* No more locks */
934   current_lock = NULL;
935
936   /* Unacquire device */
937   This->acquired = 0;
938   
939   return 0;
940 }
941
942 /******************************************************************************
943   *     GetDeviceState : returns the "state" of the mouse.
944   *
945   *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
946   *   supported.
947   */
948 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
949         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
950 ) {
951   ICOM_THIS(SysMouseAImpl,iface);
952   DWORD rx, ry, state;
953   struct DIMOUSESTATE *mstate = (struct DIMOUSESTATE *) ptr;
954   
955   TRACE(dinput,"(this=%p,0x%08lx,%p): \n",This,len,ptr);
956   
957   /* Check if the buffer is big enough */
958   if (len < sizeof(struct DIMOUSESTATE)) {
959     FIXME(dinput, "unsupported state structure.");
960     return DIERR_INVALIDPARAM;
961   }
962   
963   /* Get the mouse position */
964   EVENT_QueryPointer(&rx, &ry, &state);
965   TRACE(dinput,"(X:%ld - Y:%ld)\n", rx, ry);
966
967   /* Fill the mouse state structure */
968   if (This->absolute) {
969     mstate->lX = rx;
970     mstate->lY = ry;
971   } else {
972     mstate->lX = rx - This->win_centerX;
973     mstate->lY = ry - This->win_centerY;
974
975     if ((mstate->lX != 0) || (mstate->lY != 0))
976       This->need_warp = 1;
977   }
978   mstate->lZ = 0;
979   mstate->rgbButtons[0] = (state & MK_LBUTTON ? 0xFF : 0x00);
980   mstate->rgbButtons[1] = (state & MK_RBUTTON ? 0xFF : 0x00);
981   mstate->rgbButtons[2] = (state & MK_MBUTTON ? 0xFF : 0x00);
982   mstate->rgbButtons[3] = 0x00;
983   
984   /* Check if we need to do a mouse warping */
985   if (This->need_warp) {
986     TRACE(dinput, "Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
987     TSXWarpPointer(display, DefaultRootWindow(display),
988                    This->xwin, 0, 0, 0, 0,
989                    This->win_centerX, This->win_centerY);
990     This->need_warp = 0;
991   }
992   
993   TRACE(dinput, "(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
994         mstate->lX, mstate->lY,
995         mstate->rgbButtons[0], mstate->rgbButtons[2], mstate->rgbButtons[1]);
996   
997   return 0;
998 }
999
1000 /******************************************************************************
1001   *     GetDeviceState : gets buffered input data.
1002   */
1003 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
1004                                               DWORD dodsize,
1005                                               LPDIDEVICEOBJECTDATA dod,
1006                                               LPDWORD entries,
1007                                               DWORD flags
1008 ) {
1009   ICOM_THIS(SysMouseAImpl,iface);
1010   
1011   TRACE(dinput,"(%p)->(%ld,%p,%p(0x%08lx),0x%08lx)\n",
1012         This,dodsize,dod,entries,*entries,flags);
1013
1014   if (flags & DIGDD_PEEK)
1015     TRACE(dinput, "DIGDD_PEEK\n");
1016
1017   if (dod == NULL) {
1018     *entries = This->queue_pos;
1019     This->queue_pos = 0;
1020   } else {
1021     /* Check for buffer overflow */
1022     if (This->queue_pos > *entries) {
1023       WARN(dinput, "Buffer overflow not handled properly yet...\n");
1024       This->queue_pos = *entries;
1025     }
1026     if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
1027       ERR(dinput, "Wrong structure size !\n");
1028       return DIERR_INVALIDPARAM;
1029     }
1030
1031     TRACE(dinput, "Application retrieving %d event(s).\n", This->queue_pos); 
1032     
1033     /* Copy the buffered data into the application queue */
1034     memcpy(dod, This->data_queue, This->queue_pos * dodsize);
1035     
1036     /* Reset the event queue */
1037     This->queue_pos = 0;
1038   }
1039   
1040   /* Check if we need to do a mouse warping */
1041   if (This->need_warp) {
1042     TRACE(dinput, "Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1043     TSXWarpPointer(display, DefaultRootWindow(display),
1044                    This->xwin, 0, 0, 0, 0,
1045                    This->win_centerX, This->win_centerY);
1046     This->need_warp = 0;
1047   }
1048   
1049   return 0;
1050 }
1051
1052 /******************************************************************************
1053   *     SetProperty : change input device properties
1054   */
1055 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
1056                                             REFGUID rguid,
1057                                             LPCDIPROPHEADER ph)
1058 {
1059   ICOM_THIS(SysMouseAImpl,iface);
1060   char  xbuf[50];
1061
1062   if (HIWORD(rguid))
1063     WINE_StringFromCLSID(rguid,xbuf);
1064   else
1065     sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
1066
1067   TRACE(dinput,"(this=%p,%s,%p)\n",This,xbuf,ph);
1068   
1069   if (!HIWORD(rguid)) {
1070     switch ((DWORD)rguid) {
1071     case DIPROP_BUFFERSIZE: {
1072       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1073       
1074       TRACE(dinput,"buffersize = %ld\n",pd->dwData);
1075
1076       This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
1077                                                           pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1078       This->queue_pos  = 0;
1079       This->queue_len  = pd->dwData;
1080       break;
1081     }
1082     default:
1083       WARN(dinput,"Unknown type %ld\n",(DWORD)rguid);
1084       break;
1085     }
1086   }
1087   
1088   return 0;
1089 }
1090
1091
1092 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt={
1093         IDirectInputDevice2AImpl_QueryInterface,
1094         IDirectInputDevice2AImpl_AddRef,
1095         IDirectInputDevice2AImpl_Release,
1096         IDirectInputDevice2AImpl_GetCapabilities,
1097         IDirectInputDevice2AImpl_EnumObjects,
1098         IDirectInputDevice2AImpl_GetProperty,
1099         SysKeyboardAImpl_SetProperty,
1100         SysKeyboardAImpl_Acquire,
1101         SysKeyboardAImpl_Unacquire,
1102         SysKeyboardAImpl_GetDeviceState,
1103         SysKeyboardAImpl_GetDeviceData,
1104         IDirectInputDevice2AImpl_SetDataFormat,
1105         IDirectInputDevice2AImpl_SetEventNotification,
1106         IDirectInputDevice2AImpl_SetCooperativeLevel,
1107         IDirectInputDevice2AImpl_GetObjectInfo,
1108         IDirectInputDevice2AImpl_GetDeviceInfo,
1109         IDirectInputDevice2AImpl_RunControlPanel,
1110         IDirectInputDevice2AImpl_Initialize,
1111         IDirectInputDevice2AImpl_CreateEffect,
1112         IDirectInputDevice2AImpl_EnumEffects,
1113         IDirectInputDevice2AImpl_GetEffectInfo,
1114         IDirectInputDevice2AImpl_GetForceFeedbackState,
1115         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1116         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1117         IDirectInputDevice2AImpl_Escape,
1118         IDirectInputDevice2AImpl_Poll,
1119         IDirectInputDevice2AImpl_SendDeviceData,
1120 };
1121
1122 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt={
1123         IDirectInputDevice2AImpl_QueryInterface,
1124         IDirectInputDevice2AImpl_AddRef,
1125         SysMouseAImpl_Release,
1126         IDirectInputDevice2AImpl_GetCapabilities,
1127         IDirectInputDevice2AImpl_EnumObjects,
1128         IDirectInputDevice2AImpl_GetProperty,
1129         SysMouseAImpl_SetProperty,
1130         SysMouseAImpl_Acquire,
1131         SysMouseAImpl_Unacquire,
1132         SysMouseAImpl_GetDeviceState,
1133         SysMouseAImpl_GetDeviceData,
1134         SysMouseAImpl_SetDataFormat,
1135         IDirectInputDevice2AImpl_SetEventNotification,
1136         SysMouseAImpl_SetCooperativeLevel,
1137         IDirectInputDevice2AImpl_GetObjectInfo,
1138         IDirectInputDevice2AImpl_GetDeviceInfo,
1139         IDirectInputDevice2AImpl_RunControlPanel,
1140         IDirectInputDevice2AImpl_Initialize,
1141         IDirectInputDevice2AImpl_CreateEffect,
1142         IDirectInputDevice2AImpl_EnumEffects,
1143         IDirectInputDevice2AImpl_GetEffectInfo,
1144         IDirectInputDevice2AImpl_GetForceFeedbackState,
1145         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1146         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1147         IDirectInputDevice2AImpl_Escape,
1148         IDirectInputDevice2AImpl_Poll,
1149         IDirectInputDevice2AImpl_SendDeviceData,
1150 };