Added 16/32 DDE message conversion.
[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 : 0x%08lx - %2ld - 0x%08lx - %s\n",
106             ddoi->guidType.Data1, 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         LPDIRECTINPUTDEVICE2A 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         LPDIRECTINPUTDEVICE2A 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           _dump_cooperativelevel_DI(dwflags);
304         return 0;
305 }
306
307 HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
308         LPDIRECTINPUTDEVICE2A iface,HANDLE hnd
309 ) {
310         ICOM_THIS(IDirectInputDevice2AImpl,iface);
311         FIXME("(this=%p,0x%08lx): stub\n",This,(DWORD)hnd);
312         return 0;
313 }
314
315 ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE2A iface)
316 {
317         ICOM_THIS(IDirectInputDevice2AImpl,iface);
318         This->ref--;
319         if (This->ref)
320                 return This->ref;
321         HeapFree(GetProcessHeap(),0,This);
322         return 0;
323 }
324
325 HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
326         LPDIRECTINPUTDEVICE2A iface,REFIID riid,LPVOID *ppobj
327 )
328 {
329         ICOM_THIS(IDirectInputDevice2AImpl,iface);
330
331         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
332         if (IsEqualGUID(&IID_IUnknown,riid)) {
333                 IDirectInputDevice2_AddRef(iface);
334                 *ppobj = This;
335                 return 0;
336         }
337         if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) {
338                 IDirectInputDevice2_AddRef(iface);
339                 *ppobj = This;
340                 return 0;
341         }
342         if (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) {
343                 IDirectInputDevice2_AddRef(iface);
344                 *ppobj = This;
345                 return 0;
346         }
347         TRACE("Unsupported interface !\n");
348         return E_FAIL;
349 }
350
351 ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
352         LPDIRECTINPUTDEVICE2A iface)
353 {
354         ICOM_THIS(IDirectInputDevice2AImpl,iface);
355         return ++This->ref;
356 }
357
358 HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
359         LPDIRECTINPUTDEVICE2A iface,
360         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
361         LPVOID lpvRef,
362         DWORD dwFlags)
363 {
364         FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags);
365         if (TRACE_ON(dinput)) {
366           DPRINTF("  - flags = ");
367           _dump_EnumObjects_flags(dwFlags);
368           DPRINTF("\n");
369         }
370         
371         return DI_OK;
372 }
373         
374 HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
375         LPDIRECTINPUTDEVICE2A iface,
376         REFGUID rguid,
377         LPDIPROPHEADER pdiph)
378 {
379         FIXME("(this=%p,%s,%p): stub!\n",
380               iface, debugstr_guid(rguid), pdiph);
381         
382         if (TRACE_ON(dinput))
383           _dump_DIPROPHEADER(pdiph);
384         
385         return DI_OK;
386 }
387
388 HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
389         LPDIRECTINPUTDEVICE2A iface,
390         LPDIDEVICEOBJECTINSTANCEA pdidoi,
391         DWORD dwObj,
392         DWORD dwHow)
393 {
394         FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n",
395               iface, pdidoi, dwObj, dwHow);
396         
397         return DI_OK;
398 }
399         
400 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
401         LPDIRECTINPUTDEVICE2A iface,
402         LPDIDEVICEINSTANCEA pdidi)
403 {
404         FIXME("(this=%p,%p): stub!\n",
405               iface, pdidi);
406         
407         return DI_OK;
408 }
409         
410 HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
411         LPDIRECTINPUTDEVICE2A iface,
412         HWND hwndOwner,
413         DWORD dwFlags)
414 {
415   FIXME("(this=%p,0x%08x,0x%08lx): stub!\n",
416         iface, hwndOwner, dwFlags);
417         
418         return DI_OK;
419 }
420         
421 HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
422         LPDIRECTINPUTDEVICE2A iface,
423         HINSTANCE hinst,
424         DWORD dwVersion,
425         REFGUID rguid)
426 {
427         FIXME("(this=%p,%d,%ld,%s): stub!\n",
428               iface, hinst, dwVersion, debugstr_guid(rguid));
429         return DI_OK;
430 }
431         
432 /******************************************************************************
433  *      IDirectInputDevice2A
434  */
435
436 HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
437         LPDIRECTINPUTDEVICE2A iface,
438         REFGUID rguid,
439         LPCDIEFFECT lpeff,
440         LPDIRECTINPUTEFFECT *ppdef,
441         LPUNKNOWN pUnkOuter)
442 {
443         FIXME("(this=%p,%s,%p,%p,%p): stub!\n",
444               iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
445         return DI_OK;
446 }
447
448 HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
449         LPDIRECTINPUTDEVICE2A iface,
450         LPDIENUMEFFECTSCALLBACKA lpCallback,
451         LPVOID lpvRef,
452         DWORD dwFlags)
453 {
454         FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
455               iface, lpCallback, lpvRef, dwFlags);
456         
457         if (lpCallback)
458                 lpCallback(NULL, lpvRef);
459         return DI_OK;
460 }
461
462 HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
463         LPDIRECTINPUTDEVICE2A iface,
464         LPDIEFFECTINFOA lpdei,
465         REFGUID rguid)
466 {
467         FIXME("(this=%p,%p,%s): stub!\n",
468               iface, lpdei, debugstr_guid(rguid));
469         return DI_OK;
470 }
471
472 HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
473         LPDIRECTINPUTDEVICE2A iface,
474         LPDWORD pdwOut)
475 {
476         FIXME("(this=%p,%p): stub!\n",
477               iface, pdwOut);
478         return DI_OK;
479 }
480
481 HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
482         LPDIRECTINPUTDEVICE2A iface,
483         DWORD dwFlags)
484 {
485         FIXME("(this=%p,0x%08lx): stub!\n",
486               iface, dwFlags);
487         return DI_OK;
488 }
489
490 HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
491         LPDIRECTINPUTDEVICE2A iface,
492         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
493         LPVOID lpvRef,
494         DWORD dwFlags)
495 {
496         FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
497               iface, lpCallback, lpvRef, dwFlags);
498         if (lpCallback)
499                 lpCallback(NULL, lpvRef);
500         return DI_OK;
501 }
502
503 HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
504         LPDIRECTINPUTDEVICE2A iface,
505         LPDIEFFESCAPE lpDIEEsc)
506 {
507         FIXME("(this=%p,%p): stub!\n",
508               iface, lpDIEEsc);
509         return DI_OK;
510 }
511
512 HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
513         LPDIRECTINPUTDEVICE2A iface)
514 {
515         /* Because wine devices do not need to be polled, just return DI_NOEFFECT */
516         return DI_NOEFFECT;
517 }
518
519 HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
520         LPDIRECTINPUTDEVICE2A iface,
521         DWORD cbObjectData,
522         LPDIDEVICEOBJECTDATA rgdod,
523         LPDWORD pdwInOut,
524         DWORD dwFlags)
525 {
526         FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n",
527               iface, cbObjectData, rgdod, pdwInOut, dwFlags);
528         
529         return DI_OK;
530 }
531
532 HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE7A iface,
533                                                           LPCSTR lpszFileName,
534                                                           LPDIENUMEFFECTSINFILECALLBACK pec,
535                                                           LPVOID pvRef,
536                                                           DWORD dwFlags)
537 {
538   FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
539
540   return DI_OK;
541 }
542
543 HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE7A iface,
544                                                           LPCSTR lpszFileName,
545                                                           DWORD dwEntries,
546                                                           LPDIFILEEFFECT rgDiFileEft,
547                                                           DWORD dwFlags)
548 {
549   FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
550   
551   return DI_OK;
552 }