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