urlmon: Added UrlMkGetSessionOption implementation.
[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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <stdarg.h>
30 #include <string.h>
31 #include "wine/debug.h"
32 #include "wine/unicode.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winuser.h"
36 #include "winerror.h"
37 #include "dinput.h"
38 #include "device_private.h"
39 #include "dinput_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
42
43 /******************************************************************************
44  *      Various debugging tools
45  */
46 void _dump_cooperativelevel_DI(DWORD dwFlags) {
47     if (TRACE_ON(dinput)) {
48         unsigned int   i;
49         static const struct {
50             DWORD       mask;
51             const char  *name;
52         } flags[] = {
53 #define FE(x) { x, #x}
54             FE(DISCL_BACKGROUND),
55             FE(DISCL_EXCLUSIVE),
56             FE(DISCL_FOREGROUND),
57             FE(DISCL_NONEXCLUSIVE)
58 #undef FE
59         };
60         for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++)
61             if (flags[i].mask & dwFlags)
62                 DPRINTF("%s ",flags[i].name);
63         DPRINTF("\n");
64     }
65 }
66
67 void _dump_EnumObjects_flags(DWORD dwFlags) {
68     if (TRACE_ON(dinput)) {
69         unsigned int   i;
70         DWORD type, instance;
71         static const struct {
72             DWORD       mask;
73             const char  *name;
74         } flags[] = {
75 #define FE(x) { x, #x}
76             FE(DIDFT_RELAXIS),
77             FE(DIDFT_ABSAXIS),
78             FE(DIDFT_PSHBUTTON),
79             FE(DIDFT_TGLBUTTON),
80             FE(DIDFT_POV),
81             FE(DIDFT_COLLECTION),
82             FE(DIDFT_NODATA),       
83             FE(DIDFT_FFACTUATOR),
84             FE(DIDFT_FFEFFECTTRIGGER),
85             FE(DIDFT_OUTPUT),
86             FE(DIDFT_VENDORDEFINED),
87             FE(DIDFT_ALIAS),
88             FE(DIDFT_OPTIONAL)
89 #undef FE
90         };
91         type = (dwFlags & 0xFF0000FF);
92         instance = ((dwFlags >> 8) & 0xFFFF);
93         DPRINTF("Type:");
94         if (type == DIDFT_ALL) {
95             DPRINTF(" DIDFT_ALL");
96         } else {
97             for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) {
98                 if (flags[i].mask & type) {
99                     type &= ~flags[i].mask;
100                     DPRINTF(" %s",flags[i].name);
101                 }
102             }
103             if (type) {
104                 DPRINTF(" (unhandled: %08lx)", type);
105             }
106         }
107         DPRINTF(" / Instance: ");
108         if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) {
109             DPRINTF("DIDFT_ANYINSTANCE");
110         } else {
111             DPRINTF("%3ld", instance);
112         }
113     }
114 }
115
116 void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) {
117     if (TRACE_ON(dinput)) {
118         DPRINTF("  - dwObj = 0x%08lx\n", diph->dwObj);
119         DPRINTF("  - dwHow = %s\n",
120                 ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" :
121                  ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" :
122                   ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown")));
123     }
124 }
125
126 void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) {
127     if (TRACE_ON(dinput)) {
128         DPRINTF("    - enumerating : %s ('%s') - %2ld - 0x%08lx - %s\n",
129                 debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName);
130     }
131 }
132
133 void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) {
134     if (TRACE_ON(dinput)) {
135         DPRINTF("    - enumerating : %s ('%s'), - %2ld - 0x%08lx - %s\n",
136                 debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName));
137     }
138 }
139
140 /* This function is a helper to convert a GUID into any possible DInput GUID out there */
141 const char *_dump_dinput_GUID(const GUID *guid) {
142     unsigned int i;
143     static const struct {
144         const GUID *guid;
145         const char *name;
146     } guids[] = {
147 #define FE(x) { &x, #x}
148         FE(GUID_XAxis),
149         FE(GUID_YAxis),
150         FE(GUID_ZAxis),
151         FE(GUID_RxAxis),
152         FE(GUID_RyAxis),
153         FE(GUID_RzAxis),
154         FE(GUID_Slider),
155         FE(GUID_Button),
156         FE(GUID_Key),
157         FE(GUID_POV),
158         FE(GUID_Unknown),
159         FE(GUID_SysMouse),
160         FE(GUID_SysKeyboard),
161         FE(GUID_Joystick),
162         FE(GUID_ConstantForce),
163         FE(GUID_RampForce),
164         FE(GUID_Square),
165         FE(GUID_Sine),
166         FE(GUID_Triangle),
167         FE(GUID_SawtoothUp),
168         FE(GUID_SawtoothDown),
169         FE(GUID_Spring),
170         FE(GUID_Damper),
171         FE(GUID_Inertia),
172         FE(GUID_Friction),
173         FE(GUID_CustomForce)
174 #undef FE
175     };
176     if (guid == NULL)
177         return "null GUID";
178     for (i = 0; i < (sizeof(guids) / sizeof(guids[0])); i++) {
179         if (IsEqualGUID(guids[i].guid, guid)) {
180             return guids[i].name;
181         }
182     }
183     return "Unknown GUID";
184 }
185
186 void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) {
187     unsigned int i;
188
189     TRACE("Dumping DIDATAFORMAT structure:\n");
190     TRACE("  - dwSize: %ld\n", df->dwSize);
191     if (df->dwSize != sizeof(DIDATAFORMAT)) {
192         WARN("Non-standard DIDATAFORMAT structure size %ld\n", df->dwSize);
193     }
194     TRACE("  - dwObjsize: %ld\n", df->dwObjSize);
195     if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) {
196         WARN("Non-standard DIOBJECTDATAFORMAT structure size %ld\n", df->dwObjSize);
197     }
198     TRACE("  - dwFlags: 0x%08lx (", df->dwFlags);
199     switch (df->dwFlags) {
200         case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break;
201         case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break;
202         default: TRACE("unknown"); break;
203     }
204     TRACE(")\n");
205     TRACE("  - dwDataSize: %ld\n", df->dwDataSize);
206     TRACE("  - dwNumObjs: %ld\n", df->dwNumObjs);
207     
208     for (i = 0; i < df->dwNumObjs; i++) {
209         TRACE("  - Object %d:\n", i);
210         TRACE("      * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid));
211         TRACE("      * dwOfs: %ld\n", df->rgodf[i].dwOfs);
212         TRACE("      * dwType: 0x%08lx\n", df->rgodf[i].dwType);
213         TRACE("        "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n");
214         TRACE("      * dwFlags: 0x%08lx\n", df->rgodf[i].dwFlags);
215     }
216 }
217
218 /* Conversion between internal data buffer and external data buffer */
219 void fill_DataFormat(void *out, const void *in, DataFormat *df) {
220     int i;
221     char *in_c = (char *) in;
222     char *out_c = (char *) out;
223     
224     if (df->dt == NULL) {
225         /* This means that the app uses Wine's internal data format */
226         memcpy(out, in, df->internal_format_size);
227     } else {
228         for (i = 0; i < df->size; i++) {
229             if (df->dt[i].offset_in >= 0) {
230                 switch (df->dt[i].size) {
231                     case 1:
232                         TRACE("Copying (c) to %d from %d (value %d)\n",
233                               df->dt[i].offset_out, df->dt[i].offset_in, *((char *) (in_c + df->dt[i].offset_in)));
234                         *((char *) (out_c + df->dt[i].offset_out)) = *((char *) (in_c + df->dt[i].offset_in));
235                         break;
236                     
237                     case 2:
238                         TRACE("Copying (s) to %d from %d (value %d)\n",
239                               df->dt[i].offset_out, df->dt[i].offset_in, *((short *) (in_c + df->dt[i].offset_in)));
240                         *((short *) (out_c + df->dt[i].offset_out)) = *((short *) (in_c + df->dt[i].offset_in));
241                         break;
242                     
243                     case 4:
244                         TRACE("Copying (i) to %d from %d (value %d)\n",
245                               df->dt[i].offset_out, df->dt[i].offset_in, *((int *) (in_c + df->dt[i].offset_in)));
246                         *((int *) (out_c + df->dt[i].offset_out)) = *((int *) (in_c + df->dt[i].offset_in));
247                         break;
248                     
249                     default:
250                         memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size);
251                         break;
252                 }
253             } else {
254                 switch (df->dt[i].size) {
255                     case 1:
256                         TRACE("Copying (c) to %d default value %d\n",
257                               df->dt[i].offset_out, df->dt[i].value);
258                         *((char *) (out_c + df->dt[i].offset_out)) = (char) df->dt[i].value;
259                         break;
260                         
261                     case 2:
262                         TRACE("Copying (s) to %d default value %d\n",
263                               df->dt[i].offset_out, df->dt[i].value);
264                         *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value;
265                         break;
266                         
267                     case 4:
268                         TRACE("Copying (i) to %d default value %d\n",
269                               df->dt[i].offset_out, df->dt[i].value);
270                         *((int *) (out_c + df->dt[i].offset_out)) = (int) df->dt[i].value;
271                         break;
272                         
273                     default:
274                         memset((out_c + df->dt[i].offset_out), 0, df->dt[i].size);
275                         break;
276                 }
277             }
278         }
279     }
280 }
281
282 void release_DataFormat(DataFormat * format)
283 {
284     TRACE("Deleting DataTransform :\n");
285
286     HeapFree(GetProcessHeap(), 0, format->dt);
287 }
288
289 DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) {
290     DataFormat *ret;
291     DataTransform *dt;
292     unsigned int i, j;
293     int same = 1;
294     int *done;
295     int index = 0;
296     DWORD next = 0;
297     
298     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
299     
300     done = HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs);
301     memset(done, 0, sizeof(int) * asked_format->dwNumObjs);
302     
303     dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
304     
305     TRACE("Creating DataTransform :\n");
306     
307     for (i = 0; i < wine_format->dwNumObjs; i++) {
308         offset[i] = -1;
309         
310         for (j = 0; j < asked_format->dwNumObjs; j++) {
311             if (done[j] == 1)
312                 continue;
313             
314             if (/* Check if the application either requests any GUID and if not, it if matches
315                  * the GUID of the Wine object.
316                  */
317                 ((asked_format->rgodf[j].pguid == NULL) ||
318                  (wine_format->rgodf[i].pguid == NULL) ||
319                  (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid)))
320                 &&
321                 (/* Then check if it accepts any instance id, and if not, if it matches Wine's
322                   * instance id.
323                   */
324                  (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0xFFFF) ||
325                  (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0x00FF) || /* This is mentionned in no DX docs, but it works fine - tested on WinXP */
326                  (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(wine_format->rgodf[i].dwType)))
327                 &&
328                 ( /* Then if the asked type matches the one Wine provides */
329                  wine_format->rgodf[i].dwType & asked_format->rgodf[j].dwType)) {
330                 
331                 done[j] = 1;
332                 
333                 TRACE("Matching :\n");
334                 TRACE("   - Asked (%d) :\n", j);
335                 TRACE("       * GUID: %s ('%s')\n",
336                       debugstr_guid(asked_format->rgodf[j].pguid),
337                       _dump_dinput_GUID(asked_format->rgodf[j].pguid));
338                 TRACE("       * Offset: %3ld\n", asked_format->rgodf[j].dwOfs);
339                 TRACE("       * dwType: %08lx\n", asked_format->rgodf[j].dwType);
340                 TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
341                 
342                 TRACE("   - Wine  (%d) :\n", i);
343                 TRACE("       * GUID: %s ('%s')\n",
344                       debugstr_guid(wine_format->rgodf[i].pguid),
345                       _dump_dinput_GUID(wine_format->rgodf[i].pguid));
346                 TRACE("       * Offset: %3ld\n", wine_format->rgodf[i].dwOfs);
347                 TRACE("       * dwType: %08lx\n", wine_format->rgodf[i].dwType);
348                 TRACE("         "); _dump_EnumObjects_flags(wine_format->rgodf[i].dwType); TRACE("\n");
349                 
350                 if (wine_format->rgodf[i].dwType & DIDFT_BUTTON)
351                     dt[index].size = sizeof(BYTE);
352                 else
353                     dt[index].size = sizeof(DWORD);
354                 dt[index].offset_in = wine_format->rgodf[i].dwOfs;
355                 if (asked_format->rgodf[j].dwOfs < next) {
356                     WARN("bad format: dwOfs=%ld, changing to %ld\n", asked_format->rgodf[j].dwOfs, next);
357                     dt[index].offset_out = next;
358                     offset[i] = next;
359                 } else {
360                     dt[index].offset_out = asked_format->rgodf[j].dwOfs;
361                     offset[i] = asked_format->rgodf[j].dwOfs;
362                 }
363                 dt[index].value = 0;
364                 next = next + dt[index].size;
365                 
366                 if (wine_format->rgodf[i].dwOfs != dt[index].offset_out)
367                     same = 0;
368                 
369                 index++;
370                 break;
371             }
372         }
373         
374         if (j == asked_format->dwNumObjs)
375             same = 0;
376     }
377     
378     TRACE("Setting to default value :\n");
379     for (j = 0; j < asked_format->dwNumObjs; j++) {
380         if (done[j] == 0) {
381             TRACE("   - Asked (%d) :\n", j);
382             TRACE("       * GUID: %s ('%s')\n",
383                   debugstr_guid(asked_format->rgodf[j].pguid),
384                   _dump_dinput_GUID(asked_format->rgodf[j].pguid));
385             TRACE("       * Offset: %3ld\n", asked_format->rgodf[j].dwOfs);
386             TRACE("       * dwType: %08lx\n", asked_format->rgodf[j].dwType);
387             TRACE("         "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n");
388             
389             if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
390                 dt[index].size = sizeof(BYTE);
391             else
392                 dt[index].size = sizeof(DWORD);
393             dt[index].offset_in  = -1;
394             dt[index].offset_out = asked_format->rgodf[j].dwOfs;
395             dt[index].value = 0;
396             index++;
397             
398             same = 0;
399         }
400     }
401     
402     ret->internal_format_size = wine_format->dwDataSize;
403     ret->size = index;
404     if (same) {
405         ret->dt = NULL;
406         HeapFree(GetProcessHeap(), 0, dt);
407     } else {
408         ret->dt = dt;
409     }
410     
411     HeapFree(GetProcessHeap(), 0, done);
412     
413     return ret;
414 }
415
416 BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) {
417     DIDEVICEOBJECTINSTANCEW ddtmp;
418     device_enumobjects_AtoWcb_data* data;
419
420     data = (device_enumobjects_AtoWcb_data*) lpvRef;
421     
422     memset(&ddtmp, 0, sizeof(ddtmp));
423     
424     ddtmp.dwSize = sizeof(DIDEVICEINSTANCEW);
425     ddtmp.guidType     = lpddi->guidType;
426     ddtmp.dwOfs        = lpddi->dwOfs;
427     ddtmp.dwType       = lpddi->dwType;
428     ddtmp.dwFlags      = lpddi->dwFlags;
429     MultiByteToWideChar(CP_ACP, 0, lpddi->tszName, -1, ddtmp.tszName, MAX_PATH);
430     
431     if (lpddi->dwSize == sizeof(DIDEVICEINSTANCEA)) {
432         /**
433          * if dwSize < sizeof(DIDEVICEINSTANCEA of DInput version >= 5)
434          *  force feedback and other newer datas aren't available
435          */
436         ddtmp.dwFFMaxForce        = lpddi->dwFFMaxForce;
437         ddtmp.dwFFForceResolution = lpddi->dwFFForceResolution;
438         ddtmp.wCollectionNumber   = lpddi->wCollectionNumber;
439         ddtmp.wDesignatorIndex    = lpddi->wDesignatorIndex;
440         ddtmp.wUsagePage          = lpddi->wUsagePage;
441         ddtmp.wUsage              = lpddi->wUsage;
442         ddtmp.dwDimension         = lpddi->dwDimension;
443         ddtmp.wExponent           = lpddi->wExponent;
444         ddtmp.wReserved           = lpddi->wReserved;
445     }
446     return data->lpCallBack(&ddtmp, data->lpvRef);
447 }
448
449 /******************************************************************************
450  *      IDirectInputDeviceA
451  */
452
453 HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
454         LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
455 ) {
456     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
457     
458     TRACE("(this=%p,%p)\n",This,df);
459     
460     _dump_DIDATAFORMAT(df);
461     
462     return DI_OK;
463 }
464
465 HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
466         LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags
467 ) {
468     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
469     TRACE("(this=%p,%p,0x%08lx)\n",This,hwnd,dwflags);
470     if (TRACE_ON(dinput)) {
471         TRACE(" cooperative level : ");
472         _dump_cooperativelevel_DI(dwflags);
473     }
474     return DI_OK;
475 }
476
477 HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
478         LPDIRECTINPUTDEVICE8A iface,HANDLE hnd
479 ) {
480     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
481     FIXME("(this=%p,%p): stub\n",This,hnd);
482     return DI_OK;
483 }
484
485 ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface)
486 {
487     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
488     ULONG ref;
489     ref = InterlockedDecrement(&(This->ref));
490     if (ref == 0)
491         HeapFree(GetProcessHeap(),0,This);
492     return ref;
493 }
494
495 HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
496         LPDIRECTINPUTDEVICE8A iface,REFIID riid,LPVOID *ppobj
497 )
498 {
499     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
500     
501     TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
502     if (IsEqualGUID(&IID_IUnknown,riid)) {
503         IDirectInputDevice2_AddRef(iface);
504         *ppobj = This;
505         return DI_OK;
506     }
507     if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) {
508         IDirectInputDevice2_AddRef(iface);
509         *ppobj = This;
510         return DI_OK;
511     }
512     if (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) {
513         IDirectInputDevice2_AddRef(iface);
514         *ppobj = This;
515         return DI_OK;
516     }
517     if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
518         IDirectInputDevice7_AddRef(iface);
519         *ppobj = This;
520         return DI_OK;
521     }
522     if (IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
523         IDirectInputDevice8_AddRef(iface);
524         *ppobj = This;
525         return DI_OK;
526     }
527     TRACE("Unsupported interface !\n");
528     return E_FAIL;
529 }
530
531 HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(
532         LPDIRECTINPUTDEVICE8W iface,REFIID riid,LPVOID *ppobj
533 )
534 {
535     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
536     
537     TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
538     if (IsEqualGUID(&IID_IUnknown,riid)) {
539         IDirectInputDevice2_AddRef(iface);
540         *ppobj = This;
541         return DI_OK;
542     }
543     if (IsEqualGUID(&IID_IDirectInputDeviceW,riid)) {
544         IDirectInputDevice2_AddRef(iface);
545         *ppobj = This;
546         return DI_OK;
547     }
548     if (IsEqualGUID(&IID_IDirectInputDevice2W,riid)) {
549         IDirectInputDevice2_AddRef(iface);
550         *ppobj = This;
551         return DI_OK;
552     }
553     if (IsEqualGUID(&IID_IDirectInputDevice7W,riid)) {
554         IDirectInputDevice7_AddRef(iface);
555         *ppobj = This;
556         return DI_OK;
557     }
558     if (IsEqualGUID(&IID_IDirectInputDevice8W,riid)) {
559         IDirectInputDevice8_AddRef(iface);
560         *ppobj = This;
561         return DI_OK;
562     }
563     TRACE("Unsupported interface !\n");
564     return E_FAIL;
565 }
566
567 ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
568         LPDIRECTINPUTDEVICE8A iface)
569 {
570     IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface;
571     return InterlockedIncrement(&(This->ref));
572 }
573
574 HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
575         LPDIRECTINPUTDEVICE8A iface,
576         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
577         LPVOID lpvRef,
578         DWORD dwFlags)
579 {
580     FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags);
581     if (TRACE_ON(dinput)) {
582         DPRINTF("  - flags = ");
583         _dump_EnumObjects_flags(dwFlags);
584         DPRINTF("\n");
585     }
586     
587     return DI_OK;
588 }
589
590 HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects(
591         LPDIRECTINPUTDEVICE8W iface,
592         LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback,
593         LPVOID lpvRef,
594         DWORD dwFlags)
595 {
596     FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags);
597     if (TRACE_ON(dinput)) {
598         DPRINTF("  - flags = ");
599         _dump_EnumObjects_flags(dwFlags);
600         DPRINTF("\n");
601     }
602     
603     return DI_OK;
604 }
605
606 HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
607         LPDIRECTINPUTDEVICE8A iface,
608         REFGUID rguid,
609         LPDIPROPHEADER pdiph)
610 {
611     FIXME("(this=%p,%s,%p): stub!\n",
612           iface, debugstr_guid(rguid), pdiph);
613     
614     if (TRACE_ON(dinput))
615         _dump_DIPROPHEADER(pdiph);
616     
617     return DI_OK;
618 }
619
620 HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
621         LPDIRECTINPUTDEVICE8A iface,
622         LPDIDEVICEOBJECTINSTANCEA pdidoi,
623         DWORD dwObj,
624         DWORD dwHow)
625 {
626     FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n",
627           iface, pdidoi, dwObj, dwHow);
628     
629     return DI_OK;
630 }
631
632 HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(
633         LPDIRECTINPUTDEVICE8W iface,
634         LPDIDEVICEOBJECTINSTANCEW pdidoi,
635         DWORD dwObj,
636         DWORD dwHow)
637 {
638     FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n",
639           iface, pdidoi, dwObj, dwHow);
640     
641     return DI_OK;
642 }
643
644 HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
645         LPDIRECTINPUTDEVICE8A iface,
646         LPDIDEVICEINSTANCEA pdidi)
647 {
648     FIXME("(this=%p,%p): stub!\n",
649           iface, pdidi);
650     
651     return DI_OK;
652 }
653
654 HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo(
655         LPDIRECTINPUTDEVICE8W iface,
656         LPDIDEVICEINSTANCEW pdidi)
657 {
658     FIXME("(this=%p,%p): stub!\n",
659           iface, pdidi);
660     
661     return DI_OK;
662 }
663
664 HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
665         LPDIRECTINPUTDEVICE8A iface,
666         HWND hwndOwner,
667         DWORD dwFlags)
668 {
669     FIXME("(this=%p,%p,0x%08lx): stub!\n",
670           iface, hwndOwner, dwFlags);
671
672     return DI_OK;
673 }
674
675 HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
676         LPDIRECTINPUTDEVICE8A iface,
677         HINSTANCE hinst,
678         DWORD dwVersion,
679         REFGUID rguid)
680 {
681     FIXME("(this=%p,%p,%ld,%s): stub!\n",
682           iface, hinst, dwVersion, debugstr_guid(rguid));
683     return DI_OK;
684 }
685
686 /******************************************************************************
687  *      IDirectInputDevice2A
688  */
689
690 HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
691         LPDIRECTINPUTDEVICE8A iface,
692         REFGUID rguid,
693         LPCDIEFFECT lpeff,
694         LPDIRECTINPUTEFFECT *ppdef,
695         LPUNKNOWN pUnkOuter)
696 {
697     FIXME("(this=%p,%s,%p,%p,%p): stub!\n",
698           iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
699     return DI_OK;
700 }
701
702 HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
703         LPDIRECTINPUTDEVICE8A iface,
704         LPDIENUMEFFECTSCALLBACKA lpCallback,
705         LPVOID lpvRef,
706         DWORD dwFlags)
707 {
708     FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
709           iface, lpCallback, lpvRef, dwFlags);
710     
711     return DI_OK;
712 }
713
714 HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects(
715         LPDIRECTINPUTDEVICE8W iface,
716         LPDIENUMEFFECTSCALLBACKW lpCallback,
717         LPVOID lpvRef,
718         DWORD dwFlags)
719 {
720     FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
721           iface, lpCallback, lpvRef, dwFlags);
722     
723     return DI_OK;
724 }
725
726 HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
727         LPDIRECTINPUTDEVICE8A iface,
728         LPDIEFFECTINFOA lpdei,
729         REFGUID rguid)
730 {
731     FIXME("(this=%p,%p,%s): stub!\n",
732           iface, lpdei, debugstr_guid(rguid));
733     return DI_OK;
734 }
735
736 HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo(
737         LPDIRECTINPUTDEVICE8W iface,
738         LPDIEFFECTINFOW lpdei,
739         REFGUID rguid)
740 {
741     FIXME("(this=%p,%p,%s): stub!\n",
742           iface, lpdei, debugstr_guid(rguid));
743     return DI_OK;
744 }
745
746 HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
747         LPDIRECTINPUTDEVICE8A iface,
748         LPDWORD pdwOut)
749 {
750     FIXME("(this=%p,%p): stub!\n",
751           iface, pdwOut);
752     return DI_OK;
753 }
754
755 HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
756         LPDIRECTINPUTDEVICE8A iface,
757         DWORD dwFlags)
758 {
759     FIXME("(this=%p,0x%08lx): stub!\n",
760           iface, dwFlags);
761     return DI_OK;
762 }
763
764 HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
765         LPDIRECTINPUTDEVICE8A iface,
766         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
767         LPVOID lpvRef,
768         DWORD dwFlags)
769 {
770     FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
771           iface, lpCallback, lpvRef, dwFlags);
772     return DI_OK;
773 }
774
775 HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
776         LPDIRECTINPUTDEVICE8A iface,
777         LPDIEFFESCAPE lpDIEEsc)
778 {
779     FIXME("(this=%p,%p): stub!\n",
780           iface, lpDIEEsc);
781     return DI_OK;
782 }
783
784 HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
785         LPDIRECTINPUTDEVICE8A iface)
786 {
787     /* Because wine devices do not need to be polled, just return DI_NOEFFECT */
788     return DI_NOEFFECT;
789 }
790
791 HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
792         LPDIRECTINPUTDEVICE8A iface,
793         DWORD cbObjectData,
794         LPCDIDEVICEOBJECTDATA rgdod,
795         LPDWORD pdwInOut,
796         DWORD dwFlags)
797 {
798     FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n",
799           iface, cbObjectData, rgdod, pdwInOut, dwFlags);
800     
801     return DI_OK;
802 }
803
804 HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A iface,
805                                                           LPCSTR lpszFileName,
806                                                           LPDIENUMEFFECTSINFILECALLBACK pec,
807                                                           LPVOID pvRef,
808                                                           DWORD dwFlags)
809 {
810     FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags);
811     
812     return DI_OK;
813 }
814
815 HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W iface,
816                                                           LPCWSTR lpszFileName,
817                                                           LPDIENUMEFFECTSINFILECALLBACK pec,
818                                                           LPVOID pvRef,
819                                                           DWORD dwFlags)
820 {
821     FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags);
822     
823     return DI_OK;
824 }
825
826 HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A iface,
827                                                           LPCSTR lpszFileName,
828                                                           DWORD dwEntries,
829                                                           LPDIFILEEFFECT rgDiFileEft,
830                                                           DWORD dwFlags)
831 {
832     FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags);
833     
834     return DI_OK;
835 }
836
837 HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W iface,
838                                                           LPCWSTR lpszFileName,
839                                                           DWORD dwEntries,
840                                                           LPDIFILEEFFECT rgDiFileEft,
841                                                           DWORD dwFlags)
842 {
843     FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
844     
845     return DI_OK;
846 }
847
848 HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface,
849                                                        LPDIACTIONFORMATA lpdiaf,
850                                                        LPCSTR lpszUserName,
851                                                        DWORD dwFlags)
852 {
853     FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
854     
855     return DI_OK;
856 }
857
858 HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
859                                                        LPDIACTIONFORMATW lpdiaf,
860                                                        LPCWSTR lpszUserName,
861                                                        DWORD dwFlags)
862 {
863     FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
864   
865     return DI_OK;
866 }
867
868 HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
869                                                      LPDIACTIONFORMATA lpdiaf,
870                                                      LPCSTR lpszUserName,
871                                                      DWORD dwFlags)
872 {
873     FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags);
874     
875     return DI_OK;
876 }
877
878 HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
879                                                      LPDIACTIONFORMATW lpdiaf,
880                                                      LPCWSTR lpszUserName,
881                                                      DWORD dwFlags)
882 {
883     FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
884     
885     return DI_OK;
886 }
887
888 HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface,
889                                                      LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader)
890 {
891     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
892     
893     return DI_OK;
894 }
895
896 HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface,
897                                                      LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
898 {
899     FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
900     
901     return DI_OK;
902 }
903
904 /******************************************************************************
905  *      DInput hook thread
906  */
907
908 static LRESULT CALLBACK dinput_hook_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
909 {
910     static HHOOK kbd_hook, mouse_hook;
911     BOOL res;
912
913     TRACE("got message %x %p %p\n", message, (LPVOID)wParam, (LPVOID)lParam);
914     switch (message)
915     {
916     case WM_USER+0x10:
917         if (wParam == WH_KEYBOARD_LL)
918         {
919             if (lParam)
920             {
921                 if (kbd_hook) return 0;
922                 kbd_hook = SetWindowsHookExW(WH_KEYBOARD_LL, (LPVOID)lParam, DINPUT_instance, 0);
923                 return (LRESULT)kbd_hook;
924             }
925             else
926             {
927                 if (!kbd_hook) return 0;
928                 res = UnhookWindowsHookEx(kbd_hook);
929                 kbd_hook = NULL;
930                 return res;
931             }
932         }
933         else if (wParam == WH_MOUSE_LL)
934         {
935             if (lParam)
936             {
937                 if (mouse_hook) return 0;
938                 mouse_hook = SetWindowsHookExW(WH_MOUSE_LL, (LPVOID)lParam, DINPUT_instance, 0);
939                 return (LRESULT)mouse_hook;
940             }
941             else
942             {
943                 if (!mouse_hook) return 0;
944                 res = UnhookWindowsHookEx(mouse_hook);
945                 mouse_hook = NULL;
946                 return res;
947             }
948         }
949         return 0;
950
951     case WM_DESTROY:
952         PostQuitMessage(0);
953     }
954     return DefWindowProcW(hWnd, message, wParam, lParam);
955 }
956
957 static HANDLE signal_event;
958
959 static DWORD WINAPI hook_thread_proc(void *param)
960 {
961     static const WCHAR classW[]={'H','o','o','k','_','L','L','_','C','L',0};
962     MSG msg;
963     WNDCLASSEXW wcex;
964     HWND hwnd;
965
966     memset(&wcex, 0, sizeof(wcex));
967     wcex.cbSize = sizeof(wcex);
968     wcex.lpfnWndProc = dinput_hook_WndProc;
969     wcex.lpszClassName = classW;
970     wcex.hInstance = GetModuleHandleW(0);
971
972     if (!RegisterClassExW(&wcex)) ERR("Error registering window class\n");
973     hwnd = CreateWindowExW(0, classW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, 0);
974     *(HWND*)param = hwnd;
975
976     SetEvent(signal_event);
977     if (hwnd)
978     {
979         while (GetMessageW(&msg, 0, 0, 0))
980         {
981             TranslateMessage(&msg);
982             DispatchMessageW(&msg);
983         }
984     }
985     else ERR("Error creating message window\n");
986
987     DestroyWindow(hwnd);
988     UnregisterClassW(wcex.lpszClassName, wcex.hInstance);
989     return 0;
990 }
991
992 static CRITICAL_SECTION dinput_hook_crit;
993 static CRITICAL_SECTION_DEBUG dinput_critsect_debug =
994 {
995     0, 0, &dinput_hook_crit,
996     { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList },
997       0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") }
998 };
999 static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 };
1000
1001 static HWND get_thread_hwnd(void)
1002 {
1003     static HANDLE hook_thread;
1004     static HWND   hook_thread_hwnd;
1005
1006     EnterCriticalSection(&dinput_hook_crit);
1007     if (!hook_thread)
1008     {
1009         DWORD tid;
1010         HWND hwnd;
1011
1012         signal_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1013         hook_thread = CreateThread(NULL, 0, hook_thread_proc, &hwnd, 0, &tid);
1014         if (signal_event && hook_thread)
1015         {
1016             HANDLE handles[2];
1017             handles[0] = signal_event;
1018             handles[1] = hook_thread;
1019             WaitForMultipleObjects(2, handles, FALSE, INFINITE);
1020         }
1021         CloseHandle(signal_event);
1022
1023         if (!(hook_thread_hwnd = hwnd))
1024         {
1025             /* Thread failed to create window - reset things so we could try again later */
1026             CloseHandle(hook_thread);
1027             hook_thread = 0;
1028         }
1029     }
1030     LeaveCriticalSection(&dinput_hook_crit);
1031
1032     return hook_thread_hwnd;
1033 }
1034
1035 HHOOK set_dinput_hook(int hook_id, LPVOID proc)
1036 {
1037     return (HHOOK)SendMessageW(get_thread_hwnd(), WM_USER+0x10, (WPARAM)hook_id, (LPARAM)proc);
1038 }