1 /* DirectInput Joystick device for Mac OS/X
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2009 CodeWeavers, Aric Stewart
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.
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.
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
24 #include "wine/port.h"
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>
67 #undef GetCurrentThread
70 #undef GetCurrentProcess
96 #undef HRESULT_FACILITY
102 #undef STDMETHODCALLTYPE
103 #endif /* HAVE_CARBON_CARBON_H */
105 #include "wine/debug.h"
106 #include "wine/unicode.h"
109 #include "winerror.h"
113 #include "dinput_private.h"
114 #include "device_private.h"
115 #include "joystick_private.h"
117 WINE_DEFAULT_DEBUG_CHANNEL(dinput
);
119 #ifdef HAVE_IOHIDMANAGERCREATE
121 static IOHIDManagerRef gIOHIDManagerRef
= NULL
;
122 static CFArrayRef gCollections
= NULL
;
124 typedef struct JoystickImpl JoystickImpl
;
125 static const IDirectInputDevice8AVtbl JoystickAvt
;
126 static const IDirectInputDevice8WVtbl JoystickWvt
;
130 struct JoystickGenericImpl generic
;
134 CFMutableArrayRef elementCFArrayRef
;
138 static inline JoystickImpl
*impl_from_IDirectInputDevice8A(IDirectInputDevice8A
*iface
)
140 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface
, IDirectInputDeviceImpl
, IDirectInputDevice8A_iface
),
141 JoystickGenericImpl
, base
), JoystickImpl
, generic
);
143 static inline JoystickImpl
*impl_from_IDirectInputDevice8W(IDirectInputDevice8W
*iface
)
145 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface
, IDirectInputDeviceImpl
, IDirectInputDevice8W_iface
),
146 JoystickGenericImpl
, base
), JoystickImpl
, generic
);
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}
153 static void CFSetApplierFunctionCopyToCFArray(const void *value
, void *context
)
155 CFArrayAppendValue( ( CFMutableArrayRef
) context
, value
);
158 static CFMutableDictionaryRef
creates_osx_device_match(int usage
)
160 CFMutableDictionaryRef result
;
162 result
= CFDictionaryCreateMutable( kCFAllocatorDefault
, 0,
163 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
167 int number
= kHIDPage_GenericDesktop
;
168 CFNumberRef pageCFNumberRef
= CFNumberCreate( kCFAllocatorDefault
,
169 kCFNumberIntType
, &number
);
171 if ( pageCFNumberRef
)
173 CFNumberRef usageCFNumberRef
;
175 CFDictionarySetValue( result
, CFSTR( kIOHIDDeviceUsagePageKey
),
177 CFRelease( pageCFNumberRef
);
179 usageCFNumberRef
= CFNumberCreate( kCFAllocatorDefault
,
180 kCFNumberIntType
, &usage
);
181 if ( usageCFNumberRef
)
183 CFDictionarySetValue( result
, CFSTR( kIOHIDDeviceUsageKey
),
185 CFRelease( usageCFNumberRef
);
189 ERR("CFNumberCreate() failed.\n");
195 ERR("CFNumberCreate failed.\n");
201 ERR("CFDictionaryCreateMutable failed.\n");
208 static CFIndex
find_top_level(IOHIDDeviceRef tIOHIDDeviceRef
, CFArrayRef topLevels
)
210 CFArrayRef gElementCFArrayRef
;
213 if (!tIOHIDDeviceRef
)
216 gElementCFArrayRef
= IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef
, NULL
, 0);
218 if (gElementCFArrayRef
)
220 CFIndex idx
, cnt
= CFArrayGetCount(gElementCFArrayRef
);
221 for (idx
=0; idx
<cnt
; idx
++)
223 IOHIDElementRef tIOHIDElementRef
= (IOHIDElementRef
)CFArrayGetValueAtIndex(gElementCFArrayRef
, idx
);
224 int eleType
= IOHIDElementGetType(tIOHIDElementRef
);
226 /* Check for top-level gaming device collections */
227 if (eleType
== kIOHIDElementTypeCollection
&& IOHIDElementGetParent(tIOHIDElementRef
) == 0)
229 int tUsagePage
= IOHIDElementGetUsagePage(tIOHIDElementRef
);
230 int tUsage
= IOHIDElementGetUsage(tIOHIDElementRef
);
232 if (tUsagePage
== kHIDPage_GenericDesktop
&&
233 (tUsage
== kHIDUsage_GD_Joystick
|| tUsage
== kHIDUsage_GD_GamePad
))
235 CFArrayAppendValue((CFMutableArrayRef
)topLevels
, tIOHIDElementRef
);
244 static void get_element_children(IOHIDElementRef tElement
, CFArrayRef childElements
)
247 CFArrayRef tElementChildrenArray
= IOHIDElementGetChildren(tElement
);
249 cnt
= CFArrayGetCount(tElementChildrenArray
);
253 /* Either add the element to the array or grab its children */
254 for (idx
=0; idx
<cnt
; idx
++)
256 IOHIDElementRef tChildElementRef
;
258 tChildElementRef
= (IOHIDElementRef
)CFArrayGetValueAtIndex(tElementChildrenArray
, idx
);
259 if (IOHIDElementGetType(tChildElementRef
) == kIOHIDElementTypeCollection
)
260 get_element_children(tChildElementRef
, childElements
);
262 CFArrayAppendValue((CFMutableArrayRef
)childElements
, tChildElementRef
);
266 static int find_osx_devices(void)
269 CFMutableDictionaryRef result
;
273 gIOHIDManagerRef
= IOHIDManagerCreate( kCFAllocatorDefault
, 0L );
274 tIOReturn
= IOHIDManagerOpen( gIOHIDManagerRef
, 0L);
275 if ( kIOReturnSuccess
!= tIOReturn
)
277 ERR("Couldn't open IOHIDManager.\n");
281 matching
= CFArrayCreateMutable( kCFAllocatorDefault
, 0,
282 &kCFTypeArrayCallBacks
);
284 /* build matching dictionary */
285 result
= creates_osx_device_match(kHIDUsage_GD_Joystick
);
291 CFArrayAppendValue( ( CFMutableArrayRef
)matching
, result
);
292 result
= creates_osx_device_match(kHIDUsage_GD_GamePad
);
298 CFArrayAppendValue( ( CFMutableArrayRef
)matching
, result
);
300 IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef
, matching
);
301 devset
= IOHIDManagerCopyDevices( gIOHIDManagerRef
);
304 CFIndex countDevices
, countCollections
, idx
;
305 CFArrayRef gDevices
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
306 CFSetApplyFunction(devset
, CFSetApplierFunctionCopyToCFArray
, (void*)gDevices
);
308 countDevices
= CFArrayGetCount(gDevices
);
310 gCollections
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
314 countCollections
= 0;
315 for (idx
= 0; idx
< countDevices
; idx
++)
318 IOHIDDeviceRef tDevice
;
320 tDevice
= (IOHIDDeviceRef
) CFArrayGetValueAtIndex(gDevices
, idx
);
321 tTop
= find_top_level(tDevice
, gCollections
);
322 countCollections
+= tTop
;
327 TRACE("found %i device(s), %i collection(s)\n",(int)countDevices
,(int)countCollections
);
328 return (int)countCollections
;
333 static int get_osx_device_name(int id
, char *name
, int length
)
336 IOHIDElementRef tIOHIDElementRef
;
337 IOHIDDeviceRef tIOHIDDeviceRef
;
342 tIOHIDElementRef
= (IOHIDElementRef
)CFArrayGetValueAtIndex(gCollections
, id
);
344 if (!tIOHIDElementRef
)
346 ERR("Invalid Element requested %i\n",id
);
350 tIOHIDDeviceRef
= IOHIDElementGetDevice(tIOHIDElementRef
);
355 if (!tIOHIDDeviceRef
)
357 ERR("Invalid Device requested %i\n",id
);
361 str
= IOHIDDeviceGetProperty(tIOHIDDeviceRef
, CFSTR( kIOHIDProductKey
));
364 CFIndex len
= CFStringGetLength(str
);
367 CFStringGetCString(str
,name
,length
,kCFStringEncodingASCII
);
376 static void insert_sort_button(int header
, IOHIDElementRef tIOHIDElementRef
,
377 CFMutableArrayRef elementCFArrayRef
, int index
,
380 IOHIDElementRef targetElement
;
383 CFArraySetValueAtIndex(elementCFArrayRef
, header
+index
, NULL
);
384 targetElement
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( elementCFArrayRef
, header
+target
);
385 if (targetElement
== NULL
)
387 CFArraySetValueAtIndex(elementCFArrayRef
, header
+target
,tIOHIDElementRef
);
390 usage
= IOHIDElementGetUsage( targetElement
);
391 usage
--; /* usage 1 based index */
393 insert_sort_button(header
, targetElement
, elementCFArrayRef
, target
, usage
);
394 CFArraySetValueAtIndex(elementCFArrayRef
, header
+target
,tIOHIDElementRef
);
397 static void get_osx_device_elements(JoystickImpl
*device
, int axis_map
[8])
399 IOHIDElementRef tIOHIDElementRef
;
400 CFArrayRef gElementCFArrayRef
;
406 device
->elementCFArrayRef
= NULL
;
411 tIOHIDElementRef
= (IOHIDElementRef
)CFArrayGetValueAtIndex(gCollections
, device
->id
);
413 if (!tIOHIDElementRef
)
416 gElementCFArrayRef
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
417 get_element_children(tIOHIDElementRef
, gElementCFArrayRef
);
419 if (gElementCFArrayRef
)
421 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
422 /* build our element array in the order that dinput expects */
423 device
->elementCFArrayRef
= CFArrayCreateMutable(NULL
,0,NULL
);
425 for ( idx
= 0; idx
< cnt
; idx
++ )
427 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
428 int eleType
= IOHIDElementGetType( tIOHIDElementRef
);
431 case kIOHIDElementTypeInput_Button
:
433 int usagePage
= IOHIDElementGetUsagePage( tIOHIDElementRef
);
434 if (usagePage
!= kHIDPage_Button
)
436 /* avoid strange elements found on the 360 controler */
442 CFArrayInsertValueAtIndex(device
->elementCFArrayRef
, (axes
+povs
+buttons
), tIOHIDElementRef
);
447 case kIOHIDElementTypeInput_Axis
:
449 CFArrayInsertValueAtIndex(device
->elementCFArrayRef
, axes
, tIOHIDElementRef
);
453 case kIOHIDElementTypeInput_Misc
:
455 uint32_t usage
= IOHIDElementGetUsage( tIOHIDElementRef
);
458 case kHIDUsage_GD_Hatswitch
:
460 CFArrayInsertValueAtIndex(device
->elementCFArrayRef
, (axes
+povs
), tIOHIDElementRef
);
464 case kHIDUsage_GD_Slider
:
468 /* fallthrough, sliders are axis */
472 case kHIDUsage_GD_Rx
:
473 case kHIDUsage_GD_Ry
:
474 case kHIDUsage_GD_Rz
:
476 CFArrayInsertValueAtIndex(device
->elementCFArrayRef
, axes
, tIOHIDElementRef
);
477 axis_map
[axes
]=usage
;
482 FIXME("Unhandled usage %i\n",usage
);
487 FIXME("Unhandled type %i\n",eleType
);
492 device
->generic
.devcaps
.dwAxes
= axes
;
493 device
->generic
.devcaps
.dwButtons
= buttons
;
494 device
->generic
.devcaps
.dwPOVs
= povs
;
496 /* Sort buttons into correct order */
497 for (buttons
= 0; buttons
< device
->generic
.devcaps
.dwButtons
; buttons
++)
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
)
505 insert_sort_button(axes
+povs
, tIOHIDElementRef
, device
->elementCFArrayRef
,buttons
,usage
);
509 static void get_osx_device_elements_props(JoystickImpl
*device
)
511 CFArrayRef gElementCFArrayRef
= device
->elementCFArrayRef
;
513 if (gElementCFArrayRef
)
515 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
517 for ( idx
= 0; idx
< cnt
; idx
++ )
519 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
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;
531 static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface
)
533 JoystickImpl
*device
= impl_from_IDirectInputDevice8A(iface
);
534 IOHIDElementRef tIOHIDTopElementRef
;
535 IOHIDDeviceRef tIOHIDDeviceRef
;
536 CFArrayRef gElementCFArrayRef
= device
->elementCFArrayRef
;
538 TRACE("polling device %i\n",device
->id
);
543 tIOHIDTopElementRef
= (IOHIDElementRef
) CFArrayGetValueAtIndex(gCollections
, device
->id
);
544 tIOHIDDeviceRef
= IOHIDElementGetDevice(tIOHIDTopElementRef
);
546 if (!tIOHIDDeviceRef
)
549 if (gElementCFArrayRef
)
554 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
556 for ( idx
= 0; idx
< cnt
; idx
++ )
558 IOHIDValueRef valueRef
;
560 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
561 int eleType
= IOHIDElementGetType( tIOHIDElementRef
);
565 case kIOHIDElementTypeInput_Button
:
568 IOHIDDeviceGetValue(tIOHIDDeviceRef
, tIOHIDElementRef
, &valueRef
);
569 val
= IOHIDValueGetIntegerValue(valueRef
);
570 device
->generic
.js
.rgbButtons
[button_idx
] = val
? 0x80 : 0x00;
574 case kIOHIDElementTypeInput_Misc
:
576 uint32_t usage
= IOHIDElementGetUsage( tIOHIDElementRef
);
579 case kHIDUsage_GD_Hatswitch
:
581 IOHIDDeviceGetValue(tIOHIDDeviceRef
, tIOHIDElementRef
, &valueRef
);
582 val
= IOHIDValueGetIntegerValue(valueRef
);
584 device
->generic
.js
.rgdwPOV
[pov_idx
] = -1;
586 device
->generic
.js
.rgdwPOV
[pov_idx
] = val
* 4500;
593 case kHIDUsage_GD_Rx
:
594 case kHIDUsage_GD_Ry
:
595 case kHIDUsage_GD_Rz
:
596 case kHIDUsage_GD_Slider
:
598 IOHIDDeviceGetValue(tIOHIDDeviceRef
, tIOHIDElementRef
, &valueRef
);
599 val
= IOHIDValueGetIntegerValue(valueRef
);
603 device
->generic
.js
.lX
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
606 device
->generic
.js
.lY
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
609 device
->generic
.js
.lZ
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
611 case kHIDUsage_GD_Rx
:
612 device
->generic
.js
.lRx
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
614 case kHIDUsage_GD_Ry
:
615 device
->generic
.js
.lRy
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
617 case kHIDUsage_GD_Rz
:
618 device
->generic
.js
.lRz
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
620 case kHIDUsage_GD_Slider
:
621 device
->generic
.js
.rglSlider
[slider_idx
] = joystick_map_axis(&device
->generic
.props
[idx
], val
);
628 FIXME("unhandled usage %i\n",usage
);
633 FIXME("Unhandled type %i\n",eleType
);
639 static INT
find_joystick_devices(void)
641 static INT joystick_devices_count
= -1;
643 if (joystick_devices_count
!= -1) return joystick_devices_count
;
645 joystick_devices_count
= find_osx_devices();
647 return joystick_devices_count
;
650 static BOOL
joydev_enum_deviceA(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEA lpddi
, DWORD version
, int id
)
652 if (id
>= find_joystick_devices()) return FALSE
;
654 if (dwFlags
& DIEDFL_FORCEFEEDBACK
) {
655 WARN("force feedback not supported\n");
659 if ((dwDevType
== 0) ||
660 ((dwDevType
== DIDEVTYPE_JOYSTICK
) && (version
> 0x0300 && version
< 0x0800)) ||
661 (((dwDevType
== DI8DEVCLASS_GAMECTRL
) || (dwDevType
== DI8DEVTYPE_JOYSTICK
)) && (version
>= 0x0800)))
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);
671 lpddi
->dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
672 sprintf(lpddi
->tszInstanceName
, "Joystick %d", id
);
674 /* get the device name */
675 get_osx_device_name(id
, lpddi
->tszProductName
, MAX_PATH
);
677 lpddi
->guidFFDriver
= GUID_NULL
;
684 static BOOL
joydev_enum_deviceW(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEW lpddi
, DWORD version
, int id
)
689 if (id
>= find_joystick_devices()) return FALSE
;
691 if (dwFlags
& DIEDFL_FORCEFEEDBACK
) {
692 WARN("force feedback not supported\n");
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);
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
);
713 MultiByteToWideChar(CP_ACP
, 0, name
, -1, lpddi
->tszProductName
, MAX_PATH
);
714 lpddi
->guidFFDriver
= GUID_NULL
;
721 static HRESULT
alloc_device(REFGUID rguid
, IDirectInputImpl
*dinput
,
722 JoystickImpl
**pdev
, unsigned short index
)
725 JoystickImpl
* newDevice
;
728 LPDIDATAFORMAT df
= NULL
;
730 int axis_map
[8]; /* max axes */
731 int slider_count
= 0;
733 TRACE("%s %p %p %hu\n", debugstr_guid(rguid
), dinput
, pdev
, index
);
735 newDevice
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(JoystickImpl
));
736 if (newDevice
== 0) {
737 WARN("out of memory\n");
739 return DIERR_OUTOFMEMORY
;
742 newDevice
->id
= index
;
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
;
749 /* get the device name */
750 get_osx_device_name(index
, name
, MAX_PATH
);
751 TRACE("Name %s\n",name
);
753 /* copy the device name */
754 newDevice
->generic
.name
= HeapAlloc(GetProcessHeap(),0,strlen(name
) + 1);
755 strcpy(newDevice
->generic
.name
, name
);
757 memset(axis_map
, 0, sizeof(axis_map
));
758 get_osx_device_elements(newDevice
, axis_map
);
760 TRACE("%i axes %i buttons %i povs\n",newDevice
->generic
.devcaps
.dwAxes
,newDevice
->generic
.devcaps
.dwButtons
,newDevice
->generic
.devcaps
.dwPOVs
);
762 if (newDevice
->generic
.devcaps
.dwButtons
> 128)
764 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice
->generic
.devcaps
.dwButtons
);
765 newDevice
->generic
.devcaps
.dwButtons
= 128;
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");
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
);
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
;
783 for (i
= 0; i
< newDevice
->generic
.devcaps
.dwAxes
; i
++)
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
;
799 if (wine_obj
< 0 ) continue;
801 memcpy(&df
->rgodf
[idx
], &c_dfDIJoystick2
.rgodf
[wine_obj
], df
->dwObjSize
);
802 df
->rgodf
[idx
++].dwType
= DIDFT_MAKEINSTANCE(wine_obj
) | DIDFT_ABSAXIS
;
805 for (i
= 0; i
< newDevice
->generic
.devcaps
.dwPOVs
; i
++)
807 memcpy(&df
->rgodf
[idx
], &c_dfDIJoystick2
.rgodf
[i
+ 8], df
->dwObjSize
);
808 df
->rgodf
[idx
++].dwType
= DIDFT_MAKEINSTANCE(i
) | DIDFT_POV
;
811 for (i
= 0; i
< newDevice
->generic
.devcaps
.dwButtons
; i
++)
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
;
817 newDevice
->generic
.base
.data_format
.wine_df
= df
;
819 /* initialize default properties */
820 get_osx_device_elements_props(newDevice
);
822 IDirectInput_AddRef(&newDevice
->generic
.base
.dinput
->IDirectInput7A_iface
);
824 newDevice
->generic
.devcaps
.dwSize
= sizeof(newDevice
->generic
.devcaps
);
825 newDevice
->generic
.devcaps
.dwFlags
= DIDC_ATTACHED
;
826 if (newDevice
->generic
.base
.dinput
->dwVersion
>= 0x0800)
827 newDevice
->generic
.devcaps
.dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
829 newDevice
->generic
.devcaps
.dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
830 newDevice
->generic
.devcaps
.dwFFSamplePeriod
= 0;
831 newDevice
->generic
.devcaps
.dwFFMinTimeResolution
= 0;
832 newDevice
->generic
.devcaps
.dwFirmwareRevision
= 0;
833 newDevice
->generic
.devcaps
.dwHardwareRevision
= 0;
834 newDevice
->generic
.devcaps
.dwFFDriverVersion
= 0;
836 if (TRACE_ON(dinput
)) {
837 _dump_DIDATAFORMAT(newDevice
->generic
.base
.data_format
.wine_df
);
838 _dump_DIDEVCAPS(&newDevice
->generic
.devcaps
);
846 hr
= DIERR_OUTOFMEMORY
;
847 if (df
) HeapFree(GetProcessHeap(), 0, df
->rgodf
);
848 HeapFree(GetProcessHeap(), 0, df
);
849 release_DataFormat(&newDevice
->generic
.base
.data_format
);
850 HeapFree(GetProcessHeap(),0,newDevice
->generic
.name
);
851 HeapFree(GetProcessHeap(),0,newDevice
);
857 /******************************************************************************
858 * get_joystick_index : Get the joystick index from a given GUID
860 static unsigned short get_joystick_index(REFGUID guid
)
862 GUID wine_joystick
= DInput_Wine_OsX_Joystick_GUID
;
863 GUID dev_guid
= *guid
;
865 wine_joystick
.Data3
= 0;
868 /* for the standard joystick GUID use index 0 */
869 if(IsEqualGUID(&GUID_Joystick
,guid
)) return 0;
871 /* for the wine joystick GUIDs use the index stored in Data3 */
872 if(IsEqualGUID(&wine_joystick
, &dev_guid
)) return guid
->Data3
;
877 static HRESULT
joydev_create_deviceA(IDirectInputImpl
*dinput
, REFGUID rguid
, REFIID riid
, LPDIRECTINPUTDEVICEA
* pdev
)
879 unsigned short index
;
880 int joystick_devices_count
;
882 TRACE("%p %s %p %p\n",dinput
, debugstr_guid(rguid
), riid
, pdev
);
885 if ((joystick_devices_count
= find_joystick_devices()) == 0)
886 return DIERR_DEVICENOTREG
;
888 if ((index
= get_joystick_index(rguid
)) < 0xffff &&
889 joystick_devices_count
&& index
< joystick_devices_count
)
891 if ((riid
== NULL
) ||
892 IsEqualGUID(&IID_IDirectInputDeviceA
, riid
) ||
893 IsEqualGUID(&IID_IDirectInputDevice2A
, riid
) ||
894 IsEqualGUID(&IID_IDirectInputDevice7A
, riid
) ||
895 IsEqualGUID(&IID_IDirectInputDevice8A
, riid
))
898 HRESULT hr
= alloc_device(rguid
, dinput
, &This
, index
);
900 *pdev
= (LPDIRECTINPUTDEVICEA
)(This
? &This
->generic
.base
.IDirectInputDevice8A_iface
: NULL
);
904 WARN("no interface\n");
905 return DIERR_NOINTERFACE
;
908 return DIERR_DEVICENOTREG
;
911 static HRESULT
joydev_create_deviceW(IDirectInputImpl
*dinput
, REFGUID rguid
, REFIID riid
, LPDIRECTINPUTDEVICEW
* pdev
)
913 unsigned short index
;
914 int joystick_devices_count
;
916 TRACE("%p %s %p %p\n",dinput
, debugstr_guid(rguid
), riid
, pdev
);
919 if ((joystick_devices_count
= find_joystick_devices()) == 0)
920 return DIERR_DEVICENOTREG
;
922 if ((index
= get_joystick_index(rguid
)) < 0xffff &&
923 joystick_devices_count
&& index
< joystick_devices_count
)
925 if ((riid
== NULL
) ||
926 IsEqualGUID(&IID_IDirectInputDeviceW
, riid
) ||
927 IsEqualGUID(&IID_IDirectInputDevice2W
, riid
) ||
928 IsEqualGUID(&IID_IDirectInputDevice7W
, riid
) ||
929 IsEqualGUID(&IID_IDirectInputDevice8W
, riid
))
932 HRESULT hr
= alloc_device(rguid
, dinput
, &This
, index
);
934 *pdev
= (LPDIRECTINPUTDEVICEW
)(This
? &This
->generic
.base
.IDirectInputDevice8W_iface
: NULL
);
937 WARN("no interface\n");
938 return DIERR_NOINTERFACE
;
941 WARN("invalid device GUID %s\n",debugstr_guid(rguid
));
942 return DIERR_DEVICENOTREG
;
945 const struct dinput_device joystick_osx_device
= {
946 "Wine OS X joystick driver",
949 joydev_create_deviceA
,
950 joydev_create_deviceW
953 static const IDirectInputDevice8AVtbl JoystickAvt
=
955 IDirectInputDevice2AImpl_QueryInterface
,
956 IDirectInputDevice2AImpl_AddRef
,
957 IDirectInputDevice2AImpl_Release
,
958 JoystickAGenericImpl_GetCapabilities
,
959 IDirectInputDevice2AImpl_EnumObjects
,
960 JoystickAGenericImpl_GetProperty
,
961 JoystickAGenericImpl_SetProperty
,
962 IDirectInputDevice2AImpl_Acquire
,
963 IDirectInputDevice2AImpl_Unacquire
,
964 JoystickAGenericImpl_GetDeviceState
,
965 IDirectInputDevice2AImpl_GetDeviceData
,
966 IDirectInputDevice2AImpl_SetDataFormat
,
967 IDirectInputDevice2AImpl_SetEventNotification
,
968 IDirectInputDevice2AImpl_SetCooperativeLevel
,
969 JoystickAGenericImpl_GetObjectInfo
,
970 JoystickAGenericImpl_GetDeviceInfo
,
971 IDirectInputDevice2AImpl_RunControlPanel
,
972 IDirectInputDevice2AImpl_Initialize
,
973 IDirectInputDevice2AImpl_CreateEffect
,
974 IDirectInputDevice2AImpl_EnumEffects
,
975 IDirectInputDevice2AImpl_GetEffectInfo
,
976 IDirectInputDevice2AImpl_GetForceFeedbackState
,
977 IDirectInputDevice2AImpl_SendForceFeedbackCommand
,
978 IDirectInputDevice2AImpl_EnumCreatedEffectObjects
,
979 IDirectInputDevice2AImpl_Escape
,
980 JoystickAGenericImpl_Poll
,
981 IDirectInputDevice2AImpl_SendDeviceData
,
982 IDirectInputDevice7AImpl_EnumEffectsInFile
,
983 IDirectInputDevice7AImpl_WriteEffectToFile
,
984 IDirectInputDevice8AImpl_BuildActionMap
,
985 IDirectInputDevice8AImpl_SetActionMap
,
986 IDirectInputDevice8AImpl_GetImageInfo
989 static const IDirectInputDevice8WVtbl JoystickWvt
=
991 IDirectInputDevice2WImpl_QueryInterface
,
992 IDirectInputDevice2WImpl_AddRef
,
993 IDirectInputDevice2WImpl_Release
,
994 JoystickWGenericImpl_GetCapabilities
,
995 IDirectInputDevice2WImpl_EnumObjects
,
996 JoystickWGenericImpl_GetProperty
,
997 JoystickWGenericImpl_SetProperty
,
998 IDirectInputDevice2WImpl_Acquire
,
999 IDirectInputDevice2WImpl_Unacquire
,
1000 JoystickWGenericImpl_GetDeviceState
,
1001 IDirectInputDevice2WImpl_GetDeviceData
,
1002 IDirectInputDevice2WImpl_SetDataFormat
,
1003 IDirectInputDevice2WImpl_SetEventNotification
,
1004 IDirectInputDevice2WImpl_SetCooperativeLevel
,
1005 JoystickWGenericImpl_GetObjectInfo
,
1006 JoystickWGenericImpl_GetDeviceInfo
,
1007 IDirectInputDevice2WImpl_RunControlPanel
,
1008 IDirectInputDevice2WImpl_Initialize
,
1009 IDirectInputDevice2WImpl_CreateEffect
,
1010 IDirectInputDevice2WImpl_EnumEffects
,
1011 IDirectInputDevice2WImpl_GetEffectInfo
,
1012 IDirectInputDevice2WImpl_GetForceFeedbackState
,
1013 IDirectInputDevice2WImpl_SendForceFeedbackCommand
,
1014 IDirectInputDevice2WImpl_EnumCreatedEffectObjects
,
1015 IDirectInputDevice2WImpl_Escape
,
1016 JoystickWGenericImpl_Poll
,
1017 IDirectInputDevice2WImpl_SendDeviceData
,
1018 IDirectInputDevice7WImpl_EnumEffectsInFile
,
1019 IDirectInputDevice7WImpl_WriteEffectToFile
,
1020 IDirectInputDevice8WImpl_BuildActionMap
,
1021 IDirectInputDevice8WImpl_SetActionMap
,
1022 IDirectInputDevice8WImpl_GetImageInfo
1025 #else /* HAVE_IOHIDMANAGERCREATE */
1027 const struct dinput_device joystick_osx_device
= {
1028 "Wine OS X joystick driver",
1035 #endif /* HAVE_IOHIDMANAGERCREATE */