1 /* DirectInput Joystick device for Mac OS/X
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2009 CodeWeavers, Aric Stewart
7 *
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.
12 *
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.
17 *
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
21 */
22
23 #include "config.h"
24 #include "wine/port.h"
25
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 */
104
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"
112
113 #include "dinput_private.h"
114 #include "device_private.h"
115 #include "joystick_private.h"
116
117 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
118
119 #ifdef HAVE_IOHIDMANAGERCREATE
120
121 static IOHIDManagerRef gIOHIDManagerRef = NULL;
122 static CFArrayRef gDevices = NULL;
123
124 typedef struct JoystickImpl JoystickImpl;
125 static const IDirectInputDevice8AVtbl JoystickAvt;
126 static const IDirectInputDevice8WVtbl JoystickWvt;
127
128 struct JoystickImpl
129 {
130 struct JoystickGenericImpl generic;
131
132 /* osx private */
133 int id;
134 CFMutableArrayRef elementCFArrayRef;
135 ObjProps **propmap;
136 };
137
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}
140 };
141
142 static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context)
143 {
144 CFArrayAppendValue( ( CFMutableArrayRef ) context, value );
145 }
146
147 static CFMutableDictionaryRef creates_osx_device_match(int usage)
148 {
149 CFMutableDictionaryRef result;
150
151 result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
152 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
153
154 if ( result )
155 {
156 int number = kHIDPage_GenericDesktop;
157 CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
158 kCFNumberIntType, &number);
159
160 if ( pageCFNumberRef )
161 {
162 CFNumberRef usageCFNumberRef;
163
164 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ),
165 pageCFNumberRef );
166 CFRelease( pageCFNumberRef );
167
168 usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
169 kCFNumberIntType, &usage);
170 if ( usageCFNumberRef )
171 {
172 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ),
173 usageCFNumberRef );
174 CFRelease( usageCFNumberRef );
175 }
176 else
177 {
178 ERR("CFNumberCreate() failed.\n");
179 return NULL;
180 }
181 }
182 else
183 {
184 ERR("CFNumberCreate failed.\n");
185 return NULL;
186 }
187 }
188 else
189 {
190 ERR("CFDictionaryCreateMutable failed.\n");
191 return NULL;
192 }
193
194 return result;
195 }
196
197 static int find_osx_devices(void)
198 {
199 IOReturn tIOReturn;
200 CFMutableDictionaryRef result;
201 CFSetRef devset;
202 CFArrayRef matching;
203
204 gIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
205 tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, 0L);
206 if ( kIOReturnSuccess != tIOReturn )
207 {
208 ERR("Couldn't open IOHIDManager.\n");
209 return 0;
210 }
211
212 matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
213 &kCFTypeArrayCallBacks );
214
215 /* build matching dictionary */
216 result = creates_osx_device_match(kHIDPage_Sport);
217 if (!result)
218 {
219 CFRelease(matching);
220 return 0;
221 }
222 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
223 result = creates_osx_device_match(kHIDPage_Game);
224 if (!result)
225 {
226 CFRelease(matching);
227 return 0;
228 }
229 CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
230
231 IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef, matching);
232 devset = IOHIDManagerCopyDevices( gIOHIDManagerRef );
233 if (devset)
234 {
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);
242
243 TRACE("found %i device(s)\n",(int)count);
244 return count;
245
246 }
247 return 0;
248 }
249
250 static int get_osx_device_name(int id, char *name, int length)
251 {
252 CFStringRef str;
253 IOHIDDeviceRef tIOHIDDeviceRef;
254
255 if (!gDevices)
256 return 0;
257
258 tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, id );
259
260 if (!tIOHIDDeviceRef)
261 return 0;
262
263 if (name)
264 name[0] = 0;
265
266 if (!tIOHIDDeviceRef)
267 {
268 ERR("Invalid Device requested %i\n",id);
269 return 0;
270 }
271
272 str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
273 if (str)
274 {
275 CFIndex len = CFStringGetLength(str);
276 if (length >= len)
277 {
278 CFStringGetCString(str,name,length,kCFStringEncodingASCII);
279 return len;
280 }
281 else
282 return (len+1);
283 }
284 return 0;
285 }
286
287 static void insert_sort_button(int header, IOHIDElementRef tIOHIDElementRef,
288 CFMutableArrayRef elementCFArrayRef, int index,
289 int target)
290 {
291 IOHIDElementRef targetElement;
292 int usage;
293
294 CFArraySetValueAtIndex(elementCFArrayRef, header+index, NULL);
295 targetElement = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elementCFArrayRef, header+target);
296 if (targetElement == NULL)
297 {
298 CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
299 return;
300 }
301 usage = IOHIDElementGetUsage( targetElement );
302 usage --; /* usage 1 based index */
303
304 insert_sort_button(header, targetElement, elementCFArrayRef, target, usage);
305 CFArraySetValueAtIndex(elementCFArrayRef, header+target,tIOHIDElementRef);
306 }
307
308 static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
309 {
310 IOHIDDeviceRef tIOHIDDeviceRef;
311 CFArrayRef gElementCFArrayRef;
312 DWORD axes = 0;
313 DWORD sliders = 0;
314 DWORD buttons = 0;
315 DWORD povs = 0;
316
317 device->elementCFArrayRef = NULL;
318
319 if (!gDevices)
320 return;
321
322 tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
323
324 if (!tIOHIDDeviceRef)
325 return;
326
327 gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef,
328 NULL, 0 );
329
330 if (gElementCFArrayRef)
331 {
332 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
333 /* build our element array in the order that dinput expects */
334 device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);
335
336 for ( idx = 0; idx < cnt; idx++ )
337 {
338 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
339 int eleType = IOHIDElementGetType( tIOHIDElementRef );
340 switch(eleType)
341 {
342 case kIOHIDElementTypeInput_Button:
343 {
344 int usagePage = IOHIDElementGetUsagePage( tIOHIDElementRef );
345 if (usagePage != kHIDPage_Button)
346 {
347 /* avoid strange elements found on the 360 controler */
348 continue;
349 }
350
351 if (buttons < 128)
352 {
353 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
354 buttons++;
355 }
356 break;
357 }
358 case kIOHIDElementTypeInput_Axis:
359 {
360 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
361 axes++;
362 break;
363 }
364 case kIOHIDElementTypeInput_Misc:
365 {
366 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
367 switch(usage)
368 {
369 case kHIDUsage_GD_Hatswitch:
370 {
371 CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
372 povs++;
373 break;
374 }
375 case kHIDUsage_GD_Slider:
376 sliders ++;
377 if (sliders > 2)
378 break;
379 /* fallthrough, sliders are axis */
380 case kHIDUsage_GD_X:
381 case kHIDUsage_GD_Y:
382 case kHIDUsage_GD_Z:
383 case kHIDUsage_GD_Rx:
384 case kHIDUsage_GD_Ry:
385 case kHIDUsage_GD_Rz:
386 {
387 CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
388 axis_map[axes]=usage;
389 axes++;
390 break;
391 }
392 default:
393 FIXME("Unhandled usage %i\n",usage);
394 }
395 break;
396 }
397 default:
398 FIXME("Unhandled type %i\n",eleType);
399 }
400 }
401 }
402
403 device->generic.devcaps.dwAxes = axes;
404 device->generic.devcaps.dwButtons = buttons;
405 device->generic.devcaps.dwPOVs = povs;
406
407 /* Sort buttons into correct order */
408 for (buttons = 0; buttons < device->generic.devcaps.dwButtons; buttons++)
409 {
410 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elementCFArrayRef, axes+povs+buttons);
411 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
412 usage --; /* usage is 1 indexed we need 0 indexed */
413 if (usage == buttons)
414 continue;
415
416 insert_sort_button(axes+povs, tIOHIDElementRef, device->elementCFArrayRef,buttons,usage);
417 }
418 }
419
420 static void get_osx_device_elements_props(JoystickImpl *device)
421 {
422 CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
423
424 if (gElementCFArrayRef)
425 {
426 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
427
428 for ( idx = 0; idx < cnt; idx++ )
429 {
430 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
431
432 device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
433 device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
434 device->generic.props[idx].lMin = 0;
435 device->generic.props[idx].lMax = 0xffff;
436 device->generic.props[idx].lDeadZone = 0;
437 device->generic.props[idx].lSaturation = 0;
438 }
439 }
440 }
441
442 static void poll_osx_device_state(JoystickGenericImpl *device_in)
443 {
444 JoystickImpl *device = (JoystickImpl*)device_in;
445 IOHIDDeviceRef tIOHIDDeviceRef;
446 CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
447
448 TRACE("polling device %i\n",device->id);
449
450 if (!gDevices)
451 return;
452
453 tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
454
455 if (!tIOHIDDeviceRef)
456 return;
457
458 if (gElementCFArrayRef)
459 {
460 int button_idx = 0;
461 int pov_idx = 0;
462 int slider_idx = 0;
463 CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
464
465 for ( idx = 0; idx < cnt; idx++ )
466 {
467 IOHIDValueRef valueRef;
468 int val;
469 IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
470 int eleType = IOHIDElementGetType( tIOHIDElementRef );
471
472 switch(eleType)
473 {
474 case kIOHIDElementTypeInput_Button:
475 if(button_idx < 128)
476 {
477 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
478 val = IOHIDValueGetIntegerValue(valueRef);
479 device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00;
480 button_idx ++;
481 }
482 break;
483 case kIOHIDElementTypeInput_Misc:
484 {
485 uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
486 switch(usage)
487 {
488 case kHIDUsage_GD_Hatswitch:
489 {
490 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
491 val = IOHIDValueGetIntegerValue(valueRef);
492 if (val >= 8)
493 device->generic.js.rgdwPOV[pov_idx] = -1;
494 else
495 device->generic.js.rgdwPOV[pov_idx] = val * 4500;
496 pov_idx ++;
497 break;
498 }
499 case kHIDUsage_GD_X:
500 case kHIDUsage_GD_Y:
501 case kHIDUsage_GD_Z:
502 case kHIDUsage_GD_Rx:
503 case kHIDUsage_GD_Ry:
504 case kHIDUsage_GD_Rz:
505 case kHIDUsage_GD_Slider:
506 {
507 IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
508 val = IOHIDValueGetIntegerValue(valueRef);
509 switch (usage)
510 {
511 case kHIDUsage_GD_X:
512 device->generic.js.lX = joystick_map_axis(&device->generic.props[idx], val);
513 break;
514 case kHIDUsage_GD_Y:
515 device->generic.js.lY = joystick_map_axis(&device->generic.props[idx], val);
516 break;
517 case kHIDUsage_GD_Z:
518 device->generic.js.lZ = joystick_map_axis(&device->generic.props[idx], val);
519 break;
520 case kHIDUsage_GD_Rx:
521 device->generic.js.lRx = joystick_map_axis(&device->generic.props[idx], val);
522 break;
523 case kHIDUsage_GD_Ry:
524 device->generic.js.lRy = joystick_map_axis(&device->generic.props[idx], val);
525 break;
526 case kHIDUsage_GD_Rz:
527 device->generic.js.lRz = joystick_map_axis(&device->generic.props[idx], val);
528 break;
529 case kHIDUsage_GD_Slider:
530 device->generic.js.rglSlider[slider_idx] = joystick_map_axis(&device->generic.props[idx], val);
531 slider_idx ++;
532 break;
533 }
534 break;
535 }
536 default:
537 FIXME("unhandled usage %i\n",usage);
538 }
539 break;
540 }
541 default:
542 FIXME("Unhandled type %i\n",eleType);
543 }
544 }
545 }
546 }
547
548 static INT find_joystick_devices(void)
549 {
550 static INT joystick_devices_count = -1;
551
552 if (joystick_devices_count != -1) return joystick_devices_count;
553
554 joystick_devices_count = find_osx_devices();
555
556 return joystick_devices_count;
557 }
558
559 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
560 {
561 if (id >= find_joystick_devices()) return FALSE;
562
563 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
564 WARN("force feedback not supported\n");
565 return FALSE;
566 }
567
568 if ((dwDevType == 0) ||
569 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
570 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
571 {
572 /* Return joystick */
573 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
574 lpddi->guidInstance.Data3 = id;
575 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
576 /* we only support traditional joysticks for now */
577 if (version >= 0x0800)
578 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
579 else
580 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
581 sprintf(lpddi->tszInstanceName, "Joystick %d", id);
582
583 /* get the device name */
584 get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
585
586 lpddi->guidFFDriver = GUID_NULL;
587 return TRUE;
588 }
589
590 return FALSE;
591 }
592
593 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
594 {
595 char name[MAX_PATH];
596 char friendly[32];
597
598 if (id >= find_joystick_devices()) return FALSE;
599
600 if (dwFlags & DIEDFL_FORCEFEEDBACK) {
601 WARN("force feedback not supported\n");
602 return FALSE;
603 }
604
605 if ((dwDevType == 0) ||
606 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
607 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
608 /* Return joystick */
609 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
610 lpddi->guidInstance.Data3 = id;
611 lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
612 /* we only support traditional joysticks for now */
613 if (version >= 0x0800)
614 lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
615 else
616 lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
617 sprintf(friendly, "Joystick %d", id);
618 MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
619 /* get the device name */
620 get_osx_device_name(id, name, MAX_PATH);
621
622 MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
623 lpddi->guidFFDriver = GUID_NULL;
624 return TRUE;
625 }
626
627 return FALSE;
628 }
629
630 static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput,
631 LPDIRECTINPUTDEVICEA* pdev, unsigned short index)
632 {
633 DWORD i;
634 JoystickImpl* newDevice;
635 char name[MAX_PATH];
636 HRESULT hr;
637 LPDIDATAFORMAT df = NULL;
638 int idx = 0;
639 int axis_map[8]; /* max axes */
640 int slider_count = 0;
641
642 TRACE("%s %p %p %p %hu\n", debugstr_guid(rguid), jvt, dinput, pdev, index);
643
644 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
645 if (newDevice == 0) {
646 WARN("out of memory\n");
647 *pdev = 0;
648 return DIERR_OUTOFMEMORY;
649 }
650
651 newDevice->id = index;
652
653 newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID;
654 newDevice->generic.guidInstance.Data3 = index;
655 newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
656 newDevice->generic.joy_polldev = poll_osx_device_state;
657
658 /* get the device name */
659 get_osx_device_name(index, name, MAX_PATH);
660 TRACE("Name %s\n",name);
661
662 /* copy the device name */
663 newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
664 strcpy(newDevice->generic.name, name);
665
666 memset(axis_map, 0, sizeof(axis_map));
667 get_osx_device_elements(newDevice, axis_map);
668
669 TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
670
671 if (newDevice->generic.devcaps.dwButtons > 128)
672 {
673 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
674 newDevice->generic.devcaps.dwButtons = 128;
675 }
676
677 newDevice->generic.base.lpVtbl = jvt;
678 newDevice->generic.base.ref = 1;
679 newDevice->generic.base.dinput = dinput;
680 newDevice->generic.base.guid = *rguid;
681 InitializeCriticalSection(&newDevice->generic.base.crit);
682 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
683
684 /* Create copy of default data format */
685 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
686 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
687
688 df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
689 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
690
691 for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
692 {
693 int wine_obj = -1;
694 switch (axis_map[i])
695 {
696 case kHIDUsage_GD_X: wine_obj = 0; break;
697 case kHIDUsage_GD_Y: wine_obj = 1; break;
698 case kHIDUsage_GD_Z: wine_obj = 2; break;
699 case kHIDUsage_GD_Rx: wine_obj = 3; break;
700 case kHIDUsage_GD_Ry: wine_obj = 4; break;
701 case kHIDUsage_GD_Rz: wine_obj = 5; break;
702 case kHIDUsage_GD_Slider:
703 wine_obj = 6 + slider_count;
704 slider_count++;
705 break;
706 }
707 if (wine_obj < 0 ) continue;
708
709 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
710 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
711 }
712
713 for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
714 {
715 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
716 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
717 }
718
719 for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
720 {
721 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
722 df->rgodf[idx ].pguid = &GUID_Button;
723 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
724 }
725 newDevice->generic.base.data_format.wine_df = df;
726
727 /* initialize default properties */
728 get_osx_device_elements_props(newDevice);
729
730 IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->generic.base.dinput);
731
732 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
733 newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
734 if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
735 newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
736 else
737 newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
738 newDevice->generic.devcaps.dwFFSamplePeriod = 0;
739 newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
740 newDevice->generic.devcaps.dwFirmwareRevision = 0;
741 newDevice->generic.devcaps.dwHardwareRevision = 0;
742 newDevice->generic.devcaps.dwFFDriverVersion = 0;
743
744 if (TRACE_ON(dinput)) {
745 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
746 _dump_DIDEVCAPS(&newDevice->generic.devcaps);
747 }
748
749 *pdev = (LPDIRECTINPUTDEVICEA)newDevice;
750
751 return DI_OK;
752
753 FAILED:
754 hr = DIERR_OUTOFMEMORY;
755 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
756 HeapFree(GetProcessHeap(), 0, df);
757 release_DataFormat(&newDevice->generic.base.data_format);
758 HeapFree(GetProcessHeap(),0,newDevice->generic.name);
759 HeapFree(GetProcessHeap(),0,newDevice);
760 *pdev = 0;
761
762 return hr;
763 }
764
765 /******************************************************************************
766 * get_joystick_index : Get the joystick index from a given GUID
767 */
768 static unsigned short get_joystick_index(REFGUID guid)
769 {
770 GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
771 GUID dev_guid = *guid;
772
773 wine_joystick.Data3 = 0;
774 dev_guid.Data3 = 0;
775
776 /* for the standard joystick GUID use index 0 */
777 if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
778
779 /* for the wine joystick GUIDs use the index stored in Data3 */
780 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
781
782 return 0xffff;
783 }
784
785 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
786 {
787 unsigned short index;
788 int joystick_devices_count;
789
790 TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
791 *pdev = NULL;
792
793 if ((joystick_devices_count = find_joystick_devices()) == 0)
794 return DIERR_DEVICENOTREG;
795
796 if ((index = get_joystick_index(rguid)) < 0xffff &&
797 joystick_devices_count && index < joystick_devices_count)
798 {
799 if ((riid == NULL) ||
800 IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
801 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
802 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
803 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
804 {
805 return alloc_device(rguid, &JoystickAvt, dinput, pdev, index);
806 }
807
808 WARN("no interface\n");
809 return DIERR_NOINTERFACE;
810 }
811
812 return DIERR_DEVICENOTREG;
813 }
814
815 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
816 {
817 unsigned short index;
818 int joystick_devices_count;
819
820 TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
821 *pdev = NULL;
822
823 if ((joystick_devices_count = find_joystick_devices()) == 0)
824 return DIERR_DEVICENOTREG;
825
826 if ((index = get_joystick_index(rguid)) < 0xffff &&
827 joystick_devices_count && index < joystick_devices_count)
828 {
829 if ((riid == NULL) ||
830 IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
831 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
832 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
833 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
834 {
835 return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev, index);
836 }
837 WARN("no interface\n");
838 return DIERR_NOINTERFACE;
839 }
840
841 WARN("invalid device GUID %s\n",debugstr_guid(rguid));
842 return DIERR_DEVICENOTREG;
843 }
844
845 const struct dinput_device joystick_osx_device = {
846 "Wine OS X joystick driver",
847 joydev_enum_deviceA,
848 joydev_enum_deviceW,
849 joydev_create_deviceA,
850 joydev_create_deviceW
851 };
852
853 static const IDirectInputDevice8AVtbl JoystickAvt =
854 {
855 IDirectInputDevice2AImpl_QueryInterface,
856 IDirectInputDevice2AImpl_AddRef,
857 IDirectInputDevice2AImpl_Release,
858 JoystickAGenericImpl_GetCapabilities,
859 IDirectInputDevice2AImpl_EnumObjects,
860 JoystickAGenericImpl_GetProperty,
861 JoystickAGenericImpl_SetProperty,
862 IDirectInputDevice2AImpl_Acquire,
863 IDirectInputDevice2AImpl_Unacquire,
864 JoystickAGenericImpl_GetDeviceState,
865 IDirectInputDevice2AImpl_GetDeviceData,
866 IDirectInputDevice2AImpl_SetDataFormat,
867 IDirectInputDevice2AImpl_SetEventNotification,
868 IDirectInputDevice2AImpl_SetCooperativeLevel,
869 JoystickAGenericImpl_GetObjectInfo,
870 JoystickAGenericImpl_GetDeviceInfo,
871 IDirectInputDevice2AImpl_RunControlPanel,
872 IDirectInputDevice2AImpl_Initialize,
873 IDirectInputDevice2AImpl_CreateEffect,
874 IDirectInputDevice2AImpl_EnumEffects,
875 IDirectInputDevice2AImpl_GetEffectInfo,
876 IDirectInputDevice2AImpl_GetForceFeedbackState,
877 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
878 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
879 IDirectInputDevice2AImpl_Escape,
880 JoystickAGenericImpl_Poll,
881 IDirectInputDevice2AImpl_SendDeviceData,
882 IDirectInputDevice7AImpl_EnumEffectsInFile,
883 IDirectInputDevice7AImpl_WriteEffectToFile,
884 IDirectInputDevice8AImpl_BuildActionMap,
885 IDirectInputDevice8AImpl_SetActionMap,
886 IDirectInputDevice8AImpl_GetImageInfo
887 };
888
889 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
890 # define XCAST(fun) (typeof(JoystickWvt.fun))
891 #else
892 # define XCAST(fun) (void*)
893 #endif
894
895 static const IDirectInputDevice8WVtbl JoystickWvt =
896 {
897 IDirectInputDevice2WImpl_QueryInterface,
898 XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
899 XCAST(Release)IDirectInputDevice2AImpl_Release,
900 XCAST(GetCapabilities)JoystickAGenericImpl_GetCapabilities,
901 IDirectInputDevice2WImpl_EnumObjects,
902 XCAST(GetProperty)JoystickAGenericImpl_GetProperty,
903 XCAST(SetProperty)JoystickAGenericImpl_SetProperty,
904 XCAST(Acquire)IDirectInputDevice2AImpl_Acquire,
905 XCAST(Unacquire)IDirectInputDevice2AImpl_Unacquire,
906 XCAST(GetDeviceState)JoystickAGenericImpl_GetDeviceState,
907 XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
908 XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
909 XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
910 XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
911 JoystickWGenericImpl_GetObjectInfo,
912 JoystickWGenericImpl_GetDeviceInfo,
913 XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
914 XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
915 XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
916 IDirectInputDevice2WImpl_EnumEffects,
917 IDirectInputDevice2WImpl_GetEffectInfo,
918 XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
919 XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
920 XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
921 XCAST(Escape)IDirectInputDevice2AImpl_Escape,
922 XCAST(Poll)JoystickAGenericImpl_Poll,
923 XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
924 IDirectInputDevice7WImpl_EnumEffectsInFile,
925 IDirectInputDevice7WImpl_WriteEffectToFile,
926 IDirectInputDevice8WImpl_BuildActionMap,
927 IDirectInputDevice8WImpl_SetActionMap,
928 IDirectInputDevice8WImpl_GetImageInfo
929 };
930 #undef XCAST
931
932 #else /* HAVE_IOHIDMANAGERCREATE */
933
934 const struct dinput_device joystick_osx_device = {
935 "Wine OS X joystick driver",
936 NULL,
937 NULL,
938 NULL,
939 NULL
940 };
941
942 #endif /* HAVE_IOHIDMANAGERCREATE */
943
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.