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