dinput: COM cleanup - use interfaces instead of vtbl. Combine both Unicode and ASCII...
[wine.git] / dlls / dinput / joystick_osx.c
blob19ff6a3f586d359fec7fec12f71bb4af1b9c73bd
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
23 #include "config.h"
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>
65 #undef LoadResource
66 #undef CompareString
67 #undef GetCurrentThread
68 #undef _CDECL
69 #undef DPRINTF
70 #undef GetCurrentProcess
71 #undef AnimatePalette
72 #undef EqualRgn
73 #undef FillRgn
74 #undef FrameRgn
75 #undef GetPixel
76 #undef InvertRgn
77 #undef LineTo
78 #undef OffsetRgn
79 #undef PaintRgn
80 #undef Polygon
81 #undef ResizePalette
82 #undef SetRectRgn
83 #undef ULONG
84 #undef E_INVALIDARG
85 #undef E_OUTOFMEMORY
86 #undef E_HANDLE
87 #undef E_ACCESSDENIED
88 #undef E_UNEXPECTED
89 #undef E_FAIL
90 #undef E_ABORT
91 #undef E_POINTER
92 #undef E_NOINTERFACE
93 #undef E_NOTIMPL
94 #undef S_FALSE
95 #undef S_OK
96 #undef HRESULT_FACILITY
97 #undef IS_ERROR
98 #undef FAILED
99 #undef SUCCEEDED
100 #undef MAKE_HRESULT
101 #undef HRESULT
102 #undef STDMETHODCALLTYPE
103 #endif /* HAVE_CARBON_CARBON_H */
105 #include "wine/debug.h"
106 #include "wine/unicode.h"
107 #include "windef.h"
108 #include "winbase.h"
109 #include "winerror.h"
110 #include "winreg.h"
111 #include "dinput.h"
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;
128 struct JoystickImpl
130 struct JoystickGenericImpl generic;
132 /* osx private */
133 int id;
134 CFMutableArrayRef elementCFArrayRef;
135 ObjProps **propmap;
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 );
165 if ( result )
167 int number = kHIDPage_GenericDesktop;
168 CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
169 kCFNumberIntType, &number);
171 if ( pageCFNumberRef )
173 CFNumberRef usageCFNumberRef;
175 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ),
176 pageCFNumberRef );
177 CFRelease( pageCFNumberRef );
179 usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
180 kCFNumberIntType, &usage);
181 if ( usageCFNumberRef )
183 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ),
184 usageCFNumberRef );
185 CFRelease( usageCFNumberRef );
187 else
189 ERR("CFNumberCreate() failed.\n");
190 return NULL;
193 else
195 ERR("CFNumberCreate failed.\n");
196 return NULL;
199 else
201 ERR("CFDictionaryCreateMutable failed.\n");
202 return NULL;
205 return result;
208 static CFIndex find_top_level(IOHIDDeviceRef tIOHIDDeviceRef, CFArrayRef topLevels)
210 CFArrayRef gElementCFArrayRef;
211 CFIndex numTops = 0;
213 if (!tIOHIDDeviceRef)
214 return 0;
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);
236 numTops++;
241 return numTops;
244 static void get_element_children(IOHIDElementRef tElement, CFArrayRef childElements)
246 CFIndex idx, cnt;
247 CFArrayRef tElementChildrenArray = IOHIDElementGetChildren(tElement);
249 cnt = CFArrayGetCount(tElementChildrenArray);
250 if (cnt < 1)
251 return;
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);
261 else
262 CFArrayAppendValue((CFMutableArrayRef)childElements, tChildElementRef);
266 static int find_osx_devices(void)
268 IOReturn tIOReturn;
269 CFMutableDictionaryRef result;
270 CFSetRef devset;
271 CFArrayRef matching;
273 gIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
274 tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, 0L);
275 if ( kIOReturnSuccess != tIOReturn )
277 ERR("Couldn't open IOHIDManager.\n");
278 return 0;
281 matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
282 &kCFTypeArrayCallBacks );
284 /* build matching dictionary */
285 result = creates_osx_device_match(kHIDUsage_GD_Joystick);
286 if (!result)
288 CFRelease(matching);
289 return 0;
291 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
292 result = creates_osx_device_match(kHIDUsage_GD_GamePad);
293 if (!result)
295 CFRelease(matching);
296 return 0;
298 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
300 IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef, matching);
301 devset = IOHIDManagerCopyDevices( gIOHIDManagerRef );
302 if (devset)
304 CFIndex countDevices, countCollections, idx;
305 CFArrayRef gDevices = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
306 CFSetApplyFunction(devset, CFSetApplierFunctionCopyToCFArray, (void*)gDevices);
307 CFRelease( devset);
308 countDevices = CFArrayGetCount(gDevices);
310 gCollections = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
311 if (!gCollections)
312 return 0;
314 countCollections = 0;
315 for (idx = 0; idx < countDevices; idx++)
317 CFIndex tTop;
318 IOHIDDeviceRef tDevice;
320 tDevice = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDevices, idx);
321 tTop = find_top_level(tDevice, gCollections);
322 countCollections += tTop;
325 CFRelease(gDevices);
327 TRACE("found %i device(s), %i collection(s)\n",(int)countDevices,(int)countCollections);
328 return (int)countCollections;
330 return 0;
333 static int get_osx_device_name(int id, char *name, int length)
335 CFStringRef str;
336 IOHIDElementRef tIOHIDElementRef;
337 IOHIDDeviceRef tIOHIDDeviceRef;
339 if (!gCollections)
340 return 0;
342 tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, id);
344 if (!tIOHIDElementRef)
346 ERR("Invalid Element requested %i\n",id);
347 return 0;
350 tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDElementRef);
352 if (name)
353 name[0] = 0;
355 if (!tIOHIDDeviceRef)
357 ERR("Invalid Device requested %i\n",id);
358 return 0;
361 str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
362 if (str)
364 CFIndex len = CFStringGetLength(str);
365 if (length >= len)
367 CFStringGetCString(str,name,length,kCFStringEncodingASCII);
368 return len;
370 else
371 return (len+1);
373 return 0;
376 static void insert_sort_button(int header, IOHIDElementRef tIOHIDElementRef,
377 CFMutableArrayRef elementCFArrayRef, int index,
378 int target)
380 IOHIDElementRef targetElement;
381 int usage;
383 CFArraySetValueAtIndex(elementCFArrayRef, header+index, NULL);
384 targetElement = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, header+target);
385 if (targetElement == NULL)
387 CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
388 return;
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;
401 DWORD axes = 0;
402 DWORD sliders = 0;
403 DWORD buttons = 0;
404 DWORD povs = 0;
406 device->elementCFArrayRef = NULL;
408 if (!gCollections)
409 return;
411 tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, device->id);
413 if (!tIOHIDElementRef)
414 return;
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 );
429 switch(eleType)
431 case kIOHIDElementTypeInput_Button:
433 int usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
434 if (usagePage != kHIDPage_Button)
436 /* avoid strange elements found on the 360 controler */
437 continue;
440 if (buttons < 128)
442 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
443 buttons++;
445 break;
447 case kIOHIDElementTypeInput_Axis:
449 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
450 axes++;
451 break;
453 case kIOHIDElementTypeInput_Misc:
455 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
456 switch(usage)
458 case kHIDUsage_GD_Hatswitch:
460 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
461 povs++;
462 break;
464 case kHIDUsage_GD_Slider:
465 sliders ++;
466 if (sliders > 2)
467 break;
468 /* fallthrough, sliders are axis */
469 case kHIDUsage_GD_X:
470 case kHIDUsage_GD_Y:
471 case kHIDUsage_GD_Z:
472 case kHIDUsage_GD_Rx:
473 case kHIDUsage_GD_Ry:
474 case kHIDUsage_GD_Rz:
476 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
477 axis_map[axes]=usage;
478 axes++;
479 break;
481 default:
482 FIXME("Unhandled usage %i\n",usage);
484 break;
486 default:
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)
503 continue;
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);
540 if (!gCollections)
541 return;
543 tIOHIDTopElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gCollections, device->id);
544 tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDTopElementRef);
546 if (!tIOHIDDeviceRef)
547 return;
549 if (gElementCFArrayRef)
551 int button_idx = 0;
552 int pov_idx = 0;
553 int slider_idx = 0;
554 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
556 for ( idx = 0; idx < cnt; idx++ )
558 IOHIDValueRef valueRef;
559 int val;
560 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
561 int eleType = IOHIDElementGetType( tIOHIDElementRef );
563 switch(eleType)
565 case kIOHIDElementTypeInput_Button:
566 if(button_idx < 128)
568 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
569 val = IOHIDValueGetIntegerValue(valueRef);
570 device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00;
571 button_idx ++;
573 break;
574 case kIOHIDElementTypeInput_Misc:
576 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
577 switch(usage)
579 case kHIDUsage_GD_Hatswitch:
581 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
582 val = IOHIDValueGetIntegerValue(valueRef);
583 if (val >= 8)
584 device->generic.js.rgdwPOV[pov_idx] = -1;
585 else
586 device->generic.js.rgdwPOV[pov_idx] = val * 4500;
587 pov_idx ++;
588 break;
590 case kHIDUsage_GD_X:
591 case kHIDUsage_GD_Y:
592 case kHIDUsage_GD_Z:
593 case kHIDUsage_GD_Rx:
594 case kHIDUsage_GD_Ry:
595 case kHIDUsage_GD_Rz:
596 case kHIDUsage_GD_Slider:
598 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
599 val = IOHIDValueGetIntegerValue(valueRef);
600 switch (usage)
602 case kHIDUsage_GD_X:
603 device->generic.js.lX = joystick_map_axis(&device->generic.props[idx], val);
604 break;
605 case kHIDUsage_GD_Y:
606 device->generic.js.lY = joystick_map_axis(&device->generic.props[idx], val);
607 break;
608 case kHIDUsage_GD_Z:
609 device->generic.js.lZ = joystick_map_axis(&device->generic.props[idx], val);
610 break;
611 case kHIDUsage_GD_Rx:
612 device->generic.js.lRx = joystick_map_axis(&device->generic.props[idx], val);
613 break;
614 case kHIDUsage_GD_Ry:
615 device->generic.js.lRy = joystick_map_axis(&device->generic.props[idx], val);
616 break;
617 case kHIDUsage_GD_Rz:
618 device->generic.js.lRz = joystick_map_axis(&device->generic.props[idx], val);
619 break;
620 case kHIDUsage_GD_Slider:
621 device->generic.js.rglSlider[slider_idx] = joystick_map_axis(&device->generic.props[idx], val);
622 slider_idx ++;
623 break;
625 break;
627 default:
628 FIXME("unhandled usage %i\n",usage);
630 break;
632 default:
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");
656 return FALSE;
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);
670 else
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;
678 return TRUE;
681 return FALSE;
684 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
686 char name[MAX_PATH];
687 char friendly[32];
689 if (id >= find_joystick_devices()) return FALSE;
691 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
692 WARN("force feedback not supported\n");
693 return FALSE;
696 if ((dwDevType == 0) ||
697 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
698 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
699 /* Return joystick */
700 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
701 lpddi->guidInstance.Data3 = id;
702 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
703 /* we only support traditional joysticks for now */
704 if (version >= 0x0800)
705 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
706 else
707 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
708 sprintf(friendly, "Joystick %d", id);
709 MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
710 /* get the device name */
711 get_osx_device_name(id, name, MAX_PATH);
713 MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
714 lpddi->guidFFDriver = GUID_NULL;
715 return TRUE;
718 return FALSE;
721 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
722 JoystickImpl **pdev, unsigned short index)
724 DWORD i;
725 JoystickImpl* newDevice;
726 char name[MAX_PATH];
727 HRESULT hr;
728 LPDIDATAFORMAT df = NULL;
729 int idx = 0;
730 int axis_map[8]; /* max axes */
731 int slider_count = 0;
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");
738 *pdev = 0;
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++)
785 int wine_obj = -1;
786 switch (axis_map[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;
796 slider_count++;
797 break;
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);
828 else
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);
841 *pdev = newDevice;
843 return DI_OK;
845 FAILED:
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);
852 *pdev = 0;
854 return hr;
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;
866 dev_guid.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;
874 return 0xffff;
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);
883 *pdev = NULL;
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))
897 JoystickImpl *This;
898 HRESULT hr = alloc_device(rguid, dinput, &This, index);
900 *pdev = (LPDIRECTINPUTDEVICEA)(This ? &This->generic.base.IDirectInputDevice8A_iface : NULL);
901 return hr;
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);
917 *pdev = NULL;
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))
931 JoystickImpl *This;
932 HRESULT hr = alloc_device(rguid, dinput, &This, index);
934 *pdev = (LPDIRECTINPUTDEVICEW)(This ? &This->generic.base.IDirectInputDevice8W_iface : NULL);
935 return hr;
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",
947 joydev_enum_deviceA,
948 joydev_enum_deviceW,
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",
1029 NULL,
1030 NULL,
1031 NULL,
1032 NULL
1035 #endif /* HAVE_IOHIDMANAGERCREATE */