Added missing #include "config.h"
[wine/multimedia.git] / windows / dinput.c
blobf975b8951d00edfac59566dc90e17a2a5fa81926
1 /* DirectInput
3 * Copyright 1998 Marcus Meissner
5 * Additions (mouse support) Copyright 1998 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 <X11/Xlib.h>
26 #include <sys/signal.h>
28 #include "windows.h"
29 #include "winerror.h"
30 #include "shell.h"
31 #include "ole.h"
32 #include "compobj.h"
33 #include "interfaces.h"
34 #include "gdi.h"
35 #include "heap.h"
36 #include "win.h"
37 #include "dinput.h"
38 #include "debug.h"
40 extern BYTE InputKeyStateTable[256];
41 extern int min_keycode, max_keycode;
42 extern WORD keyc2vkey[256];
44 static IDirectInputA_VTable ddiavt;
45 static IDirectInputDeviceA_VTable SysKeyboardAvt;
46 static IDirectInputDeviceA_VTable SysMouseAvt;
48 /******************************************************************************
49 * DirectInputCreate32A
51 HRESULT WINAPI DirectInputCreate32A(HINSTANCE32 hinst, DWORD dwVersion, LPDIRECTINPUT32A *ppDI, LPUNKNOWN punkOuter) {
52 TRACE(dinput, "(0x%08lx,%04lx,%p,%p)\n",
53 (DWORD)hinst,dwVersion,ppDI,punkOuter
55 (*ppDI) = (LPDIRECTINPUT32A)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInput32A));
56 (*ppDI)->ref = 1;
57 (*ppDI)->lpvtbl = &ddiavt;
58 return 0;
60 /******************************************************************************
61 * IDirectInputA_EnumDevices
63 static HRESULT WINAPI IDirectInputA_EnumDevices(
64 LPDIRECTINPUT32A this, DWORD dwDevType, LPDIENUMDEVICESCALLBACK32A lpCallback,
65 LPVOID pvRef, DWORD dwFlags
66 ) {
67 DIDEVICEINSTANCE32A devInstance;
68 int ret;
70 TRACE(dinput, "(this=%p,0x%04lx,%p,%p,%04lx)\n", this, dwDevType, lpCallback, pvRef, dwFlags);
72 #if 0 /* Not compiled for the moment as long as I do not find
73 the needed constants */
74 /* Ignore this field for the moment */
75 if (dwDevType != 0) {
76 FIXME(dinput, "device filtering not supported.\n");
79 devInstance.dwSize = sizeof(DIDEVICEINSTANCE32A);
81 /* Return keyboard */
82 devInstance.guidInstance = GUID_SysKeyboard;
83 devInstance.guidProduct = GUID_SysKeyboard;
84 devInstance.dwDevType = 1; /* Constant unknown :-( */
85 strcpy(devInstance.tszInstanceName, "Keyboard");
86 strcpy(devInstance.tszProductName, "Wine Keyboard");
88 ret = lpCallback(&devInstance, pvRef);
89 TRACE(dinput, "Keyboard registered (%d)\n", ret);
91 if (!ret)
92 return 0;
94 /* Return mouse */
95 devInstance.guidInstance = GUID_SysMouse;
96 devInstance.guidProduct = GUID_SysMouse;
97 devInstance.dwDevType = 2; /* Constant unknown :-( */
98 strcpy(devInstance.tszInstanceName, "Mouse");
99 strcpy(devInstance.tszProductName, "Wine Mouse");
101 ret = lpCallback(&devInstance, pvRef);
102 TRACE(dinput, "Mouse registered (%d)\n", ret);
103 #endif
105 return 0;
108 static ULONG WINAPI IDirectInputA_AddRef(LPDIRECTINPUT32A this) {
109 return ++(this->ref);
112 static ULONG WINAPI IDirectInputA_Release(LPDIRECTINPUT32A this) {
113 if (!(--this->ref)) {
114 HeapFree(GetProcessHeap(),0,this);
115 return 0;
117 return this->ref;
120 static HRESULT WINAPI IDirectInputA_CreateDevice(
121 LPDIRECTINPUT32A this,REFGUID rguid,LPDIRECTINPUTDEVICE32A* pdev,
122 LPUNKNOWN punk
124 char xbuf[50];
126 WINE_StringFromCLSID(rguid,xbuf);
127 FIXME(dinput,"(this=%p,%s,%p,%p): stub\n",this,xbuf,pdev,punk);
128 if (!memcmp(&GUID_SysKeyboard,rguid,sizeof(GUID_SysKeyboard))) {
129 *pdev = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboard32A));
130 (*pdev)->ref = 1;
131 (*pdev)->lpvtbl = &SysKeyboardAvt;
132 memcpy(&((*pdev)->guid),rguid,sizeof(*rguid));
133 memset(((LPSYSKEYBOARD32A)(*pdev))->keystate,0,256);
134 return 0;
136 if (!memcmp(&GUID_SysMouse,rguid,sizeof(GUID_SysMouse))) {
137 *pdev = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouse32A));
138 (*pdev)->ref = 1;
139 (*pdev)->lpvtbl = &SysMouseAvt;
140 memcpy(&((*pdev)->guid),rguid,sizeof(*rguid));
141 return 0;
143 return E_FAIL;
146 static HRESULT WINAPI IDirectInputA_QueryInterface(
147 LPDIRECTINPUT32A this,REFIID riid,LPVOID *ppobj
149 char xbuf[50];
151 WINE_StringFromCLSID(riid,xbuf);
152 TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ppobj);
153 if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
154 this->lpvtbl->fnAddRef(this);
155 *ppobj = this;
156 return 0;
158 if (!memcmp(&IID_IDirectInputA,riid,sizeof(*riid))) {
159 this->lpvtbl->fnAddRef(this);
160 *ppobj = this;
161 return 0;
163 return E_FAIL;
166 static HRESULT WINAPI IDirectInputA_Initialize(
167 LPDIRECTINPUT32A this,HINSTANCE32 hinst,DWORD x
169 return DIERR_ALREADYINITIALIZED;
172 static IDirectInputA_VTable ddiavt= {
173 IDirectInputA_QueryInterface,
174 IDirectInputA_AddRef,
175 IDirectInputA_Release,
176 IDirectInputA_CreateDevice,
177 IDirectInputA_EnumDevices,
178 (void*)6,
179 (void*)7,
180 IDirectInputA_Initialize
183 /******************************************************************************
184 * IDirectInputDeviceA
186 static HRESULT WINAPI IDirectInputDeviceA_SetDataFormat(
187 LPDIRECTINPUTDEVICE32A this,LPCDIDATAFORMAT df
190 int i;
191 TRACE(dinput,"(this=%p,%p)\n",this,df);
193 TRACE(dinput,"df.dwSize=%ld\n",df->dwSize);
194 TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
195 TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
196 TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
197 TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
199 for (i=0;i<df->dwNumObjs;i++) {
200 char xbuf[50];
202 if (df->rgodf[i].pguid)
203 WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
204 else
205 strcpy(xbuf,"<no guid>");
206 TRACE(dinput,"df.rgodf[%d].guid %s\n",i,xbuf);
207 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
208 TRACE(dinput,"dwType 0x%02lx,dwInstance %ld\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
209 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
212 return 0;
215 static HRESULT WINAPI IDirectInputDeviceA_SetCooperativeLevel(
216 LPDIRECTINPUTDEVICE32A this,HWND32 hwnd,DWORD dwflags
218 FIXME(dinput,"(this=%p,0x%08lx,0x%08lx): stub\n",this,(DWORD)hwnd,dwflags);
219 return 0;
222 static HRESULT WINAPI IDirectInputDeviceA_SetProperty(
223 LPDIRECTINPUTDEVICE32A this,REFGUID rguid,LPCDIPROPHEADER ph
225 char xbuf[50];
227 if (HIWORD(rguid))
228 WINE_StringFromCLSID(rguid,xbuf);
229 else
230 sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
231 TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ph);
232 if (!HIWORD(rguid)) {
233 switch ((DWORD)rguid) {
234 case DIPROP_BUFFERSIZE: {
235 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
237 TRACE(dinput,"buffersize = %ld\n",pd->dwData);
238 break;
240 default:
241 WARN(dinput,"Unknown type %ld\n",(DWORD)rguid);
242 break;
245 return 0;
248 static HRESULT WINAPI IDirectInputDeviceA_SetEventNotification(
249 LPDIRECTINPUTDEVICE32A this,HANDLE32 hnd
251 FIXME(dinput,"(this=%p,0x%08lx): stub\n",this,(DWORD)hnd);
252 return 0;
255 static HRESULT WINAPI IDirectInputDeviceA_GetDeviceData(
256 LPDIRECTINPUTDEVICE32A this,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
257 LPDWORD entries,DWORD flags
259 TRACE(dinput,"IDirectInputDeviceA(%p)->GetDeviceData(%ld,%p,%p(0x%08lx),0x%08lx)\n",
260 this,dodsize,dod,entries,*entries,flags);
261 return 0;
265 static HRESULT WINAPI IDirectInputDeviceA_Acquire(LPDIRECTINPUTDEVICE32A this) {
266 FIXME(dinput,"(this=%p): stub\n",this);
267 return 0;
270 static HRESULT WINAPI IDirectInputDeviceA_Unacquire(LPDIRECTINPUTDEVICE32A this) {
271 FIXME(dinput,"(this=%p): stub\n",this);
272 return 0;
275 static ULONG WINAPI IDirectInputDeviceA_Release(LPDIRECTINPUTDEVICE32A this) {
276 this->ref--;
277 if (this->ref)
278 return this->ref;
279 HeapFree(GetProcessHeap(),0,this);
280 return 0;
283 static HRESULT WINAPI SysKeyboardA_SetProperty(
284 LPDIRECTINPUTDEVICE32A this,REFGUID rguid,LPCDIPROPHEADER ph
286 char xbuf[50];
288 if (HIWORD(rguid))
289 WINE_StringFromCLSID(rguid,xbuf);
290 else
291 sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
292 TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ph);
293 TRACE(dinput,"(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
294 ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
295 if (!HIWORD(rguid)) {
296 switch ((DWORD)rguid) {
297 case DIPROP_BUFFERSIZE: {
298 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
300 TRACE(dinput,"(buffersize=%ld)\n",pd->dwData);
301 break;
303 default:
304 WARN(dinput,"Unknown type %ld\n",(DWORD)rguid);
305 break;
308 return 0;
311 static HRESULT WINAPI SysKeyboardA_GetDeviceState(
312 LPDIRECTINPUTDEVICE32A this,DWORD len,LPVOID ptr
314 if (len==256) {
315 int keyc,vkey;
317 memset(ptr,0,256);
318 for (keyc=min_keycode;keyc<max_keycode;keyc++)
320 /* X keycode to virtual key */
321 vkey = keyc2vkey[keyc] & 0xFF;
322 /* The windows scancode is keyc-min_keycode */
323 if (InputKeyStateTable[vkey]&0x80) {
324 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
325 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
328 return 0;
330 WARN(dinput,"whoops, SysKeyboardA_GetDeviceState got len %ld?\n",len);
331 return 0;
334 static HRESULT WINAPI SysKeyboardA_GetDeviceData(
335 LPDIRECTINPUTDEVICE32A this,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
336 LPDWORD entries,DWORD flags
338 int keyc,n,vkey,xentries;
339 LPSYSKEYBOARD32A kthis = (LPSYSKEYBOARD32A)this;
341 TRACE(dinput,"(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
342 this,dodsize,dod,entries,entries?*entries:0,flags);
343 EVENT_WaitNetEvent(FALSE,TRUE);
344 if (entries)
345 xentries = *entries;
346 else
347 xentries = 1;
349 n = 0;
351 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
353 /* X keycode to virtual key */
354 vkey = keyc2vkey[keyc] & 0xFF;
355 if (kthis->keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
356 continue;
357 if (dod) {
358 /* add an entry */
359 dod[n].dwOfs = keyc-min_keycode; /* scancode */
360 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
361 dod[n].dwTimeStamp = 0; /* umm */
362 dod[n].dwSequence = 0; /* umm */
363 n++;
365 if (!(flags & DIGDD_PEEK))
366 kthis->keystate[vkey] = InputKeyStateTable[vkey]&0x80;
370 if (n) fprintf(stderr,"%d entries\n",n);
371 *entries = n;
372 return 0;
375 static HRESULT WINAPI SysKeyboardA_Acquire(LPDIRECTINPUTDEVICE32A this) {
376 FIXME(dinput,"(this=%p): stub\n",this);
377 return 0;
380 static HRESULT WINAPI SysKeyboardA_Unacquire(LPDIRECTINPUTDEVICE32A this) {
381 FIXME(dinput,"(this=%p): stub\n",this);
382 return 0;
385 static HRESULT WINAPI IDirectInputDeviceA_QueryInterface(
386 LPDIRECTINPUTDEVICE32A this,REFIID riid,LPVOID *ppobj
388 char xbuf[50];
390 WINE_StringFromCLSID(riid,xbuf);
391 TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ppobj);
392 if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
393 this->lpvtbl->fnAddRef(this);
394 *ppobj = this;
395 return 0;
397 if (!memcmp(&IID_IDirectInputDeviceA,riid,sizeof(*riid))) {
398 this->lpvtbl->fnAddRef(this);
399 *ppobj = this;
400 return 0;
402 return E_FAIL;
405 /******************************************************************************
406 * SysMouseA (DInput Mouse support)
409 /******************************************************************************
410 * SetDataFormat : the application can choose the format of the data
411 * the device driver sends back with GetDeviceState.
413 * For the moment, only the "standard" configuration (c_dfDIMouse) is supported
414 * in absolute and relative mode.
416 static HRESULT WINAPI SysMouseA_SetDataFormat(
417 LPDIRECTINPUTDEVICE32A this,LPCDIDATAFORMAT df
419 int i;
420 LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this;
422 TRACE(dinput,"(this=%p,%p)\n",this,df);
424 TRACE(dinput,"(df.dwSize=%ld)\n",df->dwSize);
425 TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
426 TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
427 TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
428 TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
430 for (i=0;i<df->dwNumObjs;i++) {
431 char xbuf[50];
433 if (df->rgodf[i].pguid)
434 WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
435 else
436 strcpy(xbuf,"<no guid>");
437 TRACE(dinput,"df.rgodf[%d].guid %s (%p)\n",i,xbuf, df->rgodf[i].pguid);
438 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
439 TRACE(dinput,"dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
440 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
443 /* Check size of data format to prevent crashes if the applications
444 sends a smaller buffer */
445 if (df->dwDataSize != sizeof(struct DIMOUSESTATE)) {
446 FIXME(dinput, "non-standard mouse configuration not supported yet.");
447 return DIERR_INVALIDPARAM;
450 /* For the moment, ignore these fields and return always as if
451 c_dfDIMouse was passed as format... */
452 if (df->dwFlags == DIDF_ABSAXIS)
453 mthis->absolute = 1;
454 else {
455 Window rw, cr;
456 int rx, ry, cx, cy;
457 unsigned int mask;
459 /* We need to get the initial "previous" position to be able
460 to return deltas */
461 mthis->absolute = 0;
463 /* Get the mouse position */
464 TSXQueryPointer(display, rootWindow, &rw, &cr,
465 &rx, &ry, &cx, &cy, &mask);
466 /* Fill the initial mouse state structure */
467 mthis->prevX = rx;
468 mthis->prevY = ry;
471 return 0;
474 /******************************************************************************
475 * GetDeviceState : returns the "state" of the mouse.
477 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
478 * supported.
480 static HRESULT WINAPI SysMouseA_GetDeviceState(
481 LPDIRECTINPUTDEVICE32A this,DWORD len,LPVOID ptr
483 Window rw, cr;
484 int rx, ry, cx, cy;
485 unsigned int mask;
486 struct DIMOUSESTATE *mstate = (struct DIMOUSESTATE *) ptr;
487 LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this;
489 TRACE(dinput,"(this=%p,0x%08lx,%p): \n",this,len,ptr);
491 /* Check if the buffer is big enough */
492 if (len < sizeof(struct DIMOUSESTATE)) {
493 FIXME(dinput, "unsupported state structure.");
494 return DIERR_INVALIDPARAM;
497 /* Get the mouse position */
498 TSXQueryPointer(display, rootWindow, &rw, &cr,
499 &rx, &ry, &cx, &cy, &mask);
500 TRACE(dinput,"(X:%d - Y:%d)\n", rx, ry);
502 /* Fill the mouse state structure */
503 if (mthis->absolute) {
504 mstate->lX = rx;
505 mstate->lY = ry;
506 } else {
507 mstate->lX = rx - mthis->prevX;
508 mstate->lY = ry - mthis->prevY;
509 /* Fill the previous positions */
510 mthis->prevX = rx;
511 mthis->prevY = ry;
513 mstate->lZ = 0;
514 mstate->rgbButtons[0] = (mask & Button1Mask ? 0xFF : 0x00);
515 mstate->rgbButtons[1] = (mask & Button3Mask ? 0xFF : 0x00); /* Windows button two is X button 3 */
516 mstate->rgbButtons[2] = (mask & Button2Mask ? 0xFF : 0x00);
517 mstate->rgbButtons[3] = (mask & Button4Mask ? 0xFF : 0x00);
519 return 0;
524 static IDirectInputDeviceA_VTable SysKeyboardAvt={
525 IDirectInputDeviceA_QueryInterface,
526 (void*)2,
527 IDirectInputDeviceA_Release,
528 (void*)4,
529 (void*)5,
530 (void*)6,
531 SysKeyboardA_SetProperty,
532 SysKeyboardA_Acquire,
533 SysKeyboardA_Unacquire,
534 SysKeyboardA_GetDeviceState,
535 SysKeyboardA_GetDeviceData,
536 IDirectInputDeviceA_SetDataFormat,
537 IDirectInputDeviceA_SetEventNotification,
538 IDirectInputDeviceA_SetCooperativeLevel,
539 (void*)15,
540 (void*)16,
541 (void*)17,
542 (void*)18,
545 static IDirectInputDeviceA_VTable SysMouseAvt={
546 IDirectInputDeviceA_QueryInterface,
547 (void*)2,
548 IDirectInputDeviceA_Release,
549 (void*)4,
550 (void*)5,
551 (void*)6,
552 IDirectInputDeviceA_SetProperty,
553 IDirectInputDeviceA_Acquire,
554 IDirectInputDeviceA_Unacquire,
555 SysMouseA_GetDeviceState,
556 IDirectInputDeviceA_GetDeviceData,
557 SysMouseA_SetDataFormat,
558 IDirectInputDeviceA_SetEventNotification,
559 IDirectInputDeviceA_SetCooperativeLevel,
560 (void*)15,
561 (void*)16,
562 (void*)17,
563 (void*)18,