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_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 */ 81 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 "devguid.h" 89 #include "dinput.h" 90 91 #include "dinput_private.h" 92 #include "device_private.h" 93 #include "joystick_private.h" 94 95 #ifdef HAVE_IOHIDMANAGERCREATE 96 97 WINE_DEFAULT_DEBUG_CHANNEL(dinput); 98 99 static CFMutableArrayRef device_main_elements = NULL; 100 101 typedef struct JoystickImpl JoystickImpl; 102 static const IDirectInputDevice8AVtbl JoystickAvt; 103 static const IDirectInputDevice8WVtbl JoystickWvt; 104 105 struct JoystickImpl 106 { 107 struct JoystickGenericImpl generic; 108 109 /* osx private */ 110 int id; 111 CFArrayRef elements; 112 ObjProps **propmap; 113 FFDeviceObjectReference ff; 114 struct list effects; 115 }; 116 117 static inline JoystickImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface) 118 { 119 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface), 120 JoystickGenericImpl, base), JoystickImpl, generic); 121 } 122 static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface) 123 { 124 return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface), 125 JoystickGenericImpl, base), JoystickImpl, generic); 126 } 127 128 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This) 129 { 130 return &This->generic.base.IDirectInputDevice8W_iface; 131 } 132 133 typedef struct _EffectImpl { 134 IDirectInputEffect IDirectInputEffect_iface; 135 LONG ref; 136 137 JoystickImpl *device; 138 FFEffectObjectReference effect; 139 GUID guid; 140 141 struct list entry; 142 } EffectImpl; 143 144 static EffectImpl *impl_from_IDirectInputEffect(IDirectInputEffect *iface) 145 { 146 return CONTAINING_RECORD(iface, EffectImpl, IDirectInputEffect_iface); 147 } 148 149 static const IDirectInputEffectVtbl EffectVtbl; 150 151 static const GUID DInput_Wine_OsX_Joystick_GUID = { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */ 152 0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A} 153 }; 154 155 static HRESULT osx_to_win32_hresult(HRESULT in) 156 { 157 /* OSX returns 16-bit COM runtime errors, which we should 158 * convert to win32 */ 159 switch(in){ 160 case 0x80000001: 161 return E_NOTIMPL; 162 case 0x80000002: 163 return E_OUTOFMEMORY; 164 case 0x80000003: 165 return E_INVALIDARG; 166 case 0x80000004: 167 return E_NOINTERFACE; 168 case 0x80000005: 169 return E_POINTER; 170 case 0x80000006: 171 return E_HANDLE; 172 case 0x80000007: 173 return E_ABORT; 174 case 0x80000008: 175 return E_FAIL; 176 case 0x80000009: 177 return E_ACCESSDENIED; 178 case 0x8000FFFF: 179 return E_UNEXPECTED; 180 } 181 return in; 182 } 183 184 static long get_device_property_long(IOHIDDeviceRef device, CFStringRef key) 185 { 186 CFTypeRef ref; 187 long result = 0; 188 189 if (device) 190 { 191 assert(IOHIDDeviceGetTypeID() == CFGetTypeID(device)); 192 193 ref = IOHIDDeviceGetProperty(device, key); 194 195 if (ref && CFNumberGetTypeID() == CFGetTypeID(ref)) 196 CFNumberGetValue((CFNumberRef)ref, kCFNumberLongType, &result); 197 } 198 199 return result; 200 } 201 202 static CFStringRef copy_device_name(IOHIDDeviceRef device) 203 { 204 CFStringRef name; 205 206 if (device) 207 { 208 CFTypeRef ref_name; 209 210 assert(IOHIDDeviceGetTypeID() == CFGetTypeID(device)); 211 212 ref_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); 213 214 if (ref_name && CFStringGetTypeID() == CFGetTypeID(ref_name)) 215 name = CFStringCreateCopy(kCFAllocatorDefault, ref_name); 216 else 217 { 218 long vendID, prodID; 219 220 vendID = get_device_property_long(device, CFSTR(kIOHIDVendorIDKey)); 221 prodID = get_device_property_long(device, CFSTR(kIOHIDProductIDKey)); 222 name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("0x%04lx 0x%04lx"), vendID, prodID); 223 } 224 } 225 else 226 { 227 ERR("NULL device\n"); 228 name = CFStringCreateCopy(kCFAllocatorDefault, CFSTR("")); 229 } 230 231 return name; 232 } 233 234 static long get_device_location_ID(IOHIDDeviceRef device) 235 { 236 return get_device_property_long(device, CFSTR(kIOHIDLocationIDKey)); 237 } 238 239 static void copy_set_to_array(const void *value, void *context) 240 { 241 CFArrayAppendValue(context, value); 242 } 243 244 static CFComparisonResult device_name_comparator(IOHIDDeviceRef device1, IOHIDDeviceRef device2) 245 { 246 CFStringRef name1 = copy_device_name(device1), name2 = copy_device_name(device2); 247 CFComparisonResult result = CFStringCompare(name1, name2, (kCFCompareForcedOrdering | kCFCompareNumerically)); 248 CFRelease(name1); 249 CFRelease(name2); 250 return result; 251 } 252 253 static CFComparisonResult device_location_name_comparator(const void *val1, const void *val2, void *context) 254 { 255 IOHIDDeviceRef device1 = (IOHIDDeviceRef)val1, device2 = (IOHIDDeviceRef)val2; 256 long loc1 = get_device_location_ID(device1), loc2 = get_device_location_ID(device2); 257 258 if (loc1 < loc2) 259 return kCFCompareLessThan; 260 else if (loc1 > loc2) 261 return kCFCompareGreaterThan; 262 /* virtual joysticks may not have a kIOHIDLocationIDKey and will default to location ID of 0, this orders virtual joysticks by their name */ 263 return device_name_comparator(device1, device2); 264 } 265 266 static const char* debugstr_cf(CFTypeRef t) 267 { 268 CFStringRef s; 269 const char* ret; 270 271 if (!t) return "(null)"; 272 273 if (CFGetTypeID(t) == CFStringGetTypeID()) 274 s = t; 275 else 276 s = CFCopyDescription(t); 277 ret = CFStringGetCStringPtr(s, kCFStringEncodingUTF8); 278 if (ret) ret = debugstr_a(ret); 279 if (!ret) 280 { 281 const UniChar* u = CFStringGetCharactersPtr(s); 282 if (u) 283 ret = debugstr_wn((const WCHAR*)u, CFStringGetLength(s)); 284 } 285 if (!ret) 286 { 287 UniChar buf[200]; 288 int len = min(CFStringGetLength(s), ARRAY_SIZE(buf)); 289 CFStringGetCharacters(s, CFRangeMake(0, len), buf); 290 ret = debugstr_wn(buf, len); 291 } 292 if (s != t) CFRelease(s); 293 return ret; 294 } 295 296 static const char* debugstr_device(IOHIDDeviceRef device) 297 { 298 return wine_dbg_sprintf("<IOHIDDevice %p product %s IOHIDLocationID %lu>", device, 299 debugstr_cf(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey))), 300 get_device_location_ID(device)); 301 } 302 303 static const char* debugstr_element(IOHIDElementRef element) 304 { 305 return wine_dbg_sprintf("<IOHIDElement %p type %d usage %u/%u device %p>", element, 306 IOHIDElementGetType(element), IOHIDElementGetUsagePage(element), 307 IOHIDElementGetUsage(element), IOHIDElementGetDevice(element)); 308 } 309 310 static IOHIDDeviceRef get_device_ref(int id) 311 { 312 IOHIDElementRef device_main_element; 313 IOHIDDeviceRef hid_device; 314 315 TRACE("id %d\n", id); 316 317 if (!device_main_elements || id >= CFArrayGetCount(device_main_elements)) 318 return 0; 319 320 device_main_element = (IOHIDElementRef)CFArrayGetValueAtIndex(device_main_elements, id); 321 if (!device_main_element) 322 { 323 ERR("Invalid Element requested %i\n",id); 324 return 0; 325 } 326 327 hid_device = IOHIDElementGetDevice(device_main_element); 328 if (!hid_device) 329 { 330 ERR("Invalid Device requested %i\n",id); 331 return 0; 332 } 333 334 TRACE("-> %s\n", debugstr_device(hid_device)); 335 return hid_device; 336 } 337 338 static HRESULT get_ff(IOHIDDeviceRef device, FFDeviceObjectReference *ret) 339 { 340 io_service_t service; 341 CFMutableDictionaryRef matching; 342 CFTypeRef location_id; 343 HRESULT hr; 344 345 TRACE("device %s\n", debugstr_device(device)); 346 347 matching = IOServiceMatching(kIOHIDDeviceKey); 348 if(!matching){ 349 WARN("IOServiceMatching failed, force feedback disabled\n"); 350 return DIERR_DEVICENOTREG; 351 } 352 353 location_id = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDLocationIDKey)); 354 if(!location_id){ 355 CFRelease(matching); 356 WARN("IOHIDDeviceGetProperty failed, force feedback disabled\n"); 357 return DIERR_DEVICENOTREG; 358 } 359 360 CFDictionaryAddValue(matching, CFSTR(kIOHIDLocationIDKey), location_id); 361 362 service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); 363 364 if (ret) 365 hr = osx_to_win32_hresult(FFCreateDevice(service, ret)); 366 else 367 hr = FFIsForceFeedback(service) == FF_OK ? S_OK : S_FALSE; 368 369 IOObjectRelease(service); 370 TRACE("-> hr 0x%08x *ret %p\n", hr, ret ? *ret : NULL); 371 return hr; 372 } 373 374 static CFMutableDictionaryRef create_osx_device_match(int usage) 375 { 376 CFMutableDictionaryRef result; 377 378 TRACE("usage %d\n", usage); 379 380 result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, 381 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); 382 383 if ( result ) 384 { 385 int number = kHIDPage_GenericDesktop; 386 CFNumberRef page = CFNumberCreate( kCFAllocatorDefault, 387 kCFNumberIntType, &number); 388 389 if (page) 390 { 391 CFNumberRef cf_usage; 392 393 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ), page ); 394 CFRelease( page ); 395 396 cf_usage = CFNumberCreate( kCFAllocatorDefault, 397 kCFNumberIntType, &usage); 398 if (cf_usage) 399 { 400 CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ), cf_usage ); 401 CFRelease( cf_usage ); 402 } 403 else 404 { 405 ERR("CFNumberCreate() failed.\n"); 406 CFRelease(result); 407 return NULL; 408 } 409 } 410 else 411 { 412 ERR("CFNumberCreate failed.\n"); 413 CFRelease(result); 414 return NULL; 415 } 416 } 417 else 418 { 419 ERR("CFDictionaryCreateMutable failed.\n"); 420 return NULL; 421 } 422 423 return result; 424 } 425 426 static CFIndex find_top_level(IOHIDDeviceRef hid_device, CFMutableArrayRef main_elements) 427 { 428 CFArrayRef elements; 429 CFIndex total = 0; 430 431 TRACE("hid_device %s\n", debugstr_device(hid_device)); 432 433 if (!hid_device) 434 return 0; 435 436 elements = IOHIDDeviceCopyMatchingElements(hid_device, NULL, 0); 437 438 if (elements) 439 { 440 CFIndex idx, cnt = CFArrayGetCount(elements); 441 for (idx=0; idx<cnt; idx++) 442 { 443 IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, idx); 444 int type = IOHIDElementGetType(element); 445 446 TRACE("element %s\n", debugstr_element(element)); 447 448 /* Check for top-level gaming device collections */ 449 if (type == kIOHIDElementTypeCollection && IOHIDElementGetParent(element) == 0) 450 { 451 int usage_page = IOHIDElementGetUsagePage(element); 452 int usage = IOHIDElementGetUsage(element); 453 454 if (usage_page == kHIDPage_GenericDesktop && 455 (usage == kHIDUsage_GD_Joystick || usage == kHIDUsage_GD_GamePad)) 456 { 457 CFArrayAppendValue(main_elements, element); 458 total++; 459 } 460 } 461 } 462 CFRelease(elements); 463 } 464 465 TRACE("-> total %d\n", (int)total); 466 return total; 467 } 468 469 static void get_element_children(IOHIDElementRef element, CFMutableArrayRef all_children) 470 { 471 CFIndex idx, cnt; 472 CFArrayRef element_children = IOHIDElementGetChildren(element); 473 474 TRACE("element %s\n", debugstr_element(element)); 475 476 cnt = CFArrayGetCount(element_children); 477 478 /* Either add the element to the array or grab its children */ 479 for (idx=0; idx<cnt; idx++) 480 { 481 IOHIDElementRef child; 482 483 child = (IOHIDElementRef)CFArrayGetValueAtIndex(element_children, idx); 484 TRACE("child %s\n", debugstr_element(child)); 485 if (IOHIDElementGetType(child) == kIOHIDElementTypeCollection) 486 get_element_children(child, all_children); 487 else 488 CFArrayAppendValue(all_children, child); 489 } 490 } 491 492 static int find_osx_devices(void) 493 { 494 IOHIDManagerRef hid_manager; 495 CFMutableDictionaryRef result; 496 CFSetRef devset; 497 CFMutableArrayRef matching; 498 499 TRACE("()\n"); 500 501 hid_manager = IOHIDManagerCreate( kCFAllocatorDefault, 0L ); 502 if (IOHIDManagerOpen( hid_manager, 0 ) != kIOReturnSuccess) 503 { 504 ERR("Couldn't open IOHIDManager.\n"); 505 CFRelease( hid_manager ); 506 return 0; 507 } 508 509 matching = CFArrayCreateMutable( kCFAllocatorDefault, 0, 510 &kCFTypeArrayCallBacks ); 511 512 /* build matching dictionary */ 513 result = create_osx_device_match(kHIDUsage_GD_Joystick); 514 if (!result) 515 { 516 CFRelease(matching); 517 goto fail; 518 } 519 CFArrayAppendValue( matching, result ); 520 CFRelease( result ); 521 result = create_osx_device_match(kHIDUsage_GD_GamePad); 522 if (!result) 523 { 524 CFRelease(matching); 525 goto fail; 526 } 527 CFArrayAppendValue( matching, result ); 528 CFRelease( result ); 529 530 IOHIDManagerSetDeviceMatchingMultiple( hid_manager, matching); 531 CFRelease( matching ); 532 devset = IOHIDManagerCopyDevices( hid_manager ); 533 if (devset) 534 { 535 CFIndex num_devices, num_main_elements, idx; 536 CFMutableArrayRef devices; 537 538 num_devices = CFSetGetCount(devset); 539 devices = CFArrayCreateMutable(kCFAllocatorDefault, num_devices, &kCFTypeArrayCallBacks); 540 CFSetApplyFunction(devset, copy_set_to_array, devices); 541 CFRelease(devset); 542 CFArraySortValues(devices, CFRangeMake(0, num_devices), device_location_name_comparator, NULL); 543 544 device_main_elements = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 545 if (!device_main_elements) 546 { 547 CFRelease( devices ); 548 goto fail; 549 } 550 551 num_main_elements = 0; 552 for (idx = 0; idx < num_devices; idx++) 553 { 554 CFIndex top; 555 IOHIDDeviceRef hid_device; 556 557 hid_device = (IOHIDDeviceRef) CFArrayGetValueAtIndex(devices, idx); 558 TRACE("hid_device %s\n", debugstr_device(hid_device)); 559 top = find_top_level(hid_device, device_main_elements); 560 num_main_elements += top; 561 } 562 563 CFRelease(devices); 564 565 TRACE("found %i device(s), %i collection(s)\n",(int)num_devices,(int)num_main_elements); 566 return (int)num_main_elements; 567 } 568 569 fail: 570 IOHIDManagerClose( hid_manager, 0 ); 571 CFRelease( hid_manager ); 572 return 0; 573 } 574 575 static int get_osx_device_name(int id, char *name, int length) 576 { 577 CFStringRef str; 578 IOHIDDeviceRef hid_device; 579 580 hid_device = get_device_ref(id); 581 582 TRACE("id %d hid_device %s\n", id, debugstr_device(hid_device)); 583 584 if (name) 585 name[0] = 0; 586 587 if (!hid_device) 588 return 0; 589 590 str = IOHIDDeviceGetProperty(hid_device, CFSTR( kIOHIDProductKey )); 591 if (str) 592 { 593 CFIndex len = CFStringGetLength(str); 594 if (length >= len) 595 { 596 CFStringGetCString(str,name,length,kCFStringEncodingASCII); 597 return len; 598 } 599 else 600 return (len+1); 601 } 602 return 0; 603 } 604 605 static CFComparisonResult button_usage_comparator(const void *val1, const void *val2, void *context) 606 { 607 IOHIDElementRef element1 = (IOHIDElementRef)val1, element2 = (IOHIDElementRef)val2; 608 int usage1 = IOHIDElementGetUsage(element1), usage2 = IOHIDElementGetUsage(element2); 609 610 if (usage1 < usage2) 611 return kCFCompareLessThan; 612 if (usage1 > usage2) 613 return kCFCompareGreaterThan; 614 return kCFCompareEqualTo; 615 } 616 617 static void get_osx_device_elements(JoystickImpl *device, int axis_map[8]) 618 { 619 IOHIDElementRef device_main_element; 620 CFMutableArrayRef elements; 621 DWORD sliders = 0; 622 623 TRACE("device %p device->id %d\n", device, device->id); 624 625 device->elements = NULL; 626 627 if (!device_main_elements || device->id >= CFArrayGetCount(device_main_elements)) 628 return; 629 630 device_main_element = (IOHIDElementRef)CFArrayGetValueAtIndex(device_main_elements, device->id); 631 TRACE("device_main_element %s\n", debugstr_element(device_main_element)); 632 if (!device_main_element) 633 return; 634 635 elements = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 636 get_element_children(device_main_element, elements); 637 638 if (elements) 639 { 640 CFIndex idx, cnt = CFArrayGetCount( elements ); 641 CFMutableArrayRef axes = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 642 CFMutableArrayRef buttons = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 643 CFMutableArrayRef povs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 644 645 for ( idx = 0; idx < cnt; idx++ ) 646 { 647 IOHIDElementRef element = ( IOHIDElementRef ) CFArrayGetValueAtIndex( elements, idx ); 648 int type = IOHIDElementGetType( element ); 649 int usage_page = IOHIDElementGetUsagePage( element ); 650 651 TRACE("element %s\n", debugstr_element(element)); 652 653 if (usage_page >= kHIDPage_VendorDefinedStart) 654 { 655 /* vendor pages can repurpose type ids, resulting in incorrect case matches below (e.g. ds4 controllers) */ 656 continue; 657 } 658 659 switch(type) 660 { 661 case kIOHIDElementTypeInput_Button: 662 { 663 TRACE("kIOHIDElementTypeInput_Button usage_page %d\n", usage_page); 664 if (usage_page != kHIDPage_Button) 665 { 666 /* avoid strange elements found on the 360 controller */ 667 continue; 668 } 669 670 if (CFArrayGetCount(buttons) < 128) 671 CFArrayAppendValue(buttons, element); 672 break; 673 } 674 case kIOHIDElementTypeInput_Axis: 675 { 676 TRACE("kIOHIDElementTypeInput_Axis\n"); 677 CFArrayAppendValue(axes, element); 678 break; 679 } 680 case kIOHIDElementTypeInput_Misc: 681 { 682 uint32_t usage = IOHIDElementGetUsage( element ); 683 switch(usage) 684 { 685 case kHIDUsage_GD_Hatswitch: 686 { 687 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Hatswitch\n"); 688 CFArrayAppendValue(povs, element); 689 break; 690 } 691 case kHIDUsage_GD_Slider: 692 sliders ++; 693 if (sliders > 2) 694 break; 695 /* fallthrough, sliders are axis */ 696 case kHIDUsage_GD_X: 697 case kHIDUsage_GD_Y: 698 case kHIDUsage_GD_Z: 699 case kHIDUsage_GD_Rx: 700 case kHIDUsage_GD_Ry: 701 case kHIDUsage_GD_Rz: 702 { 703 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_* (%d)\n", usage); 704 axis_map[CFArrayGetCount(axes)]=usage; 705 CFArrayAppendValue(axes, element); 706 break; 707 } 708 default: 709 FIXME("kIOHIDElementTypeInput_Misc / Unhandled usage %i\n", usage); 710 } 711 break; 712 } 713 default: 714 FIXME("Unhandled type %i\n",type); 715 } 716 } 717 718 /* Sort buttons into correct order */ 719 CFArraySortValues(buttons, CFRangeMake(0, CFArrayGetCount(buttons)), button_usage_comparator, NULL); 720 721 device->generic.devcaps.dwAxes = CFArrayGetCount(axes); 722 device->generic.devcaps.dwButtons = CFArrayGetCount(buttons); 723 device->generic.devcaps.dwPOVs = CFArrayGetCount(povs); 724 725 TRACE("axes %u povs %u buttons %u\n", device->generic.devcaps.dwAxes, device->generic.devcaps.dwPOVs, 726 device->generic.devcaps.dwButtons); 727 728 /* build our element array in the order that dinput expects */ 729 CFArrayAppendArray(axes, povs, CFRangeMake(0, device->generic.devcaps.dwPOVs)); 730 CFArrayAppendArray(axes, buttons, CFRangeMake(0, device->generic.devcaps.dwButtons)); 731 device->elements = axes; 732 axes = NULL; 733 734 CFRelease(povs); 735 CFRelease(buttons); 736 CFRelease(elements); 737 } 738 else 739 { 740 device->generic.devcaps.dwAxes = 0; 741 device->generic.devcaps.dwButtons = 0; 742 device->generic.devcaps.dwPOVs = 0; 743 } 744 } 745 746 static void get_osx_device_elements_props(JoystickImpl *device) 747 { 748 TRACE("device %p\n", device); 749 750 if (device->elements) 751 { 752 CFIndex idx, cnt = CFArrayGetCount( device->elements ); 753 754 for ( idx = 0; idx < cnt; idx++ ) 755 { 756 IOHIDElementRef element = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elements, idx ); 757 758 TRACE("element %s\n", debugstr_element(element)); 759 760 device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(element); 761 device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(element); 762 device->generic.props[idx].lMin = 0; 763 device->generic.props[idx].lMax = 0xffff; 764 device->generic.props[idx].lDeadZone = 0; 765 device->generic.props[idx].lSaturation = 0; 766 } 767 } 768 } 769 770 static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface) 771 { 772 JoystickImpl *device = impl_from_IDirectInputDevice8A(iface); 773 IOHIDElementRef device_main_element; 774 IOHIDDeviceRef hid_device; 775 776 TRACE("device %p device->id %i\n", device, device->id); 777 778 if (!device_main_elements || device->id >= CFArrayGetCount(device_main_elements)) 779 return; 780 781 device_main_element = (IOHIDElementRef) CFArrayGetValueAtIndex(device_main_elements, device->id); 782 hid_device = IOHIDElementGetDevice(device_main_element); 783 TRACE("main element %s hid_device %s\n", debugstr_element(device_main_element), debugstr_device(hid_device)); 784 if (!hid_device) 785 return; 786 787 if (device->elements) 788 { 789 int button_idx = 0; 790 int pov_idx = 0; 791 int slider_idx = 0; 792 int inst_id; 793 CFIndex idx, cnt = CFArrayGetCount( device->elements ); 794 795 for ( idx = 0; idx < cnt; idx++ ) 796 { 797 IOHIDValueRef valueRef; 798 int val, oldVal, newVal; 799 IOHIDElementRef element = ( IOHIDElementRef ) CFArrayGetValueAtIndex( device->elements, idx ); 800 int type = IOHIDElementGetType( element ); 801 802 TRACE("element %s\n", debugstr_element(element)); 803 804 switch(type) 805 { 806 case kIOHIDElementTypeInput_Button: 807 TRACE("kIOHIDElementTypeInput_Button\n"); 808 if(button_idx < 128) 809 { 810 valueRef = NULL; 811 if (IOHIDDeviceGetValue(hid_device, element, &valueRef) != kIOReturnSuccess) 812 return; 813 if (valueRef == NULL) 814 return; 815 val = IOHIDValueGetIntegerValue(valueRef); 816 newVal = val ? 0x80 : 0x0; 817 oldVal = device->generic.js.rgbButtons[button_idx]; 818 device->generic.js.rgbButtons[button_idx] = newVal; 819 TRACE("valueRef %s val %d oldVal %d newVal %d\n", debugstr_cf(valueRef), val, oldVal, newVal); 820 if (oldVal != newVal) 821 { 822 button_idx = device->generic.button_map[button_idx]; 823 824 inst_id = DIDFT_MAKEINSTANCE(button_idx) | DIDFT_PSHBUTTON; 825 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++); 826 } 827 button_idx ++; 828 } 829 break; 830 case kIOHIDElementTypeInput_Misc: 831 { 832 uint32_t usage = IOHIDElementGetUsage( element ); 833 switch(usage) 834 { 835 case kHIDUsage_GD_Hatswitch: 836 { 837 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Hatswitch\n"); 838 valueRef = NULL; 839 if (IOHIDDeviceGetValue(hid_device, element, &valueRef) != kIOReturnSuccess) 840 return; 841 if (valueRef == NULL) 842 return; 843 val = IOHIDValueGetIntegerValue(valueRef); 844 oldVal = device->generic.js.rgdwPOV[pov_idx]; 845 if (val >= 8) 846 newVal = -1; 847 else 848 newVal = val * 4500; 849 device->generic.js.rgdwPOV[pov_idx] = newVal; 850 TRACE("valueRef %s val %d oldVal %d newVal %d\n", debugstr_cf(valueRef), val, oldVal, newVal); 851 if (oldVal != newVal) 852 { 853 inst_id = DIDFT_MAKEINSTANCE(pov_idx) | DIDFT_POV; 854 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++); 855 } 856 pov_idx ++; 857 break; 858 } 859 case kHIDUsage_GD_X: 860 case kHIDUsage_GD_Y: 861 case kHIDUsage_GD_Z: 862 case kHIDUsage_GD_Rx: 863 case kHIDUsage_GD_Ry: 864 case kHIDUsage_GD_Rz: 865 case kHIDUsage_GD_Slider: 866 { 867 int wine_obj = -1; 868 869 valueRef = NULL; 870 if (IOHIDDeviceGetValue(hid_device, element, &valueRef) != kIOReturnSuccess) 871 return; 872 if (valueRef == NULL) 873 return; 874 val = IOHIDValueGetIntegerValue(valueRef); 875 newVal = joystick_map_axis(&device->generic.props[idx], val); 876 switch (usage) 877 { 878 case kHIDUsage_GD_X: 879 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_X\n"); 880 wine_obj = 0; 881 oldVal = device->generic.js.lX; 882 device->generic.js.lX = newVal; 883 break; 884 case kHIDUsage_GD_Y: 885 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Y\n"); 886 wine_obj = 1; 887 oldVal = device->generic.js.lY; 888 device->generic.js.lY = newVal; 889 break; 890 case kHIDUsage_GD_Z: 891 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Z\n"); 892 wine_obj = 2; 893 oldVal = device->generic.js.lZ; 894 device->generic.js.lZ = newVal; 895 break; 896 case kHIDUsage_GD_Rx: 897 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Rx\n"); 898 wine_obj = 3; 899 oldVal = device->generic.js.lRx; 900 device->generic.js.lRx = newVal; 901 break; 902 case kHIDUsage_GD_Ry: 903 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Ry\n"); 904 wine_obj = 4; 905 oldVal = device->generic.js.lRy; 906 device->generic.js.lRy = newVal; 907 break; 908 case kHIDUsage_GD_Rz: 909 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Rz\n"); 910 wine_obj = 5; 911 oldVal = device->generic.js.lRz; 912 device->generic.js.lRz = newVal; 913 break; 914 case kHIDUsage_GD_Slider: 915 TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Slider\n"); 916 wine_obj = 6 + slider_idx; 917 oldVal = device->generic.js.rglSlider[slider_idx]; 918 device->generic.js.rglSlider[slider_idx] = newVal; 919 slider_idx ++; 920 break; 921 } 922 TRACE("valueRef %s val %d oldVal %d newVal %d\n", debugstr_cf(valueRef), val, oldVal, newVal); 923 if ((wine_obj != -1) && 924 (oldVal != newVal)) 925 { 926 inst_id = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS; 927 queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++); 928 } 929 930 break; 931 } 932 default: 933 FIXME("kIOHIDElementTypeInput_Misc / unhandled usage %i\n", usage); 934 } 935 break; 936 } 937 default: 938 FIXME("Unhandled type %i\n",type); 939 } 940 } 941 } 942 } 943 944 static INT find_joystick_devices(void) 945 { 946 static INT joystick_devices_count = -1; 947 948 if (joystick_devices_count != -1) return joystick_devices_count; 949 950 joystick_devices_count = find_osx_devices(); 951 952 return joystick_devices_count; 953 } 954 955 static DWORD make_vid_pid(IOHIDDeviceRef device) 956 { 957 long vendID, prodID; 958 959 vendID = get_device_property_long(device, CFSTR(kIOHIDVendorIDKey)); 960 prodID = get_device_property_long(device, CFSTR(kIOHIDProductIDKey)); 961 962 return MAKELONG(vendID, prodID); 963 } 964 965 static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) 966 { 967 IOHIDDeviceRef device; 968 BOOL is_joystick; 969 970 TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType, dwFlags, version, id); 971 972 if (id >= find_joystick_devices()) return E_FAIL; 973 974 device = get_device_ref(id); 975 976 if ((dwDevType == 0) || 977 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || 978 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) 979 { 980 if (dwFlags & DIEDFL_FORCEFEEDBACK) { 981 if(!device) 982 return S_FALSE; 983 if(get_ff(device, NULL) != S_OK) 984 return S_FALSE; 985 } 986 is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) == kHIDUsage_GD_Joystick; 987 /* Return joystick */ 988 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID; 989 lpddi->guidInstance.Data3 = id; 990 lpddi->guidProduct = DInput_PIDVID_Product_GUID; 991 lpddi->guidProduct.Data1 = make_vid_pid(device); 992 lpddi->dwDevType = get_device_type(version, is_joystick); 993 lpddi->dwDevType |= DIDEVTYPE_HID; 994 lpddi->wUsagePage = 0x01; /* Desktop */ 995 if (is_joystick) 996 lpddi->wUsage = 0x04; /* Joystick */ 997 else 998 lpddi->wUsage = 0x05; /* Game Pad */ 999 sprintf(lpddi->tszInstanceName, "Joystick %d", id); 1000 1001 /* get the device name */ 1002 get_osx_device_name(id, lpddi->tszProductName, MAX_PATH); 1003 1004 lpddi->guidFFDriver = GUID_NULL; 1005 return S_OK; 1006 } 1007 1008 return S_FALSE; 1009 } 1010 1011 static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) 1012 { 1013 char name[MAX_PATH]; 1014 char friendly[32]; 1015 IOHIDDeviceRef device; 1016 BOOL is_joystick; 1017 1018 TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType, dwFlags, version, id); 1019 1020 if (id >= find_joystick_devices()) return E_FAIL; 1021 1022 device = get_device_ref(id); 1023 1024 if ((dwDevType == 0) || 1025 ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version < 0x0800)) || 1026 (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) { 1027 1028 if (dwFlags & DIEDFL_FORCEFEEDBACK) { 1029 if(!device) 1030 return S_FALSE; 1031 if(get_ff(device, NULL) != S_OK) 1032 return S_FALSE; 1033 } 1034 is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) == kHIDUsage_GD_Joystick; 1035 /* Return joystick */ 1036 lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID; 1037 lpddi->guidInstance.Data3 = id; 1038 lpddi->guidProduct = DInput_PIDVID_Product_GUID; 1039 lpddi->guidProduct.Data1 = make_vid_pid(device); 1040 lpddi->dwDevType = get_device_type(version, is_joystick); 1041 lpddi->dwDevType |= DIDEVTYPE_HID; 1042 lpddi->wUsagePage = 0x01; /* Desktop */ 1043 if (is_joystick) 1044 lpddi->wUsage = 0x04; /* Joystick */ 1045 else 1046 lpddi->wUsage = 0x05; /* Game Pad */ 1047 sprintf(friendly, "Joystick %d", id); 1048 MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH); 1049 1050 /* get the device name */ 1051 get_osx_device_name(id, name, MAX_PATH); 1052 1053 MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH); 1054 lpddi->guidFFDriver = GUID_NULL; 1055 return S_OK; 1056 } 1057 1058 return S_FALSE; 1059 } 1060 1061 static const char *osx_ff_axis_name(UInt8 axis) 1062 { 1063 static char ret[6]; 1064 switch(axis){ 1065 case FFJOFS_X: 1066 return "FFJOFS_X"; 1067 case FFJOFS_Y: 1068 return "FFJOFS_Y"; 1069 case FFJOFS_Z: 1070 return "FFJOFS_Z"; 1071 } 1072 sprintf(ret, "%u", (unsigned int)axis); 1073 return ret; 1074 } 1075 1076 static BOOL osx_axis_has_ff(FFCAPABILITIES *ffcaps, UInt8 axis) 1077 { 1078 int i; 1079 for(i = 0; i < ffcaps->numFfAxes; ++i) 1080 if(ffcaps->ffAxes[i] == axis) 1081 return TRUE; 1082 return FALSE; 1083 } 1084 1085 static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput, 1086 JoystickImpl **pdev, unsigned short index) 1087 { 1088 DWORD i; 1089 IOHIDDeviceRef device; 1090 JoystickImpl* newDevice; 1091 char name[MAX_PATH]; 1092 HRESULT hr; 1093 LPDIDATAFORMAT df = NULL; 1094 int idx = 0; 1095 int axis_map[8]; /* max axes */ 1096 int slider_count = 0; 1097 FFCAPABILITIES ffcaps; 1098 1099 TRACE("%s %p %p %hu\n", debugstr_guid(rguid), dinput, pdev, index); 1100 1101 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); 1102 if (newDevice == 0) { 1103 WARN("out of memory\n"); 1104 *pdev = 0; 1105 return DIERR_OUTOFMEMORY; 1106 } 1107 1108 newDevice->id = index; 1109 1110 device = get_device_ref(index); 1111 1112 newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID; 1113 newDevice->generic.guidInstance.Data3 = index; 1114 newDevice->generic.guidProduct = DInput_PIDVID_Product_GUID; 1115 newDevice->generic.guidProduct.Data1 = make_vid_pid(device); 1116 newDevice->generic.joy_polldev = poll_osx_device_state; 1117 1118 /* get the device name */ 1119 get_osx_device_name(index, name, MAX_PATH); 1120 TRACE("Name %s\n",name); 1121 1122 /* copy the device name */ 1123 newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1); 1124 strcpy(newDevice->generic.name, name); 1125 1126 list_init(&newDevice->effects); 1127 if(get_ff(device, &newDevice->ff) == S_OK){ 1128 newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK; 1129 1130 hr = FFDeviceGetForceFeedbackCapabilities(newDevice->ff, &ffcaps); 1131 if(SUCCEEDED(hr)){ 1132 TRACE("FF Capabilities:\n"); 1133 TRACE("\tsupportedEffects: 0x%x\n", (unsigned int)ffcaps.supportedEffects); 1134 TRACE("\temulatedEffects: 0x%x\n", (unsigned int)ffcaps.emulatedEffects); 1135 TRACE("\tsubType: 0x%x\n", (unsigned int)ffcaps.subType); 1136 TRACE("\tnumFfAxes: %u\n", (unsigned int)ffcaps.numFfAxes); 1137 TRACE("\tffAxes: ["); 1138 for(i = 0; i < ffcaps.numFfAxes; ++i){ 1139 TRACE("%s", osx_ff_axis_name(ffcaps.ffAxes[i])); 1140 if(i < ffcaps.numFfAxes - 1) 1141 TRACE(", "); 1142 } 1143 TRACE("]\n"); 1144 TRACE("\tstorageCapacity: %u\n", (unsigned int)ffcaps.storageCapacity); 1145 TRACE("\tplaybackCapacity: %u\n", (unsigned int)ffcaps.playbackCapacity); 1146 } 1147 1148 hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_RESET); 1149 if(FAILED(hr)) 1150 WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_RESET) failed: %08x\n", hr); 1151 1152 hr = FFDeviceSendForceFeedbackCommand(newDevice->ff, FFSFFC_SETACTUATORSON); 1153 if(FAILED(hr)) 1154 WARN("FFDeviceSendForceFeedbackCommand(FFSFFC_SETACTUATORSON) failed: %08x\n", hr); 1155 } 1156 1157 memset(axis_map, 0, sizeof(axis_map)); 1158 get_osx_device_elements(newDevice, axis_map); 1159 1160 TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs); 1161 1162 if (newDevice->generic.devcaps.dwButtons > 128) 1163 { 1164 WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons); 1165 newDevice->generic.devcaps.dwButtons = 128; 1166 } 1167 1168 newDevice->generic.base.IDirectInputDevice8A_iface.lpVtbl = &JoystickAvt; 1169 newDevice->generic.base.IDirectInputDevice8W_iface.lpVtbl = &JoystickWvt; 1170 newDevice->generic.base.ref = 1; 1171 newDevice->generic.base.dinput = dinput; 1172 newDevice->generic.base.guid = *rguid; 1173 InitializeCriticalSection(&newDevice->generic.base.crit); 1174 newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit"); 1175 1176 /* Create copy of default data format */ 1177 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED; 1178 memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); 1179 1180 df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons; 1181 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED; 1182 1183 for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++) 1184 { 1185 int wine_obj = -1; 1186 BOOL has_ff = FALSE; 1187 switch (axis_map[i]) 1188 { 1189 case kHIDUsage_GD_X: 1190 wine_obj = 0; 1191 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_X); 1192 break; 1193 case kHIDUsage_GD_Y: 1194 wine_obj = 1; 1195 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_Y); 1196 break; 1197 case kHIDUsage_GD_Z: 1198 wine_obj = 2; 1199 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_Z); 1200 break; 1201 case kHIDUsage_GD_Rx: 1202 wine_obj = 3; 1203 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RX); 1204 break; 1205 case kHIDUsage_GD_Ry: 1206 wine_obj = 4; 1207 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RY); 1208 break; 1209 case kHIDUsage_GD_Rz: 1210 wine_obj = 5; 1211 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_RZ); 1212 break; 1213 case kHIDUsage_GD_Slider: 1214 wine_obj = 6 + slider_count; 1215 has_ff = (newDevice->ff != 0) && osx_axis_has_ff(&ffcaps, FFJOFS_SLIDER(slider_count)); 1216 slider_count++; 1217 break; 1218 } 1219 if (wine_obj < 0 ) continue; 1220 1221 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize); 1222 df->rgodf[idx].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS; 1223 if(has_ff) 1224 df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR; 1225 ++idx; 1226 } 1227 1228 for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++) 1229 { 1230 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize); 1231 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV; 1232 } 1233 1234 for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++) 1235 { 1236 memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize); 1237 df->rgodf[idx ].pguid = &GUID_Button; 1238 df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; 1239 } 1240 newDevice->generic.base.data_format.wine_df = df; 1241 1242 /* initialize default properties */ 1243 get_osx_device_elements_props(newDevice); 1244 1245 IDirectInput_AddRef(&newDevice->generic.base.dinput->IDirectInput7A_iface); 1246 1247 EnterCriticalSection(&dinput->crit); 1248 list_add_tail(&dinput->devices_list, &newDevice->generic.base.entry); 1249 LeaveCriticalSection(&dinput->crit); 1250 1251 newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps); 1252 newDevice->generic.devcaps.dwFlags |= DIDC_ATTACHED; 1253 if (newDevice->generic.base.dinput->dwVersion >= 0x0800) 1254 newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); 1255 else 1256 newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); 1257 newDevice->generic.devcaps.dwFFSamplePeriod = 0; 1258 newDevice->generic.devcaps.dwFFMinTimeResolution = 0; 1259 newDevice->generic.devcaps.dwFirmwareRevision = 0; 1260 newDevice->generic.devcaps.dwHardwareRevision = 0; 1261 newDevice->generic.devcaps.dwFFDriverVersion = 0; 1262 1263 if (TRACE_ON(dinput)) { 1264 TRACE("allocated device %p\n", newDevice); 1265 _dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df); 1266 _dump_DIDEVCAPS(&newDevice->generic.devcaps); 1267 } 1268 1269 *pdev = newDevice; 1270 1271 return DI_OK; 1272 1273 FAILED: 1274 hr = DIERR_OUTOFMEMORY; 1275 if (newDevice->ff) FFReleaseDevice(newDevice->ff); 1276 if (newDevice->elements) CFRelease(newDevice->elements); 1277 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf); 1278 HeapFree(GetProcessHeap(), 0, df); 1279 release_DataFormat(&newDevice->generic.base.data_format); 1280 HeapFree(GetProcessHeap(),0,newDevice->generic.name); 1281 HeapFree(GetProcessHeap(),0,newDevice); 1282 *pdev = 0; 1283 1284 return hr; 1285 } 1286 1287 /****************************************************************************** 1288 * get_joystick_index : Get the joystick index from a given GUID 1289 */ 1290 static unsigned short get_joystick_index(REFGUID guid) 1291 { 1292 GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID; 1293 GUID dev_guid = *guid; 1294 1295 wine_joystick.Data3 = 0; 1296 dev_guid.Data3 = 0; 1297 1298 /* for the standard joystick GUID use index 0 */ 1299 if(IsEqualGUID(&GUID_Joystick,guid)) return 0; 1300 1301 /* for the wine joystick GUIDs use the index stored in Data3 */ 1302 if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3; 1303 1304 return 0xffff; 1305 } 1306 1307 static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode) 1308 { 1309 unsigned short index; 1310 int joystick_devices_count; 1311 1312 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode); 1313 *pdev = NULL; 1314 1315 if ((joystick_devices_count = find_joystick_devices()) == 0) 1316 return DIERR_DEVICENOTREG; 1317 1318 if ((index = get_joystick_index(rguid)) < 0xffff && 1319 joystick_devices_count && index < joystick_devices_count) 1320 { 1321 JoystickImpl *This; 1322 HRESULT hr; 1323 1324 if (riid == NULL) 1325 ;/* nothing */ 1326 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) || 1327 IsEqualGUID(&IID_IDirectInputDevice2A, riid) || 1328 IsEqualGUID(&IID_IDirectInputDevice7A, riid) || 1329 IsEqualGUID(&IID_IDirectInputDevice8A, riid)) 1330 { 1331 unicode = 0; 1332 } 1333 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) || 1334 IsEqualGUID(&IID_IDirectInputDevice2W, riid) || 1335 IsEqualGUID(&IID_IDirectInputDevice7W, riid) || 1336 IsEqualGUID(&IID_IDirectInputDevice8W, riid)) 1337 { 1338 unicode = 1; 1339 } 1340 else 1341 { 1342 WARN("no interface\n"); 1343 return DIERR_NOINTERFACE; 1344 } 1345 1346 hr = alloc_device(rguid, dinput, &This, index); 1347 if (!This) return hr; 1348 1349 if (unicode) 1350 *pdev = &This->generic.base.IDirectInputDevice8W_iface; 1351 else 1352 *pdev = &This->generic.base.IDirectInputDevice8A_iface; 1353 return hr; 1354 } 1355 1356 return DIERR_DEVICENOTREG; 1357 } 1358 1359 static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph) 1360 { 1361 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 1362 1363 TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph); 1364 _dump_DIPROPHEADER(pdiph); 1365 1366 if (!IS_DIPROP(rguid)) return DI_OK; 1367 1368 switch (LOWORD(rguid)) { 1369 case (DWORD_PTR) DIPROP_GUIDANDPATH: 1370 { 1371 static const WCHAR formatW[] = {'\\','\\','?','\\','h','i','d','#','v','i','d','_','%','0','4','x','&', 1372 'p','i','d','_','%','0','4','x','&','%','s','_','%','i',0}; 1373 static const WCHAR miW[] = {'m','i',0}; 1374 static const WCHAR igW[] = {'i','g',0}; 1375 1376 BOOL is_gamepad; 1377 IOHIDDeviceRef device = get_device_ref(This->id); 1378 LPDIPROPGUIDANDPATH pd = (LPDIPROPGUIDANDPATH)pdiph; 1379 WORD vid = get_device_property_long(device, CFSTR(kIOHIDVendorIDKey)); 1380 WORD pid = get_device_property_long(device, CFSTR(kIOHIDProductIDKey)); 1381 1382 if (!pid || !vid) 1383 return DIERR_UNSUPPORTED; 1384 1385 is_gamepad = is_xinput_device(&This->generic.devcaps, vid, pid); 1386 pd->guidClass = GUID_DEVCLASS_HIDCLASS; 1387 sprintfW(pd->wszPath, formatW, vid, pid, is_gamepad ? igW : miW, This->id); 1388 1389 TRACE("DIPROP_GUIDANDPATH(%s, %s): returning fake path\n", debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath)); 1390 break; 1391 } 1392 1393 default: 1394 return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph); 1395 } 1396 1397 return DI_OK; 1398 } 1399 1400 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph) 1401 { 1402 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1403 return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph); 1404 } 1405 1406 static HRESULT osx_set_autocenter(JoystickImpl *This, 1407 const DIPROPDWORD *header) 1408 { 1409 UInt32 v; 1410 HRESULT hr; 1411 if(!This->ff) 1412 return DIERR_UNSUPPORTED; 1413 v = header->dwData; 1414 hr = osx_to_win32_hresult(FFDeviceSetForceFeedbackProperty(This->ff, FFPROP_AUTOCENTER, &v)); 1415 TRACE("returning: %08x\n", hr); 1416 return hr; 1417 } 1418 1419 static HRESULT osx_set_ffgain(JoystickImpl *This, const DIPROPDWORD *header) 1420 { 1421 UInt32 v; 1422 HRESULT hr; 1423 if(!This->ff) 1424 return DIERR_UNSUPPORTED; 1425 v = header->dwData; 1426 hr = osx_to_win32_hresult(FFDeviceSetForceFeedbackProperty(This->ff, FFPROP_FFGAIN, &v)); 1427 TRACE("returning: %08x\n", hr); 1428 return hr; 1429 } 1430 1431 static HRESULT WINAPI JoystickWImpl_SetProperty(IDirectInputDevice8W *iface, 1432 const GUID *prop, const DIPROPHEADER *header) 1433 { 1434 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 1435 1436 TRACE("%p %s %p\n", This, debugstr_guid(prop), header); 1437 1438 switch(LOWORD(prop)) 1439 { 1440 case (DWORD_PTR)DIPROP_AUTOCENTER: 1441 return osx_set_autocenter(This, (const DIPROPDWORD *)header); 1442 case (DWORD_PTR)DIPROP_FFGAIN: 1443 return osx_set_ffgain(This, (const DIPROPDWORD *)header); 1444 } 1445 1446 return JoystickWGenericImpl_SetProperty(iface, prop, header); 1447 } 1448 1449 static HRESULT WINAPI JoystickAImpl_SetProperty(IDirectInputDevice8A *iface, 1450 const GUID *prop, const DIPROPHEADER *header) 1451 { 1452 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1453 1454 TRACE("%p %s %p\n", This, debugstr_guid(prop), header); 1455 1456 switch(LOWORD(prop)) 1457 { 1458 case (DWORD_PTR)DIPROP_AUTOCENTER: 1459 return osx_set_autocenter(This, (const DIPROPDWORD *)header); 1460 case (DWORD_PTR)DIPROP_FFGAIN: 1461 return osx_set_ffgain(This, (const DIPROPDWORD *)header); 1462 } 1463 1464 return JoystickAGenericImpl_SetProperty(iface, prop, header); 1465 } 1466 1467 static CFUUIDRef effect_win_to_mac(const GUID *effect) 1468 { 1469 #define DO_MAP(X) \ 1470 if(IsEqualGUID(&GUID_##X, effect)) \ 1471 return kFFEffectType_##X##_ID; 1472 DO_MAP(ConstantForce) 1473 DO_MAP(RampForce) 1474 DO_MAP(Square) 1475 DO_MAP(Sine) 1476 DO_MAP(Triangle) 1477 DO_MAP(SawtoothUp) 1478 DO_MAP(SawtoothDown) 1479 DO_MAP(Spring) 1480 DO_MAP(Damper) 1481 DO_MAP(Inertia) 1482 DO_MAP(Friction) 1483 DO_MAP(CustomForce) 1484 #undef DO_MAP 1485 WARN("Unknown effect GUID! %s\n", debugstr_guid(effect)); 1486 return 0; 1487 } 1488 1489 static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface, 1490 const GUID *type, const DIEFFECT *params, IDirectInputEffect **out, 1491 IUnknown *outer) 1492 { 1493 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 1494 EffectImpl *effect; 1495 HRESULT hr; 1496 1497 TRACE("(%p)->(%s %p %p %p)\n", This, debugstr_guid(type), params, out, outer); 1498 dump_DIEFFECT(params, type, 0); 1499 1500 if(!This->ff){ 1501 TRACE("No force feedback support\n"); 1502 *out = NULL; 1503 return DIERR_UNSUPPORTED; 1504 } 1505 1506 if(outer) 1507 WARN("aggregation not implemented\n"); 1508 1509 effect = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); 1510 effect->IDirectInputEffect_iface.lpVtbl = &EffectVtbl; 1511 effect->ref = 1; 1512 effect->guid = *type; 1513 effect->device = This; 1514 1515 /* Mac's FFEFFECT and Win's DIEFFECT are binary identical. */ 1516 hr = osx_to_win32_hresult(FFDeviceCreateEffect(This->ff, 1517 effect_win_to_mac(type), (FFEFFECT*)params, &effect->effect)); 1518 if(FAILED(hr)){ 1519 WARN("FFDeviceCreateEffect failed: %08x\n", hr); 1520 HeapFree(GetProcessHeap(), 0, effect); 1521 return hr; 1522 } 1523 1524 list_add_tail(&This->effects, &effect->entry); 1525 *out = &effect->IDirectInputEffect_iface; 1526 1527 TRACE("allocated effect: %p\n", effect); 1528 1529 return S_OK; 1530 } 1531 1532 static HRESULT WINAPI JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface, 1533 const GUID *type, const DIEFFECT *params, IDirectInputEffect **out, 1534 IUnknown *outer) 1535 { 1536 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1537 1538 TRACE("(%p)->(%s %p %p %p)\n", This, debugstr_guid(type), params, out, outer); 1539 1540 return JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface, 1541 type, params, out, outer); 1542 } 1543 1544 static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(IDirectInputDevice8W *iface, 1545 DWORD flags) 1546 { 1547 JoystickImpl *This = impl_from_IDirectInputDevice8W(iface); 1548 HRESULT hr; 1549 1550 TRACE("%p 0x%x\n", This, flags); 1551 1552 if(!This->ff) 1553 return DI_NOEFFECT; 1554 1555 hr = osx_to_win32_hresult(FFDeviceSendForceFeedbackCommand(This->ff, flags)); 1556 if(FAILED(hr)){ 1557 WARN("FFDeviceSendForceFeedbackCommand failed: %08x\n", hr); 1558 return hr; 1559 } 1560 1561 return S_OK; 1562 } 1563 1564 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(IDirectInputDevice8A *iface, 1565 DWORD flags) 1566 { 1567 JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); 1568 1569 TRACE("%p 0x%x\n", This, flags); 1570 1571 return JoystickWImpl_SendForceFeedbackCommand(&This->generic.base.IDirectInputDevice8W_iface, flags); 1572 } 1573 1574 const struct dinput_device joystick_osx_device = { 1575 "Wine OS X joystick driver", 1576 joydev_enum_deviceA, 1577 joydev_enum_deviceW, 1578 joydev_create_device 1579 }; 1580 1581 static const IDirectInputDevice8AVtbl JoystickAvt = 1582 { 1583 IDirectInputDevice2AImpl_QueryInterface, 1584 IDirectInputDevice2AImpl_AddRef, 1585 IDirectInputDevice2AImpl_Release, 1586 JoystickAGenericImpl_GetCapabilities, 1587 IDirectInputDevice2AImpl_EnumObjects, 1588 JoystickAImpl_GetProperty, 1589 JoystickAImpl_SetProperty, 1590 IDirectInputDevice2AImpl_Acquire, 1591 IDirectInputDevice2AImpl_Unacquire, 1592 JoystickAGenericImpl_GetDeviceState, 1593 IDirectInputDevice2AImpl_GetDeviceData, 1594 IDirectInputDevice2AImpl_SetDataFormat, 1595 IDirectInputDevice2AImpl_SetEventNotification, 1596 IDirectInputDevice2AImpl_SetCooperativeLevel, 1597 JoystickAGenericImpl_GetObjectInfo, 1598 JoystickAGenericImpl_GetDeviceInfo, 1599 IDirectInputDevice2AImpl_RunControlPanel, 1600 IDirectInputDevice2AImpl_Initialize, 1601 JoystickAImpl_CreateEffect, 1602 IDirectInputDevice2AImpl_EnumEffects, 1603 IDirectInputDevice2AImpl_GetEffectInfo, 1604 IDirectInputDevice2AImpl_GetForceFeedbackState, 1605 JoystickAImpl_SendForceFeedbackCommand, 1606 IDirectInputDevice2AImpl_EnumCreatedEffectObjects, 1607 IDirectInputDevice2AImpl_Escape, 1608 JoystickAGenericImpl_Poll, 1609 IDirectInputDevice2AImpl_SendDeviceData, 1610 IDirectInputDevice7AImpl_EnumEffectsInFile, 1611 IDirectInputDevice7AImpl_WriteEffectToFile, 1612 JoystickAGenericImpl_BuildActionMap, 1613 JoystickAGenericImpl_SetActionMap, 1614 IDirectInputDevice8AImpl_GetImageInfo 1615 }; 1616 1617 static const IDirectInputDevice8WVtbl JoystickWvt = 1618 { 1619 IDirectInputDevice2WImpl_QueryInterface, 1620 IDirectInputDevice2WImpl_AddRef, 1621 IDirectInputDevice2WImpl_Release, 1622 JoystickWGenericImpl_GetCapabilities, 1623 IDirectInputDevice2WImpl_EnumObjects, 1624 JoystickWImpl_GetProperty, 1625 JoystickWImpl_SetProperty, 1626 IDirectInputDevice2WImpl_Acquire, 1627 IDirectInputDevice2WImpl_Unacquire, 1628 JoystickWGenericImpl_GetDeviceState, 1629 IDirectInputDevice2WImpl_GetDeviceData, 1630 IDirectInputDevice2WImpl_SetDataFormat, 1631 IDirectInputDevice2WImpl_SetEventNotification, 1632 IDirectInputDevice2WImpl_SetCooperativeLevel, 1633 JoystickWGenericImpl_GetObjectInfo, 1634 JoystickWGenericImpl_GetDeviceInfo, 1635 IDirectInputDevice2WImpl_RunControlPanel, 1636 IDirectInputDevice2WImpl_Initialize, 1637 JoystickWImpl_CreateEffect, 1638 IDirectInputDevice2WImpl_EnumEffects, 1639 IDirectInputDevice2WImpl_GetEffectInfo, 1640 IDirectInputDevice2WImpl_GetForceFeedbackState, 1641 JoystickWImpl_SendForceFeedbackCommand, 1642 IDirectInputDevice2WImpl_EnumCreatedEffectObjects, 1643 IDirectInputDevice2WImpl_Escape, 1644 JoystickWGenericImpl_Poll, 1645 IDirectInputDevice2WImpl_SendDeviceData, 1646 IDirectInputDevice7WImpl_EnumEffectsInFile, 1647 IDirectInputDevice7WImpl_WriteEffectToFile, 1648 JoystickWGenericImpl_BuildActionMap, 1649 JoystickWGenericImpl_SetActionMap, 1650 IDirectInputDevice8WImpl_GetImageInfo 1651 }; 1652 1653 static HRESULT WINAPI effect_QueryInterface(IDirectInputEffect *iface, 1654 const GUID *guid, void **out) 1655 { 1656 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1657 1658 TRACE("%p %s %p\n", This, debugstr_guid(guid), out); 1659 1660 if(IsEqualIID(guid, &IID_IUnknown) || IsEqualIID(guid, &IID_IDirectInputEffect)){ 1661 *out = iface; 1662 IDirectInputEffect_AddRef(iface); 1663 return S_OK; 1664 } 1665 1666 return E_NOINTERFACE; 1667 } 1668 1669 static ULONG WINAPI effect_AddRef(IDirectInputEffect *iface) 1670 { 1671 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1672 ULONG ref = InterlockedIncrement(&This->ref); 1673 TRACE("%p, ref is now: %u\n", This, ref); 1674 return ref; 1675 } 1676 1677 static ULONG WINAPI effect_Release(IDirectInputEffect *iface) 1678 { 1679 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1680 ULONG ref = InterlockedDecrement(&This->ref); 1681 TRACE("%p, ref is now: %u\n", This, ref); 1682 1683 if(!ref){ 1684 list_remove(&This->entry); 1685 FFDeviceReleaseEffect(This->device->ff, This->effect); 1686 HeapFree(GetProcessHeap(), 0, This); 1687 } 1688 1689 return ref; 1690 } 1691 1692 static HRESULT WINAPI effect_Initialize(IDirectInputEffect *iface, HINSTANCE hinst, 1693 DWORD version, const GUID *guid) 1694 { 1695 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1696 TRACE("%p %p 0x%x, %s\n", This, hinst, version, debugstr_guid(guid)); 1697 return S_OK; 1698 } 1699 1700 static HRESULT WINAPI effect_GetEffectGuid(IDirectInputEffect *iface, GUID *out) 1701 { 1702 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1703 TRACE("%p %p\n", This, out); 1704 *out = This->guid; 1705 return S_OK; 1706 } 1707 1708 static HRESULT WINAPI effect_GetParameters(IDirectInputEffect *iface, 1709 DIEFFECT *effect, DWORD flags) 1710 { 1711 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1712 TRACE("%p %p 0x%x\n", This, effect, flags); 1713 return osx_to_win32_hresult(FFEffectGetParameters(This->effect, (FFEFFECT*)effect, flags)); 1714 } 1715 1716 static HRESULT WINAPI effect_SetParameters(IDirectInputEffect *iface, 1717 const DIEFFECT *effect, DWORD flags) 1718 { 1719 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1720 TRACE("%p %p 0x%x\n", This, effect, flags); 1721 dump_DIEFFECT(effect, &This->guid, flags); 1722 return osx_to_win32_hresult(FFEffectSetParameters(This->effect, (FFEFFECT*)effect, flags)); 1723 } 1724 1725 static HRESULT WINAPI effect_Start(IDirectInputEffect *iface, DWORD iterations, 1726 DWORD flags) 1727 { 1728 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1729 TRACE("%p 0x%x 0x%x\n", This, iterations, flags); 1730 return osx_to_win32_hresult(FFEffectStart(This->effect, iterations, flags)); 1731 } 1732 1733 static HRESULT WINAPI effect_Stop(IDirectInputEffect *iface) 1734 { 1735 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1736 TRACE("%p\n", This); 1737 return osx_to_win32_hresult(FFEffectStop(This->effect)); 1738 } 1739 1740 static HRESULT WINAPI effect_GetEffectStatus(IDirectInputEffect *iface, DWORD *flags) 1741 { 1742 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1743 TRACE("%p %p\n", This, flags); 1744 return osx_to_win32_hresult(FFEffectGetEffectStatus(This->effect, (UInt32*)flags)); 1745 } 1746 1747 static HRESULT WINAPI effect_Download(IDirectInputEffect *iface) 1748 { 1749 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1750 TRACE("%p\n", This); 1751 return osx_to_win32_hresult(FFEffectDownload(This->effect)); 1752 } 1753 1754 static HRESULT WINAPI effect_Unload(IDirectInputEffect *iface) 1755 { 1756 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1757 TRACE("%p\n", This); 1758 return osx_to_win32_hresult(FFEffectUnload(This->effect)); 1759 } 1760 1761 static HRESULT WINAPI effect_Escape(IDirectInputEffect *iface, DIEFFESCAPE *escape) 1762 { 1763 EffectImpl *This = impl_from_IDirectInputEffect(iface); 1764 TRACE("%p %p\n", This, escape); 1765 return osx_to_win32_hresult(FFEffectEscape(This->effect, (FFEFFESCAPE*)escape)); 1766 } 1767 1768 static const IDirectInputEffectVtbl EffectVtbl = { 1769 effect_QueryInterface, 1770 effect_AddRef, 1771 effect_Release, 1772 effect_Initialize, 1773 effect_GetEffectGuid, 1774 effect_GetParameters, 1775 effect_SetParameters, 1776 effect_Start, 1777 effect_Stop, 1778 effect_GetEffectStatus, 1779 effect_Download, 1780 effect_Unload, 1781 effect_Escape 1782 }; 1783 1784 #else /* HAVE_IOHIDMANAGERCREATE */ 1785 1786 const struct dinput_device joystick_osx_device = { 1787 "Wine OS X joystick driver", 1788 NULL, 1789 NULL, 1790 NULL 1791 }; 1792 1793 #endif /* HAVE_IOHIDMANAGERCREATE */ 1794