dinput: OS/X joystick add axes.
[wine] / dlls / dinput / joystick_osx.c
1 /*  DirectInput Joystick device for Mac OS/X
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2009 CodeWeavers, Aric Stewart
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #if defined(HAVE_CARBON_CARBON_H) && defined(HAVE_IOKIT_HID_IOHIDLIB_H)
27 #define LoadResource __carbon_LoadResource
28 #define CompareString __carbon_CompareString
29 #define GetCurrentThread __carbon_GetCurrentThread
30 #define GetCurrentProcess __carbon_GetCurrentProcess
31 #define AnimatePalette __carbon_AnimatePalette
32 #define EqualRgn __carbon_EqualRgn
33 #define FillRgn __carbon_FillRgn
34 #define FrameRgn __carbon_FrameRgn
35 #define GetPixel __carbon_GetPixel
36 #define InvertRgn __carbon_InvertRgn
37 #define LineTo __carbon_LineTo
38 #define OffsetRgn __carbon_OffsetRgn
39 #define PaintRgn __carbon_PaintRgn
40 #define Polygon __carbon_Polygon
41 #define ResizePalette __carbon_ResizePalette
42 #define SetRectRgn __carbon_SetRectRgn
43 #define ULONG __carbon_ULONG
44 #define E_INVALIDARG __carbon_E_INVALIDARG
45 #define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY
46 #define E_HANDLE __carbon_E_HANDLE
47 #define E_ACCESSDENIED __carbon_E_ACCESSDENIED
48 #define E_UNEXPECTED __carbon_E_UNEXPECTED
49 #define E_FAIL __carbon_E_FAIL
50 #define E_ABORT __carbon_E_ABORT
51 #define E_POINTER __carbon_E_POINTER
52 #define E_NOINTERFACE __carbon_E_NOINTERFACE
53 #define E_NOTIMPL __carbon_E_NOTIMPL
54 #define S_FALSE __carbon_S_FALSE
55 #define S_OK __carbon_S_OK
56 #define HRESULT_FACILITY __carbon_HRESULT_FACILITY
57 #define IS_ERROR __carbon_IS_ERROR
58 #define FAILED __carbon_FAILED
59 #define SUCCEEDED __carbon_SUCCEEDED
60 #define MAKE_HRESULT __carbon_MAKE_HRESULT
61 #define HRESULT __carbon_HRESULT
62 #define STDMETHODCALLTYPE __carbon_STDMETHODCALLTYPE
63 #include <Carbon/Carbon.h>
64 #include <IOKit/hid/IOHIDLib.h>
65 #undef LoadResource
66 #undef CompareString
67 #undef GetCurrentThread
68 #undef _CDECL
69 #undef DPRINTF
70 #undef GetCurrentProcess
71 #undef AnimatePalette
72 #undef EqualRgn
73 #undef FillRgn
74 #undef FrameRgn
75 #undef GetPixel
76 #undef InvertRgn
77 #undef LineTo
78 #undef OffsetRgn
79 #undef PaintRgn
80 #undef Polygon
81 #undef ResizePalette
82 #undef SetRectRgn
83 #undef ULONG
84 #undef E_INVALIDARG
85 #undef E_OUTOFMEMORY
86 #undef E_HANDLE
87 #undef E_ACCESSDENIED
88 #undef E_UNEXPECTED
89 #undef E_FAIL
90 #undef E_ABORT
91 #undef E_POINTER
92 #undef E_NOINTERFACE
93 #undef E_NOTIMPL
94 #undef S_FALSE
95 #undef S_OK
96 #undef HRESULT_FACILITY
97 #undef IS_ERROR
98 #undef FAILED
99 #undef SUCCEEDED
100 #undef MAKE_HRESULT
101 #undef HRESULT
102 #undef STDMETHODCALLTYPE
103 #endif /* HAVE_CARBON_CARBON_H */
104
105 #include "wine/debug.h"
106 #include "wine/unicode.h"
107 #include "windef.h"
108 #include "winbase.h"
109 #include "winerror.h"
110 #include "winreg.h"
111 #include "dinput.h"
112
113 #include "dinput_private.h"
114 #include "device_private.h"
115 #include "joystick_private.h"
116
117 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
118
119 #ifdef HAVE_IOKIT_HID_IOHIDLIB_H
120
121 static IOHIDManagerRef gIOHIDManagerRef = NULL;
122 static CFArrayRef gDevices = NULL;
123
124 typedef struct JoystickImpl JoystickImpl;
125 static const IDirectInputDevice8AVtbl JoystickAvt;
126 static const IDirectInputDevice8WVtbl JoystickWvt;
127
128 struct JoystickImpl
129 {
130     struct JoystickGenericImpl generic;
131
132     /* osx private */
133     int                    id;
134     CFMutableArrayRef      elementCFArrayRef;
135     ObjProps               **propmap;
136 };
137
138 static const GUID DInput_Wine_OsX_Joystick_GUID = { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */
139   0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A}
140 };
141
142 static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context)
143 {
144     CFArrayAppendValue( ( CFMutableArrayRef ) context, value );
145 }
146
147 static CFMutableDictionaryRef creates_osx_device_match(int usage)
148 {
149     CFMutableDictionaryRef result;
150
151     result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
152             &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
153
154     if ( result )
155     {
156         int number = kHIDPage_GenericDesktop;
157         CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
158                           kCFNumberIntType, &number);
159
160         if ( pageCFNumberRef )
161         {
162             CFNumberRef usageCFNumberRef;
163
164             CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ),
165                 pageCFNumberRef );
166             CFRelease( pageCFNumberRef );
167
168             usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
169                         kCFNumberIntType, &usage);
170             if ( usageCFNumberRef )
171             {
172                 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ),
173                     usageCFNumberRef );
174                 CFRelease( usageCFNumberRef );
175             }
176             else
177             {
178                 ERR("CFNumberCreate() failed.");
179                 return NULL;
180             }
181         }
182         else
183         {
184             ERR("CFNumberCreate failed.");
185             return NULL;
186         }
187     }
188     else
189     {
190         ERR("CFDictionaryCreateMutable failed.");
191         return NULL;
192     }
193
194     return result;
195 }
196
197 static int find_osx_devices(void)
198 {
199     IOReturn tIOReturn;
200     CFMutableDictionaryRef result;
201     CFSetRef devset;
202     CFArrayRef matching;
203
204     gIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
205     tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, 0L);
206     if ( kIOReturnSuccess != tIOReturn )
207     {
208         ERR("Couldn’t open IOHIDManager.");
209         return 0;
210     }
211
212      matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
213                         &kCFTypeArrayCallBacks );
214
215     /* build matching dictionary */
216     result = creates_osx_device_match(kHIDPage_Sport);
217     if (!result)
218     {
219         CFRelease(matching);
220         return 0;
221     }
222     CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
223     result = creates_osx_device_match(kHIDPage_Game);
224     if (!result)
225     {
226         CFRelease(matching);
227         return 0;
228     }
229     CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
230
231     IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef, matching);
232     devset = IOHIDManagerCopyDevices( gIOHIDManagerRef );
233     if (devset)
234     {
235         CFIndex count;
236         gDevices = CFArrayCreateMutable( kCFAllocatorDefault, 0,
237                         &kCFTypeArrayCallBacks );
238         CFSetApplyFunction(devset, CFSetApplierFunctionCopyToCFArray, (void*)gDevices);
239         count = CFArrayGetCount( gDevices);
240         CFRelease( devset);
241         count = CFArrayGetCount( gDevices);
242
243         TRACE("found %i device(s)\n",(int)count);
244         return count;
245
246     }
247     return 0;
248 }
249
250 static int get_osx_device_name(int id, char *name, int length)
251 {
252     CFStringRef str;
253     IOHIDDeviceRef tIOHIDDeviceRef;
254
255     if (!gDevices)
256         return 0;
257
258     tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, id );
259
260     if (!tIOHIDDeviceRef)
261         return 0;
262
263     if (name)
264         name[0] = 0;
265
266     if (!tIOHIDDeviceRef)
267     {
268         ERR("Invalid Device requested %i\n",id);
269         return 0;
270     }
271
272     str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
273     if (str)
274     {
275         CFIndex len = CFStringGetLength(str);
276         if (length >= len)
277         {
278             CFStringGetCString(str,name,length,kCFStringEncodingASCII);
279             return len;
280         }
281         else
282             return (len+1);
283     }
284     return 0;
285 }
286
287 static void get_osx_device_elements(JoystickImpl *device)
288 {
289     IOHIDDeviceRef  tIOHIDDeviceRef;
290     CFArrayRef      gElementCFArrayRef;
291     DWORD           axes = 0;
292     DWORD           buttons = 0;
293     DWORD           povs = 0;
294
295     device->elementCFArrayRef = NULL;
296
297     if (!gDevices)
298         return;
299
300     tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
301
302     if (!tIOHIDDeviceRef)
303         return;
304
305     gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef,
306                                 NULL, 0 );
307
308     if (gElementCFArrayRef)
309     {
310         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
311         /* build our element array in the order that dinput expects */
312         device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);
313
314         for ( idx = 0; idx < cnt; idx++ )
315         {
316             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
317             int eleType = IOHIDElementGetType( tIOHIDElementRef );
318             switch(eleType)
319             {
320                 case kIOHIDElementTypeInput_Button:
321                 {
322                     if (buttons < 128)
323                     {
324                         CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
325                         buttons++;
326                     }
327                     break;
328                 }
329                 case kIOHIDElementTypeInput_Axis:
330                 {
331                     CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
332                     axes++;
333                     break;
334                 }
335                 default:
336                     FIXME("Unhandled type %i\n",eleType);
337             }
338         }
339     }
340
341     device->generic.devcaps.dwAxes = axes;
342     device->generic.devcaps.dwButtons = buttons;
343     device->generic.devcaps.dwPOVs = povs;
344 }
345
346 static void get_osx_device_elements_props(JoystickImpl *device)
347 {
348     CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
349
350     if (gElementCFArrayRef)
351     {
352         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
353
354         for ( idx = 0; idx < cnt; idx++ )
355         {
356             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
357
358             device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
359             device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
360             device->generic.props[idx].lMin =  0;
361             device->generic.props[idx].lMax =  0xffff;
362             device->generic.props[idx].lDeadZone = 0;
363             device->generic.props[idx].lSaturation = 0;
364         }
365     }
366 }
367
368 static void poll_osx_device_state(JoystickGenericImpl *device_in)
369 {
370     JoystickImpl *device = (JoystickImpl*)device_in;
371     IOHIDDeviceRef tIOHIDDeviceRef;
372     CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
373
374     TRACE("polling device %i\n",device->id);
375
376     if (!gDevices)
377         return;
378
379     tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
380
381     if (!tIOHIDDeviceRef)
382         return;
383
384     if (gElementCFArrayRef)
385     {
386         int button_idx = 0;
387         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
388
389         for ( idx = 0; idx < cnt; idx++ )
390         {
391             IOHIDValueRef valueRef;
392             int val;
393             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
394             int eleType = IOHIDElementGetType( tIOHIDElementRef );
395
396             switch(eleType)
397             {
398                 case kIOHIDElementTypeInput_Button:
399                     if(button_idx < 128)
400                     {
401                         IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
402                         val = IOHIDValueGetIntegerValue(valueRef);
403                         device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00;
404                         button_idx ++;
405                     }
406                     break;
407                 default:
408                     FIXME("Unhandled type %i\n",eleType);
409             }
410         }
411     }
412 }
413
414 static INT find_joystick_devices(void)
415 {
416     static INT joystick_devices_count = -1;
417
418     if (joystick_devices_count != -1) return joystick_devices_count;
419
420     joystick_devices_count = find_osx_devices();
421
422     return  joystick_devices_count;
423 }
424
425 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
426 {
427     if (id >= find_joystick_devices()) return FALSE;
428
429     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
430         WARN("force feedback not supported\n");
431         return FALSE;
432     }
433
434     if ((dwDevType == 0) ||
435     ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
436     (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
437     {
438         /* Return joystick */
439         lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
440         lpddi->guidInstance.Data3 = id;
441         lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
442         /* we only support traditional joysticks for now */
443         if (version >= 0x0800)
444             lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
445         else
446             lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
447         sprintf(lpddi->tszInstanceName, "Joystick %d", id);
448
449         /* get the device name */
450         get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
451
452         lpddi->guidFFDriver = GUID_NULL;
453         return TRUE;
454     }
455
456     return FALSE;
457 }
458
459 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
460 {
461     char name[MAX_PATH];
462     char friendly[32];
463
464     if (id >= find_joystick_devices()) return FALSE;
465
466     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
467         WARN("force feedback not supported\n");
468         return FALSE;
469     }
470
471     if ((dwDevType == 0) ||
472     ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
473     (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
474         /* Return joystick */
475         lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
476         lpddi->guidInstance.Data3 = id;
477         lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
478         /* we only support traditional joysticks for now */
479         if (version >= 0x0800)
480             lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
481         else
482             lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
483         sprintf(friendly, "Joystick %d", id);
484         MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
485         /* get the device name */
486         get_osx_device_name(id, name, MAX_PATH);
487
488         MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
489         lpddi->guidFFDriver = GUID_NULL;
490         return TRUE;
491     }
492
493     return FALSE;
494 }
495
496 static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput,
497     LPDIRECTINPUTDEVICEA* pdev, unsigned short index)
498 {
499     DWORD i;
500     JoystickImpl* newDevice;
501     char name[MAX_PATH];
502     HRESULT hr;
503     LPDIDATAFORMAT df = NULL;
504     int idx = 0;
505
506     TRACE("%s %p %p %p %hu\n", debugstr_guid(rguid), jvt, dinput, pdev, index);
507
508     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
509     if (newDevice == 0) {
510         WARN("out of memory\n");
511         *pdev = 0;
512         return DIERR_OUTOFMEMORY;
513     }
514
515     newDevice->id = index;
516
517     newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
518     newDevice->generic.joy_polldev = poll_osx_device_state;
519
520     /* get the device name */
521     get_osx_device_name(index, name, MAX_PATH);
522     TRACE("Name %s\n",name);
523
524     /* copy the device name */
525     newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
526     strcpy(newDevice->generic.name, name);
527
528     get_osx_device_elements(newDevice);
529
530     TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
531
532     if (newDevice->generic.devcaps.dwButtons > 128)
533     {
534         WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
535         newDevice->generic.devcaps.dwButtons = 128;
536     }
537
538     newDevice->generic.base.lpVtbl = jvt;
539     newDevice->generic.base.ref = 1;
540     newDevice->generic.base.dinput = dinput;
541     newDevice->generic.base.guid = *rguid;
542     InitializeCriticalSection(&newDevice->generic.base.crit);
543     newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
544
545     /* Create copy of default data format */
546     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
547     memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
548
549     df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
550     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
551
552     for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
553     {
554         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i], df->dwObjSize);
555         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_ABSAXIS;
556     }
557
558     for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
559     {
560         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
561         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
562     }
563
564     for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
565     {
566         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
567         df->rgodf[idx  ].pguid = &GUID_Button;
568         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
569     }
570     newDevice->generic.base.data_format.wine_df = df;
571
572     /* create default properties */
573     newDevice->generic.props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps));
574     if (newDevice->generic.props == 0)
575         goto FAILED;
576
577     /* initialize default properties */
578     get_osx_device_elements_props(newDevice);
579
580     IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->generic.base.dinput);
581
582     newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
583     newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
584     if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
585         newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
586     else
587         newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
588     newDevice->generic.devcaps.dwFFSamplePeriod = 0;
589     newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
590     newDevice->generic.devcaps.dwFirmwareRevision = 0;
591     newDevice->generic.devcaps.dwHardwareRevision = 0;
592     newDevice->generic.devcaps.dwFFDriverVersion = 0;
593
594     if (TRACE_ON(dinput)) {
595         _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
596         _dump_DIDEVCAPS(&newDevice->generic.devcaps);
597     }
598
599     *pdev = (LPDIRECTINPUTDEVICEA)newDevice;
600
601     return DI_OK;
602
603 FAILED:
604     hr = DIERR_OUTOFMEMORY;
605     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
606     HeapFree(GetProcessHeap(), 0, df);
607     release_DataFormat(&newDevice->generic.base.data_format);
608     HeapFree(GetProcessHeap(),0,newDevice->generic.name);
609     HeapFree(GetProcessHeap(),0,newDevice->generic.props);
610     HeapFree(GetProcessHeap(),0,newDevice);
611     *pdev = 0;
612
613     return hr;
614 }
615
616 /******************************************************************************
617   *     get_joystick_index : Get the joystick index from a given GUID
618   */
619 static unsigned short get_joystick_index(REFGUID guid)
620 {
621     GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
622     GUID dev_guid = *guid;
623
624     wine_joystick.Data3 = 0;
625     dev_guid.Data3 = 0;
626
627     /* for the standard joystick GUID use index 0 */
628     if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
629
630     /* for the wine joystick GUIDs use the index stored in Data3 */
631     if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
632
633     return 0xffff;
634 }
635
636 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
637 {
638     unsigned short index;
639     int joystick_devices_count;
640
641     TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
642     *pdev = NULL;
643
644     if ((joystick_devices_count = find_joystick_devices()) == 0)
645         return DIERR_DEVICENOTREG;
646
647     if ((index = get_joystick_index(rguid)) < 0xffff &&
648         joystick_devices_count && index < joystick_devices_count)
649     {
650         if ((riid == NULL) ||
651         IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
652         IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
653         IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
654         IsEqualGUID(&IID_IDirectInputDevice8A, riid))
655         {
656             return alloc_device(rguid, &JoystickAvt, dinput, pdev, index);
657         }
658
659         WARN("no interface\n");
660         return DIERR_NOINTERFACE;
661     }
662
663     return DIERR_DEVICENOTREG;
664 }
665
666 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
667 {
668     unsigned short index;
669     int joystick_devices_count;
670
671     TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
672     *pdev = NULL;
673
674     if ((joystick_devices_count = find_joystick_devices()) == 0)
675         return DIERR_DEVICENOTREG;
676
677     if ((index = get_joystick_index(rguid)) < 0xffff &&
678         joystick_devices_count && index < joystick_devices_count)
679     {
680         if ((riid == NULL) ||
681         IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
682         IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
683         IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
684         IsEqualGUID(&IID_IDirectInputDevice8W, riid))
685         {
686             return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev, index);
687         }
688         WARN("no interface\n");
689         return DIERR_NOINTERFACE;
690     }
691
692     WARN("invalid device GUID %s\n",debugstr_guid(rguid));
693     return DIERR_DEVICENOTREG;
694 }
695
696 const struct dinput_device joystick_osx_device = {
697   "Wine OS X joystick driver",
698   joydev_enum_deviceA,
699   joydev_enum_deviceW,
700   joydev_create_deviceA,
701   joydev_create_deviceW
702 };
703
704 static const IDirectInputDevice8AVtbl JoystickAvt =
705 {
706     IDirectInputDevice2AImpl_QueryInterface,
707     IDirectInputDevice2AImpl_AddRef,
708     IDirectInputDevice2AImpl_Release,
709     JoystickAGenericImpl_GetCapabilities,
710     IDirectInputDevice2AImpl_EnumObjects,
711     JoystickAGenericImpl_GetProperty,
712     JoystickAGenericImpl_SetProperty,
713     JoystickAGenericImpl_Acquire,
714     JoystickAGenericImpl_Unacquire,
715     JoystickAGenericImpl_GetDeviceState,
716     IDirectInputDevice2AImpl_GetDeviceData,
717     IDirectInputDevice2AImpl_SetDataFormat,
718     IDirectInputDevice2AImpl_SetEventNotification,
719     IDirectInputDevice2AImpl_SetCooperativeLevel,
720     JoystickAGenericImpl_GetObjectInfo,
721     JoystickAGenericImpl_GetDeviceInfo,
722     IDirectInputDevice2AImpl_RunControlPanel,
723     IDirectInputDevice2AImpl_Initialize,
724     IDirectInputDevice2AImpl_CreateEffect,
725     IDirectInputDevice2AImpl_EnumEffects,
726     IDirectInputDevice2AImpl_GetEffectInfo,
727     IDirectInputDevice2AImpl_GetForceFeedbackState,
728     IDirectInputDevice2AImpl_SendForceFeedbackCommand,
729     IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
730     IDirectInputDevice2AImpl_Escape,
731     JoystickAGenericImpl_Poll,
732     IDirectInputDevice2AImpl_SendDeviceData,
733     IDirectInputDevice7AImpl_EnumEffectsInFile,
734     IDirectInputDevice7AImpl_WriteEffectToFile,
735     IDirectInputDevice8AImpl_BuildActionMap,
736     IDirectInputDevice8AImpl_SetActionMap,
737     IDirectInputDevice8AImpl_GetImageInfo
738 };
739
740 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
741 # define XCAST(fun) (typeof(JoystickWvt.fun))
742 #else
743 # define XCAST(fun) (void*)
744 #endif
745
746 static const IDirectInputDevice8WVtbl JoystickWvt =
747 {
748     IDirectInputDevice2WImpl_QueryInterface,
749     XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
750     XCAST(Release)IDirectInputDevice2AImpl_Release,
751     XCAST(GetCapabilities)JoystickAGenericImpl_GetCapabilities,
752     IDirectInputDevice2WImpl_EnumObjects,
753     XCAST(GetProperty)JoystickAGenericImpl_GetProperty,
754     XCAST(SetProperty)JoystickAGenericImpl_SetProperty,
755     XCAST(Acquire)JoystickAGenericImpl_Acquire,
756     XCAST(Unacquire)JoystickAGenericImpl_Unacquire,
757     XCAST(GetDeviceState)JoystickAGenericImpl_GetDeviceState,
758     XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
759     XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
760     XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
761     XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
762     JoystickWGenericImpl_GetObjectInfo,
763     JoystickWGenericImpl_GetDeviceInfo,
764     XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
765     XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
766     XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
767     IDirectInputDevice2WImpl_EnumEffects,
768     IDirectInputDevice2WImpl_GetEffectInfo,
769     XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
770     XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
771     XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
772     XCAST(Escape)IDirectInputDevice2AImpl_Escape,
773     XCAST(Poll)JoystickAGenericImpl_Poll,
774     XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
775     IDirectInputDevice7WImpl_EnumEffectsInFile,
776     IDirectInputDevice7WImpl_WriteEffectToFile,
777     IDirectInputDevice8WImpl_BuildActionMap,
778     IDirectInputDevice8WImpl_SetActionMap,
779     IDirectInputDevice8WImpl_GetImageInfo
780 };
781 #undef XCAST
782
783 #else /* HAVE_IOKIT_HID_IOHIDLIB_H */
784
785 const struct dinput_device joystick_osx_device = {
786   "Wine OS X joystick driver",
787   NULL,
788   NULL,
789   NULL,
790   NULL
791 };
792
793 #endif /* HAVE_IOKIT_HID_IOHIDLIB_H */