dinput: Check array indexes to avoid exceeding array bounds.
[wine/multimedia.git] / dlls / dinput / joystick_osx.c
blob69d8bd658abe62113c02baaf5dbeed4bd5719bc8
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 hid_manager = NULL;
99 static CFMutableArrayRef device_main_elements = 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 CFArrayRef elements;
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 device_main_element;
187 IOHIDDeviceRef hid_device;
189 if (!device_main_elements || id >= CFArrayGetCount(device_main_elements))
190 return 0;
192 device_main_element = (IOHIDElementRef)CFArrayGetValueAtIndex(device_main_elements, id);
193 if (!device_main_element)
195 ERR("Invalid Element requested %i\n",id);
196 return 0;
199 hid_device = IOHIDElementGetDevice(device_main_element);
200 if (!hid_device)
202 ERR("Invalid Device requested %i\n",id);
203 return 0;
206 return hid_device;
209 static HRESULT get_ff(IOHIDDeviceRef device, FFDeviceObjectReference *ret)
211 io_service_t service;
212 CFMutableDictionaryRef matching;
213 CFTypeRef location_id;
215 matching = IOServiceMatching(kIOHIDDeviceKey);
216 if(!matching){
217 WARN("IOServiceMatching failed, force feedback disabled\n");
218 return DIERR_DEVICENOTREG;
221 location_id = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey));
222 if(!location_id){
223 CFRelease(matching);
224 WARN("IOHIDDeviceGetProperty failed, force feedback disabled\n");
225 return DIERR_DEVICENOTREG;
228 CFDictionaryAddValue(matching, CFSTR(kIOHIDLocationIDKey), location_id);
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 create_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 page = CFNumberCreate( kCFAllocatorDefault,
249 kCFNumberIntType, &number);
251 if (page)
253 CFNumberRef cf_usage;
255 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ), page );
256 CFRelease( page );
258 cf_usage = CFNumberCreate( kCFAllocatorDefault,
259 kCFNumberIntType, &usage);
260 if (cf_usage)
262 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ), cf_usage );
263 CFRelease( cf_usage );
265 else
267 ERR("CFNumberCreate() failed.\n");
268 return NULL;
271 else
273 ERR("CFNumberCreate failed.\n");
274 return NULL;
277 else
279 ERR("CFDictionaryCreateMutable failed.\n");
280 return NULL;
283 return result;
286 static CFIndex find_top_level(IOHIDDeviceRef hid_device, CFMutableArrayRef main_elements)
288 CFArrayRef elements;
289 CFIndex total = 0;
291 if (!hid_device)
292 return 0;
294 elements = IOHIDDeviceCopyMatchingElements(hid_device, NULL, 0);
296 if (elements)
298 CFIndex idx, cnt = CFArrayGetCount(elements);
299 for (idx=0; idx<cnt; idx++)
301 IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, idx);
302 int type = IOHIDElementGetType(element);
304 /* Check for top-level gaming device collections */
305 if (type == kIOHIDElementTypeCollection && IOHIDElementGetParent(element) == 0)
307 int usage_page = IOHIDElementGetUsagePage(element);
308 int usage = IOHIDElementGetUsage(element);
310 if (usage_page == kHIDPage_GenericDesktop &&
311 (usage == kHIDUsage_GD_Joystick || usage == kHIDUsage_GD_GamePad))
313 CFArrayAppendValue(main_elements, element);
314 total++;
319 return total;
322 static void get_element_children(IOHIDElementRef element, CFMutableArrayRef all_children)
324 CFIndex idx, cnt;
325 CFArrayRef element_children = IOHIDElementGetChildren(element);
327 cnt = CFArrayGetCount(element_children);
329 /* Either add the element to the array or grab its children */
330 for (idx=0; idx<cnt; idx++)
332 IOHIDElementRef child;
334 child = (IOHIDElementRef)CFArrayGetValueAtIndex(element_children, idx);
335 if (IOHIDElementGetType(child) == kIOHIDElementTypeCollection)
336 get_element_children(child, all_children);
337 else
338 CFArrayAppendValue(all_children, child);
342 static int find_osx_devices(void)
344 CFMutableDictionaryRef result;
345 CFSetRef devset;
346 CFMutableArrayRef matching;
348 hid_manager = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
349 if (IOHIDManagerOpen( hid_manager, 0 ) != kIOReturnSuccess)
351 ERR("Couldn't open IOHIDManager.\n");
352 return 0;
355 matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
356 &kCFTypeArrayCallBacks );
358 /* build matching dictionary */
359 result = create_osx_device_match(kHIDUsage_GD_Joystick);
360 if (!result)
362 CFRelease(matching);
363 return 0;
365 CFArrayAppendValue( matching, result );
366 result = create_osx_device_match(kHIDUsage_GD_GamePad);
367 if (!result)
369 CFRelease(matching);
370 return 0;
372 CFArrayAppendValue( matching, result );
374 IOHIDManagerSetDeviceMatchingMultiple( hid_manager, matching);
375 devset = IOHIDManagerCopyDevices( hid_manager );
376 if (devset)
378 CFIndex num_devices, num_main_elements, idx;
379 CFMutableArrayRef devices = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
380 CFSetApplyFunction(devset, CFSetApplierFunctionCopyToCFArray, devices);
381 CFRelease( devset);
382 num_devices = CFArrayGetCount(devices);
384 device_main_elements = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
385 if (!device_main_elements)
386 return 0;
388 num_main_elements = 0;
389 for (idx = 0; idx < num_devices; idx++)
391 CFIndex top;
392 IOHIDDeviceRef hid_device;
394 hid_device = (IOHIDDeviceRef) CFArrayGetValueAtIndex(devices, idx);
395 top = find_top_level(hid_device, device_main_elements);
396 num_main_elements += top;
399 CFRelease(devices);
401 TRACE("found %i device(s), %i collection(s)\n",(int)num_devices,(int)num_main_elements);
402 return (int)num_main_elements;
404 return 0;
407 static int get_osx_device_name(int id, char *name, int length)
409 CFStringRef str;
410 IOHIDDeviceRef hid_device;
412 hid_device = get_device_ref(id);
414 if (name)
415 name[0] = 0;
417 if (!hid_device)
418 return 0;
420 str = IOHIDDeviceGetProperty(hid_device, CFSTR( kIOHIDProductKey ));
421 if (str)
423 CFIndex len = CFStringGetLength(str);
424 if (length >= len)
426 CFStringGetCString(str,name,length,kCFStringEncodingASCII);
427 return len;
429 else
430 return (len+1);
432 return 0;
435 static CFComparisonResult button_usage_comparator(const void *val1, const void *val2, void *context)
437 IOHIDElementRef element1 = (IOHIDElementRef)val1, element2 = (IOHIDElementRef)val2;
438 int usage1 = IOHIDElementGetUsage(element1), usage2 = IOHIDElementGetUsage(element2);
440 if (usage1 < usage2)
441 return kCFCompareLessThan;
442 if (usage1 > usage2)
443 return kCFCompareGreaterThan;
444 return kCFCompareEqualTo;
447 static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
449 IOHIDElementRef device_main_element;
450 CFMutableArrayRef elements;
451 DWORD sliders = 0;
453 device->elements = NULL;
455 if (!device_main_elements || device->id >= CFArrayGetCount(device_main_elements))
456 return;
458 device_main_element = (IOHIDElementRef)CFArrayGetValueAtIndex(device_main_elements, device->id);
460 if (!device_main_element)
461 return;
463 elements = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
464 get_element_children(device_main_element, elements);
466 if (elements)
468 CFIndex idx, cnt = CFArrayGetCount( elements );
469 CFMutableArrayRef axes = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
470 CFMutableArrayRef buttons = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
471 CFMutableArrayRef povs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
473 for ( idx = 0; idx < cnt; idx++ )
475 IOHIDElementRef element = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elements, idx );
476 int type = IOHIDElementGetType( element );
477 switch(type)
479 case kIOHIDElementTypeInput_Button:
481 int usage_page = IOHIDElementGetUsagePage( element );
482 if (usage_page != kHIDPage_Button)
484 /* avoid strange elements found on the 360 controller */
485 continue;
488 if (CFArrayGetCount(buttons) < 128)
489 CFArrayAppendValue(buttons, element);
490 break;
492 case kIOHIDElementTypeInput_Axis:
494 CFArrayAppendValue(axes, element);
495 break;
497 case kIOHIDElementTypeInput_Misc:
499 uint32_t usage = IOHIDElementGetUsage( element );
500 switch(usage)
502 case kHIDUsage_GD_Hatswitch:
504 CFArrayAppendValue(povs, element);
505 break;
507 case kHIDUsage_GD_Slider:
508 sliders ++;
509 if (sliders > 2)
510 break;
511 /* fallthrough, sliders are axis */
512 case kHIDUsage_GD_X:
513 case kHIDUsage_GD_Y:
514 case kHIDUsage_GD_Z:
515 case kHIDUsage_GD_Rx:
516 case kHIDUsage_GD_Ry:
517 case kHIDUsage_GD_Rz:
519 axis_map[CFArrayGetCount(axes)]=usage;
520 CFArrayAppendValue(axes, element);
521 break;
523 default:
524 FIXME("Unhandled usage %i\n",usage);
526 break;
528 default:
529 FIXME("Unhandled type %i\n",type);
533 /* Sort buttons into correct order */
534 CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)), button_usage_comparator, NULL);
536 device->generic.devcaps.dwAxes = CFArrayGetCount(axes);
537 device->generic.devcaps.dwButtons = CFArrayGetCount(buttons);
538 device->generic.devcaps.dwPOVs = CFArrayGetCount(povs);
540 /* build our element array in the order that dinput expects */
541 CFArrayAppendArray(axes, povs, CFRangeMake(0, device->generic.devcaps.dwPOVs));
542 CFArrayAppendArray(axes, buttons, CFRangeMake(0, device->generic.devcaps.dwButtons));
543 device->elements = axes;
544 axes = NULL;
546 CFRelease(povs);
547 CFRelease(buttons);
548 CFRelease(elements);
550 else
552 device->generic.devcaps.dwAxes = 0;
553 device->generic.devcaps.dwButtons = 0;
554 device->generic.devcaps.dwPOVs = 0;
558 static void get_osx_device_elements_props(JoystickImpl *device)
560 if (device->elements)
562 CFIndex idx, cnt = CFArrayGetCount( device->elements );
564 for ( idx = 0; idx < cnt; idx++ )
566 IOHIDElementRef element = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elements, idx );
568 device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(element);
569 device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(element);
570 device->generic.props[idx].lMin = 0;
571 device->generic.props[idx].lMax = 0xffff;
572 device->generic.props[idx].lDeadZone = 0;
573 device->generic.props[idx].lSaturation = 0;
578 static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
580 JoystickImpl *device = impl_from_IDirectInputDevice8A(iface);
581 IOHIDElementRef device_main_element;
582 IOHIDDeviceRef hid_device;
584 TRACE("polling device %i\n",device->id);
586 if (!device_main_elements || device->id >= CFArrayGetCount(device_main_elements))
587 return;
589 device_main_element = (IOHIDElementRef) CFArrayGetValueAtIndex(device_main_elements, device->id);
590 hid_device = IOHIDElementGetDevice(device_main_element);
592 if (!hid_device)
593 return;
595 if (device->elements)
597 int button_idx = 0;
598 int pov_idx = 0;
599 int slider_idx = 0;
600 int inst_id;
601 CFIndex idx, cnt = CFArrayGetCount( device->elements );
603 for ( idx = 0; idx < cnt; idx++ )
605 IOHIDValueRef valueRef;
606 int val, oldVal, newVal;
607 IOHIDElementRef element = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elements, idx );
608 int type = IOHIDElementGetType( element );
610 switch(type)
612 case kIOHIDElementTypeInput_Button:
613 if(button_idx < 128)
615 IOHIDDeviceGetValue(hid_device, element, &valueRef);
616 val = IOHIDValueGetIntegerValue(valueRef);
617 newVal = val ? 0x80 : 0x0;
618 oldVal = device->generic.js.rgbButtons[button_idx];
619 device->generic.js.rgbButtons[button_idx] = newVal;
620 if (oldVal != newVal)
622 inst_id = DIDFT_MAKEINSTANCE(button_idx) | DIDFT_PSHBUTTON;
623 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++);
625 button_idx ++;
627 break;
628 case kIOHIDElementTypeInput_Misc:
630 uint32_t usage = IOHIDElementGetUsage( element );
631 switch(usage)
633 case kHIDUsage_GD_Hatswitch:
635 IOHIDDeviceGetValue(hid_device, element, &valueRef);
636 val = IOHIDValueGetIntegerValue(valueRef);
637 oldVal = device->generic.js.rgdwPOV[pov_idx];
638 if (val >= 8)
639 newVal = -1;
640 else
641 newVal = val * 4500;
642 device->generic.js.rgdwPOV[pov_idx] = newVal;
643 if (oldVal != newVal)
645 inst_id = DIDFT_MAKEINSTANCE(pov_idx) | DIDFT_POV;
646 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++);
648 pov_idx ++;
649 break;
651 case kHIDUsage_GD_X:
652 case kHIDUsage_GD_Y:
653 case kHIDUsage_GD_Z:
654 case kHIDUsage_GD_Rx:
655 case kHIDUsage_GD_Ry:
656 case kHIDUsage_GD_Rz:
657 case kHIDUsage_GD_Slider:
659 int wine_obj = -1;
661 IOHIDDeviceGetValue(hid_device, element, &valueRef);
662 val = IOHIDValueGetIntegerValue(valueRef);
663 newVal = joystick_map_axis(&device->generic.props[idx], val);
664 switch (usage)
666 case kHIDUsage_GD_X:
667 wine_obj = 0;
668 oldVal = device->generic.js.lX;
669 device->generic.js.lX = newVal;
670 break;
671 case kHIDUsage_GD_Y:
672 wine_obj = 1;
673 oldVal = device->generic.js.lY;
674 device->generic.js.lY = newVal;
675 break;
676 case kHIDUsage_GD_Z:
677 wine_obj = 2;
678 oldVal = device->generic.js.lZ;
679 device->generic.js.lZ = newVal;
680 break;
681 case kHIDUsage_GD_Rx:
682 wine_obj = 3;
683 oldVal = device->generic.js.lRx;
684 device->generic.js.lRx = newVal;
685 break;
686 case kHIDUsage_GD_Ry:
687 wine_obj = 4;
688 oldVal = device->generic.js.lRy;
689 device->generic.js.lRy = newVal;
690 break;
691 case kHIDUsage_GD_Rz:
692 wine_obj = 5;
693 oldVal = device->generic.js.lRz;
694 device->generic.js.lRz = newVal;
695 break;
696 case kHIDUsage_GD_Slider:
697 wine_obj = 6 + slider_idx;
698 oldVal = device->generic.js.rglSlider[slider_idx];
699 device->generic.js.rglSlider[slider_idx] = newVal;
700 slider_idx ++;
701 break;
703 if ((wine_obj != -1) &&
704 (oldVal != newVal))
706 inst_id = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
707 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++);
710 break;
712 default:
713 FIXME("unhandled usage %i\n",usage);
715 break;
717 default:
718 FIXME("Unhandled type %i\n",type);
724 static INT find_joystick_devices(void)
726 static INT joystick_devices_count = -1;
728 if (joystick_devices_count != -1) return joystick_devices_count;
730 joystick_devices_count = find_osx_devices();
732 return joystick_devices_count;
735 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
737 if (id >= find_joystick_devices()) return E_FAIL;
739 if ((dwDevType == 0) ||
740 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
741 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
743 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
744 IOHIDDeviceRef device = get_device_ref(id);
745 if(!device)
746 return S_FALSE;
747 if(get_ff(device, NULL) != S_OK)
748 return S_FALSE;
750 /* Return joystick */
751 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
752 lpddi->guidInstance.Data3 = id;
753 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
754 /* we only support traditional joysticks for now */
755 if (version >= 0x0800)
756 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
757 else
758 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
759 sprintf(lpddi->tszInstanceName, "Joystick %d", id);
761 /* get the device name */
762 get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
764 lpddi->guidFFDriver = GUID_NULL;
765 return S_OK;
768 return S_FALSE;
771 static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
773 char name[MAX_PATH];
774 char friendly[32];
776 if (id >= find_joystick_devices()) return E_FAIL;
778 if ((dwDevType == 0) ||
779 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
780 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
781 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
782 IOHIDDeviceRef device = get_device_ref(id);
783 if(!device)
784 return S_FALSE;
785 if(get_ff(device, NULL) != S_OK)
786 return S_FALSE;
788 /* Return joystick */
789 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
790 lpddi->guidInstance.Data3 = id;
791 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
792 /* we only support traditional joysticks for now */
793 if (version >= 0x0800)
794 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
795 else
796 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
797 sprintf(friendly, "Joystick %d", id);
798 MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
799 /* get the device name */
800 get_osx_device_name(id, name, MAX_PATH);
802 MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
803 lpddi->guidFFDriver = GUID_NULL;
804 return S_OK;
807 return S_FALSE;
810 static const char *osx_ff_axis_name(UInt8 axis)
812 static char ret[6];
813 switch(axis){
814 case FFJOFS_X:
815 return "FFJOFS_X";
816 case FFJOFS_Y:
817 return "FFJOFS_Y";
818 case FFJOFS_Z:
819 return "FFJOFS_Z";
821 sprintf(ret, "%u", (unsigned int)axis);
822 return ret;
825 static BOOL osx_axis_has_ff(FFCAPABILITIES *ffcaps, UInt8 axis)
827 int i;
828 for(i = 0; i < ffcaps->numFfAxes; ++i)
829 if(ffcaps->ffAxes[i] == axis)
830 return TRUE;
831 return FALSE;
834 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
835 JoystickImpl **pdev, unsigned short index)
837 DWORD i;
838 IOHIDDeviceRef device;
839 JoystickImpl* newDevice;
840 char name[MAX_PATH];
841 HRESULT hr;
842 LPDIDATAFORMAT df = NULL;
843 int idx = 0;
844 int axis_map[8]; /* max axes */
845 int slider_count = 0;
846 FFCAPABILITIES ffcaps;
848 TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index);
850 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
851 if (newDevice == 0) {
852 WARN("out of memory\n");
853 *pdev = 0;
854 return DIERR_OUTOFMEMORY;
857 newDevice->id = index;
859 newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID;
860 newDevice->generic.guidInstance.Data3 = index;
861 newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
862 newDevice->generic.joy_polldev = poll_osx_device_state;
864 /* get the device name */
865 get_osx_device_name(index, name, MAX_PATH);
866 TRACE("Name %s\n",name);
868 /* copy the device name */
869 newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
870 strcpy(newDevice->generic.name, name);
872 list_init(&newDevice->effects);
873 device = get_device_ref(index);
874 if(get_ff(device, &newDevice->ff) == S_OK){
875 newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;
877 hr = FFDeviceGetForceFeedbackCapabilities(newDevice->ff, &ffcaps);
878 if(SUCCEEDED(hr)){
879 TRACE("FF Capabilities:\n");
880 TRACE("\tsupportedEffects: 0x%x\n", (unsigned int)ffcaps.supportedEffects);
881 TRACE("\temulatedEffects: 0x%x\n", (unsigned int)ffcaps.emulatedEffects);
882 TRACE("\tsubType: 0x%x\n", (unsigned int)ffcaps.subType);
883 TRACE("\tnumFfAxes: %u\n", (unsigned int)ffcaps.numFfAxes);
884 TRACE("\tffAxes: [");
885 for(i = 0; i < ffcaps.numFfAxes; ++i){
886 TRACE("%s", osx_ff_axis_name(ffcaps.ffAxes[i]));
887 if(i < ffcaps.numFfAxes - 1)
888 TRACE(", ");
890 TRACE("]\n");
891 TRACE("\tstorageCapacity: %u\n", (unsigned int)ffcaps.storageCapacity);
892 TRACE("\tplaybackCapacity: %u\n", (unsigned int)ffcaps.playbackCapacity);
895 hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_RESET);
896 if(FAILED(hr))
897 WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_RESET) failed: %08x\n", hr);
899 hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_SETACTUATORSON);
900 if(FAILED(hr))
901 WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_SETACTUATORSON) failed: %08x\n", hr);
904 memset(axis_map, 0, sizeof(axis_map));
905 get_osx_device_elements(newDevice, axis_map);
907 TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
909 if (newDevice->generic.devcaps.dwButtons > 128)
911 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
912 newDevice->generic.devcaps.dwButtons = 128;
915 newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt;
916 newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt;
917 newDevice->generic.base.ref = 1;
918 newDevice->generic.base.dinput = dinput;
919 newDevice->generic.base.guid = *rguid;
920 InitializeCriticalSection(&newDevice->generic.base.crit);
921 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
923 /* Create copy of default data format */
924 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
925 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
927 df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
928 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
930 for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
932 int wine_obj = -1;
933 BOOL has_ff = FALSE;
934 switch (axis_map[i])
936 case kHIDUsage_GD_X:
937 wine_obj = 0;
938 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_X);
939 break;
940 case kHIDUsage_GD_Y:
941 wine_obj = 1;
942 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_Y);
943 break;
944 case kHIDUsage_GD_Z:
945 wine_obj = 2;
946 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_Z);
947 break;
948 case kHIDUsage_GD_Rx:
949 wine_obj = 3;
950 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RX);
951 break;
952 case kHIDUsage_GD_Ry:
953 wine_obj = 4;
954 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RY);
955 break;
956 case kHIDUsage_GD_Rz:
957 wine_obj = 5;
958 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RZ);
959 break;
960 case kHIDUsage_GD_Slider:
961 wine_obj = 6 + slider_count;
962 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_SLIDER(slider_count));
963 slider_count++;
964 break;
966 if (wine_obj < 0 ) continue;
968 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
969 df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
970 if(has_ff)
971 df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR;
972 ++idx;
975 for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
977 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
978 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
981 for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
983 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
984 df->rgodf[idx ].pguid = &GUID_Button;
985 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
987 newDevice->generic.base.data_format.wine_df = df;
989 /* initialize default properties */
990 get_osx_device_elements_props(newDevice);
992 IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface);
994 EnterCriticalSection(&dinput->crit);
995 list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry);
996 LeaveCriticalSection(&dinput->crit);
998 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
999 newDevice->generic.devcaps.dwFlags |= DIDC_ATTACHED;
1000 if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
1001 newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
1002 else
1003 newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
1004 newDevice->generic.devcaps.dwFFSamplePeriod = 0;
1005 newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
1006 newDevice->generic.devcaps.dwFirmwareRevision = 0;
1007 newDevice->generic.devcaps.dwHardwareRevision = 0;
1008 newDevice->generic.devcaps.dwFFDriverVersion = 0;
1010 if (TRACE_ON(dinput)) {
1011 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
1012 _dump_DIDEVCAPS(&newDevice->generic.devcaps);
1015 *pdev = newDevice;
1017 return DI_OK;
1019 FAILED:
1020 hr = DIERR_OUTOFMEMORY;
1021 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
1022 HeapFree(GetProcessHeap(), 0, df);
1023 release_DataFormat(&newDevice->generic.base.data_format);
1024 HeapFree(GetProcessHeap(),0,newDevice->generic.name);
1025 HeapFree(GetProcessHeap(),0,newDevice);
1026 *pdev = 0;
1028 return hr;
1031 /******************************************************************************
1032 * get_joystick_index : Get the joystick index from a given GUID
1034 static unsigned short get_joystick_index(REFGUID guid)
1036 GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
1037 GUID dev_guid = *guid;
1039 wine_joystick.Data3 = 0;
1040 dev_guid.Data3 = 0;
1042 /* for the standard joystick GUID use index 0 */
1043 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
1045 /* for the wine joystick GUIDs use the index stored in Data3 */
1046 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
1048 return 0xffff;
1051 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
1053 unsigned short index;
1054 int joystick_devices_count;
1056 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
1057 *pdev = NULL;
1059 if ((joystick_devices_count = find_joystick_devices()) == 0)
1060 return DIERR_DEVICENOTREG;
1062 if ((index = get_joystick_index(rguid)) < 0xffff &&
1063 joystick_devices_count && index < joystick_devices_count)
1065 JoystickImpl *This;
1066 HRESULT hr;
1068 if (riid == NULL)
1069 ;/* nothing */
1070 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
1071 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
1072 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
1073 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
1075 unicode = 0;
1077 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
1078 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
1079 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
1080 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
1082 unicode = 1;
1084 else
1086 WARN("no interface\n");
1087 return DIERR_NOINTERFACE;
1090 hr = alloc_device(rguid, dinput, &This, index);
1091 if (!This) return hr;
1093 if (unicode)
1094 *pdev = &This->generic.base.IDirectInputDevice8W_iface;
1095 else
1096 *pdev = &This->generic.base.IDirectInputDevice8A_iface;
1097 return hr;
1100 return DIERR_DEVICENOTREG;
1103 static HRESULT osx_set_autocenter(JoystickImpl *This,
1104 const DIPROPDWORD *header)
1106 UInt32 v;
1107 HRESULT hr;
1108 if(!This->ff)
1109 return DIERR_UNSUPPORTED;
1110 v = header->dwData;
1111 hr = osx_to_win32_hresult(FFDeviceSetForceFeedbackProperty(This->ff, FFPROP_AUTOCENTER, &v));
1112 TRACE("returning: %08x\n", hr);
1113 return hr;
1116 static HRESULT osx_set_ffgain(JoystickImpl *This, const DIPROPDWORD *header)
1118 UInt32 v;
1119 HRESULT hr;
1120 if(!This->ff)
1121 return DIERR_UNSUPPORTED;
1122 v = header->dwData;
1123 hr = osx_to_win32_hresult(FFDeviceSetForceFeedbackProperty(This->ff, FFPROP_FFGAIN, &v));
1124 TRACE("returning: %08x\n", hr);
1125 return hr;
1128 static HRESULT WINAPI JoystickWImpl_SetProperty(IDirectInputDevice8W *iface,
1129 const GUID *prop, const DIPROPHEADER *header)
1131 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1133 TRACE("%p %s %p\n", This, debugstr_guid(prop), header);
1135 switch(LOWORD(prop))
1137 case (DWORD_PTR)DIPROP_AUTOCENTER:
1138 return osx_set_autocenter(This, (const DIPROPDWORD *)header);
1139 case (DWORD_PTR)DIPROP_FFGAIN:
1140 return osx_set_ffgain(This, (const DIPROPDWORD *)header);
1143 return JoystickWGenericImpl_SetProperty(iface, prop, header);
1146 static HRESULT WINAPI JoystickAImpl_SetProperty(IDirectInputDevice8A *iface,
1147 const GUID *prop, const DIPROPHEADER *header)
1149 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1151 TRACE("%p %s %p\n", This, debugstr_guid(prop), header);
1153 switch(LOWORD(prop))
1155 case (DWORD_PTR)DIPROP_AUTOCENTER:
1156 return osx_set_autocenter(This, (const DIPROPDWORD *)header);
1157 case (DWORD_PTR)DIPROP_FFGAIN:
1158 return osx_set_ffgain(This, (const DIPROPDWORD *)header);
1161 return JoystickAGenericImpl_SetProperty(iface, prop, header);
1164 static CFUUIDRef effect_win_to_mac(const GUID *effect)
1166 #define DO_MAP(X) \
1167 if(IsEqualGUID(&GUID_##X, effect)) \
1168 return kFFEffectType_##X##_ID;
1169 DO_MAP(ConstantForce)
1170 DO_MAP(RampForce)
1171 DO_MAP(Square)
1172 DO_MAP(Sine)
1173 DO_MAP(Triangle)
1174 DO_MAP(SawtoothUp)
1175 DO_MAP(SawtoothDown)
1176 DO_MAP(Spring)
1177 DO_MAP(Damper)
1178 DO_MAP(Inertia)
1179 DO_MAP(Friction)
1180 DO_MAP(CustomForce)
1181 #undef DO_MAP
1182 WARN("Unknown effect GUID! %s\n", debugstr_guid(effect));
1183 return 0;
1186 static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface,
1187 const GUID *type, const DIEFFECT *params, IDirectInputEffect **out,
1188 IUnknown *outer)
1190 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1191 EffectImpl *effect;
1192 HRESULT hr;
1194 TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
1195 dump_DIEFFECT(params, type, 0);
1197 if(!This->ff){
1198 TRACE("No force feedback support\n");
1199 *out = NULL;
1200 return S_OK;
1203 if(outer)
1204 WARN("aggregation not implemented\n");
1206 effect = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This));
1207 effect->IDirectInputEffect_iface.lpVtbl = &EffectVtbl;
1208 effect->ref = 1;
1209 effect->guid = *type;
1210 effect->device = This;
1212 /* Mac's FFEFFECT and Win's DIEFFECT are binary identical. */
1213 hr = osx_to_win32_hresult(FFDeviceCreateEffect(This->ff,
1214 effect_win_to_mac(type), (FFEFFECT*)params, &effect->effect));
1215 if(FAILED(hr)){
1216 WARN("FFDeviceCreateEffect failed: %08x\n", hr);
1217 HeapFree(GetProcessHeap(), 0, effect);
1218 return hr;
1221 list_add_tail(&This->effects, &effect->entry);
1222 *out = &effect->IDirectInputEffect_iface;
1224 TRACE("allocated effect: %p\n", effect);
1226 return S_OK;
1229 static HRESULT WINAPI JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface,
1230 const GUID *type, const DIEFFECT *params, IDirectInputEffect **out,
1231 IUnknown *outer)
1233 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1235 TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
1237 return JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface,
1238 type, params, out, outer);
1241 static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W *iface,
1242 DWORD flags)
1244 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
1245 HRESULT hr;
1247 TRACE("%p 0x%x\n", This, flags);
1249 if(!This->ff)
1250 return DI_NOEFFECT;
1252 hr = osx_to_win32_hresult(FFDeviceSendForceFeedbackCommand(This->ff, flags));
1253 if(FAILED(hr)){
1254 WARN("FFDeviceSendForceFeedbackCommand failed: %08x\n", hr);
1255 return hr;
1258 return S_OK;
1261 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(IDirectInputDevice8A *iface,
1262 DWORD flags)
1264 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
1266 TRACE("%p 0x%x\n", This, flags);
1268 return JoystickWImpl_SendForceFeedbackCommand(&This->generic.base.IDirectInputDevice8W_iface, flags);
1271 const struct dinput_device joystick_osx_device = {
1272 "Wine OS X joystick driver",
1273 joydev_enum_deviceA,
1274 joydev_enum_deviceW,
1275 joydev_create_device
1278 static const IDirectInputDevice8AVtbl JoystickAvt =
1280 IDirectInputDevice2AImpl_QueryInterface,
1281 IDirectInputDevice2AImpl_AddRef,
1282 IDirectInputDevice2AImpl_Release,
1283 JoystickAGenericImpl_GetCapabilities,
1284 IDirectInputDevice2AImpl_EnumObjects,
1285 JoystickAGenericImpl_GetProperty,
1286 JoystickAImpl_SetProperty,
1287 IDirectInputDevice2AImpl_Acquire,
1288 IDirectInputDevice2AImpl_Unacquire,
1289 JoystickAGenericImpl_GetDeviceState,
1290 IDirectInputDevice2AImpl_GetDeviceData,
1291 IDirectInputDevice2AImpl_SetDataFormat,
1292 IDirectInputDevice2AImpl_SetEventNotification,
1293 IDirectInputDevice2AImpl_SetCooperativeLevel,
1294 JoystickAGenericImpl_GetObjectInfo,
1295 JoystickAGenericImpl_GetDeviceInfo,
1296 IDirectInputDevice2AImpl_RunControlPanel,
1297 IDirectInputDevice2AImpl_Initialize,
1298 JoystickAImpl_CreateEffect,
1299 IDirectInputDevice2AImpl_EnumEffects,
1300 IDirectInputDevice2AImpl_GetEffectInfo,
1301 IDirectInputDevice2AImpl_GetForceFeedbackState,
1302 JoystickAImpl_SendForceFeedbackCommand,
1303 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1304 IDirectInputDevice2AImpl_Escape,
1305 JoystickAGenericImpl_Poll,
1306 IDirectInputDevice2AImpl_SendDeviceData,
1307 IDirectInputDevice7AImpl_EnumEffectsInFile,
1308 IDirectInputDevice7AImpl_WriteEffectToFile,
1309 JoystickAGenericImpl_BuildActionMap,
1310 JoystickAGenericImpl_SetActionMap,
1311 IDirectInputDevice8AImpl_GetImageInfo
1314 static const IDirectInputDevice8WVtbl JoystickWvt =
1316 IDirectInputDevice2WImpl_QueryInterface,
1317 IDirectInputDevice2WImpl_AddRef,
1318 IDirectInputDevice2WImpl_Release,
1319 JoystickWGenericImpl_GetCapabilities,
1320 IDirectInputDevice2WImpl_EnumObjects,
1321 JoystickWGenericImpl_GetProperty,
1322 JoystickWImpl_SetProperty,
1323 IDirectInputDevice2WImpl_Acquire,
1324 IDirectInputDevice2WImpl_Unacquire,
1325 JoystickWGenericImpl_GetDeviceState,
1326 IDirectInputDevice2WImpl_GetDeviceData,
1327 IDirectInputDevice2WImpl_SetDataFormat,
1328 IDirectInputDevice2WImpl_SetEventNotification,
1329 IDirectInputDevice2WImpl_SetCooperativeLevel,
1330 JoystickWGenericImpl_GetObjectInfo,
1331 JoystickWGenericImpl_GetDeviceInfo,
1332 IDirectInputDevice2WImpl_RunControlPanel,
1333 IDirectInputDevice2WImpl_Initialize,
1334 JoystickWImpl_CreateEffect,
1335 IDirectInputDevice2WImpl_EnumEffects,
1336 IDirectInputDevice2WImpl_GetEffectInfo,
1337 IDirectInputDevice2WImpl_GetForceFeedbackState,
1338 JoystickWImpl_SendForceFeedbackCommand,
1339 IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
1340 IDirectInputDevice2WImpl_Escape,
1341 JoystickWGenericImpl_Poll,
1342 IDirectInputDevice2WImpl_SendDeviceData,
1343 IDirectInputDevice7WImpl_EnumEffectsInFile,
1344 IDirectInputDevice7WImpl_WriteEffectToFile,
1345 JoystickWGenericImpl_BuildActionMap,
1346 JoystickWGenericImpl_SetActionMap,
1347 IDirectInputDevice8WImpl_GetImageInfo
1350 static HRESULT WINAPI effect_QueryInterface(IDirectInputEffect *iface,
1351 const GUID *guid, void **out)
1353 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1355 TRACE("%p %s %p\n", This, debugstr_guid(guid), out);
1357 if(IsEqualIID(guid, &IID_IDirectInputEffect)){
1358 *out = iface;
1359 IDirectInputEffect_AddRef(iface);
1360 return S_OK;
1363 return E_NOINTERFACE;
1366 static ULONG WINAPI effect_AddRef(IDirectInputEffect *iface)
1368 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1369 ULONG ref = InterlockedIncrement(&This->ref);
1370 TRACE("%p, ref is now: %u\n", This, ref);
1371 return ref;
1374 static ULONG WINAPI effect_Release(IDirectInputEffect *iface)
1376 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1377 ULONG ref = InterlockedDecrement(&This->ref);
1378 TRACE("%p, ref is now: %u\n", This, ref);
1380 if(!ref){
1381 list_remove(&This->entry);
1382 FFDeviceReleaseEffect(This->device->ff, This->effect);
1383 HeapFree(GetProcessHeap(), 0, This);
1386 return ref;
1389 static HRESULT WINAPI effect_Initialize(IDirectInputEffect *iface, HINSTANCE hinst,
1390 DWORD version, const GUID *guid)
1392 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1393 TRACE("%p %p 0x%x, %s\n", This, hinst, version, debugstr_guid(guid));
1394 return S_OK;
1397 static HRESULT WINAPI effect_GetEffectGuid(IDirectInputEffect *iface, GUID *out)
1399 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1400 TRACE("%p %p\n", This, out);
1401 *out = This->guid;
1402 return S_OK;
1405 static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface,
1406 DIEFFECT *effect, DWORD flags)
1408 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1409 TRACE("%p %p 0x%x\n", This, effect, flags);
1410 return osx_to_win32_hresult(FFEffectGetParameters(This->effect, (FFEFFECT*)effect, flags));
1413 static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface,
1414 const DIEFFECT *effect, DWORD flags)
1416 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1417 TRACE("%p %p 0x%x\n", This, effect, flags);
1418 dump_DIEFFECT(effect, &This->guid, flags);
1419 return osx_to_win32_hresult(FFEffectSetParameters(This->effect, (FFEFFECT*)effect, flags));
1422 static HRESULT WINAPI effect_Start(IDirectInputEffect *iface, DWORD iterations,
1423 DWORD flags)
1425 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1426 TRACE("%p 0x%x 0x%x\n", This, iterations, flags);
1427 return osx_to_win32_hresult(FFEffectStart(This->effect, iterations, flags));
1430 static HRESULT WINAPI effect_Stop(IDirectInputEffect *iface)
1432 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1433 TRACE("%p\n", This);
1434 return osx_to_win32_hresult(FFEffectStop(This->effect));
1437 static HRESULT WINAPI effect_GetEffectStatus(IDirectInputEffect *iface, DWORD *flags)
1439 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1440 TRACE("%p %p\n", This, flags);
1441 return osx_to_win32_hresult(FFEffectGetEffectStatus(This->effect, (UInt32*)flags));
1444 static HRESULT WINAPI effect_Download(IDirectInputEffect *iface)
1446 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1447 TRACE("%p\n", This);
1448 return osx_to_win32_hresult(FFEffectDownload(This->effect));
1451 static HRESULT WINAPI effect_Unload(IDirectInputEffect *iface)
1453 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1454 TRACE("%p\n", This);
1455 return osx_to_win32_hresult(FFEffectUnload(This->effect));
1458 static HRESULT WINAPI effect_Escape(IDirectInputEffect *iface, DIEFFESCAPE *escape)
1460 EffectImpl *This = impl_from_IDirectInputEffect(iface);
1461 TRACE("%p %p\n", This, escape);
1462 return osx_to_win32_hresult(FFEffectEscape(This->effect, (FFEFFESCAPE*)escape));
1465 static const IDirectInputEffectVtbl EffectVtbl = {
1466 effect_QueryInterface,
1467 effect_AddRef,
1468 effect_Release,
1469 effect_Initialize,
1470 effect_GetEffectGuid,
1471 effect_GetParameters,
1472 effect_SetParameters,
1473 effect_Start,
1474 effect_Stop,
1475 effect_GetEffectStatus,
1476 effect_Download,
1477 effect_Unload,
1478 effect_Escape
1481 #else /* HAVE_IOHIDMANAGERCREATE */
1483 const struct dinput_device joystick_osx_device = {
1484 "Wine OS X joystick driver",
1485 NULL,
1486 NULL,
1487 NULL
1490 #endif /* HAVE_IOHIDMANAGERCREATE */