/* * Opens the haptic device from the file descriptor. * * Steps: * - Open temporary DirectInputDevice interface. * - Create DirectInputDevice8 interface. * - Release DirectInputDevice interface. * - Call SDL_SYS_HapticOpenFromDevice8 */ static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance) { HRESULT ret; int ret2; LPDIRECTINPUTDEVICE8 device; LPDIRECTINPUTDEVICE8 device8; /* Open the device */ ret = IDirectInput8_CreateDevice(dinput, &instance.guidInstance, &device, NULL); if (FAILED(ret)) { DI_SetError("Creating DirectInput device", ret); return -1; } /* Now get the IDirectInputDevice8 interface, instead. */ ret = IDirectInputDevice8_QueryInterface(device, &IID_IDirectInputDevice8, (LPVOID *) &device8); /* Done with the temporary one now. */ IDirectInputDevice8_Release(device); if (FAILED(ret)) { DI_SetError("Querying DirectInput interface", ret); return -1; } ret2 = SDL_SYS_HapticOpenFromDevice8(haptic, device8, SDL_FALSE); if (ret2 < 0) { IDirectInputDevice8_Release(device8); return -1; } return 0; }
int SDL_DINPUT_HapticOpen(SDL_Haptic * haptic, SDL_hapticlist_item *item) { HRESULT ret; LPDIRECTINPUTDEVICE8 device; LPDIRECTINPUTDEVICE8 device8; /* Open the device */ ret = IDirectInput8_CreateDevice(dinput, &item->instance.guidInstance, &device, NULL); if (FAILED(ret)) { DI_SetError("Creating DirectInput device", ret); return -1; } /* Now get the IDirectInputDevice8 interface, instead. */ ret = IDirectInputDevice8_QueryInterface(device, &IID_IDirectInputDevice8, (LPVOID *)&device8); /* Done with the temporary one now. */ IDirectInputDevice8_Release(device); if (FAILED(ret)) { DI_SetError("Querying DirectInput interface", ret); return -1; } if (SDL_DINPUT_HapticOpenFromDevice(haptic, device8, SDL_FALSE) < 0) { IDirectInputDevice8_Release(device8); return -1; } return 0; }
/* * Initializes the haptic subsystem. */ int SDL_SYS_HapticInit(void) { HRESULT ret; HINSTANCE instance; if (dinput != NULL) { /* Already open. */ SDL_SetError("Haptic: SubSystem already open."); return -1; } /* Clear all the memory. */ SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist)); SDL_numhaptics = 0; ret = CoInitialize(NULL); if (FAILED(ret)) { DI_SetError("Coinitialize", ret); return -1; } ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectInput, (LPVOID) & dinput); if (FAILED(ret)) { DI_SetError("CoCreateInstance", ret); return -1; } /* Because we used CoCreateInstance, we need to Initialize it, first. */ instance = GetModuleHandle(NULL); if (instance == NULL) { SDL_SetError("GetModuleHandle() failed with error code %d.", GetLastError()); return -1; } ret = IDirectInput_Initialize(dinput, instance, DIRECTINPUT_VERSION); if (FAILED(ret)) { DI_SetError("Initializing DirectInput device", ret); return -1; } /* Look for haptic devices. */ ret = IDirectInput_EnumDevices(dinput, 0, EnumHapticsCallback, NULL, DIEDFL_FORCEFEEDBACK | DIEDFL_ATTACHEDONLY); if (FAILED(ret)) { DI_SetError("Enumerating DirectInput devices", ret); return -1; } return SDL_numhaptics; }
/* * Opens the haptic device from the file descriptor. * * Steps: * - Open temporary DirectInputDevice interface. * - Create DirectInputDevice2 interface. * - Release DirectInputDevice interface. * - Call SDL_SYS_HapticOpenFromDevice2 */ static int SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance) { HRESULT ret; int ret2; LPDIRECTINPUTDEVICE device; /* 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 = IDirectInput_CreateDevice(dinput, &instance.guidInstance, &device, NULL); if (FAILED(ret)) { DI_SetError("Creating DirectInput device", ret); goto creat_err; } /* Now get the IDirectInputDevice2 interface, instead. */ ret = IDirectInputDevice_QueryInterface(device, &IID_IDirectInputDevice2, (LPVOID *) & haptic->hwdata-> device); /* Done with the temporary one now. */ IDirectInputDevice_Release(device); if (FAILED(ret)) { DI_SetError("Querying DirectInput interface", ret); goto creat_err; } ret2 = SDL_SYS_HapticOpenFromDevice2(haptic, haptic->hwdata->device); if (ret2 < 0) { goto query_err; } return 0; query_err: IDirectInputDevice2_Release(haptic->hwdata->device); creat_err: if (haptic->hwdata != NULL) { SDL_free(haptic->hwdata); haptic->hwdata = NULL; } return -1; }
int SDL_DINPUT_HapticInit(void) { HRESULT ret; HINSTANCE instance; if (dinput != NULL) { /* Already open. */ return SDL_SetError("Haptic: SubSystem already open."); } ret = WIN_CoInitialize(); if (FAILED(ret)) { return DI_SetError("Coinitialize", ret); } coinitialized = SDL_TRUE; ret = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectInput8, (LPVOID)& dinput); if (FAILED(ret)) { SDL_SYS_HapticQuit(); return DI_SetError("CoCreateInstance", ret); } /* Because we used CoCreateInstance, we need to Initialize it, first. */ instance = GetModuleHandle(NULL); if (instance == NULL) { SDL_SYS_HapticQuit(); return SDL_SetError("GetModuleHandle() failed with error code %lu.", GetLastError()); } ret = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION); if (FAILED(ret)) { SDL_SYS_HapticQuit(); return DI_SetError("Initializing DirectInput device", ret); } /* Look for haptic devices. */ ret = IDirectInput8_EnumDevices(dinput, 0, EnumHapticsCallback, NULL, DIEDFL_FORCEFEEDBACK | DIEDFL_ATTACHEDONLY); if (FAILED(ret)) { SDL_SYS_HapticQuit(); return DI_SetError("Enumerating DirectInput devices", ret); } return 0; }
int SDL_DINPUT_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base) { HRESULT ret; REFGUID type = SDL_SYS_HapticEffectType(base); if (type == NULL) { SDL_SetError("Haptic: Unknown effect type."); return -1; } /* Get the effect. */ if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) { goto err_effectdone; } /* Create the actual effect. */ ret = IDirectInputDevice8_CreateEffect(haptic->hwdata->device, type, &effect->hweffect->effect, &effect->hweffect->ref, NULL); if (FAILED(ret)) { DI_SetError("Unable to create effect", ret); goto err_effectdone; } return 0; err_effectdone: SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type); return -1; }
/* * Runs an effect. */ int SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations) { HRESULT ret; DWORD iter; if (haptic->hwdata->bXInputHaptic) { XINPUT_VIBRATION *vib = &effect->hweffect->vibration; SDL_assert(effect->effect.type == SDL_HAPTIC_SINE); /* should catch this at higher level */ SDL_LockMutex(haptic->hwdata->mutex); haptic->hwdata->stopTicks = SDL_GetTicks() + (effect->effect.periodic.length * iterations); SDL_UnlockMutex(haptic->hwdata->mutex); return (XINPUTSETSTATE(haptic->hwdata->userid, vib) == ERROR_SUCCESS) ? 0 : -1; } /* Check if it's infinite. */ if (iterations == SDL_HAPTIC_INFINITY) { iter = INFINITE; } else iter = iterations; /* Run the effect. */ ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0); if (FAILED(ret)) { return DI_SetError("Running the effect", ret); } return 0; }
/* * Updates an effect. */ int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data) { HRESULT ret; DWORD flags; DIEFFECT temp; if (haptic->hwdata->bXInputHaptic) { /* !!! FIXME: this isn't close to right. We only support "sine" effects, * !!! FIXME: we ignore most of the parameters, and we probably get * !!! FIXME: the ones we don't ignore wrong, too. * !!! FIXME: if I had a better understanding of how the two motors * !!! FIXME: could be used in unison, perhaps I could implement other * !!! FIXME: effect types? */ /* From MSDN: "Note that the right motor is the high-frequency motor, the left motor is the low-frequency motor. They do not always need to be set to the same amount, as they provide different effects." */ XINPUT_VIBRATION *vib = &effect->hweffect->vibration; SDL_assert(data->type == SDL_HAPTIC_SINE); vib->wLeftMotorSpeed = vib->wRightMotorSpeed = data->periodic.magnitude * 2; return 0; } /* Get the effect. */ SDL_memset(&temp, 0, sizeof(DIEFFECT)); if (SDL_SYS_ToDIEFFECT(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 = DIEP_DIRECTION | DIEP_DURATION | DIEP_ENVELOPE | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS; /* Create the actual effect. */ ret = IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags); if (FAILED(ret)) { DI_SetError("Unable to update effect", ret); goto err_update; } /* Copy it over. */ SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type); SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT)); return 0; err_update: SDL_SYS_HapticFreeDIEFFECT(&temp, data->type); return -1; }
void SDL_DINPUT_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect) { HRESULT ret; ret = IDirectInputEffect_Unload(effect->hweffect->ref); if (FAILED(ret)) { DI_SetError("Removing effect from the device", ret); } SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type); }
int SDL_DINPUT_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect) { HRESULT ret; ret = IDirectInputEffect_Stop(effect->hweffect->ref); if (FAILED(ret)) { return DI_SetError("Unable to stop effect", ret); } return 0; }
int SDL_DINPUT_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data) { HRESULT ret; DWORD flags; DIEFFECT temp; /* Get the effect. */ SDL_memset(&temp, 0, sizeof(DIEFFECT)); if (SDL_SYS_ToDIEFFECT(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 = DIEP_DIRECTION | DIEP_DURATION | DIEP_ENVELOPE | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS; /* Create the actual effect. */ ret = IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags); if (ret == DIERR_NOTEXCLUSIVEACQUIRED) { IDirectInputDevice8_Unacquire(haptic->hwdata->device); ret = IDirectInputDevice8_SetCooperativeLevel(haptic->hwdata->device, SDL_HelperWindow, DISCL_EXCLUSIVE | DISCL_BACKGROUND); if (SUCCEEDED(ret)) { ret = DIERR_NOTACQUIRED; } } if (ret == DIERR_INPUTLOST || ret == DIERR_NOTACQUIRED) { ret = IDirectInputDevice8_Acquire(haptic->hwdata->device); if (SUCCEEDED(ret)) { ret = IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags); } } if (FAILED(ret)) { DI_SetError("Unable to update effect", ret); goto err_update; } /* Copy it over. */ SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type); SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT)); return 0; err_update: SDL_SYS_HapticFreeDIEFFECT(&temp, data->type); return -1; }
int SDL_DINPUT_HapticStopAll(SDL_Haptic * haptic) { HRESULT ret; /* Try to stop the effects. */ ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_STOPALL); if (FAILED(ret)) { return DI_SetError("Stopping the device", ret); } return 0; }
int SDL_DINPUT_HapticUnpause(SDL_Haptic * haptic) { HRESULT ret; /* Unpause the device. */ ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_CONTINUE); if (FAILED(ret)) { return DI_SetError("Pausing the device", ret); } return 0; }
/* * Creates a new haptic effect. */ int SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base) { HRESULT ret; REFGUID type = SDL_SYS_HapticEffectType(base); if (type == NULL) { goto err_hweffect; } /* Alloc the effect. */ effect->hweffect = (struct haptic_hweffect *) SDL_malloc(sizeof(struct haptic_hweffect)); if (effect->hweffect == NULL) { SDL_OutOfMemory(); goto err_hweffect; } SDL_zerop(effect->hweffect); if (haptic->hwdata->bXInputHaptic) { SDL_assert(base->type == SDL_HAPTIC_SINE); /* should catch this at higher level */ return SDL_SYS_HapticUpdateEffect(haptic, effect, base); } /* Get the effect. */ if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) { goto err_effectdone; } /* Create the actual effect. */ ret = IDirectInputDevice8_CreateEffect(haptic->hwdata->device, type, &effect->hweffect->effect, &effect->hweffect->ref, NULL); if (FAILED(ret)) { DI_SetError("Unable to create effect", ret); goto err_effectdone; } return 0; err_effectdone: SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type); err_hweffect: if (effect->hweffect != NULL) { SDL_free(effect->hweffect); effect->hweffect = NULL; } return -1; }
int SDL_DINPUT_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect *effect) { HRESULT ret; DWORD status; ret = IDirectInputEffect_GetEffectStatus(effect->hweffect->ref, &status); if (FAILED(ret)) { return DI_SetError("Getting effect status", ret); } if (status == 0) return SDL_FALSE; return SDL_TRUE; }
/* * Pauses the device. */ int SDL_SYS_HapticPause(SDL_Haptic * haptic) { HRESULT ret; /* Pause the device. */ ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_PAUSE); if (FAILED(ret)) { DI_SetError("Pausing the device", ret); return -1; } return 0; }
/* * Creates a new haptic effect. */ int SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * base) { HRESULT ret; /* Get the type. */ REFGUID type = SDL_SYS_HapticEffectType(base); if (type == NULL) { goto err_hweffect; } /* 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 effect. */ if (SDL_SYS_ToDIEFFECT(haptic, &effect->hweffect->effect, base) < 0) { goto err_effectdone; } /* Create the actual effect. */ ret = IDirectInputDevice2_CreateEffect(haptic->hwdata->device, type, &effect->hweffect->effect, &effect->hweffect->ref, NULL); if (FAILED(ret)) { DI_SetError("Unable to create effect", ret); goto err_effectdone; } return 0; err_effectdone: SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, base->type); err_hweffect: if (effect->hweffect != NULL) { SDL_free(effect->hweffect); effect->hweffect = NULL; } return -1; }
/* * Frees the effect. */ void SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect *effect) { HRESULT ret; if (haptic->hwdata->bXInputHaptic) { SDL_SYS_HapticStopEffect(haptic, effect); } else { ret = IDirectInputEffect_Unload(effect->hweffect->ref); if (FAILED(ret)) { DI_SetError("Removing effect from the device", ret); } SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, effect->effect.type); } SDL_free(effect->hweffect); effect->hweffect = NULL; }
/* * Updates an effect. */ int SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, struct haptic_effect *effect, SDL_HapticEffect * data) { HRESULT ret; DWORD flags; DIEFFECT temp; /* Get the effect. */ SDL_memset(&temp, 0, sizeof(DIEFFECT)); if (SDL_SYS_ToDIEFFECT(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 = DIEP_DIRECTION | DIEP_DURATION | DIEP_ENVELOPE | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS; /* Create the actual effect. */ ret = IDirectInputEffect_SetParameters(effect->hweffect->ref, &temp, flags); if (FAILED(ret)) { DI_SetError("Unable to update effect", ret); goto err_update; } /* Copy it over. */ SDL_SYS_HapticFreeDIEFFECT(&effect->hweffect->effect, data->type); SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(DIEFFECT)); return 0; err_update: SDL_SYS_HapticFreeDIEFFECT(&temp, data->type); return -1; }
/* * Stops an effect. */ int SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect *effect) { HRESULT ret; if (haptic->hwdata->bXInputHaptic) { XINPUT_VIBRATION vibration = { 0, 0 }; SDL_LockMutex(haptic->hwdata->mutex); haptic->hwdata->stopTicks = 0; SDL_UnlockMutex(haptic->hwdata->mutex); return (XINPUTSETSTATE(haptic->hwdata->userid, &vibration) == ERROR_SUCCESS) ? 0 : -1; } ret = IDirectInputEffect_Stop(effect->hweffect->ref); if (FAILED(ret)) { return DI_SetError("Unable to stop effect", ret); } return 0; }
int SDL_DINPUT_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect *effect, Uint32 iterations) { HRESULT ret; DWORD iter; /* Check if it's infinite. */ if (iterations == SDL_HAPTIC_INFINITY) { iter = INFINITE; } else { iter = iterations; } /* Run the effect. */ ret = IDirectInputEffect_Start(effect->hweffect->ref, iter, 0); if (FAILED(ret)) { return DI_SetError("Running the effect", ret); } return 0; }
int SDL_DINPUT_HapticSetGain(SDL_Haptic * haptic, int gain) { HRESULT ret; DIPROPDWORD dipdw; /* Create the weird structure thingy. */ dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = gain * 100; /* 0 to 10,000 */ /* Try to set the autocenter. */ ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device, DIPROP_FFGAIN, &dipdw.diph); if (FAILED(ret)) { return DI_SetError("Setting gain", ret); } return 0; }
int SDL_DINPUT_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) { HRESULT ret; DIPROPDWORD dipdw; /* Create the weird structure thingy. */ dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF : DIPROPAUTOCENTER_ON; /* Try to set the autocenter. */ ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device, DIPROP_AUTOCENTER, &dipdw.diph); if (FAILED(ret)) { return DI_SetError("Setting autocenter", ret); } return 0; }
/* * Stops all the playing effects on the device. */ int SDL_SYS_HapticStopAll(SDL_Haptic * haptic) { HRESULT ret; if (haptic->hwdata->bXInputHaptic) { XINPUT_VIBRATION vibration = { 0, 0 }; SDL_LockMutex(haptic->hwdata->mutex); haptic->hwdata->stopTicks = 0; SDL_UnlockMutex(haptic->hwdata->mutex); return (XINPUTSETSTATE(haptic->hwdata->userid, &vibration) == ERROR_SUCCESS) ? 0 : -1; } /* Try to stop the effects. */ ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_STOPALL); if (FAILED(ret)) { return DI_SetError("Stopping the device", ret); } return 0; }
/* * Opens the haptic device from the file descriptor. * * Steps: * - Set cooperative level. * - Set data format. * - Acquire exclusiveness. * - Reset actuators. * - Get supported featuers. */ static int SDL_SYS_HapticOpenFromDevice2(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE2 device2) { HRESULT ret; DIPROPDWORD dipdw; /* We'll use the device2 from now on. */ haptic->hwdata->device = device2; /* Grab it exclusively to use force feedback stuff. */ ret = IDirectInputDevice2_SetCooperativeLevel(haptic->hwdata->device, SDL_HelperWindow, DISCL_EXCLUSIVE | DISCL_BACKGROUND); if (FAILED(ret)) { DI_SetError("Setting cooperative level to exclusive", ret); goto acquire_err; } /* Set data format. */ ret = IDirectInputDevice2_SetDataFormat(haptic->hwdata->device, &c_dfDIJoystick2); if (FAILED(ret)) { DI_SetError("Setting data format", ret); goto acquire_err; } /* Get number of axes. */ ret = IDirectInputDevice2_EnumObjects(haptic->hwdata->device, DI_DeviceObjectCallback, haptic, DIDFT_AXIS); if (FAILED(ret)) { DI_SetError("Getting device axes", ret); goto acquire_err; } /* Acquire the device. */ ret = IDirectInputDevice2_Acquire(haptic->hwdata->device); if (FAILED(ret)) { DI_SetError("Acquiring DirectInput device", ret); goto acquire_err; } /* Reset all actuators - just in case. */ ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_RESET); if (FAILED(ret)) { DI_SetError("Resetting device", ret); goto acquire_err; } /* Enabling actuators. */ ret = IDirectInputDevice2_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_SETACTUATORSON); if (FAILED(ret)) { DI_SetError("Enabling actuators", ret); goto acquire_err; } /* Get supported effects. */ ret = IDirectInputDevice2_EnumEffects(haptic->hwdata->device, DI_EffectCallback, haptic, DIEFT_ALL); if (FAILED(ret)) { DI_SetError("Enumerating supported effects", ret); goto acquire_err; } if (haptic->supported == 0) { /* Error since device supports nothing. */ SDL_SetError("Haptic: Internal error on finding supported effects."); goto acquire_err; } /* Check autogain and autocenter. */ dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = 10000; ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device, DIPROP_FFGAIN, &dipdw.diph); if (!FAILED(ret)) { /* Gain is supported. */ haptic->supported |= SDL_HAPTIC_GAIN; } dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = DIPROPAUTOCENTER_OFF; ret = IDirectInputDevice2_SetProperty(haptic->hwdata->device, DIPROP_AUTOCENTER, &dipdw.diph); if (!FAILED(ret)) { /* Autocenter is supported. */ haptic->supported |= SDL_HAPTIC_AUTOCENTER; } /* Status is always supported. */ haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE; /* Check maximum effects. */ haptic->neffects = 128; /* This is not actually supported as thus under windows, there is no way to tell the number of EFFECTS that a device can hold, so we'll just use a "random" number instead and put warnings in SDL_haptic.h */ haptic->nplaying = 128; /* Even more impossible to get this then neffects. */ /* Prepare effects memory. */ haptic->effects = (struct haptic_effect *) SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); if (haptic->effects == NULL) { SDL_OutOfMemory(); goto acquire_err; } /* Clear the memory */ SDL_memset(haptic->effects, 0, sizeof(struct haptic_effect) * haptic->neffects); return 0; /* Error handling */ acquire_err: IDirectInputDevice2_Unacquire(haptic->hwdata->device); return -1; }
/* * Initializes the haptic subsystem. */ int SDL_SYS_HapticInit(void) { const char *env = SDL_GetHint(SDL_HINT_XINPUT_ENABLED); HRESULT ret; HINSTANCE instance; if (dinput != NULL) { /* Already open. */ return SDL_SetError("Haptic: SubSystem already open."); } /* Clear all the memory. */ SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist)); SDL_numhaptics = 0; ret = WIN_CoInitialize(); if (FAILED(ret)) { return DI_SetError("Coinitialize", ret); } coinitialized = SDL_TRUE; ret = CoCreateInstance(&CLSID_DirectInput8, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectInput8, (LPVOID) & dinput); if (FAILED(ret)) { SDL_SYS_HapticQuit(); return DI_SetError("CoCreateInstance", ret); } /* Because we used CoCreateInstance, we need to Initialize it, first. */ instance = GetModuleHandle(NULL); if (instance == NULL) { SDL_SYS_HapticQuit(); return SDL_SetError("GetModuleHandle() failed with error code %d.", GetLastError()); } ret = IDirectInput8_Initialize(dinput, instance, DIRECTINPUT_VERSION); if (FAILED(ret)) { SDL_SYS_HapticQuit(); return DI_SetError("Initializing DirectInput device", ret); } /* Look for haptic devices. */ ret = IDirectInput8_EnumDevices(dinput, 0, EnumHapticsCallback, NULL, DIEDFL_FORCEFEEDBACK | DIEDFL_ATTACHEDONLY); if (FAILED(ret)) { SDL_SYS_HapticQuit(); return DI_SetError("Enumerating DirectInput devices", ret); } if (!env || SDL_atoi(env)) { loaded_xinput = (WIN_LoadXInputDLL() == 0); } if (loaded_xinput) { DWORD i; const SDL_bool bIs14OrLater = (SDL_XInputVersion >= ((1<<16)|4)); for (i = 0; (i < SDL_XINPUT_MAX_DEVICES) && (SDL_numhaptics < MAX_HAPTICS); i++) { XINPUT_CAPABILITIES caps; if (XINPUTGETCAPABILITIES(i, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) { if ((!bIs14OrLater) || (caps.Flags & XINPUT_CAPS_FFB_SUPPORTED)) { /* !!! FIXME: I'm not bothering to query for a real name right now. */ char buf[64]; SDL_snprintf(buf, sizeof (buf), "XInput Controller #%u", i+1); SDL_hapticlist[SDL_numhaptics].name = SDL_strdup(buf); SDL_hapticlist[SDL_numhaptics].bXInputHaptic = 1; SDL_hapticlist[SDL_numhaptics].userid = (Uint8) i; SDL_numhaptics++; } } } } return SDL_numhaptics; }
/* * Opens the haptic device. * * Steps: * - Set cooperative level. * - Set data format. * - Acquire exclusiveness. * - Reset actuators. * - Get supported features. */ static int SDL_DINPUT_HapticOpenFromDevice(SDL_Haptic * haptic, LPDIRECTINPUTDEVICE8 device8, SDL_bool is_joystick) { HRESULT ret; DIPROPDWORD dipdw; /* Allocate the hwdata */ haptic->hwdata = (struct haptic_hwdata *)SDL_malloc(sizeof(*haptic->hwdata)); if (haptic->hwdata == NULL) { return SDL_OutOfMemory(); } SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); /* We'll use the device8 from now on. */ haptic->hwdata->device = device8; haptic->hwdata->is_joystick = is_joystick; /* !!! FIXME: opening a haptic device here first will make an attempt to !!! FIXME: SDL_JoystickOpen() that same device fail later, since we !!! FIXME: have it open in exclusive mode. But this will allow !!! FIXME: SDL_JoystickOpen() followed by SDL_HapticOpenFromJoystick() !!! FIXME: to work, and that's probably the common case. Still, !!! FIXME: ideally, We need to unify the opening code. */ if (!is_joystick) { /* if is_joystick, we already set this up elsewhere. */ /* Grab it exclusively to use force feedback stuff. */ ret = IDirectInputDevice8_SetCooperativeLevel(haptic->hwdata->device, SDL_HelperWindow, DISCL_EXCLUSIVE | DISCL_BACKGROUND); if (FAILED(ret)) { DI_SetError("Setting cooperative level to exclusive", ret); goto acquire_err; } /* Set data format. */ ret = IDirectInputDevice8_SetDataFormat(haptic->hwdata->device, &c_dfDIJoystick2); if (FAILED(ret)) { DI_SetError("Setting data format", ret); goto acquire_err; } /* Get number of axes. */ ret = IDirectInputDevice8_EnumObjects(haptic->hwdata->device, DI_DeviceObjectCallback, haptic, DIDFT_AXIS); if (FAILED(ret)) { DI_SetError("Getting device axes", ret); goto acquire_err; } /* Acquire the device. */ ret = IDirectInputDevice8_Acquire(haptic->hwdata->device); if (FAILED(ret)) { DI_SetError("Acquiring DirectInput device", ret); goto acquire_err; } } /* Reset all actuators - just in case. */ ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_RESET); if (FAILED(ret)) { DI_SetError("Resetting device", ret); goto acquire_err; } /* Enabling actuators. */ ret = IDirectInputDevice8_SendForceFeedbackCommand(haptic->hwdata->device, DISFFC_SETACTUATORSON); if (FAILED(ret)) { DI_SetError("Enabling actuators", ret); goto acquire_err; } /* Get supported effects. */ ret = IDirectInputDevice8_EnumEffects(haptic->hwdata->device, DI_EffectCallback, haptic, DIEFT_ALL); if (FAILED(ret)) { DI_SetError("Enumerating supported effects", ret); goto acquire_err; } if (haptic->supported == 0) { /* Error since device supports nothing. */ SDL_SetError("Haptic: Internal error on finding supported effects."); goto acquire_err; } /* Check autogain and autocenter. */ dipdw.diph.dwSize = sizeof(DIPROPDWORD); dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = 10000; ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device, DIPROP_FFGAIN, &dipdw.diph); if (!FAILED(ret)) { /* Gain is supported. */ haptic->supported |= SDL_HAPTIC_GAIN; } dipdw.diph.dwObj = 0; dipdw.diph.dwHow = DIPH_DEVICE; dipdw.dwData = DIPROPAUTOCENTER_OFF; ret = IDirectInputDevice8_SetProperty(haptic->hwdata->device, DIPROP_AUTOCENTER, &dipdw.diph); if (!FAILED(ret)) { /* Autocenter is supported. */ haptic->supported |= SDL_HAPTIC_AUTOCENTER; } /* Status is always supported. */ haptic->supported |= SDL_HAPTIC_STATUS | SDL_HAPTIC_PAUSE; /* Check maximum effects. */ haptic->neffects = 128; /* This is not actually supported as thus under windows, there is no way to tell the number of EFFECTS that a device can hold, so we'll just use a "random" number instead and put warnings in SDL_haptic.h */ haptic->nplaying = 128; /* Even more impossible to get this then neffects. */ /* Prepare effects memory. */ haptic->effects = (struct haptic_effect *) SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); if (haptic->effects == NULL) { SDL_OutOfMemory(); goto acquire_err; } /* Clear the memory */ SDL_memset(haptic->effects, 0, sizeof(struct haptic_effect) * haptic->neffects); return 0; /* Error handling */ acquire_err: IDirectInputDevice8_Unacquire(haptic->hwdata->device); return -1; }