advapi32: Make rpcrt4 a delayed import to work around circular dependencies with...
[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_IOHIDMANAGERCREATE
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.\n");
179                 return NULL;
180             }
181         }
182         else
183         {
184             ERR("CFNumberCreate failed.\n");
185             return NULL;
186         }
187     }
188     else
189     {
190         ERR("CFDictionaryCreateMutable failed.\n");
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.\n");
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 (name)
261         name[0] = 0;
262
263     if (!tIOHIDDeviceRef)
264     {
265         ERR("Invalid Device requested %i\n",id);
266         return 0;
267     }
268
269     str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
270     if (str)
271     {
272         CFIndex len = CFStringGetLength(str);
273         if (length >= len)
274         {
275             CFStringGetCString(str,name,length,kCFStringEncodingASCII);
276             return len;
277         }
278         else
279             return (len+1);
280     }
281     return 0;
282 }
283
284 static void insert_sort_button(int header, IOHIDElementRef tIOHIDElementRef,
285                                 CFMutableArrayRef elementCFArrayRef, int index,
286                                 int target)
287 {
288     IOHIDElementRef targetElement;
289     int usage;
290
291     CFArraySetValueAtIndex(elementCFArrayRef, header+index, NULL);
292     targetElement = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, header+target);
293     if (targetElement == NULL)
294     {
295         CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
296         return;
297     }
298     usage = IOHIDElementGetUsage( targetElement );
299     usage --; /* usage 1 based index */
300
301     insert_sort_button(header, targetElement, elementCFArrayRef, target, usage);
302     CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
303 }
304
305 static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
306 {
307     IOHIDDeviceRef  tIOHIDDeviceRef;
308     CFArrayRef      gElementCFArrayRef;
309     DWORD           axes = 0;
310     DWORD           sliders = 0;
311     DWORD           buttons = 0;
312     DWORD           povs = 0;
313
314     device->elementCFArrayRef = NULL;
315
316     if (!gDevices)
317         return;
318
319     tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
320
321     if (!tIOHIDDeviceRef)
322         return;
323
324     gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef,
325                                 NULL, 0 );
326
327     if (gElementCFArrayRef)
328     {
329         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
330         /* build our element array in the order that dinput expects */
331         device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);
332
333         for ( idx = 0; idx < cnt; idx++ )
334         {
335             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
336             int eleType = IOHIDElementGetType( tIOHIDElementRef );
337             switch(eleType)
338             {
339                 case kIOHIDElementTypeInput_Button:
340                 {
341                     int usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
342                     if (usagePage != kHIDPage_Button)
343                     {
344                         /* avoid strange elements found on the 360 controler */
345                         continue;
346                     }
347
348                     if (buttons < 128)
349                     {
350                         CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
351                         buttons++;
352                     }
353                     break;
354                 }
355                 case kIOHIDElementTypeInput_Axis:
356                 {
357                     CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
358                     axes++;
359                     break;
360                 }
361                 case kIOHIDElementTypeInput_Misc:
362                 {
363                     uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
364                     switch(usage)
365                     {
366                         case kHIDUsage_GD_Hatswitch:
367                         {
368                             CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
369                             povs++;
370                             break;
371                         }
372                         case kHIDUsage_GD_Slider:
373                             sliders ++;
374                             if (sliders > 2)
375                                 break;
376                             /* fallthrough, sliders are axis */
377                         case kHIDUsage_GD_X:
378                         case kHIDUsage_GD_Y:
379                         case kHIDUsage_GD_Z:
380                         case kHIDUsage_GD_Rx:
381                         case kHIDUsage_GD_Ry:
382                         case kHIDUsage_GD_Rz:
383                         {
384                             CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
385                             axis_map[axes]=usage;
386                             axes++;
387                             break;
388                         }
389                         default:
390                             FIXME("Unhandled usage %i\n",usage);
391                     }
392                     break;
393                 }
394                 default:
395                     FIXME("Unhandled type %i\n",eleType);
396             }
397         }
398     }
399
400     device->generic.devcaps.dwAxes = axes;
401     device->generic.devcaps.dwButtons = buttons;
402     device->generic.devcaps.dwPOVs = povs;
403
404     /* Sort buttons into correct order */
405     for (buttons = 0; buttons < device->generic.devcaps.dwButtons; buttons++)
406     {
407         IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elementCFArrayRef, axes+povs+buttons);
408         uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
409         usage --; /* usage is 1 indexed we need 0 indexed */
410         if (usage == buttons)
411             continue;
412
413         insert_sort_button(axes+povs, tIOHIDElementRef, device->elementCFArrayRef,buttons,usage);
414     }
415 }
416
417 static void get_osx_device_elements_props(JoystickImpl *device)
418 {
419     CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
420
421     if (gElementCFArrayRef)
422     {
423         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
424
425         for ( idx = 0; idx < cnt; idx++ )
426         {
427             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
428
429             device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
430             device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
431             device->generic.props[idx].lMin =  0;
432             device->generic.props[idx].lMax =  0xffff;
433             device->generic.props[idx].lDeadZone = 0;
434             device->generic.props[idx].lSaturation = 0;
435         }
436     }
437 }
438
439 static void poll_osx_device_state(JoystickGenericImpl *device_in)
440 {
441     JoystickImpl *device = (JoystickImpl*)device_in;
442     IOHIDDeviceRef tIOHIDDeviceRef;
443     CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
444
445     TRACE("polling device %i\n",device->id);
446
447     if (!gDevices)
448         return;
449
450     tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
451
452     if (!tIOHIDDeviceRef)
453         return;
454
455     if (gElementCFArrayRef)
456     {
457         int button_idx = 0;
458         int pov_idx = 0;
459         int slider_idx = 0;
460         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
461
462         for ( idx = 0; idx < cnt; idx++ )
463         {
464             IOHIDValueRef valueRef;
465             int val;
466             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
467             int eleType = IOHIDElementGetType( tIOHIDElementRef );
468
469             switch(eleType)
470             {
471                 case kIOHIDElementTypeInput_Button:
472                     if(button_idx < 128)
473                     {
474                         IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
475                         val = IOHIDValueGetIntegerValue(valueRef);
476                         device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00;
477                         button_idx ++;
478                     }
479                     break;
480                 case kIOHIDElementTypeInput_Misc:
481                 {
482                     uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
483                     switch(usage)
484                     {
485                         case kHIDUsage_GD_Hatswitch:
486                         {
487                             IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
488                             val = IOHIDValueGetIntegerValue(valueRef);
489                             if (val >= 8)
490                                 device->generic.js.rgdwPOV[pov_idx] = -1;
491                             else
492                                 device->generic.js.rgdwPOV[pov_idx] = val * 4500;
493                             pov_idx ++;
494                             break;
495                         }
496                         case kHIDUsage_GD_X:
497                         case kHIDUsage_GD_Y:
498                         case kHIDUsage_GD_Z:
499                         case kHIDUsage_GD_Rx:
500                         case kHIDUsage_GD_Ry:
501                         case kHIDUsage_GD_Rz:
502                         case kHIDUsage_GD_Slider:
503                         {
504                             IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
505                             val = IOHIDValueGetIntegerValue(valueRef);
506                             switch (usage)
507                             {
508                             case kHIDUsage_GD_X:
509                                 device->generic.js.lX = joystick_map_axis(&device->generic.props[idx], val);
510                                 break;
511                             case kHIDUsage_GD_Y:
512                                 device->generic.js.lY = joystick_map_axis(&device->generic.props[idx], val);
513                                 break;
514                             case kHIDUsage_GD_Z:
515                                 device->generic.js.lZ = joystick_map_axis(&device->generic.props[idx], val);
516                                 break;
517                             case kHIDUsage_GD_Rx:
518                                 device->generic.js.lRx = joystick_map_axis(&device->generic.props[idx], val);
519                                 break;
520                             case kHIDUsage_GD_Ry:
521                                 device->generic.js.lRy = joystick_map_axis(&device->generic.props[idx], val);
522                                 break;
523                             case kHIDUsage_GD_Rz:
524                                 device->generic.js.lRz = joystick_map_axis(&device->generic.props[idx], val);
525                                 break;
526                             case kHIDUsage_GD_Slider:
527                                 device->generic.js.rglSlider[slider_idx] = joystick_map_axis(&device->generic.props[idx], val);
528                                 slider_idx ++;
529                                 break;
530                             }
531                             break;
532                         }
533                         default:
534                             FIXME("unhandled usage %i\n",usage);
535                     }
536                     break;
537                 }
538                 default:
539                     FIXME("Unhandled type %i\n",eleType);
540             }
541         }
542     }
543 }
544
545 static INT find_joystick_devices(void)
546 {
547     static INT joystick_devices_count = -1;
548
549     if (joystick_devices_count != -1) return joystick_devices_count;
550
551     joystick_devices_count = find_osx_devices();
552
553     return  joystick_devices_count;
554 }
555
556 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
557 {
558     if (id >= find_joystick_devices()) return FALSE;
559
560     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
561         WARN("force feedback not supported\n");
562         return FALSE;
563     }
564
565     if ((dwDevType == 0) ||
566     ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
567     (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
568     {
569         /* Return joystick */
570         lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
571         lpddi->guidInstance.Data3 = id;
572         lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
573         /* we only support traditional joysticks for now */
574         if (version >= 0x0800)
575             lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
576         else
577             lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
578         sprintf(lpddi->tszInstanceName, "Joystick %d", id);
579
580         /* get the device name */
581         get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
582
583         lpddi->guidFFDriver = GUID_NULL;
584         return TRUE;
585     }
586
587     return FALSE;
588 }
589
590 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
591 {
592     char name[MAX_PATH];
593     char friendly[32];
594
595     if (id >= find_joystick_devices()) return FALSE;
596
597     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
598         WARN("force feedback not supported\n");
599         return FALSE;
600     }
601
602     if ((dwDevType == 0) ||
603     ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
604     (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
605         /* Return joystick */
606         lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
607         lpddi->guidInstance.Data3 = id;
608         lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
609         /* we only support traditional joysticks for now */
610         if (version >= 0x0800)
611             lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
612         else
613             lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
614         sprintf(friendly, "Joystick %d", id);
615         MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
616         /* get the device name */
617         get_osx_device_name(id, name, MAX_PATH);
618
619         MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
620         lpddi->guidFFDriver = GUID_NULL;
621         return TRUE;
622     }
623
624     return FALSE;
625 }
626
627 static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput,
628     LPDIRECTINPUTDEVICEA* pdev, unsigned short index)
629 {
630     DWORD i;
631     JoystickImpl* newDevice;
632     char name[MAX_PATH];
633     HRESULT hr;
634     LPDIDATAFORMAT df = NULL;
635     int idx = 0;
636     int axis_map[8]; /* max axes */
637     int slider_count = 0;
638
639     TRACE("%s %p %p %p %hu\n", debugstr_guid(rguid), jvt, dinput, pdev, index);
640
641     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
642     if (newDevice == 0) {
643         WARN("out of memory\n");
644         *pdev = 0;
645         return DIERR_OUTOFMEMORY;
646     }
647
648     newDevice->id = index;
649
650     newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID;
651     newDevice->generic.guidInstance.Data3 = index;
652     newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
653     newDevice->generic.joy_polldev = poll_osx_device_state;
654
655     /* get the device name */
656     get_osx_device_name(index, name, MAX_PATH);
657     TRACE("Name %s\n",name);
658
659     /* copy the device name */
660     newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
661     strcpy(newDevice->generic.name, name);
662
663     memset(axis_map, 0, sizeof(axis_map));
664     get_osx_device_elements(newDevice, axis_map);
665
666     TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
667
668     if (newDevice->generic.devcaps.dwButtons > 128)
669     {
670         WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
671         newDevice->generic.devcaps.dwButtons = 128;
672     }
673
674     newDevice->generic.base.lpVtbl = jvt;
675     newDevice->generic.base.ref = 1;
676     newDevice->generic.base.dinput = dinput;
677     newDevice->generic.base.guid = *rguid;
678     InitializeCriticalSection(&newDevice->generic.base.crit);
679     newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
680
681     /* Create copy of default data format */
682     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
683     memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
684
685     df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
686     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
687
688     for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
689     {
690         int wine_obj = -1;
691         switch (axis_map[i])
692         {
693             case kHIDUsage_GD_X: wine_obj = 0; break;
694             case kHIDUsage_GD_Y: wine_obj = 1; break;
695             case kHIDUsage_GD_Z: wine_obj = 2; break;
696             case kHIDUsage_GD_Rx: wine_obj = 3; break;
697             case kHIDUsage_GD_Ry: wine_obj = 4; break;
698             case kHIDUsage_GD_Rz: wine_obj = 5; break;
699             case kHIDUsage_GD_Slider:
700                 wine_obj = 6 + slider_count;
701                 slider_count++;
702                 break;
703         }
704         if (wine_obj < 0 ) continue;
705
706         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
707         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
708     }
709
710     for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
711     {
712         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
713         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
714     }
715
716     for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
717     {
718         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
719         df->rgodf[idx  ].pguid = &GUID_Button;
720         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
721     }
722     newDevice->generic.base.data_format.wine_df = df;
723
724     /* initialize default properties */
725     get_osx_device_elements_props(newDevice);
726
727     IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->generic.base.dinput);
728
729     newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
730     newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
731     if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
732         newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
733     else
734         newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
735     newDevice->generic.devcaps.dwFFSamplePeriod = 0;
736     newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
737     newDevice->generic.devcaps.dwFirmwareRevision = 0;
738     newDevice->generic.devcaps.dwHardwareRevision = 0;
739     newDevice->generic.devcaps.dwFFDriverVersion = 0;
740
741     if (TRACE_ON(dinput)) {
742         _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
743         _dump_DIDEVCAPS(&newDevice->generic.devcaps);
744     }
745
746     *pdev = (LPDIRECTINPUTDEVICEA)newDevice;
747
748     return DI_OK;
749
750 FAILED:
751     hr = DIERR_OUTOFMEMORY;
752     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
753     HeapFree(GetProcessHeap(), 0, df);
754     release_DataFormat(&newDevice->generic.base.data_format);
755     HeapFree(GetProcessHeap(),0,newDevice->generic.name);
756     HeapFree(GetProcessHeap(),0,newDevice);
757     *pdev = 0;
758
759     return hr;
760 }
761
762 /******************************************************************************
763   *     get_joystick_index : Get the joystick index from a given GUID
764   */
765 static unsigned short get_joystick_index(REFGUID guid)
766 {
767     GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
768     GUID dev_guid = *guid;
769
770     wine_joystick.Data3 = 0;
771     dev_guid.Data3 = 0;
772
773     /* for the standard joystick GUID use index 0 */
774     if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
775
776     /* for the wine joystick GUIDs use the index stored in Data3 */
777     if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
778
779     return 0xffff;
780 }
781
782 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
783 {
784     unsigned short index;
785     int joystick_devices_count;
786
787     TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
788     *pdev = NULL;
789
790     if ((joystick_devices_count = find_joystick_devices()) == 0)
791         return DIERR_DEVICENOTREG;
792
793     if ((index = get_joystick_index(rguid)) < 0xffff &&
794         joystick_devices_count && index < joystick_devices_count)
795     {
796         if ((riid == NULL) ||
797         IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
798         IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
799         IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
800         IsEqualGUID(&IID_IDirectInputDevice8A, riid))
801         {
802             return alloc_device(rguid, &JoystickAvt, dinput, pdev, index);
803         }
804
805         WARN("no interface\n");
806         return DIERR_NOINTERFACE;
807     }
808
809     return DIERR_DEVICENOTREG;
810 }
811
812 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
813 {
814     unsigned short index;
815     int joystick_devices_count;
816
817     TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
818     *pdev = NULL;
819
820     if ((joystick_devices_count = find_joystick_devices()) == 0)
821         return DIERR_DEVICENOTREG;
822
823     if ((index = get_joystick_index(rguid)) < 0xffff &&
824         joystick_devices_count && index < joystick_devices_count)
825     {
826         if ((riid == NULL) ||
827         IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
828         IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
829         IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
830         IsEqualGUID(&IID_IDirectInputDevice8W, riid))
831         {
832             return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev, index);
833         }
834         WARN("no interface\n");
835         return DIERR_NOINTERFACE;
836     }
837
838     WARN("invalid device GUID %s\n",debugstr_guid(rguid));
839     return DIERR_DEVICENOTREG;
840 }
841
842 const struct dinput_device joystick_osx_device = {
843   "Wine OS X joystick driver",
844   joydev_enum_deviceA,
845   joydev_enum_deviceW,
846   joydev_create_deviceA,
847   joydev_create_deviceW
848 };
849
850 static const IDirectInputDevice8AVtbl JoystickAvt =
851 {
852     IDirectInputDevice2AImpl_QueryInterface,
853     IDirectInputDevice2AImpl_AddRef,
854     IDirectInputDevice2AImpl_Release,
855     JoystickAGenericImpl_GetCapabilities,
856     IDirectInputDevice2AImpl_EnumObjects,
857     JoystickAGenericImpl_GetProperty,
858     JoystickAGenericImpl_SetProperty,
859     IDirectInputDevice2AImpl_Acquire,
860     IDirectInputDevice2AImpl_Unacquire,
861     JoystickAGenericImpl_GetDeviceState,
862     IDirectInputDevice2AImpl_GetDeviceData,
863     IDirectInputDevice2AImpl_SetDataFormat,
864     IDirectInputDevice2AImpl_SetEventNotification,
865     IDirectInputDevice2AImpl_SetCooperativeLevel,
866     JoystickAGenericImpl_GetObjectInfo,
867     JoystickAGenericImpl_GetDeviceInfo,
868     IDirectInputDevice2AImpl_RunControlPanel,
869     IDirectInputDevice2AImpl_Initialize,
870     IDirectInputDevice2AImpl_CreateEffect,
871     IDirectInputDevice2AImpl_EnumEffects,
872     IDirectInputDevice2AImpl_GetEffectInfo,
873     IDirectInputDevice2AImpl_GetForceFeedbackState,
874     IDirectInputDevice2AImpl_SendForceFeedbackCommand,
875     IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
876     IDirectInputDevice2AImpl_Escape,
877     JoystickAGenericImpl_Poll,
878     IDirectInputDevice2AImpl_SendDeviceData,
879     IDirectInputDevice7AImpl_EnumEffectsInFile,
880     IDirectInputDevice7AImpl_WriteEffectToFile,
881     IDirectInputDevice8AImpl_BuildActionMap,
882     IDirectInputDevice8AImpl_SetActionMap,
883     IDirectInputDevice8AImpl_GetImageInfo
884 };
885
886 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
887 # define XCAST(fun) (typeof(JoystickWvt.fun))
888 #else
889 # define XCAST(fun) (void*)
890 #endif
891
892 static const IDirectInputDevice8WVtbl JoystickWvt =
893 {
894     IDirectInputDevice2WImpl_QueryInterface,
895     XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
896     XCAST(Release)IDirectInputDevice2AImpl_Release,
897     XCAST(GetCapabilities)JoystickAGenericImpl_GetCapabilities,
898     IDirectInputDevice2WImpl_EnumObjects,
899     XCAST(GetProperty)JoystickAGenericImpl_GetProperty,
900     XCAST(SetProperty)JoystickAGenericImpl_SetProperty,
901     XCAST(Acquire)IDirectInputDevice2AImpl_Acquire,
902     XCAST(Unacquire)IDirectInputDevice2AImpl_Unacquire,
903     XCAST(GetDeviceState)JoystickAGenericImpl_GetDeviceState,
904     XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
905     XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
906     XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
907     XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
908     JoystickWGenericImpl_GetObjectInfo,
909     JoystickWGenericImpl_GetDeviceInfo,
910     XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
911     XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
912     XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
913     IDirectInputDevice2WImpl_EnumEffects,
914     IDirectInputDevice2WImpl_GetEffectInfo,
915     XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
916     XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
917     XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
918     XCAST(Escape)IDirectInputDevice2AImpl_Escape,
919     XCAST(Poll)JoystickAGenericImpl_Poll,
920     XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
921     IDirectInputDevice7WImpl_EnumEffectsInFile,
922     IDirectInputDevice7WImpl_WriteEffectToFile,
923     IDirectInputDevice8WImpl_BuildActionMap,
924     IDirectInputDevice8WImpl_SetActionMap,
925     IDirectInputDevice8WImpl_GetImageInfo
926 };
927 #undef XCAST
928
929 #else /* HAVE_IOHIDMANAGERCREATE */
930
931 const struct dinput_device joystick_osx_device = {
932   "Wine OS X joystick driver",
933   NULL,
934   NULL,
935   NULL,
936   NULL
937 };
938
939 #endif /* HAVE_IOHIDMANAGERCREATE */