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