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 EnterCriticalSection(&dinput->crit);
825 list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
826 LeaveCriticalSection(&dinput->crit);
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);
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;
840 if (TRACE_ON(dinput)) {
841 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
842 _dump_DIDEVCAPS(&newDevice->generic.devcaps);
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);
861 /******************************************************************************
862 * get_joystick_index : Get the joystick index from a given GUID
864 static unsigned short get_joystick_index(REFGUID guid)
866 GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
867 GUID dev_guid = *guid;
869 wine_joystick.Data3 = 0;
872 /* for the standard joystick GUID use index 0 */
873 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
875 /* for the wine joystick GUIDs use the index stored in Data3 */
876 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
881 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
883 unsigned short index;
884 int joystick_devices_count;
886 TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
889 if ((joystick_devices_count = find_joystick_devices()) == 0)
890 return DIERR_DEVICENOTREG;
892 if ((index = get_joystick_index(rguid)) < 0xffff &&
893 joystick_devices_count && index < joystick_devices_count)
895 if ((riid == NULL) ||
896 IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
897 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
898 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
899 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
902 HRESULT hr = alloc_device(rguid, dinput, &This, index);
904 *pdev = (LPDIRECTINPUTDEVICEA)(This ? &This->generic.base.IDirectInputDevice8A_iface : NULL);
908 WARN("no interface\n");
909 return DIERR_NOINTERFACE;
912 return DIERR_DEVICENOTREG;
915 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
917 unsigned short index;
918 int joystick_devices_count;
920 TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
923 if ((joystick_devices_count = find_joystick_devices()) == 0)
924 return DIERR_DEVICENOTREG;
926 if ((index = get_joystick_index(rguid)) < 0xffff &&
927 joystick_devices_count && index < joystick_devices_count)
929 if ((riid == NULL) ||
930 IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
931 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
932 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
933 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
936 HRESULT hr = alloc_device(rguid, dinput, &This, index);
938 *pdev = (LPDIRECTINPUTDEVICEW)(This ? &This->generic.base.IDirectInputDevice8W_iface : NULL);
941 WARN("no interface\n");
942 return DIERR_NOINTERFACE;
945 WARN("invalid device GUID %s\n",debugstr_guid(rguid));
946 return DIERR_DEVICENOTREG;
949 const struct dinput_device joystick_osx_device = {
950 "Wine OS X joystick driver",
953 joydev_create_deviceA,
954 joydev_create_deviceW
957 static const IDirectInputDevice8AVtbl JoystickAvt =
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
993 static const IDirectInputDevice8WVtbl JoystickWvt =
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
1029 #else /* HAVE_IOHIDMANAGERCREATE */
1031 const struct dinput_device joystick_osx_device = {
1032 "Wine OS X joystick driver",
1039 #endif /* HAVE_IOHIDMANAGERCREATE */