int MacHaptic_MaybeAddDevice( io_object_t device ) { IOReturn result; CFMutableDictionaryRef hidProperties; CFTypeRef refCF; SDL_hapticlist_item *item; if (numhaptics == -1) { return -1; /* not initialized. We'll pick these up on enumeration if we init later. */ } /* Check for force feedback. */ if (FFIsForceFeedback(device) != FF_OK) { return -1; } /* Make sure we don't already have it */ for (item = SDL_hapticlist; item ; item = item->next) { if (IOObjectIsEqualTo((io_object_t) item->dev, device)) { /* Already added */ return -1; } } item = (SDL_hapticlist_item *)SDL_calloc(1, sizeof(SDL_hapticlist_item)); if (item == NULL) { return SDL_SetError("Could not allocate haptic storage"); } /* retain it as we are going to keep it around a while */ IOObjectRetain(device); /* Set basic device data. */ HIDGetDeviceProduct(device, item->name); item->dev = device; /* Set usage pages. */ hidProperties = 0; refCF = 0; result = IORegistryEntryCreateCFProperties(device, &hidProperties, kCFAllocatorDefault, kNilOptions); if ((result == KERN_SUCCESS) && hidProperties) { refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); if (refCF) { if (!CFNumberGetValue(refCF, kCFNumberLongType, &item->usagePage)) { SDL_SetError("Haptic: Receiving device's usage page."); } refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); if (refCF) { if (!CFNumberGetValue(refCF, kCFNumberLongType, &item->usage)) { SDL_SetError("Haptic: Receiving device's usage."); } } } CFRelease(hidProperties); } if (SDL_hapticlist_tail == NULL) { SDL_hapticlist = SDL_hapticlist_tail = item; } else { SDL_hapticlist_tail->next = item; SDL_hapticlist_tail = item; } /* Device has been added. */ ++numhaptics; return numhaptics; }
/* * Initializes the haptic subsystem. */ int SDL_SYS_HapticInit(void) { int numhaptics; IOReturn result; io_iterator_t iter; CFDictionaryRef match; io_service_t device; CFMutableDictionaryRef hidProperties; CFTypeRef refCF; /* Clear all the memory. */ SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist)); /* Get HID devices. */ match = IOServiceMatching(kIOHIDDeviceKey); if (match == NULL) { return SDL_SetError("Haptic: Failed to get IOServiceMatching."); } /* Now search I/O Registry for matching devices. */ result = IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iter); if (result != kIOReturnSuccess) { return SDL_SetError("Haptic: Couldn't create a HID object iterator."); } /* IOServiceGetMatchingServices consumes dictionary. */ if (!IOIteratorIsValid(iter)) { /* No iterator. */ return 0; } numhaptics = 0; while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) { /* Check for force feedback. */ if (FFIsForceFeedback(device) == FF_OK) { /* Set basic device data. */ HIDGetDeviceProduct(device, SDL_hapticlist[numhaptics].name); SDL_hapticlist[numhaptics].dev = device; SDL_hapticlist[numhaptics].haptic = NULL; /* Set usage pages. */ hidProperties = 0; refCF = 0; result = IORegistryEntryCreateCFProperties(device, &hidProperties, kCFAllocatorDefault, kNilOptions); if ((result == KERN_SUCCESS) && hidProperties) { refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsagePageKey)); if (refCF) { if (!CFNumberGetValue(refCF, kCFNumberLongType, &SDL_hapticlist[numhaptics]. usagePage)) SDL_SetError ("Haptic: Recieving device's usage page."); refCF = CFDictionaryGetValue(hidProperties, CFSTR(kIOHIDPrimaryUsageKey)); if (refCF) { if (!CFNumberGetValue(refCF, kCFNumberLongType, &SDL_hapticlist[numhaptics]. usage)) SDL_SetError("Haptic: Recieving device's usage."); } } CFRelease(hidProperties); } /* Device has been added. */ numhaptics++; } else { /* Free the unused device. */ IOObjectRelease(device); } /* Reached haptic limit. */ if (numhaptics >= MAX_HAPTICS) break; } IOObjectRelease(iter); return numhaptics; }