urlmon: Added stub for CoInternetGetSecurityUrlEx.
[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 gCollections = 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 inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
139 {
140     return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface),
141            JoystickGenericImpl, base), JoystickImpl, generic);
142 }
143 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
144 {
145     return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
146            JoystickGenericImpl, base), JoystickImpl, generic);
147 }
148
149 static const GUID DInput_Wine_OsX_Joystick_GUID = { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */
150   0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A}
151 };
152
153 static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context)
154 {
155     CFArrayAppendValue( ( CFMutableArrayRef ) context, value );
156 }
157
158 static CFMutableDictionaryRef creates_osx_device_match(int usage)
159 {
160     CFMutableDictionaryRef result;
161
162     result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
163             &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
164
165     if ( result )
166     {
167         int number = kHIDPage_GenericDesktop;
168         CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
169                           kCFNumberIntType, &number);
170
171         if ( pageCFNumberRef )
172         {
173             CFNumberRef usageCFNumberRef;
174
175             CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ),
176                 pageCFNumberRef );
177             CFRelease( pageCFNumberRef );
178
179             usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
180                         kCFNumberIntType, &usage);
181             if ( usageCFNumberRef )
182             {
183                 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ),
184                     usageCFNumberRef );
185                 CFRelease( usageCFNumberRef );
186             }
187             else
188             {
189                 ERR("CFNumberCreate() failed.\n");
190                 return NULL;
191             }
192         }
193         else
194         {
195             ERR("CFNumberCreate failed.\n");
196             return NULL;
197         }
198     }
199     else
200     {
201         ERR("CFDictionaryCreateMutable failed.\n");
202         return NULL;
203     }
204
205     return result;
206 }
207
208 static CFIndex find_top_level(IOHIDDeviceRef tIOHIDDeviceRef, CFArrayRef topLevels)
209 {
210     CFArrayRef      gElementCFArrayRef;
211     CFIndex         numTops = 0;
212
213     if (!tIOHIDDeviceRef)
214         return 0;
215
216     gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, 0);
217
218     if (gElementCFArrayRef)
219     {
220         CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef);
221         for (idx=0; idx<cnt; idx++)
222         {
223             IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gElementCFArrayRef, idx);
224             int eleType = IOHIDElementGetType(tIOHIDElementRef);
225
226             /* Check for top-level gaming device collections */
227             if (eleType == kIOHIDElementTypeCollection && IOHIDElementGetParent(tIOHIDElementRef) == 0)
228             {
229                 int tUsagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
230                 int tUsage = IOHIDElementGetUsage(tIOHIDElementRef);
231
232                 if (tUsagePage == kHIDPage_GenericDesktop &&
233                      (tUsage == kHIDUsage_GD_Joystick || tUsage == kHIDUsage_GD_GamePad))
234                 {
235                     CFArrayAppendValue((CFMutableArrayRef)topLevels, tIOHIDElementRef);
236                     numTops++;
237                 }
238             }
239         }
240     }
241     return numTops;
242 }
243
244 static void get_element_children(IOHIDElementRef tElement, CFArrayRef childElements)
245 {
246     CFIndex    idx, cnt;
247     CFArrayRef tElementChildrenArray = IOHIDElementGetChildren(tElement);
248
249     cnt = CFArrayGetCount(tElementChildrenArray);
250     if (cnt < 1)
251         return;
252
253     /* Either add the element to the array or grab its children */
254     for (idx=0; idx<cnt; idx++)
255     {
256         IOHIDElementRef tChildElementRef;
257
258         tChildElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(tElementChildrenArray, idx);
259         if (IOHIDElementGetType(tChildElementRef) == kIOHIDElementTypeCollection)
260             get_element_children(tChildElementRef, childElements);
261         else
262             CFArrayAppendValue((CFMutableArrayRef)childElements, tChildElementRef);
263     }
264 }
265
266 static int find_osx_devices(void)
267 {
268     IOReturn tIOReturn;
269     CFMutableDictionaryRef result;
270     CFSetRef devset;
271     CFArrayRef matching;
272
273     gIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
274     tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, 0L);
275     if ( kIOReturnSuccess != tIOReturn )
276     {
277         ERR("Couldn't open IOHIDManager.\n");
278         return 0;
279     }
280
281      matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
282                         &kCFTypeArrayCallBacks );
283
284     /* build matching dictionary */
285     result = creates_osx_device_match(kHIDUsage_GD_Joystick);
286     if (!result)
287     {
288         CFRelease(matching);
289         return 0;
290     }
291     CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
292     result = creates_osx_device_match(kHIDUsage_GD_GamePad);
293     if (!result)
294     {
295         CFRelease(matching);
296         return 0;
297     }
298     CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
299
300     IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef, matching);
301     devset = IOHIDManagerCopyDevices( gIOHIDManagerRef );
302     if (devset)
303     {
304         CFIndex countDevices, countCollections, idx;
305         CFArrayRef gDevices = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
306         CFSetApplyFunction(devset, CFSetApplierFunctionCopyToCFArray, (void*)gDevices);
307         CFRelease( devset);
308         countDevices = CFArrayGetCount(gDevices);
309
310         gCollections = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
311         if (!gCollections)
312             return 0;
313
314         countCollections = 0;
315         for (idx = 0; idx < countDevices; idx++)
316         {
317             CFIndex tTop;
318             IOHIDDeviceRef tDevice;
319
320             tDevice = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDevices, idx);
321             tTop = find_top_level(tDevice, gCollections);
322             countCollections += tTop;
323         }
324
325         CFRelease(gDevices);
326
327         TRACE("found %i device(s), %i collection(s)\n",(int)countDevices,(int)countCollections);
328         return (int)countCollections;
329     }
330     return 0;
331 }
332
333 static int get_osx_device_name(int id, char *name, int length)
334 {
335     CFStringRef str;
336     IOHIDElementRef tIOHIDElementRef;
337     IOHIDDeviceRef tIOHIDDeviceRef;
338
339     if (!gCollections)
340         return 0;
341
342     tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, id);
343
344     if (!tIOHIDElementRef)
345     {
346         ERR("Invalid Element requested %i\n",id);
347         return 0;
348     }
349
350     tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDElementRef);
351
352     if (name)
353         name[0] = 0;
354
355     if (!tIOHIDDeviceRef)
356     {
357         ERR("Invalid Device requested %i\n",id);
358         return 0;
359     }
360
361     str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
362     if (str)
363     {
364         CFIndex len = CFStringGetLength(str);
365         if (length >= len)
366         {
367             CFStringGetCString(str,name,length,kCFStringEncodingASCII);
368             return len;
369         }
370         else
371             return (len+1);
372     }
373     return 0;
374 }
375
376 static void insert_sort_button(int header, IOHIDElementRef tIOHIDElementRef,
377                                 CFMutableArrayRef elementCFArrayRef, int index,
378                                 int target)
379 {
380     IOHIDElementRef targetElement;
381     int usage;
382
383     CFArraySetValueAtIndex(elementCFArrayRef, header+index, NULL);
384     targetElement = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, header+target);
385     if (targetElement == NULL)
386     {
387         CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
388         return;
389     }
390     usage = IOHIDElementGetUsage( targetElement );
391     usage --; /* usage 1 based index */
392
393     insert_sort_button(header, targetElement, elementCFArrayRef, target, usage);
394     CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
395 }
396
397 static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
398 {
399     IOHIDElementRef tIOHIDElementRef;
400     CFArrayRef      gElementCFArrayRef;
401     DWORD           axes = 0;
402     DWORD           sliders = 0;
403     DWORD           buttons = 0;
404     DWORD           povs = 0;
405
406     device->elementCFArrayRef = NULL;
407
408     if (!gCollections)
409         return;
410
411     tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, device->id);
412
413     if (!tIOHIDElementRef)
414         return;
415
416     gElementCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
417     get_element_children(tIOHIDElementRef, gElementCFArrayRef);
418
419     if (gElementCFArrayRef)
420     {
421         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
422         /* build our element array in the order that dinput expects */
423         device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);
424
425         for ( idx = 0; idx < cnt; idx++ )
426         {
427             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
428             int eleType = IOHIDElementGetType( tIOHIDElementRef );
429             switch(eleType)
430             {
431                 case kIOHIDElementTypeInput_Button:
432                 {
433                     int usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
434                     if (usagePage != kHIDPage_Button)
435                     {
436                         /* avoid strange elements found on the 360 controler */
437                         continue;
438                     }
439
440                     if (buttons < 128)
441                     {
442                         CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
443                         buttons++;
444                     }
445                     break;
446                 }
447                 case kIOHIDElementTypeInput_Axis:
448                 {
449                     CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
450                     axes++;
451                     break;
452                 }
453                 case kIOHIDElementTypeInput_Misc:
454                 {
455                     uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
456                     switch(usage)
457                     {
458                         case kHIDUsage_GD_Hatswitch:
459                         {
460                             CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
461                             povs++;
462                             break;
463                         }
464                         case kHIDUsage_GD_Slider:
465                             sliders ++;
466                             if (sliders > 2)
467                                 break;
468                             /* fallthrough, sliders are axis */
469                         case kHIDUsage_GD_X:
470                         case kHIDUsage_GD_Y:
471                         case kHIDUsage_GD_Z:
472                         case kHIDUsage_GD_Rx:
473                         case kHIDUsage_GD_Ry:
474                         case kHIDUsage_GD_Rz:
475                         {
476                             CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
477                             axis_map[axes]=usage;
478                             axes++;
479                             break;
480                         }
481                         default:
482                             FIXME("Unhandled usage %i\n",usage);
483                     }
484                     break;
485                 }
486                 default:
487                     FIXME("Unhandled type %i\n",eleType);
488             }
489         }
490     }
491
492     device->generic.devcaps.dwAxes = axes;
493     device->generic.devcaps.dwButtons = buttons;
494     device->generic.devcaps.dwPOVs = povs;
495
496     /* Sort buttons into correct order */
497     for (buttons = 0; buttons < device->generic.devcaps.dwButtons; buttons++)
498     {
499         IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elementCFArrayRef, axes+povs+buttons);
500         uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
501         usage --; /* usage is 1 indexed we need 0 indexed */
502         if (usage == buttons)
503             continue;
504
505         insert_sort_button(axes+povs, tIOHIDElementRef, device->elementCFArrayRef,buttons,usage);
506     }
507 }
508
509 static void get_osx_device_elements_props(JoystickImpl *device)
510 {
511     CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
512
513     if (gElementCFArrayRef)
514     {
515         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
516
517         for ( idx = 0; idx < cnt; idx++ )
518         {
519             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
520
521             device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
522             device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
523             device->generic.props[idx].lMin =  0;
524             device->generic.props[idx].lMax =  0xffff;
525             device->generic.props[idx].lDeadZone = 0;
526             device->generic.props[idx].lSaturation = 0;
527         }
528     }
529 }
530
531 static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
532 {
533     JoystickImpl *device = impl_from_IDirectInputDevice8A(iface);
534     IOHIDElementRef tIOHIDTopElementRef;
535     IOHIDDeviceRef tIOHIDDeviceRef;
536     CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
537
538     TRACE("polling device %i\n",device->id);
539
540     if (!gCollections)
541         return;
542
543     tIOHIDTopElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gCollections, device->id);
544     tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDTopElementRef);
545
546     if (!tIOHIDDeviceRef)
547         return;
548
549     if (gElementCFArrayRef)
550     {
551         int button_idx = 0;
552         int pov_idx = 0;
553         int slider_idx = 0;
554         CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
555
556         for ( idx = 0; idx < cnt; idx++ )
557         {
558             IOHIDValueRef valueRef;
559             int val;
560             IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
561             int eleType = IOHIDElementGetType( tIOHIDElementRef );
562
563             switch(eleType)
564             {
565                 case kIOHIDElementTypeInput_Button:
566                     if(button_idx < 128)
567                     {
568                         IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
569                         val = IOHIDValueGetIntegerValue(valueRef);
570                         device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00;
571                         button_idx ++;
572                     }
573                     break;
574                 case kIOHIDElementTypeInput_Misc:
575                 {
576                     uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
577                     switch(usage)
578                     {
579                         case kHIDUsage_GD_Hatswitch:
580                         {
581                             IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
582                             val = IOHIDValueGetIntegerValue(valueRef);
583                             if (val >= 8)
584                                 device->generic.js.rgdwPOV[pov_idx] = -1;
585                             else
586                                 device->generic.js.rgdwPOV[pov_idx] = val * 4500;
587                             pov_idx ++;
588                             break;
589                         }
590                         case kHIDUsage_GD_X:
591                         case kHIDUsage_GD_Y:
592                         case kHIDUsage_GD_Z:
593                         case kHIDUsage_GD_Rx:
594                         case kHIDUsage_GD_Ry:
595                         case kHIDUsage_GD_Rz:
596                         case kHIDUsage_GD_Slider:
597                         {
598                             IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
599                             val = IOHIDValueGetIntegerValue(valueRef);
600                             switch (usage)
601                             {
602                             case kHIDUsage_GD_X:
603                                 device->generic.js.lX = joystick_map_axis(&device->generic.props[idx], val);
604                                 break;
605                             case kHIDUsage_GD_Y:
606                                 device->generic.js.lY = joystick_map_axis(&device->generic.props[idx], val);
607                                 break;
608                             case kHIDUsage_GD_Z:
609                                 device->generic.js.lZ = joystick_map_axis(&device->generic.props[idx], val);
610                                 break;
611                             case kHIDUsage_GD_Rx:
612                                 device->generic.js.lRx = joystick_map_axis(&device->generic.props[idx], val);
613                                 break;
614                             case kHIDUsage_GD_Ry:
615                                 device->generic.js.lRy = joystick_map_axis(&device->generic.props[idx], val);
616                                 break;
617                             case kHIDUsage_GD_Rz:
618                                 device->generic.js.lRz = joystick_map_axis(&device->generic.props[idx], val);
619                                 break;
620                             case kHIDUsage_GD_Slider:
621                                 device->generic.js.rglSlider[slider_idx] = joystick_map_axis(&device->generic.props[idx], val);
622                                 slider_idx ++;
623                                 break;
624                             }
625                             break;
626                         }
627                         default:
628                             FIXME("unhandled usage %i\n",usage);
629                     }
630                     break;
631                 }
632                 default:
633                     FIXME("Unhandled type %i\n",eleType);
634             }
635         }
636     }
637 }
638
639 static INT find_joystick_devices(void)
640 {
641     static INT joystick_devices_count = -1;
642
643     if (joystick_devices_count != -1) return joystick_devices_count;
644
645     joystick_devices_count = find_osx_devices();
646
647     return  joystick_devices_count;
648 }
649
650 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
651 {
652     if (id >= find_joystick_devices()) return FALSE;
653
654     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
655         WARN("force feedback not supported\n");
656         return FALSE;
657     }
658
659     if ((dwDevType == 0) ||
660     ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
661     (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
662     {
663         /* Return joystick */
664         lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
665         lpddi->guidInstance.Data3 = id;
666         lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
667         /* we only support traditional joysticks for now */
668         if (version >= 0x0800)
669             lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
670         else
671             lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
672         sprintf(lpddi->tszInstanceName, "Joystick %d", id);
673
674         /* get the device name */
675         get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
676
677         lpddi->guidFFDriver = GUID_NULL;
678         return TRUE;
679     }
680
681     return FALSE;
682 }
683
684 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
685 {
686     char name[MAX_PATH];
687     char friendly[32];
688
689     if (id >= find_joystick_devices()) return FALSE;
690
691     if (dwFlags & DIEDFL_FORCEFEEDBACK) {
692         WARN("force feedback not supported\n");
693         return FALSE;
694     }
695
696     if ((dwDevType == 0) ||
697     ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
698     (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
699         /* Return joystick */
700         lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
701         lpddi->guidInstance.Data3 = id;
702         lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
703         /* we only support traditional joysticks for now */
704         if (version >= 0x0800)
705             lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
706         else
707             lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
708         sprintf(friendly, "Joystick %d", id);
709         MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
710         /* get the device name */
711         get_osx_device_name(id, name, MAX_PATH);
712
713         MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
714         lpddi->guidFFDriver = GUID_NULL;
715         return TRUE;
716     }
717
718     return FALSE;
719 }
720
721 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
722                             JoystickImpl **pdev, unsigned short index)
723 {
724     DWORD i;
725     JoystickImpl* newDevice;
726     char name[MAX_PATH];
727     HRESULT hr;
728     LPDIDATAFORMAT df = NULL;
729     int idx = 0;
730     int axis_map[8]; /* max axes */
731     int slider_count = 0;
732
733     TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
734
735     newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
736     if (newDevice == 0) {
737         WARN("out of memory\n");
738         *pdev = 0;
739         return DIERR_OUTOFMEMORY;
740     }
741
742     newDevice->id = index;
743
744     newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID;
745     newDevice->generic.guidInstance.Data3 = index;
746     newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
747     newDevice->generic.joy_polldev = poll_osx_device_state;
748
749     /* get the device name */
750     get_osx_device_name(index, name, MAX_PATH);
751     TRACE("Name %s\n",name);
752
753     /* copy the device name */
754     newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
755     strcpy(newDevice->generic.name, name);
756
757     memset(axis_map, 0, sizeof(axis_map));
758     get_osx_device_elements(newDevice, axis_map);
759
760     TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
761
762     if (newDevice->generic.devcaps.dwButtons > 128)
763     {
764         WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
765         newDevice->generic.devcaps.dwButtons = 128;
766     }
767
768     newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
769     newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
770     newDevice->generic.base.ref = 1;
771     newDevice->generic.base.dinput = dinput;
772     newDevice->generic.base.guid = *rguid;
773     InitializeCriticalSection(&newDevice->generic.base.crit);
774     newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
775
776     /* Create copy of default data format */
777     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
778     memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
779
780     df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
781     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
782
783     for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
784     {
785         int wine_obj = -1;
786         switch (axis_map[i])
787         {
788             case kHIDUsage_GD_X: wine_obj = 0; break;
789             case kHIDUsage_GD_Y: wine_obj = 1; break;
790             case kHIDUsage_GD_Z: wine_obj = 2; break;
791             case kHIDUsage_GD_Rx: wine_obj = 3; break;
792             case kHIDUsage_GD_Ry: wine_obj = 4; break;
793             case kHIDUsage_GD_Rz: wine_obj = 5; break;
794             case kHIDUsage_GD_Slider:
795                 wine_obj = 6 + slider_count;
796                 slider_count++;
797                 break;
798         }
799         if (wine_obj < 0 ) continue;
800
801         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
802         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
803     }
804
805     for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
806     {
807         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
808         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
809     }
810
811     for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
812     {
813         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
814         df->rgodf[idx  ].pguid = &GUID_Button;
815         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
816     }
817     newDevice->generic.base.data_format.wine_df = df;
818
819     /* initialize default properties */
820     get_osx_device_elements_props(newDevice);
821
822     IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
823
824     EnterCriticalSection(&dinput->crit);
825     list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
826     LeaveCriticalSection(&dinput->crit);
827
828     newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
829     newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
830     if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
831         newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
832     else
833         newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
834     newDevice->generic.devcaps.dwFFSamplePeriod = 0;
835     newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
836     newDevice->generic.devcaps.dwFirmwareRevision = 0;
837     newDevice->generic.devcaps.dwHardwareRevision = 0;
838     newDevice->generic.devcaps.dwFFDriverVersion = 0;
839
840     if (TRACE_ON(dinput)) {
841         _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
842         _dump_DIDEVCAPS(&newDevice->generic.devcaps);
843     }
844
845     *pdev = newDevice;
846
847     return DI_OK;
848
849 FAILED:
850     hr = DIERR_OUTOFMEMORY;
851     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
852     HeapFree(GetProcessHeap(), 0, df);
853     release_DataFormat(&newDevice->generic.base.data_format);
854     HeapFree(GetProcessHeap(),0,newDevice->generic.name);
855     HeapFree(GetProcessHeap(),0,newDevice);
856     *pdev = 0;
857
858     return hr;
859 }
860
861 /******************************************************************************
862   *     get_joystick_index : Get the joystick index from a given GUID
863   */
864 static unsigned short get_joystick_index(REFGUID guid)
865 {
866     GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
867     GUID dev_guid = *guid;
868
869     wine_joystick.Data3 = 0;
870     dev_guid.Data3 = 0;
871
872     /* for the standard joystick GUID use index 0 */
873     if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
874
875     /* for the wine joystick GUIDs use the index stored in Data3 */
876     if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
877
878     return 0xffff;
879 }
880
881 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
882 {
883     unsigned short index;
884     int joystick_devices_count;
885
886     TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
887     *pdev = NULL;
888
889     if ((joystick_devices_count = find_joystick_devices()) == 0)
890         return DIERR_DEVICENOTREG;
891
892     if ((index = get_joystick_index(rguid)) < 0xffff &&
893         joystick_devices_count && index < joystick_devices_count)
894     {
895         if ((riid == NULL) ||
896         IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
897         IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
898         IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
899         IsEqualGUID(&IID_IDirectInputDevice8A, riid))
900         {
901             JoystickImpl *This;
902             HRESULT hr = alloc_device(rguid, dinput, &This, index);
903
904             *pdev = (LPDIRECTINPUTDEVICEA)(This ? &This->generic.base.IDirectInputDevice8A_iface : NULL);
905             return hr;
906         }
907
908         WARN("no interface\n");
909         return DIERR_NOINTERFACE;
910     }
911
912     return DIERR_DEVICENOTREG;
913 }
914
915 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
916 {
917     unsigned short index;
918     int joystick_devices_count;
919
920     TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
921     *pdev = NULL;
922
923     if ((joystick_devices_count = find_joystick_devices()) == 0)
924         return DIERR_DEVICENOTREG;
925
926     if ((index = get_joystick_index(rguid)) < 0xffff &&
927         joystick_devices_count && index < joystick_devices_count)
928     {
929         if ((riid == NULL) ||
930         IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
931         IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
932         IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
933         IsEqualGUID(&IID_IDirectInputDevice8W, riid))
934         {
935             JoystickImpl *This;
936             HRESULT hr = alloc_device(rguid, dinput, &This, index);
937
938             *pdev = (LPDIRECTINPUTDEVICEW)(This ? &This->generic.base.IDirectInputDevice8W_iface : NULL);
939             return hr;
940         }
941         WARN("no interface\n");
942         return DIERR_NOINTERFACE;
943     }
944
945     WARN("invalid device GUID %s\n",debugstr_guid(rguid));
946     return DIERR_DEVICENOTREG;
947 }
948
949 const struct dinput_device joystick_osx_device = {
950   "Wine OS X joystick driver",
951   joydev_enum_deviceA,
952   joydev_enum_deviceW,
953   joydev_create_deviceA,
954   joydev_create_deviceW
955 };
956
957 static const IDirectInputDevice8AVtbl JoystickAvt =
958 {
959     IDirectInputDevice2AImpl_QueryInterface,
960     IDirectInputDevice2AImpl_AddRef,
961     IDirectInputDevice2AImpl_Release,
962     JoystickAGenericImpl_GetCapabilities,
963     IDirectInputDevice2AImpl_EnumObjects,
964     JoystickAGenericImpl_GetProperty,
965     JoystickAGenericImpl_SetProperty,
966     IDirectInputDevice2AImpl_Acquire,
967     IDirectInputDevice2AImpl_Unacquire,
968     JoystickAGenericImpl_GetDeviceState,
969     IDirectInputDevice2AImpl_GetDeviceData,
970     IDirectInputDevice2AImpl_SetDataFormat,
971     IDirectInputDevice2AImpl_SetEventNotification,
972     IDirectInputDevice2AImpl_SetCooperativeLevel,
973     JoystickAGenericImpl_GetObjectInfo,
974     JoystickAGenericImpl_GetDeviceInfo,
975     IDirectInputDevice2AImpl_RunControlPanel,
976     IDirectInputDevice2AImpl_Initialize,
977     IDirectInputDevice2AImpl_CreateEffect,
978     IDirectInputDevice2AImpl_EnumEffects,
979     IDirectInputDevice2AImpl_GetEffectInfo,
980     IDirectInputDevice2AImpl_GetForceFeedbackState,
981     IDirectInputDevice2AImpl_SendForceFeedbackCommand,
982     IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
983     IDirectInputDevice2AImpl_Escape,
984     JoystickAGenericImpl_Poll,
985     IDirectInputDevice2AImpl_SendDeviceData,
986     IDirectInputDevice7AImpl_EnumEffectsInFile,
987     IDirectInputDevice7AImpl_WriteEffectToFile,
988     IDirectInputDevice8AImpl_BuildActionMap,
989     IDirectInputDevice8AImpl_SetActionMap,
990     IDirectInputDevice8AImpl_GetImageInfo
991 };
992
993 static const IDirectInputDevice8WVtbl JoystickWvt =
994 {
995     IDirectInputDevice2WImpl_QueryInterface,
996     IDirectInputDevice2WImpl_AddRef,
997     IDirectInputDevice2WImpl_Release,
998     JoystickWGenericImpl_GetCapabilities,
999     IDirectInputDevice2WImpl_EnumObjects,
1000     JoystickWGenericImpl_GetProperty,
1001     JoystickWGenericImpl_SetProperty,
1002     IDirectInputDevice2WImpl_Acquire,
1003     IDirectInputDevice2WImpl_Unacquire,
1004     JoystickWGenericImpl_GetDeviceState,
1005     IDirectInputDevice2WImpl_GetDeviceData,
1006     IDirectInputDevice2WImpl_SetDataFormat,
1007     IDirectInputDevice2WImpl_SetEventNotification,
1008     IDirectInputDevice2WImpl_SetCooperativeLevel,
1009     JoystickWGenericImpl_GetObjectInfo,
1010     JoystickWGenericImpl_GetDeviceInfo,
1011     IDirectInputDevice2WImpl_RunControlPanel,
1012     IDirectInputDevice2WImpl_Initialize,
1013     IDirectInputDevice2WImpl_CreateEffect,
1014     IDirectInputDevice2WImpl_EnumEffects,
1015     IDirectInputDevice2WImpl_GetEffectInfo,
1016     IDirectInputDevice2WImpl_GetForceFeedbackState,
1017     IDirectInputDevice2WImpl_SendForceFeedbackCommand,
1018     IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
1019     IDirectInputDevice2WImpl_Escape,
1020     JoystickWGenericImpl_Poll,
1021     IDirectInputDevice2WImpl_SendDeviceData,
1022     IDirectInputDevice7WImpl_EnumEffectsInFile,
1023     IDirectInputDevice7WImpl_WriteEffectToFile,
1024     IDirectInputDevice8WImpl_BuildActionMap,
1025     IDirectInputDevice8WImpl_SetActionMap,
1026     IDirectInputDevice8WImpl_GetImageInfo
1027 };
1028
1029 #else /* HAVE_IOHIDMANAGERCREATE */
1030
1031 const struct dinput_device joystick_osx_device = {
1032   "Wine OS X joystick driver",
1033   NULL,
1034   NULL,
1035   NULL,
1036   NULL
1037 };
1038
1039 #endif /* HAVE_IOHIDMANAGERCREATE */