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 const GUID DInput_Wine_OsX_Joystick_GUID
= { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */
139 0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A}
142 static void CFSetApplierFunctionCopyToCFArray(const void *value
, void *context
)
144 CFArrayAppendValue( ( CFMutableArrayRef
) context
, value
);
147 static CFMutableDictionaryRef
creates_osx_device_match(int usage
)
149 CFMutableDictionaryRef result
;
151 result
= CFDictionaryCreateMutable( kCFAllocatorDefault
, 0,
152 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
156 int number
= kHIDPage_GenericDesktop
;
157 CFNumberRef pageCFNumberRef
= CFNumberCreate( kCFAllocatorDefault
,
158 kCFNumberIntType
, &number
);
160 if ( pageCFNumberRef
)
162 CFNumberRef usageCFNumberRef
;
164 CFDictionarySetValue( result
, CFSTR( kIOHIDDeviceUsagePageKey
),
166 CFRelease( pageCFNumberRef
);
168 usageCFNumberRef
= CFNumberCreate( kCFAllocatorDefault
,
169 kCFNumberIntType
, &usage
);
170 if ( usageCFNumberRef
)
172 CFDictionarySetValue( result
, CFSTR( kIOHIDDeviceUsageKey
),
174 CFRelease( usageCFNumberRef
);
178 ERR("CFNumberCreate() failed.\n");
184 ERR("CFNumberCreate failed.\n");
190 ERR("CFDictionaryCreateMutable failed.\n");
197 static CFIndex
find_top_level(IOHIDDeviceRef tIOHIDDeviceRef
, CFArrayRef topLevels
)
199 CFArrayRef gElementCFArrayRef
;
202 if (!tIOHIDDeviceRef
)
205 gElementCFArrayRef
= IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef
, NULL
, 0);
207 if (gElementCFArrayRef
)
209 CFIndex idx
, cnt
= CFArrayGetCount(gElementCFArrayRef
);
210 for (idx
=0; idx
<cnt
; idx
++)
212 IOHIDElementRef tIOHIDElementRef
= (IOHIDElementRef
)CFArrayGetValueAtIndex(gElementCFArrayRef
, idx
);
213 int eleType
= IOHIDElementGetType(tIOHIDElementRef
);
215 /* Check for top-level gaming device collections */
216 if (eleType
== kIOHIDElementTypeCollection
&& IOHIDElementGetParent(tIOHIDElementRef
) == 0)
218 int tUsagePage
= IOHIDElementGetUsagePage(tIOHIDElementRef
);
219 int tUsage
= IOHIDElementGetUsage(tIOHIDElementRef
);
221 if (tUsagePage
== kHIDPage_GenericDesktop
&&
222 (tUsage
== kHIDUsage_GD_Joystick
|| tUsage
== kHIDUsage_GD_GamePad
))
224 CFArrayAppendValue((CFMutableArrayRef
)topLevels
, tIOHIDElementRef
);
233 static void get_element_children(IOHIDElementRef tElement
, CFArrayRef childElements
)
236 CFArrayRef tElementChildrenArray
= IOHIDElementGetChildren(tElement
);
238 cnt
= CFArrayGetCount(tElementChildrenArray
);
242 /* Either add the element to the array or grab its children */
243 for (idx
=0; idx
<cnt
; idx
++)
245 IOHIDElementRef tChildElementRef
;
247 tChildElementRef
= (IOHIDElementRef
)CFArrayGetValueAtIndex(tElementChildrenArray
, idx
);
248 if (IOHIDElementGetType(tChildElementRef
) == kIOHIDElementTypeCollection
)
249 get_element_children(tChildElementRef
, childElements
);
251 CFArrayAppendValue((CFMutableArrayRef
)childElements
, tChildElementRef
);
255 static int find_osx_devices(void)
258 CFMutableDictionaryRef result
;
262 gIOHIDManagerRef
= IOHIDManagerCreate( kCFAllocatorDefault
, 0L );
263 tIOReturn
= IOHIDManagerOpen( gIOHIDManagerRef
, 0L);
264 if ( kIOReturnSuccess
!= tIOReturn
)
266 ERR("Couldn't open IOHIDManager.\n");
270 matching
= CFArrayCreateMutable( kCFAllocatorDefault
, 0,
271 &kCFTypeArrayCallBacks
);
273 /* build matching dictionary */
274 result
= creates_osx_device_match(kHIDUsage_GD_Joystick
);
280 CFArrayAppendValue( ( CFMutableArrayRef
)matching
, result
);
281 result
= creates_osx_device_match(kHIDUsage_GD_GamePad
);
287 CFArrayAppendValue( ( CFMutableArrayRef
)matching
, result
);
289 IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef
, matching
);
290 devset
= IOHIDManagerCopyDevices( gIOHIDManagerRef
);
293 CFIndex countDevices
, countCollections
, idx
;
294 CFArrayRef gDevices
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
295 CFSetApplyFunction(devset
, CFSetApplierFunctionCopyToCFArray
, (void*)gDevices
);
297 countDevices
= CFArrayGetCount(gDevices
);
299 gCollections
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
303 countCollections
= 0;
304 for (idx
= 0; idx
< countDevices
; idx
++)
307 IOHIDDeviceRef tDevice
;
309 tDevice
= (IOHIDDeviceRef
) CFArrayGetValueAtIndex(gDevices
, idx
);
310 tTop
= find_top_level(tDevice
, gCollections
);
311 countCollections
+= tTop
;
316 TRACE("found %i device(s), %i collection(s)\n",(int)countDevices
,(int)countCollections
);
317 return (int)countCollections
;
322 static int get_osx_device_name(int id
, char *name
, int length
)
325 IOHIDElementRef tIOHIDElementRef
;
326 IOHIDDeviceRef tIOHIDDeviceRef
;
331 tIOHIDElementRef
= (IOHIDElementRef
)CFArrayGetValueAtIndex(gCollections
, id
);
333 if (!tIOHIDElementRef
)
335 ERR("Invalid Element requested %i\n",id
);
339 tIOHIDDeviceRef
= IOHIDElementGetDevice(tIOHIDElementRef
);
344 if (!tIOHIDDeviceRef
)
346 ERR("Invalid Device requested %i\n",id
);
350 str
= IOHIDDeviceGetProperty(tIOHIDDeviceRef
, CFSTR( kIOHIDProductKey
));
353 CFIndex len
= CFStringGetLength(str
);
356 CFStringGetCString(str
,name
,length
,kCFStringEncodingASCII
);
365 static void insert_sort_button(int header
, IOHIDElementRef tIOHIDElementRef
,
366 CFMutableArrayRef elementCFArrayRef
, int index
,
369 IOHIDElementRef targetElement
;
372 CFArraySetValueAtIndex(elementCFArrayRef
, header
+index
, NULL
);
373 targetElement
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( elementCFArrayRef
, header
+target
);
374 if (targetElement
== NULL
)
376 CFArraySetValueAtIndex(elementCFArrayRef
, header
+target
,tIOHIDElementRef
);
379 usage
= IOHIDElementGetUsage( targetElement
);
380 usage
--; /* usage 1 based index */
382 insert_sort_button(header
, targetElement
, elementCFArrayRef
, target
, usage
);
383 CFArraySetValueAtIndex(elementCFArrayRef
, header
+target
,tIOHIDElementRef
);
386 static void get_osx_device_elements(JoystickImpl
*device
, int axis_map
[8])
388 IOHIDElementRef tIOHIDElementRef
;
389 CFArrayRef gElementCFArrayRef
;
395 device
->elementCFArrayRef
= NULL
;
400 tIOHIDElementRef
= (IOHIDElementRef
)CFArrayGetValueAtIndex(gCollections
, device
->id
);
402 if (!tIOHIDElementRef
)
405 gElementCFArrayRef
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
406 get_element_children(tIOHIDElementRef
, gElementCFArrayRef
);
408 if (gElementCFArrayRef
)
410 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
411 /* build our element array in the order that dinput expects */
412 device
->elementCFArrayRef
= CFArrayCreateMutable(NULL
,0,NULL
);
414 for ( idx
= 0; idx
< cnt
; idx
++ )
416 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
417 int eleType
= IOHIDElementGetType( tIOHIDElementRef
);
420 case kIOHIDElementTypeInput_Button
:
422 int usagePage
= IOHIDElementGetUsagePage( tIOHIDElementRef
);
423 if (usagePage
!= kHIDPage_Button
)
425 /* avoid strange elements found on the 360 controler */
431 CFArrayInsertValueAtIndex(device
->elementCFArrayRef
, (axes
+povs
+buttons
), tIOHIDElementRef
);
436 case kIOHIDElementTypeInput_Axis
:
438 CFArrayInsertValueAtIndex(device
->elementCFArrayRef
, axes
, tIOHIDElementRef
);
442 case kIOHIDElementTypeInput_Misc
:
444 uint32_t usage
= IOHIDElementGetUsage( tIOHIDElementRef
);
447 case kHIDUsage_GD_Hatswitch
:
449 CFArrayInsertValueAtIndex(device
->elementCFArrayRef
, (axes
+povs
), tIOHIDElementRef
);
453 case kHIDUsage_GD_Slider
:
457 /* fallthrough, sliders are axis */
461 case kHIDUsage_GD_Rx
:
462 case kHIDUsage_GD_Ry
:
463 case kHIDUsage_GD_Rz
:
465 CFArrayInsertValueAtIndex(device
->elementCFArrayRef
, axes
, tIOHIDElementRef
);
466 axis_map
[axes
]=usage
;
471 FIXME("Unhandled usage %i\n",usage
);
476 FIXME("Unhandled type %i\n",eleType
);
481 device
->generic
.devcaps
.dwAxes
= axes
;
482 device
->generic
.devcaps
.dwButtons
= buttons
;
483 device
->generic
.devcaps
.dwPOVs
= povs
;
485 /* Sort buttons into correct order */
486 for (buttons
= 0; buttons
< device
->generic
.devcaps
.dwButtons
; buttons
++)
488 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( device
->elementCFArrayRef
, axes
+povs
+buttons
);
489 uint32_t usage
= IOHIDElementGetUsage( tIOHIDElementRef
);
490 usage
--; /* usage is 1 indexed we need 0 indexed */
491 if (usage
== buttons
)
494 insert_sort_button(axes
+povs
, tIOHIDElementRef
, device
->elementCFArrayRef
,buttons
,usage
);
498 static void get_osx_device_elements_props(JoystickImpl
*device
)
500 CFArrayRef gElementCFArrayRef
= device
->elementCFArrayRef
;
502 if (gElementCFArrayRef
)
504 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
506 for ( idx
= 0; idx
< cnt
; idx
++ )
508 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
510 device
->generic
.props
[idx
].lDevMin
= IOHIDElementGetLogicalMin(tIOHIDElementRef
);
511 device
->generic
.props
[idx
].lDevMax
= IOHIDElementGetLogicalMax(tIOHIDElementRef
);
512 device
->generic
.props
[idx
].lMin
= 0;
513 device
->generic
.props
[idx
].lMax
= 0xffff;
514 device
->generic
.props
[idx
].lDeadZone
= 0;
515 device
->generic
.props
[idx
].lSaturation
= 0;
520 static void poll_osx_device_state(JoystickGenericImpl
*device_in
)
522 JoystickImpl
*device
= (JoystickImpl
*)device_in
;
523 IOHIDElementRef tIOHIDTopElementRef
;
524 IOHIDDeviceRef tIOHIDDeviceRef
;
525 CFArrayRef gElementCFArrayRef
= device
->elementCFArrayRef
;
527 TRACE("polling device %i\n",device
->id
);
532 tIOHIDTopElementRef
= (IOHIDElementRef
) CFArrayGetValueAtIndex(gCollections
, device
->id
);
533 tIOHIDDeviceRef
= IOHIDElementGetDevice(tIOHIDTopElementRef
);
535 if (!tIOHIDDeviceRef
)
538 if (gElementCFArrayRef
)
543 CFIndex idx
, cnt
= CFArrayGetCount( gElementCFArrayRef
);
545 for ( idx
= 0; idx
< cnt
; idx
++ )
547 IOHIDValueRef valueRef
;
549 IOHIDElementRef tIOHIDElementRef
= ( IOHIDElementRef
) CFArrayGetValueAtIndex( gElementCFArrayRef
, idx
);
550 int eleType
= IOHIDElementGetType( tIOHIDElementRef
);
554 case kIOHIDElementTypeInput_Button
:
557 IOHIDDeviceGetValue(tIOHIDDeviceRef
, tIOHIDElementRef
, &valueRef
);
558 val
= IOHIDValueGetIntegerValue(valueRef
);
559 device
->generic
.js
.rgbButtons
[button_idx
] = val
? 0x80 : 0x00;
563 case kIOHIDElementTypeInput_Misc
:
565 uint32_t usage
= IOHIDElementGetUsage( tIOHIDElementRef
);
568 case kHIDUsage_GD_Hatswitch
:
570 IOHIDDeviceGetValue(tIOHIDDeviceRef
, tIOHIDElementRef
, &valueRef
);
571 val
= IOHIDValueGetIntegerValue(valueRef
);
573 device
->generic
.js
.rgdwPOV
[pov_idx
] = -1;
575 device
->generic
.js
.rgdwPOV
[pov_idx
] = val
* 4500;
582 case kHIDUsage_GD_Rx
:
583 case kHIDUsage_GD_Ry
:
584 case kHIDUsage_GD_Rz
:
585 case kHIDUsage_GD_Slider
:
587 IOHIDDeviceGetValue(tIOHIDDeviceRef
, tIOHIDElementRef
, &valueRef
);
588 val
= IOHIDValueGetIntegerValue(valueRef
);
592 device
->generic
.js
.lX
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
595 device
->generic
.js
.lY
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
598 device
->generic
.js
.lZ
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
600 case kHIDUsage_GD_Rx
:
601 device
->generic
.js
.lRx
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
603 case kHIDUsage_GD_Ry
:
604 device
->generic
.js
.lRy
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
606 case kHIDUsage_GD_Rz
:
607 device
->generic
.js
.lRz
= joystick_map_axis(&device
->generic
.props
[idx
], val
);
609 case kHIDUsage_GD_Slider
:
610 device
->generic
.js
.rglSlider
[slider_idx
] = joystick_map_axis(&device
->generic
.props
[idx
], val
);
617 FIXME("unhandled usage %i\n",usage
);
622 FIXME("Unhandled type %i\n",eleType
);
628 static INT
find_joystick_devices(void)
630 static INT joystick_devices_count
= -1;
632 if (joystick_devices_count
!= -1) return joystick_devices_count
;
634 joystick_devices_count
= find_osx_devices();
636 return joystick_devices_count
;
639 static BOOL
joydev_enum_deviceA(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEA lpddi
, DWORD version
, int id
)
641 if (id
>= find_joystick_devices()) return FALSE
;
643 if (dwFlags
& DIEDFL_FORCEFEEDBACK
) {
644 WARN("force feedback not supported\n");
648 if ((dwDevType
== 0) ||
649 ((dwDevType
== DIDEVTYPE_JOYSTICK
) && (version
> 0x0300 && version
< 0x0800)) ||
650 (((dwDevType
== DI8DEVCLASS_GAMECTRL
) || (dwDevType
== DI8DEVTYPE_JOYSTICK
)) && (version
>= 0x0800)))
652 /* Return joystick */
653 lpddi
->guidInstance
= DInput_Wine_OsX_Joystick_GUID
;
654 lpddi
->guidInstance
.Data3
= id
;
655 lpddi
->guidProduct
= DInput_Wine_OsX_Joystick_GUID
;
656 /* we only support traditional joysticks for now */
657 if (version
>= 0x0800)
658 lpddi
->dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
660 lpddi
->dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
661 sprintf(lpddi
->tszInstanceName
, "Joystick %d", id
);
663 /* get the device name */
664 get_osx_device_name(id
, lpddi
->tszProductName
, MAX_PATH
);
666 lpddi
->guidFFDriver
= GUID_NULL
;
673 static BOOL
joydev_enum_deviceW(DWORD dwDevType
, DWORD dwFlags
, LPDIDEVICEINSTANCEW lpddi
, DWORD version
, int id
)
678 if (id
>= find_joystick_devices()) return FALSE
;
680 if (dwFlags
& DIEDFL_FORCEFEEDBACK
) {
681 WARN("force feedback not supported\n");
685 if ((dwDevType
== 0) ||
686 ((dwDevType
== DIDEVTYPE_JOYSTICK
) && (version
> 0x0300 && version
< 0x0800)) ||
687 (((dwDevType
== DI8DEVCLASS_GAMECTRL
) || (dwDevType
== DI8DEVTYPE_JOYSTICK
)) && (version
>= 0x0800))) {
688 /* Return joystick */
689 lpddi
->guidInstance
= DInput_Wine_OsX_Joystick_GUID
;
690 lpddi
->guidInstance
.Data3
= id
;
691 lpddi
->guidProduct
= DInput_Wine_OsX_Joystick_GUID
;
692 /* we only support traditional joysticks for now */
693 if (version
>= 0x0800)
694 lpddi
->dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
696 lpddi
->dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
697 sprintf(friendly
, "Joystick %d", id
);
698 MultiByteToWideChar(CP_ACP
, 0, friendly
, -1, lpddi
->tszInstanceName
, MAX_PATH
);
699 /* get the device name */
700 get_osx_device_name(id
, name
, MAX_PATH
);
702 MultiByteToWideChar(CP_ACP
, 0, name
, -1, lpddi
->tszProductName
, MAX_PATH
);
703 lpddi
->guidFFDriver
= GUID_NULL
;
710 static HRESULT
alloc_device(REFGUID rguid
, const void *jvt
, IDirectInputImpl
*dinput
,
711 LPDIRECTINPUTDEVICEA
* pdev
, unsigned short index
)
714 JoystickImpl
* newDevice
;
717 LPDIDATAFORMAT df
= NULL
;
719 int axis_map
[8]; /* max axes */
720 int slider_count
= 0;
722 TRACE("%s %p %p %p %hu\n", debugstr_guid(rguid
), jvt
, dinput
, pdev
, index
);
724 newDevice
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,sizeof(JoystickImpl
));
725 if (newDevice
== 0) {
726 WARN("out of memory\n");
728 return DIERR_OUTOFMEMORY
;
731 newDevice
->id
= index
;
733 newDevice
->generic
.guidInstance
= DInput_Wine_OsX_Joystick_GUID
;
734 newDevice
->generic
.guidInstance
.Data3
= index
;
735 newDevice
->generic
.guidProduct
= DInput_Wine_OsX_Joystick_GUID
;
736 newDevice
->generic
.joy_polldev
= poll_osx_device_state
;
738 /* get the device name */
739 get_osx_device_name(index
, name
, MAX_PATH
);
740 TRACE("Name %s\n",name
);
742 /* copy the device name */
743 newDevice
->generic
.name
= HeapAlloc(GetProcessHeap(),0,strlen(name
) + 1);
744 strcpy(newDevice
->generic
.name
, name
);
746 memset(axis_map
, 0, sizeof(axis_map
));
747 get_osx_device_elements(newDevice
, axis_map
);
749 TRACE("%i axes %i buttons %i povs\n",newDevice
->generic
.devcaps
.dwAxes
,newDevice
->generic
.devcaps
.dwButtons
,newDevice
->generic
.devcaps
.dwPOVs
);
751 if (newDevice
->generic
.devcaps
.dwButtons
> 128)
753 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice
->generic
.devcaps
.dwButtons
);
754 newDevice
->generic
.devcaps
.dwButtons
= 128;
757 newDevice
->generic
.base
.lpVtbl
= jvt
;
758 newDevice
->generic
.base
.ref
= 1;
759 newDevice
->generic
.base
.dinput
= dinput
;
760 newDevice
->generic
.base
.guid
= *rguid
;
761 InitializeCriticalSection(&newDevice
->generic
.base
.crit
);
762 newDevice
->generic
.base
.crit
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": JoystickImpl*->generic.base.crit");
764 /* Create copy of default data format */
765 if (!(df
= HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2
.dwSize
))) goto FAILED
;
766 memcpy(df
, &c_dfDIJoystick2
, c_dfDIJoystick2
.dwSize
);
768 df
->dwNumObjs
= newDevice
->generic
.devcaps
.dwAxes
+ newDevice
->generic
.devcaps
.dwPOVs
+ newDevice
->generic
.devcaps
.dwButtons
;
769 if (!(df
->rgodf
= HeapAlloc(GetProcessHeap(), 0, df
->dwNumObjs
* df
->dwObjSize
))) goto FAILED
;
771 for (i
= 0; i
< newDevice
->generic
.devcaps
.dwAxes
; i
++)
776 case kHIDUsage_GD_X
: wine_obj
= 0; break;
777 case kHIDUsage_GD_Y
: wine_obj
= 1; break;
778 case kHIDUsage_GD_Z
: wine_obj
= 2; break;
779 case kHIDUsage_GD_Rx
: wine_obj
= 3; break;
780 case kHIDUsage_GD_Ry
: wine_obj
= 4; break;
781 case kHIDUsage_GD_Rz
: wine_obj
= 5; break;
782 case kHIDUsage_GD_Slider
:
783 wine_obj
= 6 + slider_count
;
787 if (wine_obj
< 0 ) continue;
789 memcpy(&df
->rgodf
[idx
], &c_dfDIJoystick2
.rgodf
[wine_obj
], df
->dwObjSize
);
790 df
->rgodf
[idx
++].dwType
= DIDFT_MAKEINSTANCE(wine_obj
) | DIDFT_ABSAXIS
;
793 for (i
= 0; i
< newDevice
->generic
.devcaps
.dwPOVs
; i
++)
795 memcpy(&df
->rgodf
[idx
], &c_dfDIJoystick2
.rgodf
[i
+ 8], df
->dwObjSize
);
796 df
->rgodf
[idx
++].dwType
= DIDFT_MAKEINSTANCE(i
) | DIDFT_POV
;
799 for (i
= 0; i
< newDevice
->generic
.devcaps
.dwButtons
; i
++)
801 memcpy(&df
->rgodf
[idx
], &c_dfDIJoystick2
.rgodf
[i
+ 12], df
->dwObjSize
);
802 df
->rgodf
[idx
].pguid
= &GUID_Button
;
803 df
->rgodf
[idx
++].dwType
= DIDFT_MAKEINSTANCE(i
) | DIDFT_PSHBUTTON
;
805 newDevice
->generic
.base
.data_format
.wine_df
= df
;
807 /* initialize default properties */
808 get_osx_device_elements_props(newDevice
);
810 IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A
)newDevice
->generic
.base
.dinput
);
812 newDevice
->generic
.devcaps
.dwSize
= sizeof(newDevice
->generic
.devcaps
);
813 newDevice
->generic
.devcaps
.dwFlags
= DIDC_ATTACHED
;
814 if (newDevice
->generic
.base
.dinput
->dwVersion
>= 0x0800)
815 newDevice
->generic
.devcaps
.dwDevType
= DI8DEVTYPE_JOYSTICK
| (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
817 newDevice
->generic
.devcaps
.dwDevType
= DIDEVTYPE_JOYSTICK
| (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
818 newDevice
->generic
.devcaps
.dwFFSamplePeriod
= 0;
819 newDevice
->generic
.devcaps
.dwFFMinTimeResolution
= 0;
820 newDevice
->generic
.devcaps
.dwFirmwareRevision
= 0;
821 newDevice
->generic
.devcaps
.dwHardwareRevision
= 0;
822 newDevice
->generic
.devcaps
.dwFFDriverVersion
= 0;
824 if (TRACE_ON(dinput
)) {
825 _dump_DIDATAFORMAT(newDevice
->generic
.base
.data_format
.wine_df
);
826 _dump_DIDEVCAPS(&newDevice
->generic
.devcaps
);
829 *pdev
= (LPDIRECTINPUTDEVICEA
)newDevice
;
834 hr
= DIERR_OUTOFMEMORY
;
835 if (df
) HeapFree(GetProcessHeap(), 0, df
->rgodf
);
836 HeapFree(GetProcessHeap(), 0, df
);
837 release_DataFormat(&newDevice
->generic
.base
.data_format
);
838 HeapFree(GetProcessHeap(),0,newDevice
->generic
.name
);
839 HeapFree(GetProcessHeap(),0,newDevice
);
845 /******************************************************************************
846 * get_joystick_index : Get the joystick index from a given GUID
848 static unsigned short get_joystick_index(REFGUID guid
)
850 GUID wine_joystick
= DInput_Wine_OsX_Joystick_GUID
;
851 GUID dev_guid
= *guid
;
853 wine_joystick
.Data3
= 0;
856 /* for the standard joystick GUID use index 0 */
857 if(IsEqualGUID(&GUID_Joystick
,guid
)) return 0;
859 /* for the wine joystick GUIDs use the index stored in Data3 */
860 if(IsEqualGUID(&wine_joystick
, &dev_guid
)) return guid
->Data3
;
865 static HRESULT
joydev_create_deviceA(IDirectInputImpl
*dinput
, REFGUID rguid
, REFIID riid
, LPDIRECTINPUTDEVICEA
* pdev
)
867 unsigned short index
;
868 int joystick_devices_count
;
870 TRACE("%p %s %p %p\n",dinput
, debugstr_guid(rguid
), riid
, pdev
);
873 if ((joystick_devices_count
= find_joystick_devices()) == 0)
874 return DIERR_DEVICENOTREG
;
876 if ((index
= get_joystick_index(rguid
)) < 0xffff &&
877 joystick_devices_count
&& index
< joystick_devices_count
)
879 if ((riid
== NULL
) ||
880 IsEqualGUID(&IID_IDirectInputDeviceA
, riid
) ||
881 IsEqualGUID(&IID_IDirectInputDevice2A
, riid
) ||
882 IsEqualGUID(&IID_IDirectInputDevice7A
, riid
) ||
883 IsEqualGUID(&IID_IDirectInputDevice8A
, riid
))
885 return alloc_device(rguid
, &JoystickAvt
, dinput
, pdev
, index
);
888 WARN("no interface\n");
889 return DIERR_NOINTERFACE
;
892 return DIERR_DEVICENOTREG
;
895 static HRESULT
joydev_create_deviceW(IDirectInputImpl
*dinput
, REFGUID rguid
, REFIID riid
, LPDIRECTINPUTDEVICEW
* pdev
)
897 unsigned short index
;
898 int joystick_devices_count
;
900 TRACE("%p %s %p %p\n",dinput
, debugstr_guid(rguid
), riid
, pdev
);
903 if ((joystick_devices_count
= find_joystick_devices()) == 0)
904 return DIERR_DEVICENOTREG
;
906 if ((index
= get_joystick_index(rguid
)) < 0xffff &&
907 joystick_devices_count
&& index
< joystick_devices_count
)
909 if ((riid
== NULL
) ||
910 IsEqualGUID(&IID_IDirectInputDeviceW
, riid
) ||
911 IsEqualGUID(&IID_IDirectInputDevice2W
, riid
) ||
912 IsEqualGUID(&IID_IDirectInputDevice7W
, riid
) ||
913 IsEqualGUID(&IID_IDirectInputDevice8W
, riid
))
915 return alloc_device(rguid
, &JoystickWvt
, dinput
, (LPDIRECTINPUTDEVICEA
*)pdev
, index
);
917 WARN("no interface\n");
918 return DIERR_NOINTERFACE
;
921 WARN("invalid device GUID %s\n",debugstr_guid(rguid
));
922 return DIERR_DEVICENOTREG
;
925 const struct dinput_device joystick_osx_device
= {
926 "Wine OS X joystick driver",
929 joydev_create_deviceA
,
930 joydev_create_deviceW
933 static const IDirectInputDevice8AVtbl JoystickAvt
=
935 IDirectInputDevice2AImpl_QueryInterface
,
936 IDirectInputDevice2AImpl_AddRef
,
937 IDirectInputDevice2AImpl_Release
,
938 JoystickAGenericImpl_GetCapabilities
,
939 IDirectInputDevice2AImpl_EnumObjects
,
940 JoystickAGenericImpl_GetProperty
,
941 JoystickAGenericImpl_SetProperty
,
942 IDirectInputDevice2AImpl_Acquire
,
943 IDirectInputDevice2AImpl_Unacquire
,
944 JoystickAGenericImpl_GetDeviceState
,
945 IDirectInputDevice2AImpl_GetDeviceData
,
946 IDirectInputDevice2AImpl_SetDataFormat
,
947 IDirectInputDevice2AImpl_SetEventNotification
,
948 IDirectInputDevice2AImpl_SetCooperativeLevel
,
949 JoystickAGenericImpl_GetObjectInfo
,
950 JoystickAGenericImpl_GetDeviceInfo
,
951 IDirectInputDevice2AImpl_RunControlPanel
,
952 IDirectInputDevice2AImpl_Initialize
,
953 IDirectInputDevice2AImpl_CreateEffect
,
954 IDirectInputDevice2AImpl_EnumEffects
,
955 IDirectInputDevice2AImpl_GetEffectInfo
,
956 IDirectInputDevice2AImpl_GetForceFeedbackState
,
957 IDirectInputDevice2AImpl_SendForceFeedbackCommand
,
958 IDirectInputDevice2AImpl_EnumCreatedEffectObjects
,
959 IDirectInputDevice2AImpl_Escape
,
960 JoystickAGenericImpl_Poll
,
961 IDirectInputDevice2AImpl_SendDeviceData
,
962 IDirectInputDevice7AImpl_EnumEffectsInFile
,
963 IDirectInputDevice7AImpl_WriteEffectToFile
,
964 IDirectInputDevice8AImpl_BuildActionMap
,
965 IDirectInputDevice8AImpl_SetActionMap
,
966 IDirectInputDevice8AImpl_GetImageInfo
969 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
970 # define XCAST(fun) (typeof(JoystickWvt.fun))
972 # define XCAST(fun) (void*)
975 static const IDirectInputDevice8WVtbl JoystickWvt
=
977 IDirectInputDevice2WImpl_QueryInterface
,
978 XCAST(AddRef
)IDirectInputDevice2AImpl_AddRef
,
979 XCAST(Release
)IDirectInputDevice2AImpl_Release
,
980 XCAST(GetCapabilities
)JoystickAGenericImpl_GetCapabilities
,
981 IDirectInputDevice2WImpl_EnumObjects
,
982 XCAST(GetProperty
)JoystickAGenericImpl_GetProperty
,
983 XCAST(SetProperty
)JoystickAGenericImpl_SetProperty
,
984 XCAST(Acquire
)IDirectInputDevice2AImpl_Acquire
,
985 XCAST(Unacquire
)IDirectInputDevice2AImpl_Unacquire
,
986 XCAST(GetDeviceState
)JoystickAGenericImpl_GetDeviceState
,
987 XCAST(GetDeviceData
)IDirectInputDevice2AImpl_GetDeviceData
,
988 XCAST(SetDataFormat
)IDirectInputDevice2AImpl_SetDataFormat
,
989 XCAST(SetEventNotification
)IDirectInputDevice2AImpl_SetEventNotification
,
990 XCAST(SetCooperativeLevel
)IDirectInputDevice2AImpl_SetCooperativeLevel
,
991 JoystickWGenericImpl_GetObjectInfo
,
992 JoystickWGenericImpl_GetDeviceInfo
,
993 XCAST(RunControlPanel
)IDirectInputDevice2AImpl_RunControlPanel
,
994 XCAST(Initialize
)IDirectInputDevice2AImpl_Initialize
,
995 XCAST(CreateEffect
)IDirectInputDevice2AImpl_CreateEffect
,
996 IDirectInputDevice2WImpl_EnumEffects
,
997 IDirectInputDevice2WImpl_GetEffectInfo
,
998 XCAST(GetForceFeedbackState
)IDirectInputDevice2AImpl_GetForceFeedbackState
,
999 XCAST(SendForceFeedbackCommand
)IDirectInputDevice2AImpl_SendForceFeedbackCommand
,
1000 XCAST(EnumCreatedEffectObjects
)IDirectInputDevice2AImpl_EnumCreatedEffectObjects
,
1001 XCAST(Escape
)IDirectInputDevice2AImpl_Escape
,
1002 XCAST(Poll
)JoystickAGenericImpl_Poll
,
1003 XCAST(SendDeviceData
)IDirectInputDevice2AImpl_SendDeviceData
,
1004 IDirectInputDevice7WImpl_EnumEffectsInFile
,
1005 IDirectInputDevice7WImpl_WriteEffectToFile
,
1006 IDirectInputDevice8WImpl_BuildActionMap
,
1007 IDirectInputDevice8WImpl_SetActionMap
,
1008 IDirectInputDevice8WImpl_GetImageInfo
1012 #else /* HAVE_IOHIDMANAGERCREATE */
1014 const struct dinput_device joystick_osx_device
= {
1015 "Wine OS X joystick driver",
1022 #endif /* HAVE_IOHIDMANAGERCREATE */