dinput: Add a trailing '\n' to ERR() messages.
[wine/multimedia.git] / dlls / dinput / joystick_osx.c
blob21f8ca3d22afcbf44dca0788dd2f03b25bf5ea14
1 /* DirectInput Joystick device for Mac OS/X
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2009 CodeWeavers, Aric Stewart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #if defined(HAVE_CARBON_CARBON_H) && defined(HAVE_IOKIT_HID_IOHIDLIB_H)
27 #define LoadResource __carbon_LoadResource
28 #define CompareString __carbon_CompareString
29 #define GetCurrentThread __carbon_GetCurrentThread
30 #define GetCurrentProcess __carbon_GetCurrentProcess
31 #define AnimatePalette __carbon_AnimatePalette
32 #define EqualRgn __carbon_EqualRgn
33 #define FillRgn __carbon_FillRgn
34 #define FrameRgn __carbon_FrameRgn
35 #define GetPixel __carbon_GetPixel
36 #define InvertRgn __carbon_InvertRgn
37 #define LineTo __carbon_LineTo
38 #define OffsetRgn __carbon_OffsetRgn
39 #define PaintRgn __carbon_PaintRgn
40 #define Polygon __carbon_Polygon
41 #define ResizePalette __carbon_ResizePalette
42 #define SetRectRgn __carbon_SetRectRgn
43 #define ULONG __carbon_ULONG
44 #define E_INVALIDARG __carbon_E_INVALIDARG
45 #define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY
46 #define E_HANDLE __carbon_E_HANDLE
47 #define E_ACCESSDENIED __carbon_E_ACCESSDENIED
48 #define E_UNEXPECTED __carbon_E_UNEXPECTED
49 #define E_FAIL __carbon_E_FAIL
50 #define E_ABORT __carbon_E_ABORT
51 #define E_POINTER __carbon_E_POINTER
52 #define E_NOINTERFACE __carbon_E_NOINTERFACE
53 #define E_NOTIMPL __carbon_E_NOTIMPL
54 #define S_FALSE __carbon_S_FALSE
55 #define S_OK __carbon_S_OK
56 #define HRESULT_FACILITY __carbon_HRESULT_FACILITY
57 #define IS_ERROR __carbon_IS_ERROR
58 #define FAILED __carbon_FAILED
59 #define SUCCEEDED __carbon_SUCCEEDED
60 #define MAKE_HRESULT __carbon_MAKE_HRESULT
61 #define HRESULT __carbon_HRESULT
62 #define STDMETHODCALLTYPE __carbon_STDMETHODCALLTYPE
63 #include <Carbon/Carbon.h>
64 #include <IOKit/hid/IOHIDLib.h>
65 #undef LoadResource
66 #undef CompareString
67 #undef GetCurrentThread
68 #undef _CDECL
69 #undef DPRINTF
70 #undef GetCurrentProcess
71 #undef AnimatePalette
72 #undef EqualRgn
73 #undef FillRgn
74 #undef FrameRgn
75 #undef GetPixel
76 #undef InvertRgn
77 #undef LineTo
78 #undef OffsetRgn
79 #undef PaintRgn
80 #undef Polygon
81 #undef ResizePalette
82 #undef SetRectRgn
83 #undef ULONG
84 #undef E_INVALIDARG
85 #undef E_OUTOFMEMORY
86 #undef E_HANDLE
87 #undef E_ACCESSDENIED
88 #undef E_UNEXPECTED
89 #undef E_FAIL
90 #undef E_ABORT
91 #undef E_POINTER
92 #undef E_NOINTERFACE
93 #undef E_NOTIMPL
94 #undef S_FALSE
95 #undef S_OK
96 #undef HRESULT_FACILITY
97 #undef IS_ERROR
98 #undef FAILED
99 #undef SUCCEEDED
100 #undef MAKE_HRESULT
101 #undef HRESULT
102 #undef STDMETHODCALLTYPE
103 #endif /* HAVE_CARBON_CARBON_H */
105 #include "wine/debug.h"
106 #include "wine/unicode.h"
107 #include "windef.h"
108 #include "winbase.h"
109 #include "winerror.h"
110 #include "winreg.h"
111 #include "dinput.h"
113 #include "dinput_private.h"
114 #include "device_private.h"
115 #include "joystick_private.h"
117 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
119 #ifdef HAVE_IOHIDMANAGERCREATE
121 static IOHIDManagerRef gIOHIDManagerRef = NULL;
122 static CFArrayRef gDevices = NULL;
124 typedef struct JoystickImpl JoystickImpl;
125 static const IDirectInputDevice8AVtbl JoystickAvt;
126 static const IDirectInputDevice8WVtbl JoystickWvt;
128 struct JoystickImpl
130 struct JoystickGenericImpl generic;
132 /* osx private */
133 int id;
134 CFMutableArrayRef elementCFArrayRef;
135 ObjProps **propmap;
138 static const GUID DInput_Wine_OsX_Joystick_GUID = { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */
139 0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A}
142 static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context)
144 CFArrayAppendValue( ( CFMutableArrayRef ) context, value );
147 static CFMutableDictionaryRef creates_osx_device_match(int usage)
149 CFMutableDictionaryRef result;
151 result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
152 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
154 if ( result )
156 int number = kHIDPage_GenericDesktop;
157 CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
158 kCFNumberIntType, &number);
160 if ( pageCFNumberRef )
162 CFNumberRef usageCFNumberRef;
164 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ),
165 pageCFNumberRef );
166 CFRelease( pageCFNumberRef );
168 usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
169 kCFNumberIntType, &usage);
170 if ( usageCFNumberRef )
172 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ),
173 usageCFNumberRef );
174 CFRelease( usageCFNumberRef );
176 else
178 ERR("CFNumberCreate() failed.\n");
179 return NULL;
182 else
184 ERR("CFNumberCreate failed.\n");
185 return NULL;
188 else
190 ERR("CFDictionaryCreateMutable failed.\n");
191 return NULL;
194 return result;
197 static int find_osx_devices(void)
199 IOReturn tIOReturn;
200 CFMutableDictionaryRef result;
201 CFSetRef devset;
202 CFArrayRef matching;
204 gIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
205 tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, 0L);
206 if ( kIOReturnSuccess != tIOReturn )
208 ERR("Couldn't open IOHIDManager.");
209 return 0;
212 matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
213 &kCFTypeArrayCallBacks );
215 /* build matching dictionary */
216 result = creates_osx_device_match(kHIDPage_Sport);
217 if (!result)
219 CFRelease(matching);
220 return 0;
222 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
223 result = creates_osx_device_match(kHIDPage_Game);
224 if (!result)
226 CFRelease(matching);
227 return 0;
229 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
231 IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef, matching);
232 devset = IOHIDManagerCopyDevices( gIOHIDManagerRef );
233 if (devset)
235 CFIndex count;
236 gDevices = CFArrayCreateMutable( kCFAllocatorDefault, 0,
237 &kCFTypeArrayCallBacks );
238 CFSetApplyFunction(devset, CFSetApplierFunctionCopyToCFArray, (void*)gDevices);
239 count = CFArrayGetCount( gDevices);
240 CFRelease( devset);
241 count = CFArrayGetCount( gDevices);
243 TRACE("found %i device(s)\n",(int)count);
244 return count;
247 return 0;
250 static int get_osx_device_name(int id, char *name, int length)
252 CFStringRef str;
253 IOHIDDeviceRef tIOHIDDeviceRef;
255 if (!gDevices)
256 return 0;
258 tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, id );
260 if (!tIOHIDDeviceRef)
261 return 0;
263 if (name)
264 name[0] = 0;
266 if (!tIOHIDDeviceRef)
268 ERR("Invalid Device requested %i\n",id);
269 return 0;
272 str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
273 if (str)
275 CFIndex len = CFStringGetLength(str);
276 if (length >= len)
278 CFStringGetCString(str,name,length,kCFStringEncodingASCII);
279 return len;
281 else
282 return (len+1);
284 return 0;
287 static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
289 IOHIDDeviceRef tIOHIDDeviceRef;
290 CFArrayRef gElementCFArrayRef;
291 DWORD axes = 0;
292 DWORD sliders = 0;
293 DWORD buttons = 0;
294 DWORD povs = 0;
296 device->elementCFArrayRef = NULL;
298 if (!gDevices)
299 return;
301 tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
303 if (!tIOHIDDeviceRef)
304 return;
306 gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef,
307 NULL, 0 );
309 if (gElementCFArrayRef)
311 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
312 /* build our element array in the order that dinput expects */
313 device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);
315 for ( idx = 0; idx < cnt; idx++ )
317 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
318 int eleType = IOHIDElementGetType( tIOHIDElementRef );
319 switch(eleType)
321 case kIOHIDElementTypeInput_Button:
323 int usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
324 if (usagePage != kHIDPage_Button)
326 /* avoid strange elements found on the 360 controler */
327 continue;
330 if (buttons < 128)
332 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
333 buttons++;
335 break;
337 case kIOHIDElementTypeInput_Axis:
339 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
340 axes++;
341 break;
343 case kIOHIDElementTypeInput_Misc:
345 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
346 switch(usage)
348 case kHIDUsage_GD_Hatswitch:
350 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
351 povs++;
352 break;
354 case kHIDUsage_GD_Slider:
355 sliders ++;
356 if (sliders > 2)
357 break;
358 /* fallthrough, sliders are axis */
359 case kHIDUsage_GD_X:
360 case kHIDUsage_GD_Y:
361 case kHIDUsage_GD_Z:
362 case kHIDUsage_GD_Rx:
363 case kHIDUsage_GD_Ry:
364 case kHIDUsage_GD_Rz:
366 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
367 axis_map[axes]=usage;
368 axes++;
369 break;
371 default:
372 FIXME("Unhandled usage %i\n",usage);
374 break;
376 default:
377 FIXME("Unhandled type %i\n",eleType);
382 device->generic.devcaps.dwAxes = axes;
383 device->generic.devcaps.dwButtons = buttons;
384 device->generic.devcaps.dwPOVs = povs;
387 static void get_osx_device_elements_props(JoystickImpl *device)
389 CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
391 if (gElementCFArrayRef)
393 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
395 for ( idx = 0; idx < cnt; idx++ )
397 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
399 device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
400 device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
401 device->generic.props[idx].lMin = 0;
402 device->generic.props[idx].lMax = 0xffff;
403 device->generic.props[idx].lDeadZone = 0;
404 device->generic.props[idx].lSaturation = 0;
409 static void poll_osx_device_state(JoystickGenericImpl *device_in)
411 JoystickImpl *device = (JoystickImpl*)device_in;
412 IOHIDDeviceRef tIOHIDDeviceRef;
413 CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
415 TRACE("polling device %i\n",device->id);
417 if (!gDevices)
418 return;
420 tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
422 if (!tIOHIDDeviceRef)
423 return;
425 if (gElementCFArrayRef)
427 int button_idx = 0;
428 int pov_idx = 0;
429 int slider_idx = 0;
430 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
432 for ( idx = 0; idx < cnt; idx++ )
434 IOHIDValueRef valueRef;
435 int val;
436 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
437 int eleType = IOHIDElementGetType( tIOHIDElementRef );
439 switch(eleType)
441 case kIOHIDElementTypeInput_Button:
442 if(button_idx < 128)
444 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
445 val = IOHIDValueGetIntegerValue(valueRef);
446 device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00;
447 button_idx ++;
449 break;
450 case kIOHIDElementTypeInput_Misc:
452 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
453 switch(usage)
455 case kHIDUsage_GD_Hatswitch:
457 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
458 val = IOHIDValueGetIntegerValue(valueRef);
459 if (val >= 8)
460 device->generic.js.rgdwPOV[pov_idx] = -1;
461 else
462 device->generic.js.rgdwPOV[pov_idx] = val * 4500;
463 pov_idx ++;
464 break;
466 case kHIDUsage_GD_X:
467 case kHIDUsage_GD_Y:
468 case kHIDUsage_GD_Z:
469 case kHIDUsage_GD_Rx:
470 case kHIDUsage_GD_Ry:
471 case kHIDUsage_GD_Rz:
472 case kHIDUsage_GD_Slider:
474 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
475 val = IOHIDValueGetIntegerValue(valueRef);
476 switch (usage)
478 case kHIDUsage_GD_X:
479 device->generic.js.lX = joystick_map_axis(&device->generic.props[idx], val);
480 break;
481 case kHIDUsage_GD_Y:
482 device->generic.js.lY = joystick_map_axis(&device->generic.props[idx], val);
483 break;
484 case kHIDUsage_GD_Z:
485 device->generic.js.lZ = joystick_map_axis(&device->generic.props[idx], val);
486 break;
487 case kHIDUsage_GD_Rx:
488 device->generic.js.lRx = joystick_map_axis(&device->generic.props[idx], val);
489 break;
490 case kHIDUsage_GD_Ry:
491 device->generic.js.lRy = joystick_map_axis(&device->generic.props[idx], val);
492 break;
493 case kHIDUsage_GD_Rz:
494 device->generic.js.lRz = joystick_map_axis(&device->generic.props[idx], val);
495 break;
496 case kHIDUsage_GD_Slider:
497 device->generic.js.rglSlider[slider_idx] = joystick_map_axis(&device->generic.props[idx], val);
498 slider_idx ++;
499 break;
501 break;
503 default:
504 FIXME("unhandled usage %i\n",usage);
506 break;
508 default:
509 FIXME("Unhandled type %i\n",eleType);
515 static INT find_joystick_devices(void)
517 static INT joystick_devices_count = -1;
519 if (joystick_devices_count != -1) return joystick_devices_count;
521 joystick_devices_count = find_osx_devices();
523 return joystick_devices_count;
526 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
528 if (id >= find_joystick_devices()) return FALSE;
530 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
531 WARN("force feedback not supported\n");
532 return FALSE;
535 if ((dwDevType == 0) ||
536 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
537 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
539 /* Return joystick */
540 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
541 lpddi->guidInstance.Data3 = id;
542 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
543 /* we only support traditional joysticks for now */
544 if (version >= 0x0800)
545 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
546 else
547 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
548 sprintf(lpddi->tszInstanceName, "Joystick %d", id);
550 /* get the device name */
551 get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
553 lpddi->guidFFDriver = GUID_NULL;
554 return TRUE;
557 return FALSE;
560 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
562 char name[MAX_PATH];
563 char friendly[32];
565 if (id >= find_joystick_devices()) return FALSE;
567 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
568 WARN("force feedback not supported\n");
569 return FALSE;
572 if ((dwDevType == 0) ||
573 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
574 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
575 /* Return joystick */
576 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
577 lpddi->guidInstance.Data3 = id;
578 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
579 /* we only support traditional joysticks for now */
580 if (version >= 0x0800)
581 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
582 else
583 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
584 sprintf(friendly, "Joystick %d", id);
585 MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
586 /* get the device name */
587 get_osx_device_name(id, name, MAX_PATH);
589 MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
590 lpddi->guidFFDriver = GUID_NULL;
591 return TRUE;
594 return FALSE;
597 static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput,
598 LPDIRECTINPUTDEVICEA* pdev, unsigned short index)
600 DWORD i;
601 JoystickImpl* newDevice;
602 char name[MAX_PATH];
603 HRESULT hr;
604 LPDIDATAFORMAT df = NULL;
605 int idx = 0;
606 int axis_map[8]; /* max axes */
607 int slider_count = 0;
609 TRACE("%s %p %p %p %hu\n", debugstr_guid(rguid), jvt, dinput, pdev, index);
611 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
612 if (newDevice == 0) {
613 WARN("out of memory\n");
614 *pdev = 0;
615 return DIERR_OUTOFMEMORY;
618 newDevice->id = index;
620 newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
621 newDevice->generic.joy_polldev = poll_osx_device_state;
623 /* get the device name */
624 get_osx_device_name(index, name, MAX_PATH);
625 TRACE("Name %s\n",name);
627 /* copy the device name */
628 newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
629 strcpy(newDevice->generic.name, name);
631 memset(axis_map, 0, sizeof(axis_map));
632 get_osx_device_elements(newDevice, axis_map);
634 TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
636 if (newDevice->generic.devcaps.dwButtons > 128)
638 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
639 newDevice->generic.devcaps.dwButtons = 128;
642 newDevice->generic.base.lpVtbl = jvt;
643 newDevice->generic.base.ref = 1;
644 newDevice->generic.base.dinput = dinput;
645 newDevice->generic.base.guid = *rguid;
646 InitializeCriticalSection(&newDevice->generic.base.crit);
647 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
649 /* Create copy of default data format */
650 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
651 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
653 df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
654 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
656 for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
658 int wine_obj = -1;
659 switch (axis_map[i])
661 case kHIDUsage_GD_X: wine_obj = 0; break;
662 case kHIDUsage_GD_Y: wine_obj = 1; break;
663 case kHIDUsage_GD_Z: wine_obj = 2; break;
664 case kHIDUsage_GD_Rx: wine_obj = 3; break;
665 case kHIDUsage_GD_Ry: wine_obj = 4; break;
666 case kHIDUsage_GD_Rz: wine_obj = 5; break;
667 case kHIDUsage_GD_Slider:
668 wine_obj = 6 + slider_count;
669 slider_count++;
670 break;
672 if (wine_obj < 0 ) continue;
674 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
675 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
678 for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
680 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
681 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
684 for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
686 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
687 df->rgodf[idx ].pguid = &GUID_Button;
688 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
690 newDevice->generic.base.data_format.wine_df = df;
692 /* create default properties */
693 newDevice->generic.props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps));
694 if (newDevice->generic.props == 0)
695 goto FAILED;
697 /* initialize default properties */
698 get_osx_device_elements_props(newDevice);
700 IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->generic.base.dinput);
702 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
703 newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
704 if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
705 newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
706 else
707 newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
708 newDevice->generic.devcaps.dwFFSamplePeriod = 0;
709 newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
710 newDevice->generic.devcaps.dwFirmwareRevision = 0;
711 newDevice->generic.devcaps.dwHardwareRevision = 0;
712 newDevice->generic.devcaps.dwFFDriverVersion = 0;
714 if (TRACE_ON(dinput)) {
715 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
716 _dump_DIDEVCAPS(&newDevice->generic.devcaps);
719 *pdev = (LPDIRECTINPUTDEVICEA)newDevice;
721 return DI_OK;
723 FAILED:
724 hr = DIERR_OUTOFMEMORY;
725 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
726 HeapFree(GetProcessHeap(), 0, df);
727 release_DataFormat(&newDevice->generic.base.data_format);
728 HeapFree(GetProcessHeap(),0,newDevice->generic.name);
729 HeapFree(GetProcessHeap(),0,newDevice->generic.props);
730 HeapFree(GetProcessHeap(),0,newDevice);
731 *pdev = 0;
733 return hr;
736 /******************************************************************************
737 * get_joystick_index : Get the joystick index from a given GUID
739 static unsigned short get_joystick_index(REFGUID guid)
741 GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
742 GUID dev_guid = *guid;
744 wine_joystick.Data3 = 0;
745 dev_guid.Data3 = 0;
747 /* for the standard joystick GUID use index 0 */
748 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
750 /* for the wine joystick GUIDs use the index stored in Data3 */
751 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
753 return 0xffff;
756 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
758 unsigned short index;
759 int joystick_devices_count;
761 TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
762 *pdev = NULL;
764 if ((joystick_devices_count = find_joystick_devices()) == 0)
765 return DIERR_DEVICENOTREG;
767 if ((index = get_joystick_index(rguid)) < 0xffff &&
768 joystick_devices_count && index < joystick_devices_count)
770 if ((riid == NULL) ||
771 IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
772 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
773 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
774 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
776 return alloc_device(rguid, &JoystickAvt, dinput, pdev, index);
779 WARN("no interface\n");
780 return DIERR_NOINTERFACE;
783 return DIERR_DEVICENOTREG;
786 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
788 unsigned short index;
789 int joystick_devices_count;
791 TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
792 *pdev = NULL;
794 if ((joystick_devices_count = find_joystick_devices()) == 0)
795 return DIERR_DEVICENOTREG;
797 if ((index = get_joystick_index(rguid)) < 0xffff &&
798 joystick_devices_count && index < joystick_devices_count)
800 if ((riid == NULL) ||
801 IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
802 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
803 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
804 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
806 return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev, index);
808 WARN("no interface\n");
809 return DIERR_NOINTERFACE;
812 WARN("invalid device GUID %s\n",debugstr_guid(rguid));
813 return DIERR_DEVICENOTREG;
816 const struct dinput_device joystick_osx_device = {
817 "Wine OS X joystick driver",
818 joydev_enum_deviceA,
819 joydev_enum_deviceW,
820 joydev_create_deviceA,
821 joydev_create_deviceW
824 static const IDirectInputDevice8AVtbl JoystickAvt =
826 IDirectInputDevice2AImpl_QueryInterface,
827 IDirectInputDevice2AImpl_AddRef,
828 IDirectInputDevice2AImpl_Release,
829 JoystickAGenericImpl_GetCapabilities,
830 IDirectInputDevice2AImpl_EnumObjects,
831 JoystickAGenericImpl_GetProperty,
832 JoystickAGenericImpl_SetProperty,
833 JoystickAGenericImpl_Acquire,
834 JoystickAGenericImpl_Unacquire,
835 JoystickAGenericImpl_GetDeviceState,
836 IDirectInputDevice2AImpl_GetDeviceData,
837 IDirectInputDevice2AImpl_SetDataFormat,
838 IDirectInputDevice2AImpl_SetEventNotification,
839 IDirectInputDevice2AImpl_SetCooperativeLevel,
840 JoystickAGenericImpl_GetObjectInfo,
841 JoystickAGenericImpl_GetDeviceInfo,
842 IDirectInputDevice2AImpl_RunControlPanel,
843 IDirectInputDevice2AImpl_Initialize,
844 IDirectInputDevice2AImpl_CreateEffect,
845 IDirectInputDevice2AImpl_EnumEffects,
846 IDirectInputDevice2AImpl_GetEffectInfo,
847 IDirectInputDevice2AImpl_GetForceFeedbackState,
848 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
849 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
850 IDirectInputDevice2AImpl_Escape,
851 JoystickAGenericImpl_Poll,
852 IDirectInputDevice2AImpl_SendDeviceData,
853 IDirectInputDevice7AImpl_EnumEffectsInFile,
854 IDirectInputDevice7AImpl_WriteEffectToFile,
855 IDirectInputDevice8AImpl_BuildActionMap,
856 IDirectInputDevice8AImpl_SetActionMap,
857 IDirectInputDevice8AImpl_GetImageInfo
860 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
861 # define XCAST(fun) (typeof(JoystickWvt.fun))
862 #else
863 # define XCAST(fun) (void*)
864 #endif
866 static const IDirectInputDevice8WVtbl JoystickWvt =
868 IDirectInputDevice2WImpl_QueryInterface,
869 XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
870 XCAST(Release)IDirectInputDevice2AImpl_Release,
871 XCAST(GetCapabilities)JoystickAGenericImpl_GetCapabilities,
872 IDirectInputDevice2WImpl_EnumObjects,
873 XCAST(GetProperty)JoystickAGenericImpl_GetProperty,
874 XCAST(SetProperty)JoystickAGenericImpl_SetProperty,
875 XCAST(Acquire)JoystickAGenericImpl_Acquire,
876 XCAST(Unacquire)JoystickAGenericImpl_Unacquire,
877 XCAST(GetDeviceState)JoystickAGenericImpl_GetDeviceState,
878 XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
879 XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
880 XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
881 XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
882 JoystickWGenericImpl_GetObjectInfo,
883 JoystickWGenericImpl_GetDeviceInfo,
884 XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
885 XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
886 XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
887 IDirectInputDevice2WImpl_EnumEffects,
888 IDirectInputDevice2WImpl_GetEffectInfo,
889 XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
890 XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
891 XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
892 XCAST(Escape)IDirectInputDevice2AImpl_Escape,
893 XCAST(Poll)JoystickAGenericImpl_Poll,
894 XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
895 IDirectInputDevice7WImpl_EnumEffectsInFile,
896 IDirectInputDevice7WImpl_WriteEffectToFile,
897 IDirectInputDevice8WImpl_BuildActionMap,
898 IDirectInputDevice8WImpl_SetActionMap,
899 IDirectInputDevice8WImpl_GetImageInfo
901 #undef XCAST
903 #else /* HAVE_IOHIDMANAGERCREATE */
905 const struct dinput_device joystick_osx_device = {
906 "Wine OS X joystick driver",
907 NULL,
908 NULL,
909 NULL,
910 NULL
913 #endif /* HAVE_IOHIDMANAGERCREATE */