Fix SetDataFormat and implement GetDeviceInfo for mouse device.
[wine] / dlls / dinput / device.c
1 /*              DirectInput Device
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  *
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /* This file contains all the Device specific functions that can be used as stubs
23    by real device implementations.
24
25    It also contains all the helper functions.
26 */
27 #include "config.h"
28
29 #include <string.h>
30 #include "wine/debug.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "windef.h"
34 #include "dinput.h"
35 #include "device_private.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
38
39 /******************************************************************************
40  *      Various debugging tools
41  */
42 void _dump_cooperativelevel_DI(DWORD dwFlags) {
43   int   i;
44   const struct {
45     DWORD       mask;
46     char        *name;
47   } flags[] = {
48 #define FE(x) { x, #x},
49     FE(DISCL_BACKGROUND)
50     FE(DISCL_EXCLUSIVE)
51     FE(DISCL_FOREGROUND)
52     FE(DISCL_NONEXCLUSIVE)
53 #undef FE
54   };
55   for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
56     if (flags[i].mask & dwFlags)
57       DPRINTF("%s ",flags[i].name);
58   DPRINTF("\n");
59 }
60
61 void _dump_EnumObjects_flags(DWORD dwFlags) {
62   int   i;
63   const struct {
64     DWORD       mask;
65     char        *name;
66   } flags[] = {
67 #define FE(x) { x, #x},
68     FE(DIDFT_ABSAXIS)
69     FE(DIDFT_ALL)
70     FE(DIDFT_AXIS)
71     FE(DIDFT_BUTTON)
72     FE(DIDFT_COLLECTION)
73     FE(DIDFT_FFACTUATOR)
74     FE(DIDFT_FFEFFECTTRIGGER)
75     FE(DIDFT_NOCOLLECTION)
76     FE(DIDFT_NODATA)
77     FE(DIDFT_OUTPUT)
78     FE(DIDFT_POV)
79     FE(DIDFT_PSHBUTTON)
80     FE(DIDFT_RELAXIS)
81     FE(DIDFT_TGLBUTTON)
82 #undef FE
83   };
84   if (dwFlags == DIDFT_ALL) {
85     DPRINTF("DIDFT_ALL");
86     return;
87   }
88   for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
89     if (flags[i].mask & dwFlags)
90       DPRINTF("%s ",flags[i].name);
91   if (dwFlags & DIDFT_INSTANCEMASK)
92     DPRINTF("Instance(%04lx) ", dwFlags >> 8);
93 }
94
95 void _dump_DIPROPHEADER(DIPROPHEADER *diph) {
96   DPRINTF("  - dwObj = 0x%08lx\n", diph->dwObj);
97   DPRINTF("  - dwHow = %s\n",
98           ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" :
99            ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" :
100             ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown")));
101 }
102
103 void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) {
104   if (TRACE_ON(dinput)) {
105     DPRINTF("    - enumerating : %s - %2ld - 0x%08lx - %s\n",
106             debugstr_guid(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName);
107   }
108 }
109
110 /* Conversion between internal data buffer and external data buffer */
111 void fill_DataFormat(void *out, void *in, DataFormat *df) {
112   int i;
113   char *in_c = (char *) in;
114   char *out_c = (char *) out;
115
116   if (df->dt == NULL) {
117     /* This means that the app uses Wine's internal data format */
118     memcpy(out, in, df->internal_format_size);
119   } else {
120     for (i = 0; i < df->size; i++) {
121       if (df->dt[i].offset_in >= 0) {
122         switch (df->dt[i].size) {
123         case 1:
124           TRACE("Copying (c) to %d from %d (value %d)\n",
125                 df->dt[i].offset_out, df->dt[i].offset_in, *((char *) (in_c + df->dt[i].offset_in)));
126           *((char *) (out_c + df->dt[i].offset_out)) = *((char *) (in_c + df->dt[i].offset_in));
127           break;
128
129         case 2:
130           TRACE("Copying (s) to %d from %d (value %d)\n",
131                 df->dt[i].offset_out, df->dt[i].offset_in, *((short *) (in_c + df->dt[i].offset_in)));
132           *((short *) (out_c + df->dt[i].offset_out)) = *((short *) (in_c + df->dt[i].offset_in));
133           break;
134
135         case 4:
136           TRACE("Copying (i) to %d from %d (value %d)\n",
137                 df->dt[i].offset_out, df->dt[i].offset_in, *((int *) (in_c + df->dt[i].offset_in)));
138           *((int *) (out_c + df->dt[i].offset_out)) = *((int *) (in_c + df->dt[i].offset_in));
139           break;
140
141         default:
142           memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size);
143         }
144       } else {
145         switch (df->dt[i].size) {
146         case 1:
147           TRACE("Copying (c) to %d default value %d\n",
148                 df->dt[i].offset_out, df->dt[i].value);
149           *((char *) (out_c + df->dt[i].offset_out)) = (char) df->dt[i].value;
150           break;
151
152         case 2:
153           TRACE("Copying (s) to %d default value %d\n",
154                 df->dt[i].offset_out, df->dt[i].value);
155           *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value;
156           break;
157
158         case 4:
159           TRACE("Copying (i) to %d default value %d\n",
160                 df->dt[i].offset_out, df->dt[i].value);
161           *((int *) (out_c + df->dt[i].offset_out)) = (int) df->dt[i].value;
162           break;
163
164         default:
165           memset((out_c + df->dt[i].offset_out), df->dt[i].size, 0);
166         }
167       }
168     }
169   }
170 }
171
172 DataFormat *create_DataFormat(DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) {
173   DataFormat *ret;
174   DataTransform *dt;
175   int i, j;
176   int same = 1;
177   int *done;
178   int index = 0;
179
180   ret = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
181
182   done = (int *) HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs);
183   memset(done, 0, sizeof(int) * asked_format->dwNumObjs);
184
185   dt = (DataTransform *) HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
186
187   TRACE("Creating DataTransform : \n");
188
189   for (i = 0; i < wine_format->dwNumObjs; i++) {
190     offset[i] = -1;
191
192     for (j = 0; j < asked_format->dwNumObjs; j++) {
193       if (done[j] == 1)
194         continue;
195
196       if (((asked_format->rgodf[j].pguid == NULL) || (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid)))
197           &&
198           (wine_format->rgodf[i].dwType & asked_format->rgodf[j].dwType)) {
199
200         done[j] = 1;
201
202         TRACE("Matching : \n");
203         TRACE("   - Asked (%d) : %s - Ofs = %3ld - (Type = 0x%02x | Instance = %04x)\n",
204               j, debugstr_guid(asked_format->rgodf[j].pguid),
205               asked_format->rgodf[j].dwOfs,
206               DIDFT_GETTYPE(asked_format->rgodf[j].dwType), DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType));
207
208         TRACE("   - Wine  (%d) : %s - Ofs = %3ld - (Type = 0x%02x | Instance = %04x)\n",
209               j, debugstr_guid(wine_format->rgodf[i].pguid),
210               wine_format->rgodf[i].dwOfs,
211               DIDFT_GETTYPE(wine_format->rgodf[i].dwType), DIDFT_GETINSTANCE(wine_format->rgodf[i].dwType));
212
213         if (wine_format->rgodf[i].dwType & DIDFT_BUTTON)
214           dt[index].size = sizeof(BYTE);
215         else
216           dt[index].size = sizeof(DWORD);
217         dt[index].offset_in  = wine_format ->rgodf[i].dwOfs;
218         dt[index].offset_out = asked_format->rgodf[j].dwOfs;
219         dt[index].value = 0;
220         index++;
221
222         if (wine_format->rgodf[i].dwOfs != asked_format->rgodf[j].dwOfs)
223           same = 0;
224
225         offset[i] = asked_format->rgodf[j].dwOfs;
226         break;
227       }
228     }
229
230     if (j == asked_format->dwNumObjs)
231       same = 0;
232   }
233
234   TRACE("Setting to default value :\n");
235   for (j = 0; j < asked_format->dwNumObjs; j++) {
236     if (done[j] == 0) {
237       TRACE(" - Asked (%d) : %s - Ofs = %3ld - (Type = 0x%02x | Instance = %04x)\n",
238             j, debugstr_guid(asked_format->rgodf[j].pguid),
239             asked_format->rgodf[j].dwOfs,
240             DIDFT_GETTYPE(asked_format->rgodf[j].dwType), DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType));
241
242
243       if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
244         dt[index].size = sizeof(BYTE);
245       else
246         dt[index].size = sizeof(DWORD);
247       dt[index].offset_in  = -1;
248       dt[index].offset_out = asked_format->rgodf[j].dwOfs;
249       dt[index].value = 0;
250       index++;
251
252       same = 0;
253     }
254   }
255
256   ret->internal_format_size = wine_format->dwDataSize;
257   ret->size = index;
258   if (same) {
259     ret->dt = NULL;
260     HeapFree(GetProcessHeap(), 0, dt);
261   } else {
262     ret->dt = dt;
263   }
264
265   HeapFree(GetProcessHeap(), 0, done);
266
267   return ret;
268 }
269
270 /******************************************************************************
271  *      IDirectInputDeviceA
272  */
273
274 HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
275         LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
276 ) {
277   int i;
278   ICOM_THIS(IDirectInputDevice2AImpl,iface);
279
280   TRACE("(this=%p,%p)\n",This,df);
281
282   TRACE("df.dwSize=%ld\n",df->dwSize);
283   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
284   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
285   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
286   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
287
288   for (i=0;i<df->dwNumObjs;i++) {
289     TRACE("df.rgodf[%d].guid %s\n",i,debugstr_guid(df->rgodf[i].pguid));
290     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
291     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
292     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
293   }
294   return 0;
295 }
296
297 HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
298         LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags
299 ) {
300         ICOM_THIS(IDirectInputDevice2AImpl,iface);
301         TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
302         if (TRACE_ON(dinput)) {
303             TRACE(" cooperative level : ");
304             _dump_cooperativelevel_DI(dwflags);
305         }
306         return 0;
307 }
308
309 HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
310         LPDIRECTINPUTDEVICE8A iface,HANDLE hnd
311 ) {
312         ICOM_THIS(IDirectInputDevice2AImpl,iface);
313         FIXME("(this=%p,0x%08lx): stub\n",This,(DWORD)hnd);
314         return 0;
315 }
316
317 ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface)
318 {
319         ICOM_THIS(IDirectInputDevice2AImpl,iface);
320         This->ref--;
321         if (This->ref)
322                 return This->ref;
323         HeapFree(GetProcessHeap(),0,This);
324         return 0;
325 }
326
327 HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
328         LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj
329 )
330 {
331         ICOM_THIS(IDirectInputDevice2AImpl,iface);
332
333         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
334         if (IsEqualGUID(&IID_IUnknown,riid)) {
335                 IDirectInputDevice2_AddRef(iface);
336                 *ppobj = This;
337                 return 0;
338         }
339         if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) {
340                 IDirectInputDevice2_AddRef(iface);
341                 *ppobj = This;
342                 return 0;
343         }
344         if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
345                 IDirectInputDevice7_AddRef(iface);
346                 *ppobj = This;
347                 return 0;
348         }
349         TRACE("Unsupported interface !\n");
350         return E_FAIL;
351 }
352
353 ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
354         LPDIRECTINPUTDEVICE8A iface)
355 {
356         ICOM_THIS(IDirectInputDevice2AImpl,iface);
357         return ++This->ref;
358 }
359
360 HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
361         LPDIRECTINPUTDEVICE8A iface,
362         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
363         LPVOID lpvRef,
364         DWORD dwFlags)
365 {
366         FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags);
367         if (TRACE_ON(dinput)) {
368           DPRINTF("  - flags = ");
369           _dump_EnumObjects_flags(dwFlags);
370           DPRINTF("\n");
371         }
372
373         return DI_OK;
374 }
375
376 HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
377         LPDIRECTINPUTDEVICE8A iface,
378         REFGUID rguid,
379         LPDIPROPHEADER pdiph)
380 {
381         FIXME("(this=%p,%s,%p): stub!\n",
382               iface, debugstr_guid(rguid), pdiph);
383
384         if (TRACE_ON(dinput))
385           _dump_DIPROPHEADER(pdiph);
386
387         return DI_OK;
388 }
389
390 HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
391         LPDIRECTINPUTDEVICE8A iface,
392         LPDIDEVICEOBJECTINSTANCEA pdidoi,
393         DWORD dwObj,
394         DWORD dwHow)
395 {
396         FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n",
397               iface, pdidoi, dwObj, dwHow);
398
399         return DI_OK;
400 }
401
402 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
403         LPDIRECTINPUTDEVICE8A iface,
404         LPDIDEVICEINSTANCEA pdidi)
405 {
406         FIXME("(this=%p,%p): stub!\n",
407               iface, pdidi);
408
409         return DI_OK;
410 }
411
412 HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
413         LPDIRECTINPUTDEVICE8A iface,
414         HWND hwndOwner,
415         DWORD dwFlags)
416 {
417   FIXME("(this=%p,%p,0x%08lx): stub!\n",
418         iface, hwndOwner, dwFlags);
419
420         return DI_OK;
421 }
422
423 HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
424         LPDIRECTINPUTDEVICE8A iface,
425         HINSTANCE hinst,
426         DWORD dwVersion,
427         REFGUID rguid)
428 {
429         FIXME("(this=%p,%p,%ld,%s): stub!\n",
430               iface, hinst, dwVersion, debugstr_guid(rguid));
431         return DI_OK;
432 }
433
434 /******************************************************************************
435  *      IDirectInputDevice2A
436  */
437
438 HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
439         LPDIRECTINPUTDEVICE8A iface,
440         REFGUID rguid,
441         LPCDIEFFECT lpeff,
442         LPDIRECTINPUTEFFECT *ppdef,
443         LPUNKNOWN pUnkOuter)
444 {
445         FIXME("(this=%p,%s,%p,%p,%p): stub!\n",
446               iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
447         return DI_OK;
448 }
449
450 HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
451         LPDIRECTINPUTDEVICE8A iface,
452         LPDIENUMEFFECTSCALLBACKA lpCallback,
453         LPVOID lpvRef,
454         DWORD dwFlags)
455 {
456         FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
457               iface, lpCallback, lpvRef, dwFlags);
458
459         if (lpCallback)
460                 lpCallback(NULL, lpvRef);
461         return DI_OK;
462 }
463
464 HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
465         LPDIRECTINPUTDEVICE8A iface,
466         LPDIEFFECTINFOA lpdei,
467         REFGUID rguid)
468 {
469         FIXME("(this=%p,%p,%s): stub!\n",
470               iface, lpdei, debugstr_guid(rguid));
471         return DI_OK;
472 }
473
474 HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
475         LPDIRECTINPUTDEVICE8A iface,
476         LPDWORD pdwOut)
477 {
478         FIXME("(this=%p,%p): stub!\n",
479               iface, pdwOut);
480         return DI_OK;
481 }
482
483 HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
484         LPDIRECTINPUTDEVICE8A iface,
485         DWORD dwFlags)
486 {
487         FIXME("(this=%p,0x%08lx): stub!\n",
488               iface, dwFlags);
489         return DI_OK;
490 }
491
492 HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
493         LPDIRECTINPUTDEVICE8A iface,
494         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
495         LPVOID lpvRef,
496         DWORD dwFlags)
497 {
498         FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
499               iface, lpCallback, lpvRef, dwFlags);
500         if (lpCallback)
501                 lpCallback(NULL, lpvRef);
502         return DI_OK;
503 }
504
505 HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
506         LPDIRECTINPUTDEVICE8A iface,
507         LPDIEFFESCAPE lpDIEEsc)
508 {
509         FIXME("(this=%p,%p): stub!\n",
510               iface, lpDIEEsc);
511         return DI_OK;
512 }
513
514 HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
515         LPDIRECTINPUTDEVICE8A iface)
516 {
517         /* Because wine devices do not need to be polled, just return DI_NOEFFECT */
518         return DI_NOEFFECT;
519 }
520
521 HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
522         LPDIRECTINPUTDEVICE8A iface,
523         DWORD cbObjectData,
524         LPCDIDEVICEOBJECTDATA rgdod,
525         LPDWORD pdwInOut,
526         DWORD dwFlags)
527 {
528         FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n",
529               iface, cbObjectData, rgdod, pdwInOut, dwFlags);
530
531         return DI_OK;
532 }
533
534 HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface,
535                                                           LPCSTR lpszFileName,
536                                                           LPDIENUMEFFECTSINFILECALLBACK pec,
537                                                           LPVOID pvRef,
538                                                           DWORD dwFlags)
539 {
540   FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
541
542   return DI_OK;
543 }
544
545 HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface,
546                                                           LPCSTR lpszFileName,
547                                                           DWORD dwEntries,
548                                                           LPDIFILEEFFECT rgDiFileEft,
549                                                           DWORD dwFlags)
550 {
551   FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
552
553   return DI_OK;
554 }
555
556 HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface,
557                                                        LPDIACTIONFORMATA lpdiaf,
558                                                        LPCSTR lpszUserName,
559                                                        DWORD dwFlags)
560 {
561   FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
562
563   return DI_OK;
564 }
565
566 HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
567                                                      LPDIACTIONFORMATA lpdiaf,
568                                                      LPCSTR lpszUserName,
569                                                      DWORD dwFlags)
570 {
571   FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
572
573   return DI_OK;
574 }
575
576 HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface,
577                                                      LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader)
578 {
579   FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
580
581   return DI_OK;
582 }