bool Joystick::openGamepad(int deviceindex) { if (!SDL_IsGameController(deviceindex)) return false; if (isGamepad()) { SDL_GameControllerClose(controller); controller = nullptr; } controller = SDL_GameControllerOpen(deviceindex); return isGamepad(); }
Joystick::JoystickInput Joystick::getGamepadMapping(const GamepadInput &input) const { Joystick::JoystickInput jinput; jinput.type = INPUT_TYPE_MAX_ENUM; if (!isGamepad()) return jinput; SDL_GameControllerButtonBind sdlbind = {}; sdlbind.bindType = SDL_CONTROLLER_BINDTYPE_NONE; SDL_GameControllerButton sdlbutton; SDL_GameControllerAxis sdlaxis; switch (input.type) { case INPUT_TYPE_BUTTON: if (getConstant(input.button, sdlbutton)) sdlbind = SDL_GameControllerGetBindForButton(controller, sdlbutton); break; case INPUT_TYPE_AXIS: if (getConstant(input.axis, sdlaxis)) sdlbind = SDL_GameControllerGetBindForAxis(controller, sdlaxis); break; default: break; } switch (sdlbind.bindType) { case SDL_CONTROLLER_BINDTYPE_BUTTON: jinput.type = INPUT_TYPE_BUTTON; jinput.button = sdlbind.value.button; break; case SDL_CONTROLLER_BINDTYPE_AXIS: jinput.type = INPUT_TYPE_AXIS; jinput.axis = sdlbind.value.axis; break; case SDL_CONTROLLER_BINDTYPE_HAT: if (getConstant(sdlbind.value.hat.hat_mask, jinput.hat.value)) { jinput.type = INPUT_TYPE_HAT; jinput.hat.index = sdlbind.value.hat.hat; } break; case SDL_CONTROLLER_BINDTYPE_NONE: default: break; } return jinput; }
float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const { if (!isConnected() || !isGamepad()) return 0.f; SDL_GameControllerAxis sdlaxis; if (!getConstant(axis, sdlaxis)) return 0.f; Sint16 value = SDL_GameControllerGetAxis(controller, sdlaxis); return clampval((float) value / 32768.0f); }
bool Joystick::isGamepadDown(const std::vector<GamepadButton> &blist) const { if (!isConnected() || !isGamepad()) return false; SDL_GameControllerButton sdlbutton; for (GamepadButton button : blist) { if (!getConstant(button, sdlbutton)) continue; if (SDL_GameControllerGetButton(controller, sdlbutton) == 1) return true; } return false; }
bool Joystick::isVibrationSupported() { if (!checkCreateHaptic()) return false; unsigned int features = SDL_HapticQuery(haptic); if ((features & SDL_HAPTIC_LEFTRIGHT) != 0) return true; // Some gamepad drivers only support left/right motors via a custom effect. if (isGamepad() && (features & SDL_HAPTIC_CUSTOM) != 0) return true; // Test for simple sine wave support as a last resort. if ((features & SDL_HAPTIC_SINE) != 0) return true; return false; }
bool Joystick::setVibration(float left, float right, float duration) { left = std::min(std::max(left, 0.0f), 1.0f); right = std::min(std::max(right, 0.0f), 1.0f); if (left == 0.0f && right == 0.0f) return setVibration(); if (!checkCreateHaptic()) return false; Uint32 length = SDL_HAPTIC_INFINITY; if (duration >= 0.0f) { float maxduration = std::numeric_limits<Uint32>::max() / 1000.0f; length = Uint32(std::min(duration, maxduration) * 1000); } bool success = false; unsigned int features = SDL_HapticQuery(haptic); int axes = SDL_HapticNumAxes(haptic); if ((features & SDL_HAPTIC_LEFTRIGHT) != 0) { memset(&vibration.effect, 0, sizeof(SDL_HapticEffect)); vibration.effect.type = SDL_HAPTIC_LEFTRIGHT; vibration.effect.leftright.length = length; vibration.effect.leftright.large_magnitude = Uint16(left * LOVE_UINT16_MAX); vibration.effect.leftright.small_magnitude = Uint16(right * LOVE_UINT16_MAX); success = runVibrationEffect(); } // Some gamepad drivers only give support for controlling individual motors // through a custom FF effect. if (!success && isGamepad() && (features & SDL_HAPTIC_CUSTOM) && axes == 2) { // NOTE: this may cause issues with drivers which support custom effects // but aren't similar to https://github.com/d235j/360Controller . // Custom effect data is clamped to 0x7FFF in SDL. vibration.data[0] = vibration.data[2] = Uint16(left * 0x7FFF); vibration.data[1] = vibration.data[3] = Uint16(right * 0x7FFF); memset(&vibration.effect, 0, sizeof(SDL_HapticEffect)); vibration.effect.type = SDL_HAPTIC_CUSTOM; vibration.effect.custom.length = length; vibration.effect.custom.channels = 2; vibration.effect.custom.period = 10; vibration.effect.custom.samples = 2; vibration.effect.custom.data = vibration.data; success = runVibrationEffect(); } // Fall back to a simple sine wave if all else fails. This only supports a // single strength value. if (!success && (features & SDL_HAPTIC_SINE) != 0) { memset(&vibration.effect, 0, sizeof(SDL_HapticEffect)); vibration.effect.type = SDL_HAPTIC_SINE; vibration.effect.periodic.length = length; vibration.effect.periodic.period = 10; float strength = std::max(left, right); vibration.effect.periodic.magnitude = Sint16(strength * 0x7FFF); success = runVibrationEffect(); } if (success) { vibration.left = left; vibration.right = right; if (length == SDL_HAPTIC_INFINITY) vibration.endtime = SDL_HAPTIC_INFINITY; else vibration.endtime = SDL_GetTicks() + length; } else { vibration.left = vibration.right = 0.0f; vibration.endtime = SDL_HAPTIC_INFINITY; } return success; }