dinput: Debug print DIEFFECT structure.
[wine.git] / dlls / dinput / joystick_osx.c
blobfe7c10fea0298256b6b7879b72738b1a2a58e528
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 HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
845 JoystickImpl **pdev, unsigned short index)
847 DWORD i;
848 IOHIDDeviceRef device;
849 JoystickImpl* newDevice;
850 char name[MAX_PATH];
851 HRESULT hr;
852 LPDIDATAFORMAT df = NULL;
853 int idx = 0;
854 int axis_map[8]; /* max axes */
855 int slider_count = 0;
856 FFCAPABILITIES ffcaps;
858 TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
860 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
861 if (newDevice == 0) {
862 WARN("out of memory\n");
863 *pdev = 0;
864 return DIERR_OUTOFMEMORY;
867 newDevice->id = index;
869 newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID;
870 newDevice->generic.guidInstance.Data3 = index;
871 newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
872 newDevice->generic.joy_polldev = poll_osx_device_state;
874 /* get the device name */
875 get_osx_device_name(index, name, MAX_PATH);
876 TRACE("Name %s\n",name);
878 /* copy the device name */
879 newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
880 strcpy(newDevice->generic.name, name);
882 list_init(&newDevice->effects);
883 device = get_device_ref(index);
884 if(get_ff(device, &newDevice->ff) == S_OK){
885 newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;
887 hr = FFDeviceGetForceFeedbackCapabilities(newDevice->ff, &ffcaps);
888 if(SUCCEEDED(hr)){
889 TRACE("FF Capabilities:\n");
890 TRACE("\tsupportedEffects: 0x%x\n", (unsigned int)ffcaps.supportedEffects);
891 TRACE("\temulatedEffects: 0x%x\n", (unsigned int)ffcaps.emulatedEffects);
892 TRACE("\tsubType: 0x%x\n", (unsigned int)ffcaps.subType);
893 TRACE("\tnumFfAxes: %u\n", (unsigned int)ffcaps.numFfAxes);
894 TRACE("\tffAxes: [");
895 for(i = 0; i < ffcaps.numFfAxes; ++i){
896 TRACE("%s", osx_ff_axis_name(ffcaps.ffAxes[i]));
897 if(i < ffcaps.numFfAxes - 1)
898 TRACE(", ");
900 TRACE("]\n");
901 TRACE("\tstorageCapacity: %u\n", (unsigned int)ffcaps.storageCapacity);
902 TRACE("\tplaybackCapacity: %u\n", (unsigned int)ffcaps.playbackCapacity);
905 hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_RESET);
906 if(FAILED(hr))
907 WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_RESET) failed: %08x\n", hr);
909 hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_SETACTUATORSON);
910 if(FAILED(hr))
911 WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_SETACTUATORSON) failed: %08x\n", hr);
914 memset(axis_map, 0, sizeof(axis_map));
915 get_osx_device_elements(newDevice, axis_map);
917 TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
919 if (newDevice->generic.devcaps.dwButtons > 128)
921 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
922 newDevice->generic.devcaps.dwButtons = 128;
925 newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
926 newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
927 newDevice->generic.base.ref = 1;
928 newDevice->generic.base.dinput = dinput;
929 newDevice->generic.base.guid = *rguid;
930 InitializeCriticalSection(&newDevice->generic.base.crit);
931 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
933 /* Create copy of default data format */
934 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
935 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
937 df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
938 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
940 for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
942 int wine_obj = -1;
943 switch (axis_map[i])
945 case kHIDUsage_GD_X: wine_obj = 0; break;
946 case kHIDUsage_GD_Y: wine_obj = 1; break;
947 case kHIDUsage_GD_Z: wine_obj = 2; break;
948 case kHIDUsage_GD_Rx: wine_obj = 3; break;
949 case kHIDUsage_GD_Ry: wine_obj = 4; break;
950 case kHIDUsage_GD_Rz: wine_obj = 5; break;
951 case kHIDUsage_GD_Slider:
952 wine_obj = 6 + slider_count;
953 slider_count++;
954 break;
956 if (wine_obj < 0 ) continue;
958 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
959 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
962 for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
964 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
965 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
968 for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
970 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
971 df->rgodf[idx ].pguid = &GUID_Button;
972 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
974 newDevice->generic.base.data_format.wine_df = df;
976 /* initialize default properties */
977 get_osx_device_elements_props(newDevice);
979 IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
981 EnterCriticalSection(&dinput->crit);
982 list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
983 LeaveCriticalSection(&dinput->crit);
985 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
986 newDevice->generic.devcaps.dwFlags |= DIDC_ATTACHED;
987 if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
988 newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
989 else
990 newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
991 newDevice->generic.devcaps.dwFFSamplePeriod = 0;
992 newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
993 newDevice->generic.devcaps.dwFirmwareRevision = 0;
994 newDevice->generic.devcaps.dwHardwareRevision = 0;
995 newDevice->generic.devcaps.dwFFDriverVersion = 0;
997 if (TRACE_ON(dinput)) {
998 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
999 _dump_DIDEVCAPS(&newDevice->generic.devcaps);
1002 *pdev = newDevice;
1004 return DI_OK;
1006 FAILED:
1007 hr = DIERR_OUTOFMEMORY;
1008 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
1009 HeapFree(GetProcessHeap(), 0, df);
1010 release_DataFormat(&newDevice->generic.base.data_format);
1011 HeapFree(GetProcessHeap(),0,newDevice->generic.name);
1012 HeapFree(GetProcessHeap(),0,newDevice);
1013 *pdev = 0;
1015 return hr;
1018 /******************************************************************************
1019 * get_joystick_index : Get the joystick index from a given GUID
1021 static unsigned short get_joystick_index(REFGUID guid)
1023 GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
1024 GUID dev_guid = *guid;
1026 wine_joystick.Data3 = 0;
1027 dev_guid.Data3 = 0;
1029 /* for the standard joystick GUID use index 0 */
1030 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
1032 /* for the wine joystick GUIDs use the index stored in Data3 */
1033 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
1035 return 0xffff;
1038 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
1040 unsigned short index;
1041 int joystick_devices_count;
1043 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
1044 *pdev = NULL;
1046 if ((joystick_devices_count = find_joystick_devices()) == 0)
1047 return DIERR_DEVICENOTREG;
1049 if ((index = get_joystick_index(rguid)) < 0xffff &&
1050 joystick_devices_count && index < joystick_devices_count)
1052 JoystickImpl *This;
1053 HRESULT hr;
1055 if (riid == NULL)
1056 ;/* nothing */
1057 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
1058 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
1059 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
1060 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
1062 unicode = 0;
1064 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
1065 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
1066 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
1067 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
1069 unicode = 1;
1071 else
1073 WARN("no interface\n");
1074 return DIERR_NOINTERFACE;
1077 hr = alloc_device(rguid, dinput, &This, index);
1078 if (!This) return hr;
1080 if (unicode)
1081 *pdev = &This->generic.base.IDirectInputDevice8W_iface;
1082 else
1083 *pdev = &This->generic.base.IDirectInputDevice8A_iface;
1084 return hr;
1087 return DIERR_DEVICENOTREG;
1090 static CFUUIDRef effect_win_to_mac(const GUID *effect)
1092 #define DO_MAP(X) \
1093 if(IsEqualGUID(&GUID_##X, effect)) \
1094 return kFFEffectType_##X##_ID;
1095 DO_MAP(ConstantForce)
1096 DO_MAP(RampForce)
1097 DO_MAP(Square)
1098 DO_MAP(Sine)
1099 DO_MAP(Triangle)
1100 DO_MAP(SawtoothUp)
1101 DO_MAP(SawtoothDown)
1102 DO_MAP(Spring)
1103 DO_MAP(Damper)
1104 DO_MAP(Inertia)
1105 DO_MAP(Friction)
1106 DO_MAP(CustomForce)
1107 #undef DO_MAP
1108 WARN("Unknown effect GUID! %s\n", debugstr_guid(effect));
1109 return 0;
1112 static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface,
1113 const GUID *type, const DIEFFECT *params, IDirectInputEffect **out,
1114 IUnknown *outer)
1116 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1117 EffectImpl *effect;
1118 HRESULT hr;
1120 TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
1121 dump_DIEFFECT(params, type, 0);
1123 if(!This->ff){
1124 TRACE("No force feedback support\n");
1125 *out = NULL;
1126 return S_OK;
1129 if(outer)
1130 WARN("aggregation not implemented\n");
1132 effect = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
1133 effect->IDirectInputEffect_iface.lpVtbl = &EffectVtbl;
1134 effect->ref = 1;
1135 effect->guid = *type;
1136 effect->device = This;
1138 /* Mac's FFEFFECT and Win's DIEFFECT are binary identical. */
1139 hr = osx_to_win32_hresult(FFDeviceCreateEffect(This->ff,
1140 effect_win_to_mac(type), (FFEFFECT*)params, &effect->effect));
1141 if(FAILED(hr)){
1142 WARN("FFDeviceCreateEffect failed: %08x\n", hr);
1143 HeapFree(GetProcessHeap(), 0, effect);
1144 return hr;
1147 list_add_tail(&This->effects, &effect->entry);
1148 *out = &effect->IDirectInputEffect_iface;
1150 TRACE("allocated effect: %p\n", effect);
1152 return S_OK;
1155 static HRESULT WINAPI JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface,
1156 const GUID *type, const DIEFFECT *params, IDirectInputEffect **out,
1157 IUnknown *outer)
1159 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1161 TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
1163 return JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface,
1164 type, params, out, outer);
1167 const struct dinput_device joystick_osx_device = {
1168 "Wine OS X joystick driver",
1169 joydev_enum_deviceA,
1170 joydev_enum_deviceW,
1171 joydev_create_device
1174 static const IDirectInputDevice8AVtbl JoystickAvt =
1176 IDirectInputDevice2AImpl_QueryInterface,
1177 IDirectInputDevice2AImpl_AddRef,
1178 IDirectInputDevice2AImpl_Release,
1179 JoystickAGenericImpl_GetCapabilities,
1180 IDirectInputDevice2AImpl_EnumObjects,
1181 JoystickAGenericImpl_GetProperty,
1182 JoystickAGenericImpl_SetProperty,
1183 IDirectInputDevice2AImpl_Acquire,
1184 IDirectInputDevice2AImpl_Unacquire,
1185 JoystickAGenericImpl_GetDeviceState,
1186 IDirectInputDevice2AImpl_GetDeviceData,
1187 IDirectInputDevice2AImpl_SetDataFormat,
1188 IDirectInputDevice2AImpl_SetEventNotification,
1189 IDirectInputDevice2AImpl_SetCooperativeLevel,
1190 JoystickAGenericImpl_GetObjectInfo,
1191 JoystickAGenericImpl_GetDeviceInfo,
1192 IDirectInputDevice2AImpl_RunControlPanel,
1193 IDirectInputDevice2AImpl_Initialize,
1194 JoystickAImpl_CreateEffect,
1195 IDirectInputDevice2AImpl_EnumEffects,
1196 IDirectInputDevice2AImpl_GetEffectInfo,
1197 IDirectInputDevice2AImpl_GetForceFeedbackState,
1198 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1199 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1200 IDirectInputDevice2AImpl_Escape,
1201 JoystickAGenericImpl_Poll,
1202 IDirectInputDevice2AImpl_SendDeviceData,
1203 IDirectInputDevice7AImpl_EnumEffectsInFile,
1204 IDirectInputDevice7AImpl_WriteEffectToFile,
1205 JoystickAGenericImpl_BuildActionMap,
1206 JoystickAGenericImpl_SetActionMap,
1207 IDirectInputDevice8AImpl_GetImageInfo
1210 static const IDirectInputDevice8WVtbl JoystickWvt =
1212 IDirectInputDevice2WImpl_QueryInterface,
1213 IDirectInputDevice2WImpl_AddRef,
1214 IDirectInputDevice2WImpl_Release,
1215 JoystickWGenericImpl_GetCapabilities,
1216 IDirectInputDevice2WImpl_EnumObjects,
1217 JoystickWGenericImpl_GetProperty,
1218 JoystickWGenericImpl_SetProperty,
1219 IDirectInputDevice2WImpl_Acquire,
1220 IDirectInputDevice2WImpl_Unacquire,
1221 JoystickWGenericImpl_GetDeviceState,
1222 IDirectInputDevice2WImpl_GetDeviceData,
1223 IDirectInputDevice2WImpl_SetDataFormat,
1224 IDirectInputDevice2WImpl_SetEventNotification,
1225 IDirectInputDevice2WImpl_SetCooperativeLevel,
1226 JoystickWGenericImpl_GetObjectInfo,
1227 JoystickWGenericImpl_GetDeviceInfo,
1228 IDirectInputDevice2WImpl_RunControlPanel,
1229 IDirectInputDevice2WImpl_Initialize,
1230 JoystickWImpl_CreateEffect,
1231 IDirectInputDevice2WImpl_EnumEffects,
1232 IDirectInputDevice2WImpl_GetEffectInfo,
1233 IDirectInputDevice2WImpl_GetForceFeedbackState,
1234 IDirectInputDevice2WImpl_SendForceFeedbackCommand,
1235 IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
1236 IDirectInputDevice2WImpl_Escape,
1237 JoystickWGenericImpl_Poll,
1238 IDirectInputDevice2WImpl_SendDeviceData,
1239 IDirectInputDevice7WImpl_EnumEffectsInFile,
1240 IDirectInputDevice7WImpl_WriteEffectToFile,
1241 JoystickWGenericImpl_BuildActionMap,
1242 JoystickWGenericImpl_SetActionMap,
1243 IDirectInputDevice8WImpl_GetImageInfo
1246 static HRESULT WINAPI effect_QueryInterface(IDirectInputEffect *iface,
1247 const GUID *guid, void **out)
1249 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1251 TRACE("%p %s %p\n", This, debugstr_guid(guid), out);
1253 if(IsEqualIID(guid, &IID_IDirectInputEffect)){
1254 *out = iface;
1255 IDirectInputEffect_AddRef(iface);
1256 return S_OK;
1259 return E_NOINTERFACE;
1262 static ULONG WINAPI effect_AddRef(IDirectInputEffect *iface)
1264 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1265 ULONG ref = InterlockedIncrement(&This->ref);
1266 TRACE("%p, ref is now: %u\n", This, ref);
1267 return ref;
1270 static ULONG WINAPI effect_Release(IDirectInputEffect *iface)
1272 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1273 ULONG ref = InterlockedDecrement(&This->ref);
1274 TRACE("%p, ref is now: %u\n", This, ref);
1276 if(!ref){
1277 list_remove(&This->entry);
1278 FFDeviceReleaseEffect(This->device->ff, This->effect);
1279 HeapFree(GetProcessHeap(), 0, This);
1282 return ref;
1285 static HRESULT WINAPI effect_Initialize(IDirectInputEffect *iface, HINSTANCE hinst,
1286 DWORD version, const GUID *guid)
1288 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1289 TRACE("%p %p 0x%x, %s\n", This, hinst, version, debugstr_guid(guid));
1290 return S_OK;
1293 static HRESULT WINAPI effect_GetEffectGuid(IDirectInputEffect *iface, GUID *out)
1295 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1296 TRACE("%p %p\n", This, out);
1297 *out = This->guid;
1298 return S_OK;
1301 static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface,
1302 DIEFFECT *effect, DWORD flags)
1304 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1305 TRACE("%p %p 0x%x\n", This, effect, flags);
1306 return osx_to_win32_hresult(FFEffectGetParameters(This->effect, (FFEFFECT*)effect, flags));
1309 static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface,
1310 const DIEFFECT *effect, DWORD flags)
1312 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1313 TRACE("%p %p 0x%x\n", This, effect, flags);
1314 dump_DIEFFECT(effect, &This->guid, flags);
1315 return osx_to_win32_hresult(FFEffectSetParameters(This->effect, (FFEFFECT*)effect, flags));
1318 static HRESULT WINAPI effect_Start(IDirectInputEffect *iface, DWORD iterations,
1319 DWORD flags)
1321 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1322 TRACE("%p 0x%x 0x%x\n", This, iterations, flags);
1323 return osx_to_win32_hresult(FFEffectStart(This->effect, iterations, flags));
1326 static HRESULT WINAPI effect_Stop(IDirectInputEffect *iface)
1328 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1329 TRACE("%p\n", This);
1330 return osx_to_win32_hresult(FFEffectStop(This->effect));
1333 static HRESULT WINAPI effect_GetEffectStatus(IDirectInputEffect *iface, DWORD *flags)
1335 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1336 TRACE("%p %p\n", This, flags);
1337 return osx_to_win32_hresult(FFEffectGetEffectStatus(This->effect, (UInt32*)flags));
1340 static HRESULT WINAPI effect_Download(IDirectInputEffect *iface)
1342 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1343 TRACE("%p\n", This);
1344 return osx_to_win32_hresult(FFEffectDownload(This->effect));
1347 static HRESULT WINAPI effect_Unload(IDirectInputEffect *iface)
1349 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1350 TRACE("%p\n", This);
1351 return osx_to_win32_hresult(FFEffectUnload(This->effect));
1354 static HRESULT WINAPI effect_Escape(IDirectInputEffect *iface, DIEFFESCAPE *escape)
1356 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1357 TRACE("%p %p\n", This, escape);
1358 return osx_to_win32_hresult(FFEffectEscape(This->effect, (FFEFFESCAPE*)escape));
1361 static const IDirectInputEffectVtbl EffectVtbl = {
1362 effect_QueryInterface,
1363 effect_AddRef,
1364 effect_Release,
1365 effect_Initialize,
1366 effect_GetEffectGuid,
1367 effect_GetParameters,
1368 effect_SetParameters,
1369 effect_Start,
1370 effect_Stop,
1371 effect_GetEffectStatus,
1372 effect_Download,
1373 effect_Unload,
1374 effect_Escape
1377 #else /* HAVE_IOHIDMANAGERCREATE */
1379 const struct dinput_device joystick_osx_device = {
1380 "Wine OS X joystick driver",
1381 NULL,
1382 NULL,
1383 NULL
1386 #endif /* HAVE_IOHIDMANAGERCREATE */