/* * Stops all currently playing effects. */ int SDL_SYS_HapticStopAll(SDL_Haptic * haptic) { HRESULT ret; ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, FFSFFC_STOPALL); if (ret != FF_OK) { return SDL_SetError("Haptic: Error stopping device: %s.", FFStrError(ret)); } return 0; }
/* * Stops an effect. */ int SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect) { HRESULT ret; ret = FFEffectStop(effect->hweffect->ref); if (ret != FF_OK) { return SDL_SetError("Haptic: Unable to stop the effect: %s.", FFStrError(ret)); } return 0; }
/* * Unpauses the device. */ int SDL_SYS_HapticUnpause(SDL_Haptic * haptic) { HRESULT ret; ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, FFSFFC_CONTINUE); if (ret != FF_OK) { return SDL_SetError("Haptic: Error pausing device: %s.", FFStrError(ret)); } return 0; }
/* * Sets the gain. */ int SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) { HRESULT ret; Uint32 val; val = gain * 100; /* Mac OS X uses 0 to 10,000 */ ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, FFPROP_FFGAIN, &val); if (ret != FF_OK) { return SDL_SetError("Haptic: Error setting gain: %s.", FFStrError(ret)); } return 0; }
/* * Frees the effect. */ void SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect) { HRESULT ret; ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref); if (ret != FF_OK) { SDL_SetError("Haptic: Error removing the effect from the device: %s.", FFStrError(ret)); } SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, effect->effect.type); SDL_free(effect->hweffect); effect->hweffect = NULL; }
/* * Creates a new haptic effect. */ int SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base) { HRESULT ret; CFUUIDRef type; /* Alloc the effect. */ effect->hweffect = (struct haptic_hweffect *) SDL_malloc(sizeof(struct haptic_hweffect)); if (effect->hweffect == NULL) { SDL_OutOfMemory(); goto err_hweffect; } /* Get the type. */ type = SDL_SYS_HapticEffectType(base->type); if (type == NULL) { goto err_hweffect; } /* Get the effect. */ if (SDL_SYS_ToFFEFFECT(haptic, &effect->hweffect->effect, base) < 0) { goto err_effectdone; } /* Create the actual effect. */ ret = FFDeviceCreateEffect(haptic->hwdata->device, type, &effect->hweffect->effect, &effect->hweffect->ref); if (ret != FF_OK) { SDL_SetError("Haptic: Unable to create effect: %s.", FFStrError(ret)); goto err_effectdone; } return 0; err_effectdone: SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, base->type); err_hweffect: if (effect->hweffect != NULL) { SDL_free(effect->hweffect); effect->hweffect = NULL; } return -1; }
/* * Gets the status of a haptic effect. */ int SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect) { HRESULT ret; FFEffectStatusFlag status; ret = FFEffectGetEffectStatus(effect->hweffect->ref, &status); if (ret != FF_OK) { SDL_SetError("Haptic: Unable to get effect status: %s.", FFStrError(ret)); return -1; } if (status == 0) return SDL_FALSE; return SDL_TRUE; /* Assume it's playing or emulated. */ }
/* * Updates an effect. */ int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data) { HRESULT ret; FFEffectParameterFlag flags; FFEFFECT temp; /* Get the effect. */ SDL_memset(&temp, 0, sizeof(FFEFFECT)); if (SDL_SYS_ToFFEFFECT(haptic, &temp, data) < 0) { goto err_update; } /* Set the flags. Might be worthwhile to diff temp with loaded effect and * only change those parameters. */ flags = FFEP_DIRECTION | FFEP_DURATION | FFEP_ENVELOPE | FFEP_STARTDELAY | FFEP_TRIGGERBUTTON | FFEP_TRIGGERREPEATINTERVAL | FFEP_TYPESPECIFICPARAMS; /* Create the actual effect. */ ret = FFEffectSetParameters(effect->hweffect->ref, &temp, flags); if (ret != FF_OK) { SDL_SetError("Haptic: Unable to update effect: %s.", FFStrError(ret)); goto err_update; } /* Copy it over. */ SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, data->type); SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(FFEFFECT)); return 0; err_update: SDL_SYS_HapticFreeFFEFFECT(&temp, data->type); return -1; }
/* * Sets the autocentering. */ int SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) { HRESULT ret; Uint32 val; /* Mac OS X only has 0 (off) and 1 (on) */ if (autocenter == 0) val = 0; else val = 1; ret = FFDeviceSetForceFeedbackProperty(haptic->hwdata->device, FFPROP_AUTOCENTER, &val); if (ret != FF_OK) { return SDL_SetError("Haptic: Error setting autocenter: %s.", FFStrError(ret)); } return 0; }
/* * Runs an effect. */ int SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations) { HRESULT ret; Uint32 iter; /* Check if it's infinite. */ if (iterations == SDL_HAPTIC_INFINITY) { iter = FF_INFINITE; } else iter = iterations; /* Run the effect. */ ret = FFEffectStart(effect->hweffect->ref, iter, 0); if (ret != FF_OK) { return SDL_SetError("Haptic: Unable to run the effect: %s.", FFStrError(ret)); } return 0; }
/* * Opens the haptic device from the file descriptor. */ static int SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service) { HRESULT ret; int ret2; /* Allocate the hwdata */ haptic->hwdata = (struct haptic_hwdata *) SDL_malloc(sizeof(*haptic->hwdata)); if (haptic->hwdata == NULL) { SDL_OutOfMemory(); goto creat_err; } SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); /* Open the device */ ret = FFCreateDevice(service, &haptic->hwdata->device); if (ret != FF_OK) { SDL_SetError("Haptic: Unable to create device from service: %s.", FFStrError(ret)); goto creat_err; } /* Get supported features. */ ret2 = GetSupportedFeatures(haptic); if (ret2 < 0) { goto open_err; } /* Reset and then enable actuators. */ ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, FFSFFC_RESET); if (ret != FF_OK) { SDL_SetError("Haptic: Unable to reset device: %s.", FFStrError(ret)); goto open_err; } ret = FFDeviceSendForceFeedbackCommand(haptic->hwdata->device, FFSFFC_SETACTUATORSON); if (ret != FF_OK) { SDL_SetError("Haptic: Unable to enable actuators: %s.", FFStrError(ret)); goto open_err; } /* Allocate effects memory. */ haptic->effects = (struct haptic_effect *) SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); if (haptic->effects == NULL) { SDL_OutOfMemory(); goto open_err; } /* Clear the memory */ SDL_memset(haptic->effects, 0, sizeof(struct haptic_effect) * haptic->neffects); return 0; /* Error handling */ open_err: FFReleaseDevice(haptic->hwdata->device); creat_err: if (haptic->hwdata != NULL) { SDL_free(haptic->hwdata); haptic->hwdata = NULL; } return -1; }
/* * Gets supported features. */ static unsigned int GetSupportedFeatures(SDL_Haptic * haptic) { HRESULT ret; FFDeviceObjectReference device; FFCAPABILITIES features; unsigned int supported; Uint32 val; device = haptic->hwdata->device; ret = FFDeviceGetForceFeedbackCapabilities(device, &features); if (ret != FF_OK) { return SDL_SetError("Haptic: Unable to get device's supported features."); } supported = 0; /* Get maximum effects. */ haptic->neffects = features.storageCapacity; haptic->nplaying = features.playbackCapacity; /* Test for effects. */ FF_TEST(FFCAP_ET_CONSTANTFORCE, SDL_HAPTIC_CONSTANT); FF_TEST(FFCAP_ET_RAMPFORCE, SDL_HAPTIC_RAMP); /* !!! FIXME: put this back when we have more bits in 2.1 */ /* FF_TEST(FFCAP_ET_SQUARE, SDL_HAPTIC_SQUARE); */ FF_TEST(FFCAP_ET_SINE, SDL_HAPTIC_SINE); FF_TEST(FFCAP_ET_TRIANGLE, SDL_HAPTIC_TRIANGLE); FF_TEST(FFCAP_ET_SAWTOOTHUP, SDL_HAPTIC_SAWTOOTHUP); FF_TEST(FFCAP_ET_SAWTOOTHDOWN, SDL_HAPTIC_SAWTOOTHDOWN); FF_TEST(FFCAP_ET_SPRING, SDL_HAPTIC_SPRING); FF_TEST(FFCAP_ET_DAMPER, SDL_HAPTIC_DAMPER); FF_TEST(FFCAP_ET_INERTIA, SDL_HAPTIC_INERTIA); FF_TEST(FFCAP_ET_FRICTION, SDL_HAPTIC_FRICTION); FF_TEST(FFCAP_ET_CUSTOMFORCE, SDL_HAPTIC_CUSTOM); /* Check if supports gain. */ ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_FFGAIN, &val, sizeof(val)); if (ret == FF_OK) { supported |= SDL_HAPTIC_GAIN; } else if (ret != FFERR_UNSUPPORTED) { return SDL_SetError("Haptic: Unable to get if device supports gain: %s.", FFStrError(ret)); } /* Checks if supports autocenter. */ ret = FFDeviceGetForceFeedbackProperty(device, FFPROP_AUTOCENTER, &val, sizeof(val)); if (ret == FF_OK) { supported |= SDL_HAPTIC_AUTOCENTER; } else if (ret != FFERR_UNSUPPORTED) { return SDL_SetError ("Haptic: Unable to get if device supports autocenter: %s.", FFStrError(ret)); } /* Check for axes, we have an artificial limit on axes */ haptic->naxes = ((features.numFfAxes) > 3) ? 3 : features.numFfAxes; /* Actually store the axes we want to use */ SDL_memcpy(haptic->hwdata->axes, features.ffAxes, haptic->naxes * sizeof(Uint8)); /* Always supported features. */ supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE; haptic->supported = supported; return 0; }