user32: Get the graphics driver name from the desktop window registry entry.
[wine.git] / dlls / dinput / joystick_osx.c
blob622b0546f081712cb4cf92d405013d06d3193cc4
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_IOKIT_HID_IOHIDLIB_H)
27 #define DWORD UInt32
28 #define LPDWORD UInt32*
29 #define LONG SInt32
30 #define LPLONG SInt32*
31 #define E_PENDING __carbon_E_PENDING
32 #define ULONG __carbon_ULONG
33 #define E_INVALIDARG __carbon_E_INVALIDARG
34 #define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY
35 #define E_HANDLE __carbon_E_HANDLE
36 #define E_ACCESSDENIED __carbon_E_ACCESSDENIED
37 #define E_UNEXPECTED __carbon_E_UNEXPECTED
38 #define E_FAIL __carbon_E_FAIL
39 #define E_ABORT __carbon_E_ABORT
40 #define E_POINTER __carbon_E_POINTER
41 #define E_NOINTERFACE __carbon_E_NOINTERFACE
42 #define E_NOTIMPL __carbon_E_NOTIMPL
43 #define S_FALSE __carbon_S_FALSE
44 #define S_OK __carbon_S_OK
45 #define HRESULT_FACILITY __carbon_HRESULT_FACILITY
46 #define IS_ERROR __carbon_IS_ERROR
47 #define FAILED __carbon_FAILED
48 #define SUCCEEDED __carbon_SUCCEEDED
49 #define MAKE_HRESULT __carbon_MAKE_HRESULT
50 #define HRESULT __carbon_HRESULT
51 #define STDMETHODCALLTYPE __carbon_STDMETHODCALLTYPE
52 #include <IOKit/IOKitLib.h>
53 #include <IOKit/hid/IOHIDLib.h>
54 #include <ForceFeedback/ForceFeedback.h>
55 #undef ULONG
56 #undef E_INVALIDARG
57 #undef E_OUTOFMEMORY
58 #undef E_HANDLE
59 #undef E_ACCESSDENIED
60 #undef E_UNEXPECTED
61 #undef E_FAIL
62 #undef E_ABORT
63 #undef E_POINTER
64 #undef E_NOINTERFACE
65 #undef E_NOTIMPL
66 #undef S_FALSE
67 #undef S_OK
68 #undef HRESULT_FACILITY
69 #undef IS_ERROR
70 #undef FAILED
71 #undef SUCCEEDED
72 #undef MAKE_HRESULT
73 #undef HRESULT
74 #undef STDMETHODCALLTYPE
75 #undef DWORD
76 #undef LPDWORD
77 #undef LONG
78 #undef LPLONG
79 #undef E_PENDING
80 #endif /* HAVE_IOKIT_HID_IOHIDLIB_H */
82 #include "wine/debug.h"
83 #include "wine/unicode.h"
84 #include "windef.h"
85 #include "winbase.h"
86 #include "winerror.h"
87 #include "winreg.h"
88 #include "dinput.h"
90 #include "dinput_private.h"
91 #include "device_private.h"
92 #include "joystick_private.h"
94 #ifdef HAVE_IOHIDMANAGERCREATE
96 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
98 static IOHIDManagerRef gIOHIDManagerRef = NULL;
99 static CFArrayRef gCollections = NULL;
101 typedef struct JoystickImpl JoystickImpl;
102 static const IDirectInputDevice8AVtbl JoystickAvt;
103 static const IDirectInputDevice8WVtbl JoystickWvt;
105 struct JoystickImpl
107 struct JoystickGenericImpl generic;
109 /* osx private */
110 int id;
111 CFMutableArrayRef elementCFArrayRef;
112 ObjProps **propmap;
113 FFDeviceObjectReference ff;
114 struct list effects;
117 static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
119 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface),
120 JoystickGenericImpl, base), JoystickImpl, generic);
122 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
124 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
125 JoystickGenericImpl, base), JoystickImpl, generic);
128 typedef struct _EffectImpl {
129 IDirectInputEffect IDirectInputEffect_iface;
130 LONG ref;
132 JoystickImpl *device;
133 FFEffectObjectReference effect;
134 GUID guid;
136 struct list entry;
137 } EffectImpl;
139 static EffectImpl *impl_from_IDirectInputEffect(IDirectInputEffect *iface)
141 return CONTAINING_RECORD(iface, EffectImpl, IDirectInputEffect_iface);
144 static const IDirectInputEffectVtbl EffectVtbl;
146 static const GUID DInput_Wine_OsX_Joystick_GUID = { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */
147 0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A}
150 static HRESULT osx_to_win32_hresult(HRESULT in)
152 /* OSX returns 16-bit COM runtime errors, which we should
153 * convert to win32 */
154 switch(in){
155 case 0x80000001:
156 return E_NOTIMPL;
157 case 0x80000002:
158 return E_OUTOFMEMORY;
159 case 0x80000003:
160 return E_INVALIDARG;
161 case 0x80000004:
162 return E_NOINTERFACE;
163 case 0x80000005:
164 return E_POINTER;
165 case 0x80000006:
166 return E_HANDLE;
167 case 0x80000007:
168 return E_ABORT;
169 case 0x80000008:
170 return E_FAIL;
171 case 0x80000009:
172 return E_ACCESSDENIED;
173 case 0x8000FFFF:
174 return E_UNEXPECTED;
176 return in;
179 static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context)
181 CFArrayAppendValue( ( CFMutableArrayRef ) context, value );
184 static IOHIDDeviceRef get_device_ref(int id)
186 IOHIDElementRef tIOHIDElementRef;
187 IOHIDDeviceRef tIOHIDDeviceRef;
189 if (!gCollections)
190 return 0;
192 tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, id);
193 if (!tIOHIDElementRef)
195 ERR("Invalid Element requested %i\n",id);
196 return 0;
199 tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDElementRef);
200 if (!tIOHIDDeviceRef)
202 ERR("Invalid Device requested %i\n",id);
203 return 0;
206 return tIOHIDDeviceRef;
209 static HRESULT get_ff(IOHIDDeviceRef device, FFDeviceObjectReference *ret)
211 io_service_t service;
212 CFMutableDictionaryRef matching;
213 CFTypeRef type;
215 matching = IOServiceMatching(kIOHIDDeviceKey);
216 if(!matching){
217 WARN("IOServiceMatching failed, force feedback disabled\n");
218 return DIERR_DEVICENOTREG;
221 type = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey));
222 if(!matching){
223 CFRelease(matching);
224 WARN("IOHIDDeviceGetProperty failed, force feedback disabled\n");
225 return DIERR_DEVICENOTREG;
228 CFDictionaryAddValue(matching, CFSTR(kIOHIDLocationIDKey), type);
230 service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
232 if(!ret)
233 return FFIsForceFeedback(service) == FF_OK ? S_OK : S_FALSE;
235 return osx_to_win32_hresult(FFCreateDevice(service, ret));
238 static CFMutableDictionaryRef creates_osx_device_match(int usage)
240 CFMutableDictionaryRef result;
242 result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
243 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
245 if ( result )
247 int number = kHIDPage_GenericDesktop;
248 CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
249 kCFNumberIntType, &number);
251 if ( pageCFNumberRef )
253 CFNumberRef usageCFNumberRef;
255 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ),
256 pageCFNumberRef );
257 CFRelease( pageCFNumberRef );
259 usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
260 kCFNumberIntType, &usage);
261 if ( usageCFNumberRef )
263 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ),
264 usageCFNumberRef );
265 CFRelease( usageCFNumberRef );
267 else
269 ERR("CFNumberCreate() failed.\n");
270 return NULL;
273 else
275 ERR("CFNumberCreate failed.\n");
276 return NULL;
279 else
281 ERR("CFDictionaryCreateMutable failed.\n");
282 return NULL;
285 return result;
288 static CFIndex find_top_level(IOHIDDeviceRef tIOHIDDeviceRef, CFArrayRef topLevels)
290 CFArrayRef gElementCFArrayRef;
291 CFIndex numTops = 0;
293 if (!tIOHIDDeviceRef)
294 return 0;
296 gElementCFArrayRef = IOHIDDeviceCopyMatchingElements(tIOHIDDeviceRef, NULL, 0);
298 if (gElementCFArrayRef)
300 CFIndex idx, cnt = CFArrayGetCount(gElementCFArrayRef);
301 for (idx=0; idx<cnt; idx++)
303 IOHIDElementRef tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gElementCFArrayRef, idx);
304 int eleType = IOHIDElementGetType(tIOHIDElementRef);
306 /* Check for top-level gaming device collections */
307 if (eleType == kIOHIDElementTypeCollection && IOHIDElementGetParent(tIOHIDElementRef) == 0)
309 int tUsagePage = IOHIDElementGetUsagePage(tIOHIDElementRef);
310 int tUsage = IOHIDElementGetUsage(tIOHIDElementRef);
312 if (tUsagePage == kHIDPage_GenericDesktop &&
313 (tUsage == kHIDUsage_GD_Joystick || tUsage == kHIDUsage_GD_GamePad))
315 CFArrayAppendValue((CFMutableArrayRef)topLevels, tIOHIDElementRef);
316 numTops++;
321 return numTops;
324 static void get_element_children(IOHIDElementRef tElement, CFArrayRef childElements)
326 CFIndex idx, cnt;
327 CFArrayRef tElementChildrenArray = IOHIDElementGetChildren(tElement);
329 cnt = CFArrayGetCount(tElementChildrenArray);
330 if (cnt < 1)
331 return;
333 /* Either add the element to the array or grab its children */
334 for (idx=0; idx<cnt; idx++)
336 IOHIDElementRef tChildElementRef;
338 tChildElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(tElementChildrenArray, idx);
339 if (IOHIDElementGetType(tChildElementRef) == kIOHIDElementTypeCollection)
340 get_element_children(tChildElementRef, childElements);
341 else
342 CFArrayAppendValue((CFMutableArrayRef)childElements, tChildElementRef);
346 static int find_osx_devices(void)
348 IOReturn tIOReturn;
349 CFMutableDictionaryRef result;
350 CFSetRef devset;
351 CFArrayRef matching;
353 gIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
354 tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, 0L);
355 if ( kIOReturnSuccess != tIOReturn )
357 ERR("Couldn't open IOHIDManager.\n");
358 return 0;
361 matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
362 &kCFTypeArrayCallBacks );
364 /* build matching dictionary */
365 result = creates_osx_device_match(kHIDUsage_GD_Joystick);
366 if (!result)
368 CFRelease(matching);
369 return 0;
371 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
372 result = creates_osx_device_match(kHIDUsage_GD_GamePad);
373 if (!result)
375 CFRelease(matching);
376 return 0;
378 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
380 IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef, matching);
381 devset = IOHIDManagerCopyDevices( gIOHIDManagerRef );
382 if (devset)
384 CFIndex countDevices, countCollections, idx;
385 CFArrayRef gDevices = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
386 CFSetApplyFunction(devset, CFSetApplierFunctionCopyToCFArray, (void*)gDevices);
387 CFRelease( devset);
388 countDevices = CFArrayGetCount(gDevices);
390 gCollections = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
391 if (!gCollections)
392 return 0;
394 countCollections = 0;
395 for (idx = 0; idx < countDevices; idx++)
397 CFIndex tTop;
398 IOHIDDeviceRef tDevice;
400 tDevice = (IOHIDDeviceRef) CFArrayGetValueAtIndex(gDevices, idx);
401 tTop = find_top_level(tDevice, gCollections);
402 countCollections += tTop;
405 CFRelease(gDevices);
407 TRACE("found %i device(s), %i collection(s)\n",(int)countDevices,(int)countCollections);
408 return (int)countCollections;
410 return 0;
413 static int get_osx_device_name(int id, char *name, int length)
415 CFStringRef str;
416 IOHIDDeviceRef tIOHIDDeviceRef;
418 tIOHIDDeviceRef = get_device_ref(id);
420 if (name)
421 name[0] = 0;
423 if (!tIOHIDDeviceRef)
424 return 0;
426 str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
427 if (str)
429 CFIndex len = CFStringGetLength(str);
430 if (length >= len)
432 CFStringGetCString(str,name,length,kCFStringEncodingASCII);
433 return len;
435 else
436 return (len+1);
438 return 0;
441 static void insert_sort_button(int header, IOHIDElementRef tIOHIDElementRef,
442 CFMutableArrayRef elementCFArrayRef, int index,
443 int target)
445 IOHIDElementRef targetElement;
446 int usage;
448 CFArraySetValueAtIndex(elementCFArrayRef, header+index, NULL);
449 targetElement = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, header+target);
450 if (targetElement == NULL)
452 CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
453 return;
455 usage = IOHIDElementGetUsage( targetElement );
456 usage --; /* usage 1 based index */
458 insert_sort_button(header, targetElement, elementCFArrayRef, target, usage);
459 CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
462 static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
464 IOHIDElementRef tIOHIDElementRef;
465 CFArrayRef gElementCFArrayRef;
466 DWORD axes = 0;
467 DWORD sliders = 0;
468 DWORD buttons = 0;
469 DWORD povs = 0;
471 device->elementCFArrayRef = NULL;
473 if (!gCollections)
474 return;
476 tIOHIDElementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(gCollections, device->id);
478 if (!tIOHIDElementRef)
479 return;
481 gElementCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
482 get_element_children(tIOHIDElementRef, gElementCFArrayRef);
484 if (gElementCFArrayRef)
486 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
487 /* build our element array in the order that dinput expects */
488 device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);
490 for ( idx = 0; idx < cnt; idx++ )
492 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
493 int eleType = IOHIDElementGetType( tIOHIDElementRef );
494 switch(eleType)
496 case kIOHIDElementTypeInput_Button:
498 int usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
499 if (usagePage != kHIDPage_Button)
501 /* avoid strange elements found on the 360 controller */
502 continue;
505 if (buttons < 128)
507 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
508 buttons++;
510 break;
512 case kIOHIDElementTypeInput_Axis:
514 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
515 axes++;
516 break;
518 case kIOHIDElementTypeInput_Misc:
520 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
521 switch(usage)
523 case kHIDUsage_GD_Hatswitch:
525 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
526 povs++;
527 break;
529 case kHIDUsage_GD_Slider:
530 sliders ++;
531 if (sliders > 2)
532 break;
533 /* fallthrough, sliders are axis */
534 case kHIDUsage_GD_X:
535 case kHIDUsage_GD_Y:
536 case kHIDUsage_GD_Z:
537 case kHIDUsage_GD_Rx:
538 case kHIDUsage_GD_Ry:
539 case kHIDUsage_GD_Rz:
541 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
542 axis_map[axes]=usage;
543 axes++;
544 break;
546 default:
547 FIXME("Unhandled usage %i\n",usage);
549 break;
551 default:
552 FIXME("Unhandled type %i\n",eleType);
557 device->generic.devcaps.dwAxes = axes;
558 device->generic.devcaps.dwButtons = buttons;
559 device->generic.devcaps.dwPOVs = povs;
561 /* Sort buttons into correct order */
562 for (buttons = 0; buttons < device->generic.devcaps.dwButtons; buttons++)
564 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elementCFArrayRef, axes+povs+buttons);
565 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
566 usage --; /* usage is 1 indexed we need 0 indexed */
567 if (usage == buttons)
568 continue;
570 insert_sort_button(axes+povs, tIOHIDElementRef, device->elementCFArrayRef,buttons,usage);
574 static void get_osx_device_elements_props(JoystickImpl *device)
576 CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
578 if (gElementCFArrayRef)
580 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
582 for ( idx = 0; idx < cnt; idx++ )
584 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
586 device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
587 device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
588 device->generic.props[idx].lMin = 0;
589 device->generic.props[idx].lMax = 0xffff;
590 device->generic.props[idx].lDeadZone = 0;
591 device->generic.props[idx].lSaturation = 0;
596 static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
598 JoystickImpl *device = impl_from_IDirectInputDevice8A(iface);
599 IOHIDElementRef tIOHIDTopElementRef;
600 IOHIDDeviceRef tIOHIDDeviceRef;
601 CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
603 TRACE("polling device %i\n",device->id);
605 if (!gCollections)
606 return;
608 tIOHIDTopElementRef = (IOHIDElementRef) CFArrayGetValueAtIndex(gCollections, device->id);
609 tIOHIDDeviceRef = IOHIDElementGetDevice(tIOHIDTopElementRef);
611 if (!tIOHIDDeviceRef)
612 return;
614 if (gElementCFArrayRef)
616 int button_idx = 0;
617 int pov_idx = 0;
618 int slider_idx = 0;
619 int inst_id;
620 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
622 for ( idx = 0; idx < cnt; idx++ )
624 IOHIDValueRef valueRef;
625 int val, oldVal, newVal;
626 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
627 int eleType = IOHIDElementGetType( tIOHIDElementRef );
629 switch(eleType)
631 case kIOHIDElementTypeInput_Button:
632 if(button_idx < 128)
634 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
635 val = IOHIDValueGetIntegerValue(valueRef);
636 newVal = val ? 0x80 : 0x0;
637 oldVal = device->generic.js.rgbButtons[button_idx];
638 device->generic.js.rgbButtons[button_idx] = newVal;
639 if (oldVal != newVal)
641 inst_id = DIDFT_MAKEINSTANCE(button_idx) | DIDFT_PSHBUTTON;
642 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++);
644 button_idx ++;
646 break;
647 case kIOHIDElementTypeInput_Misc:
649 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
650 switch(usage)
652 case kHIDUsage_GD_Hatswitch:
654 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
655 val = IOHIDValueGetIntegerValue(valueRef);
656 oldVal = device->generic.js.rgdwPOV[pov_idx];
657 if (val >= 8)
658 newVal = -1;
659 else
660 newVal = val * 4500;
661 device->generic.js.rgdwPOV[pov_idx] = newVal;
662 if (oldVal != newVal)
664 inst_id = DIDFT_MAKEINSTANCE(pov_idx) | DIDFT_POV;
665 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++);
667 pov_idx ++;
668 break;
670 case kHIDUsage_GD_X:
671 case kHIDUsage_GD_Y:
672 case kHIDUsage_GD_Z:
673 case kHIDUsage_GD_Rx:
674 case kHIDUsage_GD_Ry:
675 case kHIDUsage_GD_Rz:
676 case kHIDUsage_GD_Slider:
678 int wine_obj = -1;
680 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
681 val = IOHIDValueGetIntegerValue(valueRef);
682 newVal = joystick_map_axis(&device->generic.props[idx], val);
683 switch (usage)
685 case kHIDUsage_GD_X:
686 wine_obj = 0;
687 oldVal = device->generic.js.lX;
688 device->generic.js.lX = newVal;
689 break;
690 case kHIDUsage_GD_Y:
691 wine_obj = 1;
692 oldVal = device->generic.js.lY;
693 device->generic.js.lY = newVal;
694 break;
695 case kHIDUsage_GD_Z:
696 wine_obj = 2;
697 oldVal = device->generic.js.lZ;
698 device->generic.js.lZ = newVal;
699 break;
700 case kHIDUsage_GD_Rx:
701 wine_obj = 3;
702 oldVal = device->generic.js.lRx;
703 device->generic.js.lRx = newVal;
704 break;
705 case kHIDUsage_GD_Ry:
706 wine_obj = 4;
707 oldVal = device->generic.js.lRy;
708 device->generic.js.lRy = newVal;
709 break;
710 case kHIDUsage_GD_Rz:
711 wine_obj = 5;
712 oldVal = device->generic.js.lRz;
713 device->generic.js.lRz = newVal;
714 break;
715 case kHIDUsage_GD_Slider:
716 wine_obj = 6 + slider_idx;
717 oldVal = device->generic.js.rglSlider[slider_idx];
718 device->generic.js.rglSlider[slider_idx] = newVal;
719 slider_idx ++;
720 break;
722 if ((wine_obj != -1) &&
723 (oldVal != newVal))
725 inst_id = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
726 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++);
729 break;
731 default:
732 FIXME("unhandled usage %i\n",usage);
734 break;
736 default:
737 FIXME("Unhandled type %i\n",eleType);
743 static INT find_joystick_devices(void)
745 static INT joystick_devices_count = -1;
747 if (joystick_devices_count != -1) return joystick_devices_count;
749 joystick_devices_count = find_osx_devices();
751 return joystick_devices_count;
754 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
756 if (id >= find_joystick_devices()) return E_FAIL;
758 if ((dwDevType == 0) ||
759 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
760 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
762 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
763 IOHIDDeviceRef device = get_device_ref(id);
764 if(!device)
765 return S_FALSE;
766 if(get_ff(device, NULL) != S_OK)
767 return S_FALSE;
769 /* Return joystick */
770 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
771 lpddi->guidInstance.Data3 = id;
772 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
773 /* we only support traditional joysticks for now */
774 if (version >= 0x0800)
775 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
776 else
777 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
778 sprintf(lpddi->tszInstanceName, "Joystick %d", id);
780 /* get the device name */
781 get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
783 lpddi->guidFFDriver = GUID_NULL;
784 return S_OK;
787 return S_FALSE;
790 static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
792 char name[MAX_PATH];
793 char friendly[32];
795 if (id >= find_joystick_devices()) return E_FAIL;
797 if ((dwDevType == 0) ||
798 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
799 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
800 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
801 IOHIDDeviceRef device = get_device_ref(id);
802 if(!device)
803 return S_FALSE;
804 if(get_ff(device, NULL) != S_OK)
805 return S_FALSE;
807 /* Return joystick */
808 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
809 lpddi->guidInstance.Data3 = id;
810 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
811 /* we only support traditional joysticks for now */
812 if (version >= 0x0800)
813 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
814 else
815 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
816 sprintf(friendly, "Joystick %d", id);
817 MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
818 /* get the device name */
819 get_osx_device_name(id, name, MAX_PATH);
821 MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
822 lpddi->guidFFDriver = GUID_NULL;
823 return S_OK;
826 return S_FALSE;
829 static const char *osx_ff_axis_name(UInt8 axis)
831 static char ret[6];
832 switch(axis){
833 case FFJOFS_X:
834 return "FFJOFS_X";
835 case FFJOFS_Y:
836 return "FFJOFS_Y";
837 case FFJOFS_Z:
838 return "FFJOFS_Z";
840 sprintf(ret, "%u", (unsigned int)axis);
841 return ret;
844 static BOOL osx_axis_has_ff(FFCAPABILITIES *ffcaps, UInt8 axis)
846 int i;
847 for(i = 0; i < ffcaps->numFfAxes; ++i)
848 if(ffcaps->ffAxes[i] == axis)
849 return TRUE;
850 return FALSE;
853 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
854 JoystickImpl **pdev, unsigned short index)
856 DWORD i;
857 IOHIDDeviceRef device;
858 JoystickImpl* newDevice;
859 char name[MAX_PATH];
860 HRESULT hr;
861 LPDIDATAFORMAT df = NULL;
862 int idx = 0;
863 int axis_map[8]; /* max axes */
864 int slider_count = 0;
865 FFCAPABILITIES ffcaps;
867 TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
869 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
870 if (newDevice == 0) {
871 WARN("out of memory\n");
872 *pdev = 0;
873 return DIERR_OUTOFMEMORY;
876 newDevice->id = index;
878 newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID;
879 newDevice->generic.guidInstance.Data3 = index;
880 newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
881 newDevice->generic.joy_polldev = poll_osx_device_state;
883 /* get the device name */
884 get_osx_device_name(index, name, MAX_PATH);
885 TRACE("Name %s\n",name);
887 /* copy the device name */
888 newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
889 strcpy(newDevice->generic.name, name);
891 list_init(&newDevice->effects);
892 device = get_device_ref(index);
893 if(get_ff(device, &newDevice->ff) == S_OK){
894 newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;
896 hr = FFDeviceGetForceFeedbackCapabilities(newDevice->ff, &ffcaps);
897 if(SUCCEEDED(hr)){
898 TRACE("FF Capabilities:\n");
899 TRACE("\tsupportedEffects: 0x%x\n", (unsigned int)ffcaps.supportedEffects);
900 TRACE("\temulatedEffects: 0x%x\n", (unsigned int)ffcaps.emulatedEffects);
901 TRACE("\tsubType: 0x%x\n", (unsigned int)ffcaps.subType);
902 TRACE("\tnumFfAxes: %u\n", (unsigned int)ffcaps.numFfAxes);
903 TRACE("\tffAxes: [");
904 for(i = 0; i < ffcaps.numFfAxes; ++i){
905 TRACE("%s", osx_ff_axis_name(ffcaps.ffAxes[i]));
906 if(i < ffcaps.numFfAxes - 1)
907 TRACE(", ");
909 TRACE("]\n");
910 TRACE("\tstorageCapacity: %u\n", (unsigned int)ffcaps.storageCapacity);
911 TRACE("\tplaybackCapacity: %u\n", (unsigned int)ffcaps.playbackCapacity);
914 hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_RESET);
915 if(FAILED(hr))
916 WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_RESET) failed: %08x\n", hr);
918 hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_SETACTUATORSON);
919 if(FAILED(hr))
920 WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_SETACTUATORSON) failed: %08x\n", hr);
923 memset(axis_map, 0, sizeof(axis_map));
924 get_osx_device_elements(newDevice, axis_map);
926 TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
928 if (newDevice->generic.devcaps.dwButtons > 128)
930 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
931 newDevice->generic.devcaps.dwButtons = 128;
934 newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
935 newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
936 newDevice->generic.base.ref = 1;
937 newDevice->generic.base.dinput = dinput;
938 newDevice->generic.base.guid = *rguid;
939 InitializeCriticalSection(&newDevice->generic.base.crit);
940 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
942 /* Create copy of default data format */
943 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
944 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
946 df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
947 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
949 for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
951 int wine_obj = -1;
952 BOOL has_ff = FALSE;
953 switch (axis_map[i])
955 case kHIDUsage_GD_X:
956 wine_obj = 0;
957 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_X);
958 break;
959 case kHIDUsage_GD_Y:
960 wine_obj = 1;
961 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_Y);
962 break;
963 case kHIDUsage_GD_Z:
964 wine_obj = 2;
965 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_Z);
966 break;
967 case kHIDUsage_GD_Rx:
968 wine_obj = 3;
969 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RX);
970 break;
971 case kHIDUsage_GD_Ry:
972 wine_obj = 4;
973 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RY);
974 break;
975 case kHIDUsage_GD_Rz:
976 wine_obj = 5;
977 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RZ);
978 break;
979 case kHIDUsage_GD_Slider:
980 wine_obj = 6 + slider_count;
981 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_SLIDER(slider_count));
982 slider_count++;
983 break;
985 if (wine_obj < 0 ) continue;
987 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
988 df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
989 if(has_ff)
990 df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR;
991 ++idx;
994 for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
996 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
997 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
1000 for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
1002 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
1003 df->rgodf[idx ].pguid = &GUID_Button;
1004 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
1006 newDevice->generic.base.data_format.wine_df = df;
1008 /* initialize default properties */
1009 get_osx_device_elements_props(newDevice);
1011 IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
1013 EnterCriticalSection(&dinput->crit);
1014 list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
1015 LeaveCriticalSection(&dinput->crit);
1017 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
1018 newDevice->generic.devcaps.dwFlags |= DIDC_ATTACHED;
1019 if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
1020 newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
1021 else
1022 newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
1023 newDevice->generic.devcaps.dwFFSamplePeriod = 0;
1024 newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
1025 newDevice->generic.devcaps.dwFirmwareRevision = 0;
1026 newDevice->generic.devcaps.dwHardwareRevision = 0;
1027 newDevice->generic.devcaps.dwFFDriverVersion = 0;
1029 if (TRACE_ON(dinput)) {
1030 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
1031 _dump_DIDEVCAPS(&newDevice->generic.devcaps);
1034 *pdev = newDevice;
1036 return DI_OK;
1038 FAILED:
1039 hr = DIERR_OUTOFMEMORY;
1040 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
1041 HeapFree(GetProcessHeap(), 0, df);
1042 release_DataFormat(&newDevice->generic.base.data_format);
1043 HeapFree(GetProcessHeap(),0,newDevice->generic.name);
1044 HeapFree(GetProcessHeap(),0,newDevice);
1045 *pdev = 0;
1047 return hr;
1050 /******************************************************************************
1051 * get_joystick_index : Get the joystick index from a given GUID
1053 static unsigned short get_joystick_index(REFGUID guid)
1055 GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
1056 GUID dev_guid = *guid;
1058 wine_joystick.Data3 = 0;
1059 dev_guid.Data3 = 0;
1061 /* for the standard joystick GUID use index 0 */
1062 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
1064 /* for the wine joystick GUIDs use the index stored in Data3 */
1065 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
1067 return 0xffff;
1070 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
1072 unsigned short index;
1073 int joystick_devices_count;
1075 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
1076 *pdev = NULL;
1078 if ((joystick_devices_count = find_joystick_devices()) == 0)
1079 return DIERR_DEVICENOTREG;
1081 if ((index = get_joystick_index(rguid)) < 0xffff &&
1082 joystick_devices_count && index < joystick_devices_count)
1084 JoystickImpl *This;
1085 HRESULT hr;
1087 if (riid == NULL)
1088 ;/* nothing */
1089 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
1090 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
1091 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
1092 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
1094 unicode = 0;
1096 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
1097 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
1098 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
1099 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
1101 unicode = 1;
1103 else
1105 WARN("no interface\n");
1106 return DIERR_NOINTERFACE;
1109 hr = alloc_device(rguid, dinput, &This, index);
1110 if (!This) return hr;
1112 if (unicode)
1113 *pdev = &This->generic.base.IDirectInputDevice8W_iface;
1114 else
1115 *pdev = &This->generic.base.IDirectInputDevice8A_iface;
1116 return hr;
1119 return DIERR_DEVICENOTREG;
1122 static HRESULT osx_set_autocenter(JoystickImpl *This,
1123 const DIPROPDWORD *header)
1125 UInt32 v;
1126 HRESULT hr;
1127 if(!This->ff)
1128 return DIERR_UNSUPPORTED;
1129 v = header->dwData;
1130 hr = osx_to_win32_hresult(FFDeviceSetForceFeedbackProperty(This->ff, FFPROP_AUTOCENTER, &v));
1131 TRACE("returning: %08x\n", hr);
1132 return hr;
1135 static HRESULT osx_set_ffgain(JoystickImpl *This, const DIPROPDWORD *header)
1137 UInt32 v;
1138 HRESULT hr;
1139 if(!This->ff)
1140 return DIERR_UNSUPPORTED;
1141 v = header->dwData;
1142 hr = osx_to_win32_hresult(FFDeviceSetForceFeedbackProperty(This->ff, FFPROP_FFGAIN, &v));
1143 TRACE("returning: %08x\n", hr);
1144 return hr;
1147 static HRESULT WINAPI JoystickWImpl_SetProperty(IDirectInputDevice8W *iface,
1148 const GUID *prop, const DIPROPHEADER *header)
1150 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1152 TRACE("%p %s %p\n", This, debugstr_guid(prop), header);
1154 switch(LOWORD(prop))
1156 case (DWORD_PTR)DIPROP_AUTOCENTER:
1157 return osx_set_autocenter(This, (const DIPROPDWORD *)header);
1158 case (DWORD_PTR)DIPROP_FFGAIN:
1159 return osx_set_ffgain(This, (const DIPROPDWORD *)header);
1162 return JoystickWGenericImpl_SetProperty(iface, prop, header);
1165 static HRESULT WINAPI JoystickAImpl_SetProperty(IDirectInputDevice8A *iface,
1166 const GUID *prop, const DIPROPHEADER *header)
1168 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1170 TRACE("%p %s %p\n", This, debugstr_guid(prop), header);
1172 switch(LOWORD(prop))
1174 case (DWORD_PTR)DIPROP_AUTOCENTER:
1175 return osx_set_autocenter(This, (const DIPROPDWORD *)header);
1176 case (DWORD_PTR)DIPROP_FFGAIN:
1177 return osx_set_ffgain(This, (const DIPROPDWORD *)header);
1180 return JoystickAGenericImpl_SetProperty(iface, prop, header);
1183 static CFUUIDRef effect_win_to_mac(const GUID *effect)
1185 #define DO_MAP(X) \
1186 if(IsEqualGUID(&GUID_##X, effect)) \
1187 return kFFEffectType_##X##_ID;
1188 DO_MAP(ConstantForce)
1189 DO_MAP(RampForce)
1190 DO_MAP(Square)
1191 DO_MAP(Sine)
1192 DO_MAP(Triangle)
1193 DO_MAP(SawtoothUp)
1194 DO_MAP(SawtoothDown)
1195 DO_MAP(Spring)
1196 DO_MAP(Damper)
1197 DO_MAP(Inertia)
1198 DO_MAP(Friction)
1199 DO_MAP(CustomForce)
1200 #undef DO_MAP
1201 WARN("Unknown effect GUID! %s\n", debugstr_guid(effect));
1202 return 0;
1205 static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface,
1206 const GUID *type, const DIEFFECT *params, IDirectInputEffect **out,
1207 IUnknown *outer)
1209 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1210 EffectImpl *effect;
1211 HRESULT hr;
1213 TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
1214 dump_DIEFFECT(params, type, 0);
1216 if(!This->ff){
1217 TRACE("No force feedback support\n");
1218 *out = NULL;
1219 return S_OK;
1222 if(outer)
1223 WARN("aggregation not implemented\n");
1225 effect = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
1226 effect->IDirectInputEffect_iface.lpVtbl = &EffectVtbl;
1227 effect->ref = 1;
1228 effect->guid = *type;
1229 effect->device = This;
1231 /* Mac's FFEFFECT and Win's DIEFFECT are binary identical. */
1232 hr = osx_to_win32_hresult(FFDeviceCreateEffect(This->ff,
1233 effect_win_to_mac(type), (FFEFFECT*)params, &effect->effect));
1234 if(FAILED(hr)){
1235 WARN("FFDeviceCreateEffect failed: %08x\n", hr);
1236 HeapFree(GetProcessHeap(), 0, effect);
1237 return hr;
1240 list_add_tail(&This->effects, &effect->entry);
1241 *out = &effect->IDirectInputEffect_iface;
1243 TRACE("allocated effect: %p\n", effect);
1245 return S_OK;
1248 static HRESULT WINAPI JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface,
1249 const GUID *type, const DIEFFECT *params, IDirectInputEffect **out,
1250 IUnknown *outer)
1252 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1254 TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
1256 return JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface,
1257 type, params, out, outer);
1260 static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W *iface,
1261 DWORD flags)
1263 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1264 HRESULT hr;
1266 TRACE("%p 0x%x\n", This, flags);
1268 if(!This->ff)
1269 return DI_NOEFFECT;
1271 hr = osx_to_win32_hresult(FFDeviceSendForceFeedbackCommand(This->ff, flags));
1272 if(FAILED(hr)){
1273 WARN("FFDeviceSendForceFeedbackCommand failed: %08x\n", hr);
1274 return hr;
1277 return S_OK;
1280 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(IDirectInputDevice8A *iface,
1281 DWORD flags)
1283 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1285 TRACE("%p 0x%x\n", This, flags);
1287 return JoystickWImpl_SendForceFeedbackCommand(&This->generic.base.IDirectInputDevice8W_iface, flags);
1290 const struct dinput_device joystick_osx_device = {
1291 "Wine OS X joystick driver",
1292 joydev_enum_deviceA,
1293 joydev_enum_deviceW,
1294 joydev_create_device
1297 static const IDirectInputDevice8AVtbl JoystickAvt =
1299 IDirectInputDevice2AImpl_QueryInterface,
1300 IDirectInputDevice2AImpl_AddRef,
1301 IDirectInputDevice2AImpl_Release,
1302 JoystickAGenericImpl_GetCapabilities,
1303 IDirectInputDevice2AImpl_EnumObjects,
1304 JoystickAGenericImpl_GetProperty,
1305 JoystickAImpl_SetProperty,
1306 IDirectInputDevice2AImpl_Acquire,
1307 IDirectInputDevice2AImpl_Unacquire,
1308 JoystickAGenericImpl_GetDeviceState,
1309 IDirectInputDevice2AImpl_GetDeviceData,
1310 IDirectInputDevice2AImpl_SetDataFormat,
1311 IDirectInputDevice2AImpl_SetEventNotification,
1312 IDirectInputDevice2AImpl_SetCooperativeLevel,
1313 JoystickAGenericImpl_GetObjectInfo,
1314 JoystickAGenericImpl_GetDeviceInfo,
1315 IDirectInputDevice2AImpl_RunControlPanel,
1316 IDirectInputDevice2AImpl_Initialize,
1317 JoystickAImpl_CreateEffect,
1318 IDirectInputDevice2AImpl_EnumEffects,
1319 IDirectInputDevice2AImpl_GetEffectInfo,
1320 IDirectInputDevice2AImpl_GetForceFeedbackState,
1321 JoystickAImpl_SendForceFeedbackCommand,
1322 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1323 IDirectInputDevice2AImpl_Escape,
1324 JoystickAGenericImpl_Poll,
1325 IDirectInputDevice2AImpl_SendDeviceData,
1326 IDirectInputDevice7AImpl_EnumEffectsInFile,
1327 IDirectInputDevice7AImpl_WriteEffectToFile,
1328 JoystickAGenericImpl_BuildActionMap,
1329 JoystickAGenericImpl_SetActionMap,
1330 IDirectInputDevice8AImpl_GetImageInfo
1333 static const IDirectInputDevice8WVtbl JoystickWvt =
1335 IDirectInputDevice2WImpl_QueryInterface,
1336 IDirectInputDevice2WImpl_AddRef,
1337 IDirectInputDevice2WImpl_Release,
1338 JoystickWGenericImpl_GetCapabilities,
1339 IDirectInputDevice2WImpl_EnumObjects,
1340 JoystickWGenericImpl_GetProperty,
1341 JoystickWImpl_SetProperty,
1342 IDirectInputDevice2WImpl_Acquire,
1343 IDirectInputDevice2WImpl_Unacquire,
1344 JoystickWGenericImpl_GetDeviceState,
1345 IDirectInputDevice2WImpl_GetDeviceData,
1346 IDirectInputDevice2WImpl_SetDataFormat,
1347 IDirectInputDevice2WImpl_SetEventNotification,
1348 IDirectInputDevice2WImpl_SetCooperativeLevel,
1349 JoystickWGenericImpl_GetObjectInfo,
1350 JoystickWGenericImpl_GetDeviceInfo,
1351 IDirectInputDevice2WImpl_RunControlPanel,
1352 IDirectInputDevice2WImpl_Initialize,
1353 JoystickWImpl_CreateEffect,
1354 IDirectInputDevice2WImpl_EnumEffects,
1355 IDirectInputDevice2WImpl_GetEffectInfo,
1356 IDirectInputDevice2WImpl_GetForceFeedbackState,
1357 JoystickWImpl_SendForceFeedbackCommand,
1358 IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
1359 IDirectInputDevice2WImpl_Escape,
1360 JoystickWGenericImpl_Poll,
1361 IDirectInputDevice2WImpl_SendDeviceData,
1362 IDirectInputDevice7WImpl_EnumEffectsInFile,
1363 IDirectInputDevice7WImpl_WriteEffectToFile,
1364 JoystickWGenericImpl_BuildActionMap,
1365 JoystickWGenericImpl_SetActionMap,
1366 IDirectInputDevice8WImpl_GetImageInfo
1369 static HRESULT WINAPI effect_QueryInterface(IDirectInputEffect *iface,
1370 const GUID *guid, void **out)
1372 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1374 TRACE("%p %s %p\n", This, debugstr_guid(guid), out);
1376 if(IsEqualIID(guid, &IID_IDirectInputEffect)){
1377 *out = iface;
1378 IDirectInputEffect_AddRef(iface);
1379 return S_OK;
1382 return E_NOINTERFACE;
1385 static ULONG WINAPI effect_AddRef(IDirectInputEffect *iface)
1387 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1388 ULONG ref = InterlockedIncrement(&This->ref);
1389 TRACE("%p, ref is now: %u\n", This, ref);
1390 return ref;
1393 static ULONG WINAPI effect_Release(IDirectInputEffect *iface)
1395 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1396 ULONG ref = InterlockedDecrement(&This->ref);
1397 TRACE("%p, ref is now: %u\n", This, ref);
1399 if(!ref){
1400 list_remove(&This->entry);
1401 FFDeviceReleaseEffect(This->device->ff, This->effect);
1402 HeapFree(GetProcessHeap(), 0, This);
1405 return ref;
1408 static HRESULT WINAPI effect_Initialize(IDirectInputEffect *iface, HINSTANCE hinst,
1409 DWORD version, const GUID *guid)
1411 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1412 TRACE("%p %p 0x%x, %s\n", This, hinst, version, debugstr_guid(guid));
1413 return S_OK;
1416 static HRESULT WINAPI effect_GetEffectGuid(IDirectInputEffect *iface, GUID *out)
1418 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1419 TRACE("%p %p\n", This, out);
1420 *out = This->guid;
1421 return S_OK;
1424 static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface,
1425 DIEFFECT *effect, DWORD flags)
1427 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1428 TRACE("%p %p 0x%x\n", This, effect, flags);
1429 return osx_to_win32_hresult(FFEffectGetParameters(This->effect, (FFEFFECT*)effect, flags));
1432 static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface,
1433 const DIEFFECT *effect, DWORD flags)
1435 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1436 TRACE("%p %p 0x%x\n", This, effect, flags);
1437 dump_DIEFFECT(effect, &This->guid, flags);
1438 return osx_to_win32_hresult(FFEffectSetParameters(This->effect, (FFEFFECT*)effect, flags));
1441 static HRESULT WINAPI effect_Start(IDirectInputEffect *iface, DWORD iterations,
1442 DWORD flags)
1444 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1445 TRACE("%p 0x%x 0x%x\n", This, iterations, flags);
1446 return osx_to_win32_hresult(FFEffectStart(This->effect, iterations, flags));
1449 static HRESULT WINAPI effect_Stop(IDirectInputEffect *iface)
1451 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1452 TRACE("%p\n", This);
1453 return osx_to_win32_hresult(FFEffectStop(This->effect));
1456 static HRESULT WINAPI effect_GetEffectStatus(IDirectInputEffect *iface, DWORD *flags)
1458 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1459 TRACE("%p %p\n", This, flags);
1460 return osx_to_win32_hresult(FFEffectGetEffectStatus(This->effect, (UInt32*)flags));
1463 static HRESULT WINAPI effect_Download(IDirectInputEffect *iface)
1465 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1466 TRACE("%p\n", This);
1467 return osx_to_win32_hresult(FFEffectDownload(This->effect));
1470 static HRESULT WINAPI effect_Unload(IDirectInputEffect *iface)
1472 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1473 TRACE("%p\n", This);
1474 return osx_to_win32_hresult(FFEffectUnload(This->effect));
1477 static HRESULT WINAPI effect_Escape(IDirectInputEffect *iface, DIEFFESCAPE *escape)
1479 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1480 TRACE("%p %p\n", This, escape);
1481 return osx_to_win32_hresult(FFEffectEscape(This->effect, (FFEFFESCAPE*)escape));
1484 static const IDirectInputEffectVtbl EffectVtbl = {
1485 effect_QueryInterface,
1486 effect_AddRef,
1487 effect_Release,
1488 effect_Initialize,
1489 effect_GetEffectGuid,
1490 effect_GetParameters,
1491 effect_SetParameters,
1492 effect_Start,
1493 effect_Stop,
1494 effect_GetEffectStatus,
1495 effect_Download,
1496 effect_Unload,
1497 effect_Escape
1500 #else /* HAVE_IOHIDMANAGERCREATE */
1502 const struct dinput_device joystick_osx_device = {
1503 "Wine OS X joystick driver",
1504 NULL,
1505 NULL,
1506 NULL
1509 #endif /* HAVE_IOHIDMANAGERCREATE */