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 (JoystickImpl *) iface;
142 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
144 return (JoystickImpl *) iface;
147 static const GUID DInput_Wine_OsX_Joystick_GUID = { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */
148 0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A}
151 static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context)
153 CFArrayAppendValue( ( CFMutableArrayRef ) context, value );
156 static CFMutableDictionaryRef creates_osx_device_match(int usage)
158 CFMutableDictionaryRef result;
160 result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
161 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
165 int number = kHIDPage_GenericDesktop;
166 CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
167 kCFNumberIntType, &number);
169 if ( pageCFNumberRef )
171 CFNumberRef usageCFNumberRef;
173 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ),
175 CFRelease( pageCFNumberRef );
177 usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
178 kCFNumberIntType, &usage);
179 if ( usageCFNumberRef )
181 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ),
183 CFRelease( usageCFNumberRef );
187 ERR("CFNumberCreate() failed.\n");
193 ERR("CFNumberCreate failed.\n");
199 ERR("CFDictionaryCreateMutable failed.\n");
206 static CFIndex find_top_level(IOHIDDeviceRef tIOHIDDeviceRef, CFArrayRef topLevels)
208 CFArrayRef gElementCFArrayRef;
211 if (!tIOHIDDeviceRef)
214 gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, 0);
216 if (gElementCFArrayRef)
218 CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef);
219 for (idx=0; idx<cnt; idx++)
221 IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gElementCFArrayRef, idx);
222 int eleType = IOHIDElementGetType(tIOHIDElementRef);
224 /* Check for top-level gaming device collections */
225 if (eleType == kIOHIDElementTypeCollection && IOHIDElementGetParent(tIOHIDElementRef) == 0)
227 int tUsagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
228 int tUsage = IOHIDElementGetUsage(tIOHIDElementRef);
230 if (tUsagePage == kHIDPage_GenericDesktop &&
231 (tUsage == kHIDUsage_GD_Joystick || tUsage == kHIDUsage_GD_GamePad))
233 CFArrayAppendValue((CFMutableArrayRef)topLevels, tIOHIDElementRef);
242 static void get_element_children(IOHIDElementRef tElement, CFArrayRef childElements)
245 CFArrayRef tElementChildrenArray = IOHIDElementGetChildren(tElement);
247 cnt = CFArrayGetCount(tElementChildrenArray);
251 /* Either add the element to the array or grab its children */
252 for (idx=0; idx<cnt; idx++)
254 IOHIDElementRef tChildElementRef;
256 tChildElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(tElementChildrenArray, idx);
257 if (IOHIDElementGetType(tChildElementRef) == kIOHIDElementTypeCollection)
258 get_element_children(tChildElementRef, childElements);
260 CFArrayAppendValue((CFMutableArrayRef)childElements, tChildElementRef);
264 static int find_osx_devices(void)
267 CFMutableDictionaryRef result;
271 gIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
272 tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, 0L);
273 if ( kIOReturnSuccess != tIOReturn )
275 ERR("Couldn't open IOHIDManager.\n");
279 matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
280 &kCFTypeArrayCallBacks );
282 /* build matching dictionary */
283 result = creates_osx_device_match(kHIDUsage_GD_Joystick);
289 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
290 result = creates_osx_device_match(kHIDUsage_GD_GamePad);
296 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
298 IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef, matching);
299 devset = IOHIDManagerCopyDevices( gIOHIDManagerRef );
302 CFIndex countDevices, countCollections, idx;
303 CFArrayRef gDevices = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
304 CFSetApplyFunction(devset, CFSetApplierFunctionCopyToCFArray, (void*)gDevices);
306 countDevices = CFArrayGetCount(gDevices);
308 gCollections = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
312 countCollections = 0;
313 for (idx = 0; idx < countDevices; idx++)
316 IOHIDDeviceRef tDevice;
318 tDevice = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDevices, idx);
319 tTop = find_top_level(tDevice, gCollections);
320 countCollections += tTop;
325 TRACE("found %i device(s), %i collection(s)\n",(int)countDevices,(int)countCollections);
326 return (int)countCollections;
331 static int get_osx_device_name(int id, char *name, int length)
334 IOHIDElementRef tIOHIDElementRef;
335 IOHIDDeviceRef tIOHIDDeviceRef;
340 tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, id);
342 if (!tIOHIDElementRef)
344 ERR("Invalid Element requested %i\n",id);
348 tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDElementRef);
353 if (!tIOHIDDeviceRef)
355 ERR("Invalid Device requested %i\n",id);
359 str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
362 CFIndex len = CFStringGetLength(str);
365 CFStringGetCString(str,name,length,kCFStringEncodingASCII);
374 static void insert_sort_button(int header, IOHIDElementRef tIOHIDElementRef,
375 CFMutableArrayRef elementCFArrayRef, int index,
378 IOHIDElementRef targetElement;
381 CFArraySetValueAtIndex(elementCFArrayRef, header+index, NULL);
382 targetElement = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, header+target);
383 if (targetElement == NULL)
385 CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
388 usage = IOHIDElementGetUsage( targetElement );
389 usage --; /* usage 1 based index */
391 insert_sort_button(header, targetElement, elementCFArrayRef, target, usage);
392 CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
395 static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
397 IOHIDElementRef tIOHIDElementRef;
398 CFArrayRef gElementCFArrayRef;
404 device->elementCFArrayRef = NULL;
409 tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, device->id);
411 if (!tIOHIDElementRef)
414 gElementCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
415 get_element_children(tIOHIDElementRef, gElementCFArrayRef);
417 if (gElementCFArrayRef)
419 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
420 /* build our element array in the order that dinput expects */
421 device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);
423 for ( idx = 0; idx < cnt; idx++ )
425 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
426 int eleType = IOHIDElementGetType( tIOHIDElementRef );
429 case kIOHIDElementTypeInput_Button:
431 int usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
432 if (usagePage != kHIDPage_Button)
434 /* avoid strange elements found on the 360 controler */
440 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
445 case kIOHIDElementTypeInput_Axis:
447 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
451 case kIOHIDElementTypeInput_Misc:
453 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
456 case kHIDUsage_GD_Hatswitch:
458 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
462 case kHIDUsage_GD_Slider:
466 /* fallthrough, sliders are axis */
470 case kHIDUsage_GD_Rx:
471 case kHIDUsage_GD_Ry:
472 case kHIDUsage_GD_Rz:
474 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
475 axis_map[axes]=usage;
480 FIXME("Unhandled usage %i\n",usage);
485 FIXME("Unhandled type %i\n",eleType);
490 device->generic.devcaps.dwAxes = axes;
491 device->generic.devcaps.dwButtons = buttons;
492 device->generic.devcaps.dwPOVs = povs;
494 /* Sort buttons into correct order */
495 for (buttons = 0; buttons < device->generic.devcaps.dwButtons; buttons++)
497 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elementCFArrayRef, axes+povs+buttons);
498 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
499 usage --; /* usage is 1 indexed we need 0 indexed */
500 if (usage == buttons)
503 insert_sort_button(axes+povs, tIOHIDElementRef, device->elementCFArrayRef,buttons,usage);
507 static void get_osx_device_elements_props(JoystickImpl *device)
509 CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
511 if (gElementCFArrayRef)
513 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
515 for ( idx = 0; idx < cnt; idx++ )
517 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
519 device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
520 device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
521 device->generic.props[idx].lMin = 0;
522 device->generic.props[idx].lMax = 0xffff;
523 device->generic.props[idx].lDeadZone = 0;
524 device->generic.props[idx].lSaturation = 0;
529 static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
531 JoystickImpl *device = impl_from_IDirectInputDevice8A(iface);
532 IOHIDElementRef tIOHIDTopElementRef;
533 IOHIDDeviceRef tIOHIDDeviceRef;
534 CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
536 TRACE("polling device %i\n",device->id);
541 tIOHIDTopElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gCollections, device->id);
542 tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDTopElementRef);
544 if (!tIOHIDDeviceRef)
547 if (gElementCFArrayRef)
552 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
554 for ( idx = 0; idx < cnt; idx++ )
556 IOHIDValueRef valueRef;
558 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
559 int eleType = IOHIDElementGetType( tIOHIDElementRef );
563 case kIOHIDElementTypeInput_Button:
566 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
567 val = IOHIDValueGetIntegerValue(valueRef);
568 device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00;
572 case kIOHIDElementTypeInput_Misc:
574 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
577 case kHIDUsage_GD_Hatswitch:
579 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
580 val = IOHIDValueGetIntegerValue(valueRef);
582 device->generic.js.rgdwPOV[pov_idx] = -1;
584 device->generic.js.rgdwPOV[pov_idx] = val * 4500;
591 case kHIDUsage_GD_Rx:
592 case kHIDUsage_GD_Ry:
593 case kHIDUsage_GD_Rz:
594 case kHIDUsage_GD_Slider:
596 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
597 val = IOHIDValueGetIntegerValue(valueRef);
601 device->generic.js.lX = joystick_map_axis(&device->generic.props[idx], val);
604 device->generic.js.lY = joystick_map_axis(&device->generic.props[idx], val);
607 device->generic.js.lZ = joystick_map_axis(&device->generic.props[idx], val);
609 case kHIDUsage_GD_Rx:
610 device->generic.js.lRx = joystick_map_axis(&device->generic.props[idx], val);
612 case kHIDUsage_GD_Ry:
613 device->generic.js.lRy = joystick_map_axis(&device->generic.props[idx], val);
615 case kHIDUsage_GD_Rz:
616 device->generic.js.lRz = joystick_map_axis(&device->generic.props[idx], val);
618 case kHIDUsage_GD_Slider:
619 device->generic.js.rglSlider[slider_idx] = joystick_map_axis(&device->generic.props[idx], val);
626 FIXME("unhandled usage %i\n",usage);
631 FIXME("Unhandled type %i\n",eleType);
637 static INT find_joystick_devices(void)
639 static INT joystick_devices_count = -1;
641 if (joystick_devices_count != -1) return joystick_devices_count;
643 joystick_devices_count = find_osx_devices();
645 return joystick_devices_count;
648 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
650 if (id >= find_joystick_devices()) return FALSE;
652 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
653 WARN("force feedback not supported\n");
657 if ((dwDevType == 0) ||
658 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
659 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
661 /* Return joystick */
662 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
663 lpddi->guidInstance.Data3 = id;
664 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
665 /* we only support traditional joysticks for now */
666 if (version >= 0x0800)
667 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
669 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
670 sprintf(lpddi->tszInstanceName, "Joystick %d", id);
672 /* get the device name */
673 get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
675 lpddi->guidFFDriver = GUID_NULL;
682 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
687 if (id >= find_joystick_devices()) return FALSE;
689 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
690 WARN("force feedback not supported\n");
694 if ((dwDevType == 0) ||
695 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
696 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
697 /* Return joystick */
698 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
699 lpddi->guidInstance.Data3 = id;
700 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
701 /* we only support traditional joysticks for now */
702 if (version >= 0x0800)
703 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
705 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
706 sprintf(friendly, "Joystick %d", id);
707 MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
708 /* get the device name */
709 get_osx_device_name(id, name, MAX_PATH);
711 MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
712 lpddi->guidFFDriver = GUID_NULL;
719 static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput,
720 LPDIRECTINPUTDEVICEA* pdev, unsigned short index)
723 JoystickImpl* newDevice;
726 LPDIDATAFORMAT df = NULL;
728 int axis_map[8]; /* max axes */
729 int slider_count = 0;
731 TRACE("%s %p %p %p %hu\n", debugstr_guid(rguid), jvt, dinput, pdev, index);
733 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
734 if (newDevice == 0) {
735 WARN("out of memory\n");
737 return DIERR_OUTOFMEMORY;
740 newDevice->id = index;
742 newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID;
743 newDevice->generic.guidInstance.Data3 = index;
744 newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
745 newDevice->generic.joy_polldev = poll_osx_device_state;
747 /* get the device name */
748 get_osx_device_name(index, name, MAX_PATH);
749 TRACE("Name %s\n",name);
751 /* copy the device name */
752 newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
753 strcpy(newDevice->generic.name, name);
755 memset(axis_map, 0, sizeof(axis_map));
756 get_osx_device_elements(newDevice, axis_map);
758 TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
760 if (newDevice->generic.devcaps.dwButtons > 128)
762 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
763 newDevice->generic.devcaps.dwButtons = 128;
766 newDevice->generic.base.lpVtbl = jvt;
767 newDevice->generic.base.ref = 1;
768 newDevice->generic.base.dinput = dinput;
769 newDevice->generic.base.guid = *rguid;
770 InitializeCriticalSection(&newDevice->generic.base.crit);
771 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
773 /* Create copy of default data format */
774 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
775 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
777 df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
778 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
780 for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
785 case kHIDUsage_GD_X: wine_obj = 0; break;
786 case kHIDUsage_GD_Y: wine_obj = 1; break;
787 case kHIDUsage_GD_Z: wine_obj = 2; break;
788 case kHIDUsage_GD_Rx: wine_obj = 3; break;
789 case kHIDUsage_GD_Ry: wine_obj = 4; break;
790 case kHIDUsage_GD_Rz: wine_obj = 5; break;
791 case kHIDUsage_GD_Slider:
792 wine_obj = 6 + slider_count;
796 if (wine_obj < 0 ) continue;
798 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
799 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
802 for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
804 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
805 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
808 for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
810 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
811 df->rgodf[idx ].pguid = &GUID_Button;
812 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
814 newDevice->generic.base.data_format.wine_df = df;
816 /* initialize default properties */
817 get_osx_device_elements_props(newDevice);
819 IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
821 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
822 newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
823 if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
824 newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
826 newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
827 newDevice->generic.devcaps.dwFFSamplePeriod = 0;
828 newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
829 newDevice->generic.devcaps.dwFirmwareRevision = 0;
830 newDevice->generic.devcaps.dwHardwareRevision = 0;
831 newDevice->generic.devcaps.dwFFDriverVersion = 0;
833 if (TRACE_ON(dinput)) {
834 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
835 _dump_DIDEVCAPS(&newDevice->generic.devcaps);
838 *pdev = (LPDIRECTINPUTDEVICEA)newDevice;
843 hr = DIERR_OUTOFMEMORY;
844 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
845 HeapFree(GetProcessHeap(), 0, df);
846 release_DataFormat(&newDevice->generic.base.data_format);
847 HeapFree(GetProcessHeap(),0,newDevice->generic.name);
848 HeapFree(GetProcessHeap(),0,newDevice);
854 /******************************************************************************
855 * get_joystick_index : Get the joystick index from a given GUID
857 static unsigned short get_joystick_index(REFGUID guid)
859 GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
860 GUID dev_guid = *guid;
862 wine_joystick.Data3 = 0;
865 /* for the standard joystick GUID use index 0 */
866 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
868 /* for the wine joystick GUIDs use the index stored in Data3 */
869 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
874 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
876 unsigned short index;
877 int joystick_devices_count;
879 TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
882 if ((joystick_devices_count = find_joystick_devices()) == 0)
883 return DIERR_DEVICENOTREG;
885 if ((index = get_joystick_index(rguid)) < 0xffff &&
886 joystick_devices_count && index < joystick_devices_count)
888 if ((riid == NULL) ||
889 IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
890 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
891 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
892 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
894 return alloc_device(rguid, &JoystickAvt, dinput, pdev, index);
897 WARN("no interface\n");
898 return DIERR_NOINTERFACE;
901 return DIERR_DEVICENOTREG;
904 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
906 unsigned short index;
907 int joystick_devices_count;
909 TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
912 if ((joystick_devices_count = find_joystick_devices()) == 0)
913 return DIERR_DEVICENOTREG;
915 if ((index = get_joystick_index(rguid)) < 0xffff &&
916 joystick_devices_count && index < joystick_devices_count)
918 if ((riid == NULL) ||
919 IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
920 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
921 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
922 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
924 return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev, index);
926 WARN("no interface\n");
927 return DIERR_NOINTERFACE;
930 WARN("invalid device GUID %s\n",debugstr_guid(rguid));
931 return DIERR_DEVICENOTREG;
934 const struct dinput_device joystick_osx_device = {
935 "Wine OS X joystick driver",
938 joydev_create_deviceA,
939 joydev_create_deviceW
942 static const IDirectInputDevice8AVtbl JoystickAvt =
944 IDirectInputDevice2AImpl_QueryInterface,
945 IDirectInputDevice2AImpl_AddRef,
946 IDirectInputDevice2AImpl_Release,
947 JoystickAGenericImpl_GetCapabilities,
948 IDirectInputDevice2AImpl_EnumObjects,
949 JoystickAGenericImpl_GetProperty,
950 JoystickAGenericImpl_SetProperty,
951 IDirectInputDevice2AImpl_Acquire,
952 IDirectInputDevice2AImpl_Unacquire,
953 JoystickAGenericImpl_GetDeviceState,
954 IDirectInputDevice2AImpl_GetDeviceData,
955 IDirectInputDevice2AImpl_SetDataFormat,
956 IDirectInputDevice2AImpl_SetEventNotification,
957 IDirectInputDevice2AImpl_SetCooperativeLevel,
958 JoystickAGenericImpl_GetObjectInfo,
959 JoystickAGenericImpl_GetDeviceInfo,
960 IDirectInputDevice2AImpl_RunControlPanel,
961 IDirectInputDevice2AImpl_Initialize,
962 IDirectInputDevice2AImpl_CreateEffect,
963 IDirectInputDevice2AImpl_EnumEffects,
964 IDirectInputDevice2AImpl_GetEffectInfo,
965 IDirectInputDevice2AImpl_GetForceFeedbackState,
966 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
967 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
968 IDirectInputDevice2AImpl_Escape,
969 JoystickAGenericImpl_Poll,
970 IDirectInputDevice2AImpl_SendDeviceData,
971 IDirectInputDevice7AImpl_EnumEffectsInFile,
972 IDirectInputDevice7AImpl_WriteEffectToFile,
973 IDirectInputDevice8AImpl_BuildActionMap,
974 IDirectInputDevice8AImpl_SetActionMap,
975 IDirectInputDevice8AImpl_GetImageInfo
978 static const IDirectInputDevice8WVtbl JoystickWvt =
980 IDirectInputDevice2WImpl_QueryInterface,
981 IDirectInputDevice2WImpl_AddRef,
982 IDirectInputDevice2WImpl_Release,
983 JoystickWGenericImpl_GetCapabilities,
984 IDirectInputDevice2WImpl_EnumObjects,
985 JoystickWGenericImpl_GetProperty,
986 JoystickWGenericImpl_SetProperty,
987 IDirectInputDevice2WImpl_Acquire,
988 IDirectInputDevice2WImpl_Unacquire,
989 JoystickWGenericImpl_GetDeviceState,
990 IDirectInputDevice2WImpl_GetDeviceData,
991 IDirectInputDevice2WImpl_SetDataFormat,
992 IDirectInputDevice2WImpl_SetEventNotification,
993 IDirectInputDevice2WImpl_SetCooperativeLevel,
994 JoystickWGenericImpl_GetObjectInfo,
995 JoystickWGenericImpl_GetDeviceInfo,
996 IDirectInputDevice2WImpl_RunControlPanel,
997 IDirectInputDevice2WImpl_Initialize,
998 IDirectInputDevice2WImpl_CreateEffect,
999 IDirectInputDevice2WImpl_EnumEffects,
1000 IDirectInputDevice2WImpl_GetEffectInfo,
1001 IDirectInputDevice2WImpl_GetForceFeedbackState,
1002 IDirectInputDevice2WImpl_SendForceFeedbackCommand,
1003 IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
1004 IDirectInputDevice2WImpl_Escape,
1005 JoystickWGenericImpl_Poll,
1006 IDirectInputDevice2WImpl_SendDeviceData,
1007 IDirectInputDevice7WImpl_EnumEffectsInFile,
1008 IDirectInputDevice7WImpl_WriteEffectToFile,
1009 IDirectInputDevice8WImpl_BuildActionMap,
1010 IDirectInputDevice8WImpl_SetActionMap,
1011 IDirectInputDevice8WImpl_GetImageInfo
1014 #else /* HAVE_IOHIDMANAGERCREATE */
1016 const struct dinput_device joystick_osx_device = {
1017 "Wine OS X joystick driver",
1024 #endif /* HAVE_IOHIDMANAGERCREATE */