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