Fixed some deadlock(s) in message sending.
[wine.git] / windows / dinput.c
blobc22e20692730017f9b7b58ab5e6ed3ee5febebce
1 /* DirectInput
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
6 */
7 /* Status:
9 * - Tomb Raider 2 Demo:
10 * Playable using keyboard only.
11 * - WingCommander Prophecy Demo:
12 * Doesn't get Input Focus.
14 * - Fallout : works great in X and DGA mode
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.)
21 #include "config.h"
22 #include <string.h>
23 #include <unistd.h>
24 #include <assert.h>
25 #include <sys/signal.h>
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "wine/obj_base.h"
30 #include "dinput.h"
31 #include "debug.h"
32 #include "message.h"
33 #include "display.h"
34 #include "mouse.h"
35 #include "sysmetrics.h"
37 DEFAULT_DEBUG_CHANNEL(dinput)
39 extern BYTE InputKeyStateTable[256];
40 extern int min_keycode, max_keycode;
41 extern WORD keyc2vkey[256];
43 static ICOM_VTABLE(IDirectInputA) ddiavt;
44 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt;
45 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt;
47 typedef struct IDirectInputAImpl IDirectInputAImpl;
48 typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl;
49 typedef struct SysKeyboardAImpl SysKeyboardAImpl;
50 typedef struct SysMouseAImpl SysMouseAImpl;
52 struct IDirectInputDevice2AImpl
54 ICOM_VTABLE(IDirectInputDevice2A)* lpvtbl;
55 DWORD ref;
56 GUID guid;
59 struct SysKeyboardAImpl
61 /* IDirectInputDevice2AImpl */
62 ICOM_VTABLE(IDirectInputDevice2A)* lpvtbl;
63 DWORD ref;
64 GUID guid;
65 /* SysKeyboardAImpl */
66 BYTE keystate[256];
69 struct SysMouseAImpl
71 /* IDirectInputDevice2AImpl */
72 ICOM_VTABLE(IDirectInputDevice2A)* lpvtbl;
73 DWORD ref;
74 GUID guid;
75 /* SysMouseAImpl */
76 BYTE absolute;
77 /* Previous position for relative moves */
78 LONG prevX, prevY;
79 LPMOUSE_EVENT_PROC prev_handler;
80 HWND win;
81 DWORD win_centerX, win_centerY;
82 LPDIDEVICEOBJECTDATA data_queue;
83 int queue_pos, queue_len;
84 int need_warp;
85 int acquired;
89 /* UIDs for Wine "drivers".
90 When enumerating each device supporting DInput, they have two UIDs :
91 - the 'windows' UID
92 - a vendor UID */
93 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
94 0x9e573ed8,
95 0x7734,
96 0x11d2,
97 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
99 static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
100 0x0ab8648a,
101 0x7735,
102 0x11d2,
103 {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41}
106 /* FIXME: This is ugly and not thread safe :/ */
107 static IDirectInputDevice2A* current_lock = NULL;
109 /******************************************************************************
110 * Various debugging tools
112 static void _dump_cooperativelevel(DWORD dwFlags) {
113 int i;
114 const struct {
115 DWORD mask;
116 char *name;
117 } flags[] = {
118 #define FE(x) { x, #x},
119 FE(DISCL_BACKGROUND)
120 FE(DISCL_EXCLUSIVE)
121 FE(DISCL_FOREGROUND)
122 FE(DISCL_NONEXCLUSIVE)
124 for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
125 if (flags[i].mask & dwFlags)
126 DUMP("%s ",flags[i].name);
127 DUMP("\n");
130 struct IDirectInputAImpl
132 ICOM_VTABLE(IDirectInputA)* lpvtbl;
133 DWORD ref;
136 /******************************************************************************
137 * DirectInputCreate32A
139 HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
141 IDirectInputAImpl* This;
142 TRACE(dinput, "(0x%08lx,%04lx,%p,%p)\n",
143 (DWORD)hinst,dwVersion,ppDI,punkOuter
145 This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
146 This->ref = 1;
147 This->lpvtbl = &ddiavt;
148 *ppDI=(IDirectInputA*)This;
149 return 0;
151 /******************************************************************************
152 * IDirectInputA_EnumDevices
154 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
155 LPDIRECTINPUTA iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
156 LPVOID pvRef, DWORD dwFlags
159 ICOM_THIS(IDirectInputAImpl,iface);
160 DIDEVICEINSTANCEA devInstance;
161 int ret;
163 TRACE(dinput, "(this=%p,0x%04lx,%p,%p,%04lx)\n", This, dwDevType, lpCallback, pvRef, dwFlags);
165 devInstance.dwSize = sizeof(DIDEVICEINSTANCEA);
167 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
168 /* Return keyboard */
169 devInstance.guidInstance = GUID_SysKeyboard; /* DInput's GUID */
170 devInstance.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
171 devInstance.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
172 strcpy(devInstance.tszInstanceName, "Keyboard");
173 strcpy(devInstance.tszProductName, "Wine Keyboard");
175 ret = lpCallback(&devInstance, pvRef);
176 TRACE(dinput, "Keyboard registered\n");
178 if (ret == DIENUM_STOP)
179 return 0;
182 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
183 /* Return mouse */
184 devInstance.guidInstance = GUID_SysMouse; /* DInput's GUID */
185 devInstance.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
186 devInstance.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
187 strcpy(devInstance.tszInstanceName, "Mouse");
188 strcpy(devInstance.tszProductName, "Wine Mouse");
190 ret = lpCallback(&devInstance, pvRef);
191 TRACE(dinput, "Mouse registered\n");
194 /* Should also do joystick enumerations.... */
196 return 0;
199 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUTA iface)
201 ICOM_THIS(IDirectInputAImpl,iface);
202 return ++(This->ref);
205 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUTA iface)
207 ICOM_THIS(IDirectInputAImpl,iface);
208 if (!(--This->ref)) {
209 HeapFree(GetProcessHeap(),0,This);
210 return 0;
212 return This->ref;
215 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(
216 LPDIRECTINPUTA iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev,
217 LPUNKNOWN punk
219 ICOM_THIS(IDirectInputAImpl,iface);
220 char xbuf[50];
222 WINE_StringFromCLSID(rguid,xbuf);
223 FIXME(dinput,"(this=%p,%s,%p,%p): stub\n",This,xbuf,pdev,punk);
224 if ((!memcmp(&GUID_SysKeyboard,rguid,sizeof(GUID_SysKeyboard))) || /* Generic Keyboard */
225 (!memcmp(&DInput_Wine_Keyboard_GUID,rguid,sizeof(GUID_SysKeyboard)))) { /* Wine Keyboard */
226 SysKeyboardAImpl* newDevice;
227 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardAImpl));
228 newDevice->ref = 1;
229 newDevice->lpvtbl = &SysKeyboardAvt;
230 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
231 memset(newDevice->keystate,0,256);
232 *pdev=(IDirectInputDeviceA*)newDevice;
233 return DI_OK;
235 if ((!memcmp(&GUID_SysMouse,rguid,sizeof(GUID_SysMouse))) || /* Generic Mouse */
236 (!memcmp(&DInput_Wine_Mouse_GUID,rguid,sizeof(GUID_SysMouse)))) { /* Wine Mouse */
237 SysKeyboardAImpl* newDevice;
238 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
239 newDevice->ref = 1;
240 newDevice->lpvtbl = &SysMouseAvt;
241 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
242 *pdev=(IDirectInputDeviceA*)newDevice;
243 return DI_OK;
245 return E_FAIL;
248 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(
249 LPDIRECTINPUTA iface,REFIID riid,LPVOID *ppobj
251 ICOM_THIS(IDirectInputAImpl,iface);
252 char xbuf[50];
254 WINE_StringFromCLSID(riid,xbuf);
255 TRACE(dinput,"(this=%p,%s,%p)\n",This,xbuf,ppobj);
256 if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
257 IDirectInputA_AddRef(iface);
258 *ppobj = This;
259 return 0;
261 if (!memcmp(&IID_IDirectInputA,riid,sizeof(*riid))) {
262 IDirectInputA_AddRef(iface);
263 *ppobj = This;
264 return 0;
266 return E_FAIL;
269 static HRESULT WINAPI IDirectInputAImpl_Initialize(
270 LPDIRECTINPUTA iface,HINSTANCE hinst,DWORD x
272 return DIERR_ALREADYINITIALIZED;
275 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUTA iface,
276 REFGUID rguid) {
277 ICOM_THIS(IDirectInputAImpl,iface);
278 char xbuf[50];
280 WINE_StringFromCLSID(rguid,xbuf);
281 FIXME(dinput,"(%p)->(%s): stub\n",This,xbuf);
283 return DI_OK;
286 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUTA iface,
287 HWND hwndOwner,
288 DWORD dwFlags) {
289 ICOM_THIS(IDirectInputAImpl,iface);
290 FIXME(dinput,"(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags);
292 return DI_OK;
295 static ICOM_VTABLE(IDirectInputA) ddiavt= {
296 IDirectInputAImpl_QueryInterface,
297 IDirectInputAImpl_AddRef,
298 IDirectInputAImpl_Release,
299 IDirectInputAImpl_CreateDevice,
300 IDirectInputAImpl_EnumDevices,
301 IDirectInputAImpl_GetDeviceStatus,
302 IDirectInputAImpl_RunControlPanel,
303 IDirectInputAImpl_Initialize
306 /******************************************************************************
307 * IDirectInputDeviceA
310 static HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
311 LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
314 int i;
315 TRACE(dinput,"(this=%p,%p)\n",This,df);
317 TRACE(dinput,"df.dwSize=%ld\n",df->dwSize);
318 TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
319 TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
320 TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
321 TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
323 for (i=0;i<df->dwNumObjs;i++) {
324 char xbuf[50];
326 if (df->rgodf[i].pguid)
327 WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
328 else
329 strcpy(xbuf,"<no guid>");
330 TRACE(dinput,"df.rgodf[%d].guid %s\n",i,xbuf);
331 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
332 TRACE(dinput,"dwType 0x%02lx,dwInstance %ld\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
333 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
336 return 0;
339 static HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
340 LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
342 ICOM_THIS(IDirectInputDevice2AImpl,iface);
343 FIXME(dinput,"(this=%p,0x%08lx,0x%08lx): stub\n",This,(DWORD)hwnd,dwflags);
344 if (TRACE_ON(dinput))
345 _dump_cooperativelevel(dwflags);
346 return 0;
349 static HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
350 LPDIRECTINPUTDEVICE2A iface,HANDLE hnd
352 ICOM_THIS(IDirectInputDevice2AImpl,iface);
353 FIXME(dinput,"(this=%p,0x%08lx): stub\n",This,(DWORD)hnd);
354 return 0;
357 static ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE2A iface)
359 ICOM_THIS(IDirectInputDevice2AImpl,iface);
360 This->ref--;
361 if (This->ref)
362 return This->ref;
363 HeapFree(GetProcessHeap(),0,This);
364 return 0;
367 static HRESULT WINAPI SysKeyboardAImpl_SetProperty(
368 LPDIRECTINPUTDEVICE2A iface,REFGUID rguid,LPCDIPROPHEADER ph
371 ICOM_THIS(SysKeyboardAImpl,iface);
372 char xbuf[50];
374 if (HIWORD(rguid))
375 WINE_StringFromCLSID(rguid,xbuf);
376 else
377 sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
378 TRACE(dinput,"(this=%p,%s,%p)\n",This,xbuf,ph);
379 TRACE(dinput,"(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
380 ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
381 if (!HIWORD(rguid)) {
382 switch ((DWORD)rguid) {
383 case (DWORD) DIPROP_BUFFERSIZE: {
384 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
386 TRACE(dinput,"(buffersize=%ld)\n",pd->dwData);
387 break;
389 default:
390 WARN(dinput,"Unknown type %ld\n",(DWORD)rguid);
391 break;
394 return 0;
397 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(
398 LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
401 if (len==256) {
402 int keyc,vkey;
404 memset(ptr,0,256);
405 for (keyc=min_keycode;keyc<max_keycode;keyc++)
407 /* X keycode to virtual key */
408 vkey = keyc2vkey[keyc] & 0xFF;
409 /* The windows scancode is keyc-min_keycode */
410 if (InputKeyStateTable[vkey]&0x80) {
411 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
412 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
415 return 0;
417 WARN(dinput,"whoops, SysKeyboardAImpl_GetDeviceState got len %ld?\n",len);
418 return 0;
421 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData(
422 LPDIRECTINPUTDEVICE2A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
423 LPDWORD entries,DWORD flags
426 ICOM_THIS(SysKeyboardAImpl,iface);
427 int keyc,n,vkey,xentries;
429 TRACE(dinput,"(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
430 This,dodsize,dod,entries,entries?*entries:0,flags);
431 EVENT_WaitNetEvent(FALSE,TRUE);
432 if (entries)
433 xentries = *entries;
434 else
435 xentries = 1;
437 n = 0;
439 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
441 /* X keycode to virtual key */
442 vkey = keyc2vkey[keyc] & 0xFF;
443 if (This->keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
444 continue;
445 if (dod) {
446 /* add an entry */
447 dod[n].dwOfs = keyc-min_keycode; /* scancode */
448 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
449 dod[n].dwTimeStamp = 0; /* umm */
450 dod[n].dwSequence = 0; /* umm */
451 n++;
453 if (!(flags & DIGDD_PEEK))
454 This->keystate[vkey] = InputKeyStateTable[vkey]&0x80;
458 if (n) fprintf(stderr,"%d entries\n",n);
459 *entries = n;
460 return 0;
463 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
465 ICOM_THIS(SysKeyboardAImpl,iface);
466 TRACE(dinput,"(this=%p): stub\n",This);
467 return 0;
470 static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
472 ICOM_THIS(SysKeyboardAImpl,iface);
473 TRACE(dinput,"(this=%p): stub\n",This);
474 return 0;
477 static HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
478 LPDIRECTINPUTDEVICE2A iface,REFIID riid,LPVOID *ppobj
481 ICOM_THIS(IDirectInputDevice2AImpl,iface);
482 char xbuf[50];
484 WINE_StringFromCLSID(riid,xbuf);
485 TRACE(dinput,"(this=%p,%s,%p)\n",This,xbuf,ppobj);
486 if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
487 IDirectInputDevice2_AddRef(iface);
488 *ppobj = This;
489 return 0;
491 if (!memcmp(&IID_IDirectInputDeviceA,riid,sizeof(*riid))) {
492 IDirectInputDevice2_AddRef(iface);
493 *ppobj = This;
494 return 0;
496 if (!memcmp(&IID_IDirectInputDevice2A,riid,sizeof(*riid))) {
497 IDirectInputDevice2_AddRef(iface);
498 *ppobj = This;
499 return 0;
501 return E_FAIL;
504 static ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
505 LPDIRECTINPUTDEVICE2A iface)
507 ICOM_THIS(IDirectInputDevice2AImpl,iface);
508 return ++This->ref;
511 static HRESULT WINAPI IDirectInputDevice2AImpl_GetCapabilities(
512 LPDIRECTINPUTDEVICE2A iface,
513 LPDIDEVCAPS lpDIDevCaps)
515 FIXME(dinput, "stub!\n");
516 return DI_OK;
519 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
520 LPDIRECTINPUTDEVICE2A iface,
521 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
522 LPVOID lpvRef,
523 DWORD dwFlags)
525 FIXME(dinput, "stub!\n");
526 #if 0
527 if (lpCallback)
528 lpCallback(NULL, lpvRef);
529 #endif
530 return DI_OK;
533 static HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
534 LPDIRECTINPUTDEVICE2A iface,
535 REFGUID rguid,
536 LPDIPROPHEADER pdiph)
538 FIXME(dinput, "stub!\n");
539 return DI_OK;
542 static HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
543 LPDIRECTINPUTDEVICE2A iface,
544 LPDIDEVICEOBJECTINSTANCEA pdidoi,
545 DWORD dwObj,
546 DWORD dwHow)
548 FIXME(dinput, "stub!\n");
549 return DI_OK;
552 static HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
553 LPDIRECTINPUTDEVICE2A iface,
554 LPDIDEVICEINSTANCEA pdidi)
556 FIXME(dinput, "stub!\n");
557 return DI_OK;
560 static HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
561 LPDIRECTINPUTDEVICE2A iface,
562 HWND hwndOwner,
563 DWORD dwFlags)
565 FIXME(dinput, "stub!\n");
566 return DI_OK;
569 static HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
570 LPDIRECTINPUTDEVICE2A iface,
571 HINSTANCE hinst,
572 DWORD dwVersion,
573 REFGUID rguid)
575 FIXME(dinput, "stub!\n");
576 return DI_OK;
579 /******************************************************************************
580 * IDirectInputDevice2A
583 static HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
584 LPDIRECTINPUTDEVICE2A iface,
585 REFGUID rguid,
586 LPCDIEFFECT lpeff,
587 LPDIRECTINPUTEFFECT *ppdef,
588 LPUNKNOWN pUnkOuter)
590 FIXME(dinput, "stub!\n");
591 return DI_OK;
594 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
595 LPDIRECTINPUTDEVICE2A iface,
596 LPDIENUMEFFECTSCALLBACKA lpCallback,
597 LPVOID lpvRef,
598 DWORD dwFlags)
600 FIXME(dinput, "stub!\n");
601 if (lpCallback)
602 lpCallback(NULL, lpvRef);
603 return DI_OK;
606 static HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
607 LPDIRECTINPUTDEVICE2A iface,
608 LPDIEFFECTINFOA lpdei,
609 REFGUID rguid)
611 FIXME(dinput, "stub!\n");
612 return DI_OK;
615 static HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
616 LPDIRECTINPUTDEVICE2A iface,
617 LPDWORD pdwOut)
619 FIXME(dinput, "stub!\n");
620 return DI_OK;
623 static HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
624 LPDIRECTINPUTDEVICE2A iface,
625 DWORD dwFlags)
627 FIXME(dinput, "stub!\n");
628 return DI_OK;
631 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
632 LPDIRECTINPUTDEVICE2A iface,
633 LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
634 LPVOID lpvRef,
635 DWORD dwFlags)
637 FIXME(dinput, "stub!\n");
638 if (lpCallback)
639 lpCallback(NULL, lpvRef);
640 return DI_OK;
643 static HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
644 LPDIRECTINPUTDEVICE2A iface,
645 LPDIEFFESCAPE lpDIEEsc)
647 FIXME(dinput, "stub!\n");
648 return DI_OK;
651 static HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
652 LPDIRECTINPUTDEVICE2A iface)
654 FIXME(dinput, "stub!\n");
655 return DI_OK;
658 static HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
659 LPDIRECTINPUTDEVICE2A iface,
660 DWORD cbObjectData,
661 LPDIDEVICEOBJECTDATA rgdod,
662 LPDWORD pdwInOut,
663 DWORD dwFlags)
665 FIXME(dinput, "stub!\n");
666 return DI_OK;
669 /******************************************************************************
670 * SysMouseA (DInput Mouse support)
673 /******************************************************************************
674 * Release : release the mouse buffer.
676 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
678 ICOM_THIS(SysMouseAImpl,iface);
680 This->ref--;
681 if (This->ref)
682 return This->ref;
684 /* Free the data queue */
685 if (This->data_queue != NULL)
686 HeapFree(GetProcessHeap(),0,This->data_queue);
688 /* Install the previous event handler (in case of releasing an aquired
689 mouse device) */
690 if (This->prev_handler != NULL)
691 MOUSE_Enable(This->prev_handler);
693 HeapFree(GetProcessHeap(),0,This);
694 return 0;
698 /******************************************************************************
699 * SetCooperativeLevel : store the window in which we will do our
700 * grabbing.
702 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
703 LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
706 ICOM_THIS(SysMouseAImpl,iface);
708 TRACE(dinput,"(this=%p,0x%08lx,0x%08lx): stub\n",This,(DWORD)hwnd,dwflags);
710 if (TRACE_ON(dinput))
711 _dump_cooperativelevel(dwflags);
713 /* Store the window which asks for the mouse */
714 This->win = hwnd;
716 return 0;
720 /******************************************************************************
721 * SetDataFormat : the application can choose the format of the data
722 * the device driver sends back with GetDeviceState.
724 * For the moment, only the "standard" configuration (c_dfDIMouse) is supported
725 * in absolute and relative mode.
727 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
728 LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
731 ICOM_THIS(SysMouseAImpl,iface);
732 int i;
734 TRACE(dinput,"(this=%p,%p)\n",This,df);
736 TRACE(dinput,"(df.dwSize=%ld)\n",df->dwSize);
737 TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
738 TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
739 TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
740 TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
742 for (i=0;i<df->dwNumObjs;i++) {
743 char xbuf[50];
745 if (df->rgodf[i].pguid)
746 WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
747 else
748 strcpy(xbuf,"<no guid>");
749 TRACE(dinput,"df.rgodf[%d].guid %s (%p)\n",i,xbuf, df->rgodf[i].pguid);
750 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
751 TRACE(dinput,"dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
752 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
755 /* Check size of data format to prevent crashes if the applications
756 sends a smaller buffer */
757 if (df->dwDataSize != sizeof(struct DIMOUSESTATE)) {
758 FIXME(dinput, "non-standard mouse configuration not supported yet.");
759 return DIERR_INVALIDPARAM;
762 /* For the moment, ignore these fields and return always as if
763 c_dfDIMouse was passed as format... */
765 /* Check if the mouse is in absolute or relative mode */
766 if (df->dwFlags == DIDF_ABSAXIS)
767 This->absolute = 1;
768 else
769 This->absolute = 0;
771 return 0;
774 #define GEN_EVENT(offset,data,time,seq) \
776 if (This->queue_pos < This->queue_len) { \
777 This->data_queue[This->queue_pos].dwOfs = offset; \
778 This->data_queue[This->queue_pos].dwData = data; \
779 This->data_queue[This->queue_pos].dwTimeStamp = time; \
780 This->data_queue[This->queue_pos].dwSequence = seq; \
781 This->queue_pos++; \
785 /* Our private mouse event handler */
786 static void WINAPI dinput_mouse_event( DWORD dwFlags, DWORD dx, DWORD dy,
787 DWORD cButtons, DWORD dwExtraInfo )
789 DWORD posX, posY, keyState, time, extra;
790 SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
792 if ( !IsBadReadPtr( (LPVOID)dwExtraInfo, sizeof(WINE_MOUSEEVENT) )
793 && ((WINE_MOUSEEVENT *)dwExtraInfo)->magic == WINE_MOUSEEVENT_MAGIC ) {
794 WINE_MOUSEEVENT *wme = (WINE_MOUSEEVENT *)dwExtraInfo;
795 keyState = wme->keyState;
796 time = wme->time;
797 extra = (DWORD)wme->hWnd;
799 assert( dwFlags & MOUSEEVENTF_ABSOLUTE );
800 posX = (dx * SYSMETRICS_CXSCREEN) >> 16;
801 posY = (dy * SYSMETRICS_CYSCREEN) >> 16;
802 } else {
803 ERR(dinput, "Mouse event not supported...\n");
804 return ;
807 TRACE(dinput, " %ld %ld ", posX, posY);
809 if ( dwFlags & MOUSEEVENTF_MOVE ) {
810 if (This->absolute) {
811 if (posX != This->prevX)
812 GEN_EVENT(DIMOFS_X, posX, time, 0);
813 if (posY != This->prevY)
814 GEN_EVENT(DIMOFS_Y, posY, time, 0);
815 } else {
816 /* Relative mouse input : the real fun starts here... */
817 if (This->need_warp) {
818 if (posX != This->prevX)
819 GEN_EVENT(DIMOFS_X, posX - This->prevX, time, 0);
820 if (posY != This->prevY)
821 GEN_EVENT(DIMOFS_Y, posY - This->prevY, time, 0);
822 } else {
823 /* This is the first time the event handler has been called after a
824 GetData of GetState. */
825 if (posX != This->win_centerX) {
826 GEN_EVENT(DIMOFS_X, posX - This->win_centerX, time, 0);
827 This->need_warp = 1;
830 if (posY != This->win_centerY) {
831 GEN_EVENT(DIMOFS_Y, posY - This->win_centerY, time, 0);
832 This->need_warp = 1;
837 if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) {
838 if (TRACE_ON(dinput))
839 DUMP(" LD ");
841 GEN_EVENT(DIMOFS_BUTTON0, 0xFF, time, 0);
843 if ( dwFlags & MOUSEEVENTF_LEFTUP ) {
844 if (TRACE_ON(dinput))
845 DUMP(" LU ");
847 GEN_EVENT(DIMOFS_BUTTON0, 0x00, time, 0);
849 if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) {
850 if (TRACE_ON(dinput))
851 DUMP(" RD ");
853 GEN_EVENT(DIMOFS_BUTTON1, 0xFF, time, 0);
855 if ( dwFlags & MOUSEEVENTF_RIGHTUP ) {
856 if (TRACE_ON(dinput))
857 DUMP(" RU ");
859 GEN_EVENT(DIMOFS_BUTTON1, 0x00, time, 0);
861 if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) {
862 if (TRACE_ON(dinput))
863 DUMP(" MD ");
865 GEN_EVENT(DIMOFS_BUTTON2, 0xFF, time, 0);
867 if ( dwFlags & MOUSEEVENTF_MIDDLEUP ) {
868 if (TRACE_ON(dinput))
869 DUMP(" MU ");
871 GEN_EVENT(DIMOFS_BUTTON2, 0x00, time, 0);
873 if (TRACE_ON(dinput))
874 DUMP("\n");
876 This->prevX = posX;
877 This->prevY = posY;
881 /******************************************************************************
882 * Acquire : gets exclusive control of the mouse
884 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
886 ICOM_THIS(SysMouseAImpl,iface);
887 RECT rect;
889 TRACE(dinput,"(this=%p)\n",This);
891 if (This->acquired == 0) {
892 POINT point;
894 /* This stores the current mouse handler. */
895 This->prev_handler = mouse_event;
897 /* Store (in a global variable) the current lock */
898 current_lock = (IDirectInputDevice2A*)This;
900 /* Install our own mouse event handler */
901 MOUSE_Enable(dinput_mouse_event);
903 /* Get the window dimension and find the center */
904 GetWindowRect(This->win, &rect);
905 This->win_centerX = (rect.right - rect.left) / 2;
906 This->win_centerY = (rect.bottom - rect.top ) / 2;
908 /* Warp the mouse to the center of the window */
909 TRACE(dinput, "Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
910 point.x = This->win_centerX;
911 point.y = This->win_centerY;
912 MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
913 DISPLAY_MoveCursor(point.x, point.y);
915 This->acquired = 1;
917 return 0;
920 /******************************************************************************
921 * Unacquire : frees the mouse
923 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
925 ICOM_THIS(SysMouseAImpl,iface);
927 TRACE(dinput,"(this=%p)\n",This);
929 /* Reinstall previous mouse event handler */
930 MOUSE_Enable(This->prev_handler);
931 This->prev_handler = NULL;
933 /* No more locks */
934 current_lock = NULL;
936 /* Unacquire device */
937 This->acquired = 0;
939 return 0;
942 /******************************************************************************
943 * GetDeviceState : returns the "state" of the mouse.
945 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
946 * supported.
948 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
949 LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
951 ICOM_THIS(SysMouseAImpl,iface);
952 DWORD rx, ry, state;
953 struct DIMOUSESTATE *mstate = (struct DIMOUSESTATE *) ptr;
955 TRACE(dinput,"(this=%p,0x%08lx,%p): \n",This,len,ptr);
957 /* Check if the buffer is big enough */
958 if (len < sizeof(struct DIMOUSESTATE)) {
959 FIXME(dinput, "unsupported state structure.");
960 return DIERR_INVALIDPARAM;
963 /* Get the mouse position */
964 EVENT_QueryPointer(&rx, &ry, &state);
965 TRACE(dinput,"(X:%ld - Y:%ld)\n", rx, ry);
967 /* Fill the mouse state structure */
968 if (This->absolute) {
969 mstate->lX = rx;
970 mstate->lY = ry;
971 } else {
972 mstate->lX = rx - This->win_centerX;
973 mstate->lY = ry - This->win_centerY;
975 if ((mstate->lX != 0) || (mstate->lY != 0))
976 This->need_warp = 1;
978 mstate->lZ = 0;
979 mstate->rgbButtons[0] = (state & MK_LBUTTON ? 0xFF : 0x00);
980 mstate->rgbButtons[1] = (state & MK_RBUTTON ? 0xFF : 0x00);
981 mstate->rgbButtons[2] = (state & MK_MBUTTON ? 0xFF : 0x00);
982 mstate->rgbButtons[3] = 0x00;
984 /* Check if we need to do a mouse warping */
985 if (This->need_warp) {
986 POINT point;
988 TRACE(dinput, "Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
989 point.x = This->win_centerX;
990 point.y = This->win_centerY;
991 MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
992 DISPLAY_MoveCursor(point.x, point.y);
994 This->need_warp = 0;
997 TRACE(dinput, "(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
998 mstate->lX, mstate->lY,
999 mstate->rgbButtons[0], mstate->rgbButtons[2], mstate->rgbButtons[1]);
1001 return 0;
1004 /******************************************************************************
1005 * GetDeviceState : gets buffered input data.
1007 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
1008 DWORD dodsize,
1009 LPDIDEVICEOBJECTDATA dod,
1010 LPDWORD entries,
1011 DWORD flags
1013 ICOM_THIS(SysMouseAImpl,iface);
1015 TRACE(dinput,"(%p)->(%ld,%p,%p(0x%08lx),0x%08lx)\n",
1016 This,dodsize,dod,entries,*entries,flags);
1018 if (flags & DIGDD_PEEK)
1019 TRACE(dinput, "DIGDD_PEEK\n");
1021 if (dod == NULL) {
1022 *entries = This->queue_pos;
1023 This->queue_pos = 0;
1024 } else {
1025 /* Check for buffer overflow */
1026 if (This->queue_pos > *entries) {
1027 WARN(dinput, "Buffer overflow not handled properly yet...\n");
1028 This->queue_pos = *entries;
1030 if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
1031 ERR(dinput, "Wrong structure size !\n");
1032 return DIERR_INVALIDPARAM;
1035 TRACE(dinput, "Application retrieving %d event(s).\n", This->queue_pos);
1037 /* Copy the buffered data into the application queue */
1038 memcpy(dod, This->data_queue, This->queue_pos * dodsize);
1040 /* Reset the event queue */
1041 This->queue_pos = 0;
1044 /* Check if we need to do a mouse warping */
1045 if (This->need_warp) {
1046 POINT point;
1048 TRACE(dinput, "Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1049 point.x = This->win_centerX;
1050 point.y = This->win_centerY;
1051 MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1052 DISPLAY_MoveCursor(point.x, point.y);
1054 This->need_warp = 0;
1057 return 0;
1060 /******************************************************************************
1061 * SetProperty : change input device properties
1063 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
1064 REFGUID rguid,
1065 LPCDIPROPHEADER ph)
1067 ICOM_THIS(SysMouseAImpl,iface);
1068 char xbuf[50];
1070 if (HIWORD(rguid))
1071 WINE_StringFromCLSID(rguid,xbuf);
1072 else
1073 sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
1075 TRACE(dinput,"(this=%p,%s,%p)\n",This,xbuf,ph);
1077 if (!HIWORD(rguid)) {
1078 switch ((DWORD)rguid) {
1079 case (DWORD) DIPROP_BUFFERSIZE: {
1080 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
1082 TRACE(dinput,"buffersize = %ld\n",pd->dwData);
1084 This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
1085 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1086 This->queue_pos = 0;
1087 This->queue_len = pd->dwData;
1088 break;
1090 default:
1091 WARN(dinput,"Unknown type %ld\n",(DWORD)rguid);
1092 break;
1096 return 0;
1100 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt={
1101 IDirectInputDevice2AImpl_QueryInterface,
1102 IDirectInputDevice2AImpl_AddRef,
1103 IDirectInputDevice2AImpl_Release,
1104 IDirectInputDevice2AImpl_GetCapabilities,
1105 IDirectInputDevice2AImpl_EnumObjects,
1106 IDirectInputDevice2AImpl_GetProperty,
1107 SysKeyboardAImpl_SetProperty,
1108 SysKeyboardAImpl_Acquire,
1109 SysKeyboardAImpl_Unacquire,
1110 SysKeyboardAImpl_GetDeviceState,
1111 SysKeyboardAImpl_GetDeviceData,
1112 IDirectInputDevice2AImpl_SetDataFormat,
1113 IDirectInputDevice2AImpl_SetEventNotification,
1114 IDirectInputDevice2AImpl_SetCooperativeLevel,
1115 IDirectInputDevice2AImpl_GetObjectInfo,
1116 IDirectInputDevice2AImpl_GetDeviceInfo,
1117 IDirectInputDevice2AImpl_RunControlPanel,
1118 IDirectInputDevice2AImpl_Initialize,
1119 IDirectInputDevice2AImpl_CreateEffect,
1120 IDirectInputDevice2AImpl_EnumEffects,
1121 IDirectInputDevice2AImpl_GetEffectInfo,
1122 IDirectInputDevice2AImpl_GetForceFeedbackState,
1123 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1124 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1125 IDirectInputDevice2AImpl_Escape,
1126 IDirectInputDevice2AImpl_Poll,
1127 IDirectInputDevice2AImpl_SendDeviceData,
1130 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt={
1131 IDirectInputDevice2AImpl_QueryInterface,
1132 IDirectInputDevice2AImpl_AddRef,
1133 SysMouseAImpl_Release,
1134 IDirectInputDevice2AImpl_GetCapabilities,
1135 IDirectInputDevice2AImpl_EnumObjects,
1136 IDirectInputDevice2AImpl_GetProperty,
1137 SysMouseAImpl_SetProperty,
1138 SysMouseAImpl_Acquire,
1139 SysMouseAImpl_Unacquire,
1140 SysMouseAImpl_GetDeviceState,
1141 SysMouseAImpl_GetDeviceData,
1142 SysMouseAImpl_SetDataFormat,
1143 IDirectInputDevice2AImpl_SetEventNotification,
1144 SysMouseAImpl_SetCooperativeLevel,
1145 IDirectInputDevice2AImpl_GetObjectInfo,
1146 IDirectInputDevice2AImpl_GetDeviceInfo,
1147 IDirectInputDevice2AImpl_RunControlPanel,
1148 IDirectInputDevice2AImpl_Initialize,
1149 IDirectInputDevice2AImpl_CreateEffect,
1150 IDirectInputDevice2AImpl_EnumEffects,
1151 IDirectInputDevice2AImpl_GetEffectInfo,
1152 IDirectInputDevice2AImpl_GetForceFeedbackState,
1153 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1154 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1155 IDirectInputDevice2AImpl_Escape,
1156 IDirectInputDevice2AImpl_Poll,
1157 IDirectInputDevice2AImpl_SendDeviceData,