New file, some helper functions for icon cache.
[wine/multimedia.git] / windows / dinput.c
blobfbc2fc0f4b139ddbc1ab7e7d8425000942c72a14
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"
39 #include "message.h"
41 extern BYTE InputKeyStateTable[256];
42 extern int min_keycode, max_keycode;
43 extern WORD keyc2vkey[256];
45 static IDirectInputA_VTable ddiavt;
46 static IDirectInputDeviceA_VTable SysKeyboardAvt;
47 static IDirectInputDeviceA_VTable SysMouseAvt;
49 /* UIDs for Wine "drivers".
50 When enumerating each device supporting DInput, they have two UIDs :
51 - the 'windows' UID
52 - a vendor UID */
53 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
54 0x9e573ed8,
55 0x7734,
56 0x11d2,
57 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
59 static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
60 0x0ab8648a,
61 0x7735,
62 0x11d2,
63 {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41}
66 /******************************************************************************
67 * DirectInputCreate32A
69 HRESULT WINAPI DirectInputCreate32A(HINSTANCE32 hinst, DWORD dwVersion, LPDIRECTINPUT32A *ppDI, LPUNKNOWN punkOuter) {
70 TRACE(dinput, "(0x%08lx,%04lx,%p,%p)\n",
71 (DWORD)hinst,dwVersion,ppDI,punkOuter
73 (*ppDI) = (LPDIRECTINPUT32A)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInput32A));
74 (*ppDI)->ref = 1;
75 (*ppDI)->lpvtbl = &ddiavt;
76 return 0;
78 /******************************************************************************
79 * IDirectInputA_EnumDevices
81 static HRESULT WINAPI IDirectInputA_EnumDevices(
82 LPDIRECTINPUT32A this, DWORD dwDevType, LPDIENUMDEVICESCALLBACK32A lpCallback,
83 LPVOID pvRef, DWORD dwFlags
84 ) {
85 DIDEVICEINSTANCE32A devInstance;
86 int ret;
88 TRACE(dinput, "(this=%p,0x%04lx,%p,%p,%04lx)\n", this, dwDevType, lpCallback, pvRef, dwFlags);
90 devInstance.dwSize = sizeof(DIDEVICEINSTANCE32A);
92 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
93 /* Return keyboard */
94 devInstance.guidInstance = GUID_SysKeyboard; /* DInput's GUID */
95 devInstance.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
96 devInstance.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
97 strcpy(devInstance.tszInstanceName, "Keyboard");
98 strcpy(devInstance.tszProductName, "Wine Keyboard");
100 ret = lpCallback(&devInstance, pvRef);
101 TRACE(dinput, "Keyboard registered\n");
103 if (ret == DIENUM_STOP)
104 return 0;
107 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
108 /* Return mouse */
109 devInstance.guidInstance = GUID_SysMouse; /* DInput's GUID */
110 devInstance.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
111 devInstance.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
112 strcpy(devInstance.tszInstanceName, "Mouse");
113 strcpy(devInstance.tszProductName, "Wine Mouse");
115 ret = lpCallback(&devInstance, pvRef);
116 TRACE(dinput, "Mouse registered\n");
119 /* Should also do joystick enumerations.... */
121 return 0;
124 static ULONG WINAPI IDirectInputA_AddRef(LPDIRECTINPUT32A this) {
125 return ++(this->ref);
128 static ULONG WINAPI IDirectInputA_Release(LPDIRECTINPUT32A this) {
129 if (!(--this->ref)) {
130 HeapFree(GetProcessHeap(),0,this);
131 return 0;
133 return this->ref;
136 static HRESULT WINAPI IDirectInputA_CreateDevice(
137 LPDIRECTINPUT32A this,REFGUID rguid,LPDIRECTINPUTDEVICE32A* pdev,
138 LPUNKNOWN punk
140 char xbuf[50];
142 WINE_StringFromCLSID(rguid,xbuf);
143 FIXME(dinput,"(this=%p,%s,%p,%p): stub\n",this,xbuf,pdev,punk);
144 if ((!memcmp(&GUID_SysKeyboard,rguid,sizeof(GUID_SysKeyboard))) || /* Generic Keyboard */
145 (!memcmp(&DInput_Wine_Keyboard_GUID,rguid,sizeof(GUID_SysKeyboard)))) { /* Wine Keyboard */
146 *pdev = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboard32A));
147 (*pdev)->ref = 1;
148 (*pdev)->lpvtbl = &SysKeyboardAvt;
149 memcpy(&((*pdev)->guid),rguid,sizeof(*rguid));
150 memset(((LPSYSKEYBOARD32A)(*pdev))->keystate,0,256);
151 return 0;
153 if ((!memcmp(&GUID_SysMouse,rguid,sizeof(GUID_SysMouse))) || /* Generic Mouse */
154 (!memcmp(&DInput_Wine_Mouse_GUID,rguid,sizeof(GUID_SysKeyboard)))) { /* Wine Mouse */
155 *pdev = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouse32A));
156 (*pdev)->ref = 1;
157 (*pdev)->lpvtbl = &SysMouseAvt;
158 memcpy(&((*pdev)->guid),rguid,sizeof(*rguid));
159 return 0;
161 return E_FAIL;
164 static HRESULT WINAPI IDirectInputA_QueryInterface(
165 LPDIRECTINPUT32A this,REFIID riid,LPVOID *ppobj
167 char xbuf[50];
169 WINE_StringFromCLSID(riid,xbuf);
170 TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ppobj);
171 if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
172 this->lpvtbl->fnAddRef(this);
173 *ppobj = this;
174 return 0;
176 if (!memcmp(&IID_IDirectInputA,riid,sizeof(*riid))) {
177 this->lpvtbl->fnAddRef(this);
178 *ppobj = this;
179 return 0;
181 return E_FAIL;
184 static HRESULT WINAPI IDirectInputA_Initialize(
185 LPDIRECTINPUT32A this,HINSTANCE32 hinst,DWORD x
187 return DIERR_ALREADYINITIALIZED;
190 static IDirectInputA_VTable ddiavt= {
191 IDirectInputA_QueryInterface,
192 IDirectInputA_AddRef,
193 IDirectInputA_Release,
194 IDirectInputA_CreateDevice,
195 IDirectInputA_EnumDevices,
196 (void*)6,
197 (void*)7,
198 IDirectInputA_Initialize
201 /******************************************************************************
202 * IDirectInputDeviceA
204 static HRESULT WINAPI IDirectInputDeviceA_SetDataFormat(
205 LPDIRECTINPUTDEVICE32A this,LPCDIDATAFORMAT df
208 int i;
209 TRACE(dinput,"(this=%p,%p)\n",this,df);
211 TRACE(dinput,"df.dwSize=%ld\n",df->dwSize);
212 TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
213 TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
214 TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
215 TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
217 for (i=0;i<df->dwNumObjs;i++) {
218 char xbuf[50];
220 if (df->rgodf[i].pguid)
221 WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
222 else
223 strcpy(xbuf,"<no guid>");
224 TRACE(dinput,"df.rgodf[%d].guid %s\n",i,xbuf);
225 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
226 TRACE(dinput,"dwType 0x%02lx,dwInstance %ld\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
227 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
230 return 0;
233 static HRESULT WINAPI IDirectInputDeviceA_SetCooperativeLevel(
234 LPDIRECTINPUTDEVICE32A this,HWND32 hwnd,DWORD dwflags
236 FIXME(dinput,"(this=%p,0x%08lx,0x%08lx): stub\n",this,(DWORD)hwnd,dwflags);
237 return 0;
240 static HRESULT WINAPI IDirectInputDeviceA_SetProperty(
241 LPDIRECTINPUTDEVICE32A this,REFGUID rguid,LPCDIPROPHEADER ph
243 char xbuf[50];
245 if (HIWORD(rguid))
246 WINE_StringFromCLSID(rguid,xbuf);
247 else
248 sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
249 TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ph);
250 if (!HIWORD(rguid)) {
251 switch ((DWORD)rguid) {
252 case DIPROP_BUFFERSIZE: {
253 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
255 TRACE(dinput,"buffersize = %ld\n",pd->dwData);
256 break;
258 default:
259 WARN(dinput,"Unknown type %ld\n",(DWORD)rguid);
260 break;
263 return 0;
266 static HRESULT WINAPI IDirectInputDeviceA_SetEventNotification(
267 LPDIRECTINPUTDEVICE32A this,HANDLE32 hnd
269 FIXME(dinput,"(this=%p,0x%08lx): stub\n",this,(DWORD)hnd);
270 return 0;
273 static HRESULT WINAPI IDirectInputDeviceA_GetDeviceData(
274 LPDIRECTINPUTDEVICE32A this,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
275 LPDWORD entries,DWORD flags
277 TRACE(dinput,"IDirectInputDeviceA(%p)->GetDeviceData(%ld,%p,%p(0x%08lx),0x%08lx)\n",
278 this,dodsize,dod,entries,*entries,flags);
279 return 0;
283 static HRESULT WINAPI IDirectInputDeviceA_Acquire(LPDIRECTINPUTDEVICE32A this) {
284 TRACE(dinput,"(this=%p): stub\n",this);
285 return 0;
288 static HRESULT WINAPI IDirectInputDeviceA_Unacquire(LPDIRECTINPUTDEVICE32A this) {
289 TRACE(dinput,"(this=%p): stub\n",this);
290 return 0;
293 static ULONG WINAPI IDirectInputDeviceA_Release(LPDIRECTINPUTDEVICE32A this) {
294 this->ref--;
295 if (this->ref)
296 return this->ref;
297 HeapFree(GetProcessHeap(),0,this);
298 return 0;
301 static HRESULT WINAPI SysKeyboardA_SetProperty(
302 LPDIRECTINPUTDEVICE32A this,REFGUID rguid,LPCDIPROPHEADER ph
304 char xbuf[50];
306 if (HIWORD(rguid))
307 WINE_StringFromCLSID(rguid,xbuf);
308 else
309 sprintf(xbuf,"<special guid %ld>",(DWORD)rguid);
310 TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ph);
311 TRACE(dinput,"(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
312 ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
313 if (!HIWORD(rguid)) {
314 switch ((DWORD)rguid) {
315 case DIPROP_BUFFERSIZE: {
316 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
318 TRACE(dinput,"(buffersize=%ld)\n",pd->dwData);
319 break;
321 default:
322 WARN(dinput,"Unknown type %ld\n",(DWORD)rguid);
323 break;
326 return 0;
329 static HRESULT WINAPI SysKeyboardA_GetDeviceState(
330 LPDIRECTINPUTDEVICE32A this,DWORD len,LPVOID ptr
332 if (len==256) {
333 int keyc,vkey;
335 memset(ptr,0,256);
336 for (keyc=min_keycode;keyc<max_keycode;keyc++)
338 /* X keycode to virtual key */
339 vkey = keyc2vkey[keyc] & 0xFF;
340 /* The windows scancode is keyc-min_keycode */
341 if (InputKeyStateTable[vkey]&0x80) {
342 ((LPBYTE)ptr)[keyc-min_keycode]=0x80;
343 ((LPBYTE)ptr)[(keyc-min_keycode)|0x80]=0x80;
346 return 0;
348 WARN(dinput,"whoops, SysKeyboardA_GetDeviceState got len %ld?\n",len);
349 return 0;
352 static HRESULT WINAPI SysKeyboardA_GetDeviceData(
353 LPDIRECTINPUTDEVICE32A this,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
354 LPDWORD entries,DWORD flags
356 int keyc,n,vkey,xentries;
357 LPSYSKEYBOARD32A kthis = (LPSYSKEYBOARD32A)this;
359 TRACE(dinput,"(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
360 this,dodsize,dod,entries,entries?*entries:0,flags);
361 EVENT_WaitNetEvent(FALSE,TRUE);
362 if (entries)
363 xentries = *entries;
364 else
365 xentries = 1;
367 n = 0;
369 for (keyc=min_keycode;(keyc<max_keycode) && (n<*entries);keyc++)
371 /* X keycode to virtual key */
372 vkey = keyc2vkey[keyc] & 0xFF;
373 if (kthis->keystate[vkey] == (InputKeyStateTable[vkey]&0x80))
374 continue;
375 if (dod) {
376 /* add an entry */
377 dod[n].dwOfs = keyc-min_keycode; /* scancode */
378 dod[n].dwData = InputKeyStateTable[vkey]&0x80;
379 dod[n].dwTimeStamp = 0; /* umm */
380 dod[n].dwSequence = 0; /* umm */
381 n++;
383 if (!(flags & DIGDD_PEEK))
384 kthis->keystate[vkey] = InputKeyStateTable[vkey]&0x80;
388 if (n) fprintf(stderr,"%d entries\n",n);
389 *entries = n;
390 return 0;
393 static HRESULT WINAPI SysKeyboardA_Acquire(LPDIRECTINPUTDEVICE32A this) {
394 TRACE(dinput,"(this=%p): stub\n",this);
395 return 0;
398 static HRESULT WINAPI SysKeyboardA_Unacquire(LPDIRECTINPUTDEVICE32A this) {
399 TRACE(dinput,"(this=%p): stub\n",this);
400 return 0;
403 static HRESULT WINAPI IDirectInputDeviceA_QueryInterface(
404 LPDIRECTINPUTDEVICE32A this,REFIID riid,LPVOID *ppobj
406 char xbuf[50];
408 WINE_StringFromCLSID(riid,xbuf);
409 TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ppobj);
410 if (!memcmp(&IID_IUnknown,riid,sizeof(*riid))) {
411 this->lpvtbl->fnAddRef(this);
412 *ppobj = this;
413 return 0;
415 if (!memcmp(&IID_IDirectInputDeviceA,riid,sizeof(*riid))) {
416 this->lpvtbl->fnAddRef(this);
417 *ppobj = this;
418 return 0;
420 return E_FAIL;
423 /******************************************************************************
424 * SysMouseA (DInput Mouse support)
427 /******************************************************************************
428 * SetDataFormat : the application can choose the format of the data
429 * the device driver sends back with GetDeviceState.
431 * For the moment, only the "standard" configuration (c_dfDIMouse) is supported
432 * in absolute and relative mode.
434 static HRESULT WINAPI SysMouseA_SetDataFormat(
435 LPDIRECTINPUTDEVICE32A this,LPCDIDATAFORMAT df
437 int i;
438 LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this;
440 TRACE(dinput,"(this=%p,%p)\n",this,df);
442 TRACE(dinput,"(df.dwSize=%ld)\n",df->dwSize);
443 TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
444 TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
445 TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
446 TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
448 for (i=0;i<df->dwNumObjs;i++) {
449 char xbuf[50];
451 if (df->rgodf[i].pguid)
452 WINE_StringFromCLSID(df->rgodf[i].pguid,xbuf);
453 else
454 strcpy(xbuf,"<no guid>");
455 TRACE(dinput,"df.rgodf[%d].guid %s (%p)\n",i,xbuf, df->rgodf[i].pguid);
456 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
457 TRACE(dinput,"dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
458 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
461 /* Check size of data format to prevent crashes if the applications
462 sends a smaller buffer */
463 if (df->dwDataSize != sizeof(struct DIMOUSESTATE)) {
464 FIXME(dinput, "non-standard mouse configuration not supported yet.");
465 return DIERR_INVALIDPARAM;
468 /* For the moment, ignore these fields and return always as if
469 c_dfDIMouse was passed as format... */
470 if (df->dwFlags == DIDF_ABSAXIS)
471 mthis->absolute = 1;
472 else {
473 Window rw, cr;
474 int rx, ry, cx, cy;
475 unsigned int mask;
477 /* We need to get the initial "previous" position to be able
478 to return deltas */
479 mthis->absolute = 0;
481 /* Get the mouse position */
482 TSXQueryPointer(display, rootWindow, &rw, &cr,
483 &rx, &ry, &cx, &cy, &mask);
484 /* Fill the initial mouse state structure */
485 mthis->prevX = rx;
486 mthis->prevY = ry;
489 return 0;
492 /******************************************************************************
493 * GetDeviceState : returns the "state" of the mouse.
495 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
496 * supported.
498 static HRESULT WINAPI SysMouseA_GetDeviceState(
499 LPDIRECTINPUTDEVICE32A this,DWORD len,LPVOID ptr
501 Window rw, cr;
502 int rx, ry, cx, cy;
503 unsigned int mask;
504 struct DIMOUSESTATE *mstate = (struct DIMOUSESTATE *) ptr;
505 LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this;
507 TRACE(dinput,"(this=%p,0x%08lx,%p): \n",this,len,ptr);
509 /* Check if the buffer is big enough */
510 if (len < sizeof(struct DIMOUSESTATE)) {
511 FIXME(dinput, "unsupported state structure.");
512 return DIERR_INVALIDPARAM;
515 /* Get the mouse position */
516 TSXQueryPointer(display, rootWindow, &rw, &cr,
517 &rx, &ry, &cx, &cy, &mask);
518 TRACE(dinput,"(X:%d - Y:%d)\n", rx, ry);
520 /* Fill the mouse state structure */
521 if (mthis->absolute) {
522 mstate->lX = rx;
523 mstate->lY = ry;
524 } else {
525 mstate->lX = rx - mthis->prevX;
526 mstate->lY = ry - mthis->prevY;
527 /* Fill the previous positions */
528 mthis->prevX = rx;
529 mthis->prevY = ry;
531 mstate->lZ = 0;
532 mstate->rgbButtons[0] = (mask & Button1Mask ? 0xFF : 0x00);
533 mstate->rgbButtons[1] = (mask & Button3Mask ? 0xFF : 0x00); /* Windows button two is X button 3 */
534 mstate->rgbButtons[2] = (mask & Button2Mask ? 0xFF : 0x00);
535 mstate->rgbButtons[3] = (mask & Button4Mask ? 0xFF : 0x00);
537 return 0;
542 static IDirectInputDeviceA_VTable SysKeyboardAvt={
543 IDirectInputDeviceA_QueryInterface,
544 (void*)2,
545 IDirectInputDeviceA_Release,
546 (void*)4,
547 (void*)5,
548 (void*)6,
549 SysKeyboardA_SetProperty,
550 SysKeyboardA_Acquire,
551 SysKeyboardA_Unacquire,
552 SysKeyboardA_GetDeviceState,
553 SysKeyboardA_GetDeviceData,
554 IDirectInputDeviceA_SetDataFormat,
555 IDirectInputDeviceA_SetEventNotification,
556 IDirectInputDeviceA_SetCooperativeLevel,
557 (void*)15,
558 (void*)16,
559 (void*)17,
560 (void*)18,
563 static IDirectInputDeviceA_VTable SysMouseAvt={
564 IDirectInputDeviceA_QueryInterface,
565 (void*)2,
566 IDirectInputDeviceA_Release,
567 (void*)4,
568 (void*)5,
569 (void*)6,
570 IDirectInputDeviceA_SetProperty,
571 IDirectInputDeviceA_Acquire,
572 IDirectInputDeviceA_Unacquire,
573 SysMouseA_GetDeviceState,
574 IDirectInputDeviceA_GetDeviceData,
575 SysMouseA_SetDataFormat,
576 IDirectInputDeviceA_SetEventNotification,
577 IDirectInputDeviceA_SetCooperativeLevel,
578 (void*)15,
579 (void*)16,
580 (void*)17,
581 (void*)18,