bool Joystick::UpdateOutput() { #ifdef USE_SDL_HAPTIC std::list<EffectIDState>::iterator i = m_state_out.begin(), e = m_state_out.end(); for ( ; i != e; ++i) { if (i->changed) // if SetState was called on this output { if (-1 == i->id) // effect isn't currently uploaded { if (i->effect.type) // if outputstate is >0 this would be true if ((i->id = SDL_HapticNewEffect( m_haptic, &i->effect )) > -1) // upload the effect SDL_HapticRunEffect(m_haptic, i->id, 1); // run the effect } else // effect is already uploaded { if (i->effect.type) // if ouputstate >0 SDL_HapticUpdateEffect(m_haptic, i->id, &i->effect); // update the effect else { SDL_HapticStopEffect(m_haptic, i->id); // else, stop and remove the effect SDL_HapticDestroyEffect(m_haptic, i->id); i->id = -1; // mark it as not uploaded } } i->changed = false; } } #endif return true; }
void ForceFeedback::update( float force, float /*dt*/, std::ostream & error_output) { if (!enabled || !haptic || (effect_id == -1)) return; // Clamp force. force = Clamp(force, -1.0f, 1.0f); // Low pass filter. lastforce = (lastforce + force) * 0.5f; // Update effect. effect.constant.level = Sint16(lastforce * 32767); int new_effect_id = SDL_HapticUpdateEffect(haptic, effect_id, &effect); if (new_effect_id == -1) { error_output << "Failed to update force feedback effect: " << SDL_GetError(); return; } else { effect_id = new_effect_id; } // Run effect. if (SDL_HapticRunEffect(haptic, effect_id, 1) == -1) { error_output << "Failed to run force feedback effect: " << SDL_GetError(); return; } }
/* * Runs simple rumble on a haptic device */ int SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length) { int ret; SDL_HapticPeriodic *efx; if (!ValidHaptic(haptic)) { return -1; } if (haptic->rumble_id < 0) { SDL_SetError("Haptic: Rumble effect not initialized on haptic device"); return -1; } /* Clamp strength. */ if (strength > 1.0f) { strength = 1.0f; } else if (strength < 0.0f) { strength = 0.0f; } /* New effect. */ efx = &haptic->rumble_effect.periodic; efx->magnitude = (Sint16)(32767.0f*strength); efx->length = length; ret = SDL_HapticUpdateEffect(haptic, haptic->rumble_id, &haptic->rumble_effect); return SDL_HapticRunEffect(haptic, haptic->rumble_id, 1); }
void SdlManager::SdlController::RunHapticLeftRight(float left, float right) { CriticalCode criticalCode(criticalSection); if(!haptic) return; hapticEffect.leftright.length = SDL_HAPTIC_INFINITY; hapticEffect.leftright.large_magnitude = uint16_t(left * 0xffff); hapticEffect.leftright.small_magnitude = uint16_t(right * 0xffff); if(hapticEffectIndex >= 0 && hapticEffect.type == SDL_HAPTIC_LEFTRIGHT) { SDL_HapticStopEffect(haptic, hapticEffectIndex); SDL_HapticUpdateEffect(haptic, hapticEffectIndex, &hapticEffect); } else { if(hapticEffectIndex >= 0) { SDL_HapticStopEffect(haptic, hapticEffectIndex); SDL_HapticDestroyEffect(haptic, hapticEffectIndex); } hapticEffect.type = SDL_HAPTIC_LEFTRIGHT; hapticEffectIndex = SDL_HapticNewEffect(haptic, &hapticEffect); } SDL_HapticRunEffect(haptic, hapticEffectIndex, 1); }
bool SdlRumbleEffect::update() { if (isActive()) { mId = SDL_HapticUpdateEffect(mHaptic, mId, &mEffect); } return isActive(); }
JNIEXPORT jint JNICALL Java_at_wisch_joystick_FFJoystick_updateEffectNative (JNIEnv *env, jclass, jint hapticDeviceIndex, jint effectIndex, jobject jEffect, jint effectType) { SDL_HapticEffect *effect = getEffectFromJavaEffect(env, jEffect, effectType); int num = SDL_HapticUpdateEffect(ffjoysticks[hapticDeviceIndex], effectIndex, effect); if (num < 0) { throwException(env, SDL_GetError()); return -24; } if (effect->type == SDL_HAPTIC_CUSTOM){ delete(effect->custom.data); } delete(effect); return 0; }
static bool sdl_joypad_set_rumble(unsigned pad, enum retro_rumble_effect effect, uint16_t strength) { SDL_HapticEffect efx; sdl_joypad_t *joypad = (sdl_joypad_t*)&sdl_pads[pad]; memset(&efx, 0, sizeof(efx)); if (!joypad->joypad || !joypad->haptic) return false; efx.type = SDL_HAPTIC_LEFTRIGHT; efx.leftright.type = SDL_HAPTIC_LEFTRIGHT; efx.leftright.length = 5000; switch (effect) { case RETRO_RUMBLE_STRONG: efx.leftright.large_magnitude = strength; break; case RETRO_RUMBLE_WEAK: efx.leftright.small_magnitude = strength; break; default: return false; } if (joypad->rumble_effect == -1) { joypad->rumble_effect = SDL_HapticNewEffect(sdl_pads[pad].haptic, &efx); if (joypad->rumble_effect < 0) { RARCH_WARN("[SDL]: Failed to create rumble effect for joypad %u: %s\n", pad, SDL_GetError()); joypad->rumble_effect = -2; return false; } } else if (joypad->rumble_effect >= 0) SDL_HapticUpdateEffect(joypad->haptic, joypad->rumble_effect, &efx); if (joypad->rumble_effect < 0) return false; if (SDL_HapticRunEffect(joypad->haptic, joypad->rumble_effect, 1) < 0) { RARCH_WARN("[SDL]: Failed to set rumble effect on joypad %u: %s\n", pad, SDL_GetError()); return false; } return true; }
void Joystick::HapticEffect::Update() { if (m_id == -1 && m_effect.type > 0) { m_id = SDL_HapticNewEffect(m_haptic, &m_effect); if (m_id > -1) SDL_HapticRunEffect(m_haptic, m_id, 1); } else if (m_id > -1 && m_effect.type == 0) { SDL_HapticStopEffect(m_haptic, m_id); SDL_HapticDestroyEffect(m_haptic, m_id); m_id = -1; } else if (m_id > -1) { SDL_HapticUpdateEffect(m_haptic, m_id, &m_effect); } }
/** * @brief Runs a rumble effect. * * @brief Current modifier being added. */ static void spfx_hapticRumble( double mod ) { #if SDL_VERSION_ATLEAST(1,3,0) SDL_HapticEffect *efx; double len, mag; if (haptic_rumble >= 0) { /* Not time to update yet. */ if ((haptic_lastUpdate > 0.) || shake_off || (mod > SHAKE_MAX/3.)) return; /* Stop the effect if it was playing. */ SDL_HapticStopEffect( haptic, haptic_rumble ); /* Get length and magnitude. */ len = 1000. * shake_rad / SHAKE_DECAY; mag = 32767. * (shake_rad / SHAKE_MAX); /* Update the effect. */ efx = &haptic_rumbleEffect; efx->periodic.magnitude = (uint32_t)mag;; efx->periodic.length = (uint32_t)len; efx->periodic.fade_length = MIN( efx->periodic.length, 1000 ); if (SDL_HapticUpdateEffect( haptic, haptic_rumble, &haptic_rumbleEffect ) < 0) { WARN("Failed to update haptic effect: %s.", SDL_GetError()); return; } /* Run the new effect. */ SDL_HapticRunEffect( haptic, haptic_rumble, 1 ); /* Set timer again. */ haptic_lastUpdate = HAPTIC_UPDATE_INTERVAL; } #else /* SDL_VERSION_ATLEAST(1,3,0) */ (void) mod; #endif /* SDL_VERSION_ATLEAST(1,3,0) */ }
bool Joystick::runVibrationEffect() { if (vibration.id != -1) { if (SDL_HapticUpdateEffect(haptic, vibration.id, &vibration.effect) == 0) { if (SDL_HapticRunEffect(haptic, vibration.id, 1) == 0) return true; } // If the effect fails to update, we should destroy and re-create it. SDL_HapticDestroyEffect(haptic, vibration.id); vibration.id = -1; } vibration.id = SDL_HapticNewEffect(haptic, &vibration.effect); if (vibration.id != -1 && SDL_HapticRunEffect(haptic, vibration.id, 1) == 0) return true; return false; }
void JoystickInfo::DoHapticEffect(int type, int pad, int force) { if (type > 1) return; if ( !(conf->options & (PADOPTION_FORCEFEEDBACK << 16 * pad)) ) return; #if SDL_MAJOR_VERSION >= 2 int joyid = conf->get_joyid(pad); if (!JoystickIdWithinBounds(joyid)) return; JoystickInfo* pjoy = s_vjoysticks[joyid]; if (pjoy->haptic == NULL) return; if (pjoy->haptic_effect_id[type] < 0) return; // FIXME: might need to multiply force pjoy->haptic_effect_data[type].periodic.magnitude = force * conf->ff_intensity ; // force/32767 strength // Upload the new effect SDL_HapticUpdateEffect(pjoy->haptic, pjoy->haptic_effect_id[type], &pjoy->haptic_effect_data[type]); // run the effect once SDL_HapticRunEffect( pjoy->haptic, pjoy->haptic_effect_id[type], 1 ); #endif }
/* * Runs simple rumble on a haptic device */ int SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length) { SDL_HapticEffect *efx; Sint16 magnitude; if (!ValidHaptic(haptic)) { return -1; } if (haptic->rumble_id < 0) { return SDL_SetError("Haptic: Rumble effect not initialized on haptic device"); } /* Clamp strength. */ if (strength > 1.0f) { strength = 1.0f; } else if (strength < 0.0f) { strength = 0.0f; } magnitude = (Sint16)(32767.0f*strength); efx = &haptic->rumble_effect; if (efx->type == SDL_HAPTIC_SINE) { efx->periodic.magnitude = magnitude; efx->periodic.length = length; } else if (efx->type == SDL_HAPTIC_LEFTRIGHT) { efx->leftright.small_magnitude = efx->leftright.large_magnitude = magnitude; efx->leftright.length = length; } else { SDL_assert(0 && "This should have been caught elsewhere"); } if (SDL_HapticUpdateEffect(haptic, haptic->rumble_id, &haptic->rumble_effect) < 0) { return -1; } return SDL_HapticRunEffect(haptic, haptic->rumble_id, 1); }
bool Joystick::UpdateOutput() { #ifdef USE_SDL_HAPTIC for (auto &i : m_state_out) { if (i.changed) // if SetState was called on this output { if (-1 == i.id) // effect isn't currently uploaded { if (i.effect.type) // if outputstate is >0 this would be true { if ((i.id = SDL_HapticNewEffect(m_haptic, &i.effect)) > -1) // upload the effect { SDL_HapticRunEffect(m_haptic, i.id, 1); // run the effect } } } else // effect is already uploaded { if (i.effect.type) // if ouputstate >0 { SDL_HapticUpdateEffect(m_haptic, i.id, &i.effect); // update the effect } else { SDL_HapticStopEffect(m_haptic, i.id); // else, stop and remove the effect SDL_HapticDestroyEffect(m_haptic, i.id); i.id = -1; // mark it as not uploaded } } i.changed = false; } } #endif return true; }
bool SDL2FFBDevice::uploadEffect(const int idx, const FFBEffectTypes type, std::shared_ptr<FFBEffectParameters> parameters) { SDL_HapticEffect* underlEff; int intIdx; std::shared_ptr<FFBEffect> effect = SDL2FFBEffectFactory::createEffect(type); std::shared_ptr<SDL2FFBEffect> sdlEff; CHECK_EFFECT_IDX(idx); if (type != FFBEffectTypes::NONE) sdlEff = std::static_pointer_cast<SDL2FFBEffect>(effect); else return false; if (sdlEff == nullptr) return false; if (!sdlEff->setParameters(parameters)) return false; /* There is no effect in the selected slot */ if (m_effects[idx]->type() != FFBEffectTypes::NONE) { /* Effects are not of the same type, delete the previous effect and create a new one */ if (*m_effects[idx] != *sdlEff) { if (!removeEffect(idx)) { return false; } } else { /* Effects are of the same type, update it */ underlEff = sdlEff->createFFstruct(); if (underlEff == nullptr) return false; intIdx = SDL_HapticUpdateEffect(c_haptic, std::static_pointer_cast<SDL2FFBEffect>(m_effects[idx])->internalIdx(), underlEff); if (intIdx < 0) { QMessageBox::critical(nullptr, SDL2DEV_ERR_CAPTION, QString("Unable to update the effect:\n%1").arg(SDL_GetError())); m_effects[idx]->setStatus(FFBEffect::FFBEffectStatus::UPLOADED); return true; } sdlEff->setStatus(m_effects[idx]->status()); goto out; } } underlEff = sdlEff->createFFstruct(); if (underlEff == nullptr) return false; intIdx = SDL_HapticNewEffect(c_haptic, underlEff); if (intIdx < 0) { QMessageBox::critical(nullptr, SDL2DEV_ERR_CAPTION, QString("Unable to create effect:\n%1").arg(SDL_GetError())); return false; } sdlEff->setStatus(FFBEffect::FFBEffectStatus::UPLOADED); out: sdlEff->setInternalIdx(intIdx); delete underlEff; m_effects[idx] = sdlEff; return true; }
// First time (lazy) initialization. void gfctrlJoyInit(void) { #ifndef SDL_JOYSTICK gfctrlJoyPresent = GFCTRL_JOY_NONE; for (int index = 0; index < GFCTRL_JOY_NUMBER; index++) { if (!Joysticks[index]) { Joysticks[index] = new jsJoystick(index); } // Don't configure the joystick if it doesn't work if (Joysticks[index]->notWorking()) { delete Joysticks[index]; Joysticks[index] = 0; } else { gfctrlJoyPresent = GFCTRL_JOY_PRESENT; } } #else #if SDL_MAJOR_VERSION >= 2 memset(&cfx, 0, sizeof(cfx)); if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC) < 0) { #else if (SDL_Init(SDL_INIT_JOYSTICK) < 0) { #endif GfLogError("Couldn't initialize SDL: %s\n", SDL_GetError()); gfctrlJoyPresent = GFCTRL_JOY_UNTESTED; return; } #if SDL_MAJOR_VERSION >= 2 // Ignore the joystick events, we will poll directly as it is faster SDL_JoystickEventState(SDL_IGNORE); #endif gfctrlJoyPresent = SDL_NumJoysticks(); if (gfctrlJoyPresent > GFCTRL_JOY_NUMBER) gfctrlJoyPresent = GFCTRL_JOY_NUMBER; for (int index = 0; index < gfctrlJoyPresent; index++) { if (!Joysticks[index]) { Joysticks[index] = SDL_JoystickOpen(index); } // Don't configure the joystick if it doesn't work if (Joysticks[index] == NULL) { GfLogError("Couldn't open joystick %d: %s\n", index, SDL_GetError()); #if SDL_MAJOR_VERSION >= 2 } else { cfx_timeout[index] = 0; rfx_timeout[index] = 0; // Find which Haptic device relates to this joystick Haptics[index] = SDL_HapticOpenFromJoystick(Joysticks[index]); if (!Haptics[index]) { GfLogInfo("Joystick %d does not support haptic\n", index); break; #if 0 } else { // add an CF effect on startup gfctrlJoyConstantForce(index, 50000, 9000); #endif } // Check for Rumble capability if (SDL_HapticRumbleSupported(Haptics[index]) == SDL_TRUE) { if (SDL_HapticRumbleInit(Haptics[index]) != 0) GfLogError("Couldn't init rumble on joystick %d: %s\n", index, SDL_GetError()); #if 0 else gfctrlJoyRumble(index, 0.5); #endif } #endif } } #endif } #if SDL_JOYSTICK void gfctrlJoyConstantForce(int index, unsigned int level, int dir) { #if SDL_MAJOR_VERSION >= 2 if (!Haptics[index]) return; if ((SDL_HapticQuery(Haptics[index]) & SDL_HAPTIC_CONSTANT) == 0) return; cfx[index].type = SDL_HAPTIC_CONSTANT; cfx[index].constant.direction.type = SDL_HAPTIC_POLAR; cfx[index].constant.direction.dir[0] = dir; cfx[index].constant.length = 1000; cfx[index].constant.level = level; cfx[index].constant.attack_length = 0; cfx[index].constant.fade_length = 1000; #if __WIN32__ if (SDL_HapticGetEffectStatus(Haptics[index], id[index]) == SDL_TRUE) #else // Linux SDL doesn't support checking status at the moment :-( if (cfx_timeout[index] > SDL_GetTicks()) #endif SDL_HapticUpdateEffect(Haptics[index], id[index], &cfx[index]); else { SDL_HapticDestroyEffect(Haptics[index], id[index]); id[index] = SDL_HapticNewEffect(Haptics[index], &cfx[index]); SDL_HapticRunEffect(Haptics[index], id[index], 1); } cfx_timeout[index] = SDL_GetTicks() + cfx[index].constant.length; #endif } void gfctrlJoyRumble(int index, float level) { #if SDL_MAJOR_VERSION >= 2 if (!Haptics[index]) return; if (SDL_HapticRumbleSupported(Haptics[index]) != SDL_TRUE) return; // we have to stop the rumble before updating if (rfx_timeout[index] > SDL_GetTicks()) { if (SDL_HapticRumbleStop(Haptics[index]) != 0) GfLogError("Failed to stop rumble: %s\n", SDL_GetError() ); } if (SDL_HapticRumblePlay(Haptics[index], level, 100) != 0) GfLogError("Failed to play rumble: %s\n", SDL_GetError() ); rfx_timeout[index] = SDL_GetTicks() + 100; #endif } #endif // Shutdown time. void gfctrlJoyShutdown(void) { if (gfctrlJoyPresent != GFCTRL_JOY_UNTESTED) #ifndef SDL_JOYSTICK for (int index = 0; index < GFCTRL_JOY_NUMBER; index++) delete Joysticks[index]; #else for (int index = 0; index < gfctrlJoyPresent; index++) { SDL_JoystickClose(Joysticks[index]); Joysticks[index] = NULL; #if SDL_MAJOR_VERSION >= 2 if (Haptics[index]) { SDL_HapticClose(Haptics[index]); Haptics[index] = NULL; } #endif } #endif gfctrlJoyPresent = GFCTRL_JOY_UNTESTED; } /** Create the joystick control @ingroup ctrl @return pointer on a tCtrlJoyInfo structure <br>0 .. if no joystick present @note call GfctrlJoyRelease to free the tCtrlJoyInfo structure @see GfctrlJoyRelease @see tCtrlJoyInfo */ tCtrlJoyInfo * GfctrlJoyCreate(void) { if (gfctrlJoyPresent == GFCTRL_JOY_UNTESTED) gfctrlJoyInit(); tCtrlJoyInfo* joyInfo = (tCtrlJoyInfo *)calloc(1, sizeof(tCtrlJoyInfo)); #if SDL_JOYSTICK joyInfoCopy = joyInfo; #endif return joyInfo; } /** Release the tCtrlJoyInfo structure @ingroup ctrl @param joyInfo joystick structure @return none */ void GfctrlJoyRelease(tCtrlJoyInfo *joyInfo) { freez(joyInfo); }