mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-22 06:13:45 -07:00
Added new controller support
Using the SDLJoystick API, I added support for new controllers
This commit is contained in:
parent
5505336a8a
commit
aababcd87f
10 changed files with 682 additions and 328 deletions
|
@ -154,6 +154,11 @@ namespace Ship {
|
|||
(*this)["SDL CONTROLLER 3"]["GUID"] = "";
|
||||
(*this)["SDL CONTROLLER 4"]["GUID"] = "";
|
||||
|
||||
(*this)["Joystick CONTROLLER 1"]["GUID"] = "";
|
||||
(*this)["Joystick CONTROLLER 2"]["GUID"] = "";
|
||||
(*this)["Joystick CONTROLLER 3"]["GUID"] = "";
|
||||
(*this)["Joystick CONTROLLER 4"]["GUID"] = "";
|
||||
|
||||
return File.generate(Val);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,12 +9,12 @@
|
|||
extern "C" uint8_t __osMaxControllers;
|
||||
|
||||
namespace Ship {
|
||||
SDLController::SDLController(int32_t dwControllerNumber) : Controller(dwControllerNumber), Cont(nullptr), guid(INVALID_SDL_CONTROLLER_GUID) {
|
||||
|
||||
SDLController::SDLController(int32_t dwControllerNumber) : Controller(dwControllerNumber), guid(INVALID_SDL_CONTROLLER_GUID) {
|
||||
|
||||
}
|
||||
|
||||
SDLController::~SDLController() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool SDLController::IsGuidInUse(const std::string& guid) {
|
||||
|
@ -32,81 +32,6 @@ namespace Ship {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SDLController::Open() {
|
||||
std::string ConfSection = GetConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
for (int i = 0; i < SDL_NumJoysticks(); i++) {
|
||||
if (SDL_IsGameController(i)) {
|
||||
// Get the GUID from SDL
|
||||
char GuidBuf[33];
|
||||
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), GuidBuf, sizeof(GuidBuf));
|
||||
auto NewGuid = std::string(GuidBuf);
|
||||
|
||||
// Invalid GUID read. Go to next.
|
||||
if (NewGuid.compare(INVALID_SDL_CONTROLLER_GUID) == 0) {
|
||||
SPDLOG_ERROR("SDL Controller returned invalid guid");
|
||||
continue;
|
||||
}
|
||||
|
||||
// The GUID is in use, we want to use a different physical controller. Go to next.
|
||||
if (IsGuidInUse(NewGuid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the GUID is blank from the config, OR if the config GUID matches, load the controller.
|
||||
if (Conf[ConfSection]["GUID"].compare("") == 0 || Conf[ConfSection]["GUID"].compare(INVALID_SDL_CONTROLLER_GUID) == 0 || Conf[ConfSection]["GUID"].compare(NewGuid) == 0) {
|
||||
auto NewCont = SDL_GameControllerOpen(i);
|
||||
|
||||
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO))
|
||||
{
|
||||
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
|
||||
}
|
||||
|
||||
// We failed to load the controller. Go to next.
|
||||
if (NewCont == nullptr) {
|
||||
SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
guid = NewGuid;
|
||||
Cont = NewCont;
|
||||
|
||||
std::string BindingConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pBindingConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& BindingConf = *pBindingConf.get();
|
||||
|
||||
if (!BindingConf.has(BindingConfSection)) {
|
||||
CreateDefaultBinding();
|
||||
}
|
||||
|
||||
LoadBinding();
|
||||
LoadAxisThresholds();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Cont != nullptr;
|
||||
}
|
||||
|
||||
bool SDLController::Close() {
|
||||
if (Cont != nullptr) {
|
||||
SDL_GameControllerClose(Cont);
|
||||
}
|
||||
Cont = nullptr;
|
||||
guid = "";
|
||||
ButtonMapping.clear();
|
||||
ThresholdMapping.clear();
|
||||
dwPressedButtons = 0;
|
||||
wStickX = 0;
|
||||
wStickY = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLController::LoadAxisThresholds() {
|
||||
std::string ConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
|
@ -156,241 +81,6 @@ namespace Ship {
|
|||
wStickY = -ay;
|
||||
}
|
||||
|
||||
void SDLController::ReadFromSource() {
|
||||
std::string ConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
SDL_GameControllerUpdate();
|
||||
|
||||
// If the controller is disconnected, close it.
|
||||
if (Cont != nullptr && !SDL_GameControllerGetAttached(Cont)) {
|
||||
Close();
|
||||
}
|
||||
|
||||
// Attempt to load the controller if it's not loaded
|
||||
if (Cont == nullptr) {
|
||||
// If we failed to load the controller, don't process it.
|
||||
if (!Open()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasSensor(Cont, SDL_SENSOR_GYRO))
|
||||
{
|
||||
float gyroData[3];
|
||||
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
|
||||
|
||||
const char* contName = SDL_GameControllerName(Cont);
|
||||
const int isSpecialController = !strcmp("PS5 Controller", contName);
|
||||
const float gyroSensitivity = Game::Settings.controller.gyro_sensitivity;
|
||||
|
||||
if (Game::Settings.controller.gyroDriftX == 0) {
|
||||
Game::Settings.controller.gyroDriftX = gyroData[0];
|
||||
}
|
||||
|
||||
if (Game::Settings.controller.gyroDriftY == 0) {
|
||||
if (isSpecialController == 1) {
|
||||
Game::Settings.controller.gyroDriftY = gyroData[2];
|
||||
}
|
||||
else {
|
||||
Game::Settings.controller.gyroDriftY = gyroData[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (isSpecialController == 1) {
|
||||
wGyroX = gyroData[0] - Game::Settings.controller.gyroDriftX;
|
||||
wGyroY = -gyroData[2] - Game::Settings.controller.gyroDriftY;
|
||||
}
|
||||
else {
|
||||
wGyroX = gyroData[0] - Game::Settings.controller.gyroDriftX;
|
||||
wGyroY = gyroData[1] - Game::Settings.controller.gyroDriftY;
|
||||
}
|
||||
|
||||
wGyroX *= gyroSensitivity;
|
||||
wGyroY *= gyroSensitivity;
|
||||
}
|
||||
|
||||
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
|
||||
if (ButtonMapping.contains(i)) {
|
||||
if (SDL_GameControllerGetButton(Cont, (SDL_GameControllerButton)i)) {
|
||||
dwPressedButtons |= ButtonMapping[i];
|
||||
}
|
||||
else {
|
||||
dwPressedButtons &= ~ButtonMapping[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_GameControllerAxis StickAxisX = SDL_CONTROLLER_AXIS_INVALID;
|
||||
SDL_GameControllerAxis StickAxisY = SDL_CONTROLLER_AXIS_INVALID;
|
||||
int32_t StickDeadzone = 0;
|
||||
|
||||
for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
|
||||
auto Axis = (SDL_GameControllerAxis)i;
|
||||
auto PosScancode = i + AXIS_SCANCODE_BIT;
|
||||
auto NegScancode = -PosScancode;
|
||||
auto AxisThreshold = ThresholdMapping[i];
|
||||
auto PosButton = ButtonMapping[PosScancode];
|
||||
auto NegButton = ButtonMapping[NegScancode];
|
||||
auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
|
||||
|
||||
#ifdef TARGET_WEB
|
||||
// Firefox has a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1606562
|
||||
// It sets down y to 32768.0f / 32767.0f, which is greater than the allowed 1.0f,
|
||||
// which SDL then converts to a int16_t by multiplying by 32767.0f, which overflows into -32768.
|
||||
// Maximum up will hence never become -32768 with the current version of SDL2,
|
||||
// so this workaround should be safe in compliant browsers.
|
||||
if (AxisValue == -32768) {
|
||||
AxisValue = 32767;
|
||||
}
|
||||
#endif
|
||||
|
||||
// If the axis is NOT mapped to the control stick.
|
||||
if (!(
|
||||
PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT ||
|
||||
PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN ||
|
||||
NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT ||
|
||||
NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) {
|
||||
if (AxisValue > AxisThreshold) {
|
||||
dwPressedButtons |= PosButton;
|
||||
dwPressedButtons &= ~NegButton;
|
||||
}
|
||||
else if (AxisValue < -AxisThreshold) {
|
||||
dwPressedButtons &= ~PosButton;
|
||||
dwPressedButtons |= NegButton;
|
||||
}
|
||||
else {
|
||||
dwPressedButtons &= ~PosButton;
|
||||
dwPressedButtons &= ~NegButton;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT) {
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
|
||||
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", StickAxisX, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisX = Axis;
|
||||
}
|
||||
|
||||
if (PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN) {
|
||||
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
|
||||
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", StickAxisY, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisY = Axis;
|
||||
}
|
||||
|
||||
if (NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT) {
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
|
||||
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", StickAxisX, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisX = Axis;
|
||||
}
|
||||
|
||||
if (NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN) {
|
||||
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
|
||||
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", StickAxisY, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisY = Axis;
|
||||
}
|
||||
}
|
||||
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
|
||||
auto AxisValueX = SDL_GameControllerGetAxis(Cont, StickAxisX);
|
||||
auto AxisValueY = SDL_GameControllerGetAxis(Cont, StickAxisY);
|
||||
NormalizeStickAxis(AxisValueX, AxisValueY, StickDeadzone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDLController::WriteToSource(ControllerCallback* controller)
|
||||
{
|
||||
if (SDL_GameControllerHasRumble(Cont)) {
|
||||
if (controller->rumble > 0) {
|
||||
SDL_GameControllerRumble(Cont, 0xFFFF * Game::Settings.controller.rumble_strength, 0xFFFF * Game::Settings.controller.rumble_strength, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasLED(Cont)) {
|
||||
switch (controller->ledColor) {
|
||||
case 0:
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 255, 0, 0);
|
||||
break;
|
||||
case 1:
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 0x1E, 0x69, 0x1B);
|
||||
break;
|
||||
case 2:
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 0x64, 0x14, 0x00);
|
||||
break;
|
||||
case 3:
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 0x00, 0x3C, 0x64);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDLController::CreateDefaultBinding() {
|
||||
std::string ConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
Conf[ConfSection][STR(BTN_CRIGHT)] = std::to_string((SDL_CONTROLLER_AXIS_RIGHTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_CLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_RIGHTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_CDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_RIGHTY + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_CUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_RIGHTY + AXIS_SCANCODE_BIT));
|
||||
//Conf[ConfSection][STR(BTN_CRIGHT + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_X);
|
||||
//Conf[ConfSection][STR(BTN_CLEFT + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_Y);
|
||||
//Conf[ConfSection][STR(BTN_CDOWN + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
|
||||
//Conf[ConfSection][STR(BTN_CUP + "_2")] = std::to_string(SDL_CONTROLLER_BUTTON_RIGHTSTICK);
|
||||
Conf[ConfSection][STR(BTN_R)] = std::to_string((SDL_CONTROLLER_AXIS_TRIGGERRIGHT + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_L)] = std::to_string(SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
|
||||
Conf[ConfSection][STR(BTN_DRIGHT)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
||||
Conf[ConfSection][STR(BTN_DLEFT)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_LEFT);
|
||||
Conf[ConfSection][STR(BTN_DDOWN)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
||||
Conf[ConfSection][STR(BTN_DUP)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_UP);
|
||||
Conf[ConfSection][STR(BTN_START)] = std::to_string(SDL_CONTROLLER_BUTTON_START);
|
||||
Conf[ConfSection][STR(BTN_Z)] = std::to_string((SDL_CONTROLLER_AXIS_TRIGGERLEFT + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_B)] = std::to_string(SDL_CONTROLLER_BUTTON_B);
|
||||
Conf[ConfSection][STR(BTN_A)] = std::to_string(SDL_CONTROLLER_BUTTON_A);
|
||||
Conf[ConfSection][STR(BTN_STICKRIGHT)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
|
||||
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTX) + "_threshold"] = std::to_string(16.0);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTY) + "_threshold"] = std::to_string(16.0);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTX) + "_threshold"] = std::to_string(0x4000);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTY) + "_threshold"] = std::to_string(0x4000);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERLEFT) + "_threshold"] = std::to_string(0x1E00);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + "_threshold"] = std::to_string(0x1E00);
|
||||
|
||||
Conf.Save();
|
||||
}
|
||||
|
||||
void SDLController::SetButtonMapping(const std::string& szButtonName, int32_t dwScancode) {
|
||||
if (guid.compare(INVALID_SDL_CONTROLLER_GUID)) {
|
||||
return;
|
||||
|
@ -400,7 +90,7 @@ namespace Ship {
|
|||
}
|
||||
|
||||
std::string SDLController::GetControllerType() {
|
||||
return "SDL";
|
||||
return "Base";
|
||||
}
|
||||
|
||||
std::string SDLController::GetConfSection() {
|
||||
|
|
|
@ -10,9 +10,6 @@ namespace Ship {
|
|||
SDLController(int32_t dwControllerNumber);
|
||||
~SDLController();
|
||||
|
||||
void ReadFromSource();
|
||||
void WriteToSource(ControllerCallback* controller);
|
||||
|
||||
std::string GetGuid() { return guid; };
|
||||
|
||||
protected:
|
||||
|
@ -20,17 +17,13 @@ namespace Ship {
|
|||
void SetButtonMapping(const std::string& szButtonName, int32_t dwScancode);
|
||||
std::string GetConfSection();
|
||||
std::string GetBindingConfSection();
|
||||
void CreateDefaultBinding();
|
||||
static bool IsGuidInUse(const std::string& guid);
|
||||
|
||||
private:
|
||||
std::string guid;
|
||||
SDL_GameController* Cont;
|
||||
std::map<int32_t, int16_t> ThresholdMapping;
|
||||
|
||||
void LoadAxisThresholds();
|
||||
void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold);
|
||||
bool Open();
|
||||
bool Close();
|
||||
|
||||
std::string guid;
|
||||
std::map<int32_t, int16_t> ThresholdMapping;
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
|
315
libultraship/libultraship/SDLGamepadController.cpp
Normal file
315
libultraship/libultraship/SDLGamepadController.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
#include "SDLGamepadController.h"
|
||||
|
||||
#include "GameSettings.h"
|
||||
#include "GlobalCtx2.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "stox.h"
|
||||
#include "Window.h"
|
||||
|
||||
extern "C" uint8_t __osMaxControllers;
|
||||
float gyroDriftX;
|
||||
float gyroDriftY;
|
||||
|
||||
namespace Ship {
|
||||
|
||||
|
||||
SDLGamepadController::SDLGamepadController(int32_t dwControllerNumber) : SDLController(dwControllerNumber), Cont(nullptr) {
|
||||
|
||||
}
|
||||
|
||||
SDLGamepadController::~SDLGamepadController() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool SDLGamepadController::Open() {
|
||||
std::string ConfSection = GetConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
for (int i = 0; i < SDL_NumJoysticks(); i++) {
|
||||
if (SDL_IsGameController(i)) {
|
||||
// Get the GUID from SDL
|
||||
char GuidBuf[33];
|
||||
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), GuidBuf, sizeof(GuidBuf));
|
||||
auto NewGuid = std::string(GuidBuf);
|
||||
|
||||
// Invalid GUID read. Go to next.
|
||||
if (NewGuid.compare(INVALID_SDL_CONTROLLER_GUID) == 0) {
|
||||
SPDLOG_ERROR("SDL Controller returned invalid guid");
|
||||
continue;
|
||||
}
|
||||
|
||||
// The GUID is in use, we want to use a different physical controller. Go to next.
|
||||
if (IsGuidInUse(NewGuid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the GUID is blank from the config, OR if the config GUID matches, load the controller.
|
||||
if (Conf[ConfSection]["GUID"].compare("") == 0 || Conf[ConfSection]["GUID"].compare(INVALID_SDL_CONTROLLER_GUID) == 0 || Conf[ConfSection]["GUID"].compare(NewGuid) == 0) {
|
||||
auto NewCont = SDL_GameControllerOpen(i);
|
||||
|
||||
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO))
|
||||
{
|
||||
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
|
||||
}
|
||||
|
||||
// We failed to load the controller. Go to next.
|
||||
if (NewCont == nullptr) {
|
||||
SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
guid = NewGuid;
|
||||
Cont = NewCont;
|
||||
|
||||
std::string BindingConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pBindingConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& BindingConf = *pBindingConf.get();
|
||||
|
||||
if (!BindingConf.has(BindingConfSection)) {
|
||||
CreateDefaultBinding();
|
||||
}
|
||||
|
||||
LoadBinding();
|
||||
LoadAxisThresholds();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Cont != nullptr;
|
||||
}
|
||||
|
||||
bool SDLGamepadController::Close() {
|
||||
if (Cont != nullptr) {
|
||||
SDL_GameControllerClose(Cont);
|
||||
}
|
||||
Cont = nullptr;
|
||||
guid = "";
|
||||
ButtonMapping.clear();
|
||||
ThresholdMapping.clear();
|
||||
dwPressedButtons = 0;
|
||||
wStickX = 0;
|
||||
wStickY = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLGamepadController::ReadFromSource() {
|
||||
std::string ConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
SDL_GameControllerUpdate();
|
||||
|
||||
// If the controller is disconnected, close it.
|
||||
if (Cont != nullptr && !SDL_GameControllerGetAttached(Cont)) {
|
||||
Close();
|
||||
}
|
||||
|
||||
// Attempt to load the controller if it's not loaded
|
||||
if (Cont == nullptr) {
|
||||
// If we failed to load the controller, don't process it.
|
||||
if (!Open()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasSensor(Cont, SDL_SENSOR_GYRO))
|
||||
{
|
||||
float gyroData[3];
|
||||
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
|
||||
|
||||
const char* contName = SDL_GameControllerName(Cont);
|
||||
const int isSpecialController = strcmp("PS5 Controller", contName);
|
||||
const float gyroSensitivity = Game::Settings.controller.gyro_sensitivity;
|
||||
|
||||
if (gyroDriftX == 0) {
|
||||
if (isSpecialController == 0) {
|
||||
gyroDriftX = gyroData[2];
|
||||
}
|
||||
else {
|
||||
gyroDriftX = gyroData[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (gyroDriftY == 0) {
|
||||
gyroDriftY = gyroData[1];
|
||||
}
|
||||
|
||||
if (isSpecialController == 0) {
|
||||
wGyroX = gyroData[2] - gyroDriftX;
|
||||
}
|
||||
else {
|
||||
wGyroX = gyroData[0] - gyroDriftX;
|
||||
}
|
||||
|
||||
wGyroY = gyroData[1] - gyroDriftY;
|
||||
|
||||
wGyroX *= gyroSensitivity;
|
||||
wGyroY *= gyroSensitivity;
|
||||
}
|
||||
|
||||
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
|
||||
if (ButtonMapping.contains(i)) {
|
||||
if (SDL_GameControllerGetButton(Cont, (SDL_GameControllerButton)i)) {
|
||||
dwPressedButtons |= ButtonMapping[i];
|
||||
}
|
||||
else {
|
||||
dwPressedButtons &= ~ButtonMapping[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_GameControllerAxis StickAxisX = SDL_CONTROLLER_AXIS_INVALID;
|
||||
SDL_GameControllerAxis StickAxisY = SDL_CONTROLLER_AXIS_INVALID;
|
||||
int32_t StickDeadzone = 0;
|
||||
|
||||
for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
|
||||
auto Axis = (SDL_GameControllerAxis)i;
|
||||
auto PosScancode = i + AXIS_SCANCODE_BIT;
|
||||
auto NegScancode = -PosScancode;
|
||||
auto AxisThreshold = ThresholdMapping[i];
|
||||
auto PosButton = ButtonMapping[PosScancode];
|
||||
auto NegButton = ButtonMapping[NegScancode];
|
||||
auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
|
||||
|
||||
|
||||
// If the axis is NOT mapped to the control stick.
|
||||
if (!(
|
||||
PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT ||
|
||||
PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN ||
|
||||
NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT ||
|
||||
NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) {
|
||||
if (AxisValue > AxisThreshold) {
|
||||
dwPressedButtons |= PosButton;
|
||||
dwPressedButtons &= ~NegButton;
|
||||
}
|
||||
else if (AxisValue < -AxisThreshold) {
|
||||
dwPressedButtons &= ~PosButton;
|
||||
dwPressedButtons |= NegButton;
|
||||
}
|
||||
else {
|
||||
dwPressedButtons &= ~PosButton;
|
||||
dwPressedButtons &= ~NegButton;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT) {
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
|
||||
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", StickAxisX, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisX = Axis;
|
||||
}
|
||||
|
||||
if (PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN) {
|
||||
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
|
||||
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", StickAxisY, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisY = Axis;
|
||||
}
|
||||
|
||||
if (NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT) {
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
|
||||
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", StickAxisX, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisX = Axis;
|
||||
}
|
||||
|
||||
if (NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN) {
|
||||
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
|
||||
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", StickAxisY, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisY = Axis;
|
||||
}
|
||||
}
|
||||
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
|
||||
auto AxisValueX = SDL_GameControllerGetAxis(Cont, StickAxisX);
|
||||
auto AxisValueY = SDL_GameControllerGetAxis(Cont, StickAxisY);
|
||||
NormalizeStickAxis(AxisValueX, AxisValueY, StickDeadzone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDLGamepadController::WriteToSource(ControllerCallback* controller)
|
||||
{
|
||||
if (SDL_GameControllerHasRumble(Cont)) {
|
||||
if (controller->rumble > 0) {
|
||||
SDL_GameControllerRumble(Cont, 0xFFFF * Game::Settings.controller.rumble_strength, 0xFFFF * Game::Settings.controller.rumble_strength, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasLED(Cont)) {
|
||||
if (controller->ledColor == 1) {
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 255, 0, 0);
|
||||
}
|
||||
else {
|
||||
SDL_JoystickSetLED(SDL_GameControllerGetJoystick(Cont), 0, 255, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDLGamepadController::CreateDefaultBinding() {
|
||||
std::string ConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
Conf[ConfSection][STR(BTN_CRIGHT)] = std::to_string((SDL_CONTROLLER_AXIS_RIGHTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_CLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_RIGHTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_CDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_RIGHTY + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_CUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_RIGHTY + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_R)] = std::to_string((SDL_CONTROLLER_AXIS_TRIGGERRIGHT + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_L)] = std::to_string(SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
|
||||
Conf[ConfSection][STR(BTN_DRIGHT)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
|
||||
Conf[ConfSection][STR(BTN_DLEFT)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_LEFT);
|
||||
Conf[ConfSection][STR(BTN_DDOWN)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_DOWN);
|
||||
Conf[ConfSection][STR(BTN_DUP)] = std::to_string(SDL_CONTROLLER_BUTTON_DPAD_UP);
|
||||
Conf[ConfSection][STR(BTN_START)] = std::to_string(SDL_CONTROLLER_BUTTON_START);
|
||||
Conf[ConfSection][STR(BTN_Z)] = std::to_string((SDL_CONTROLLER_AXIS_TRIGGERLEFT + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_B)] = std::to_string(SDL_CONTROLLER_BUTTON_B);
|
||||
Conf[ConfSection][STR(BTN_A)] = std::to_string(SDL_CONTROLLER_BUTTON_A);
|
||||
Conf[ConfSection][STR(BTN_STICKRIGHT)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
|
||||
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTX) + "_threshold"] = std::to_string(16.0);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTY) + "_threshold"] = std::to_string(16.0);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTX) + "_threshold"] = std::to_string(0x4000);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTY) + "_threshold"] = std::to_string(0x4000);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERLEFT) + "_threshold"] = std::to_string(0x1E00);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + "_threshold"] = std::to_string(0x1E00);
|
||||
|
||||
Conf.Save();
|
||||
}
|
||||
|
||||
std::string SDLGamepadController::GetControllerType() {
|
||||
return "SDL";
|
||||
}
|
||||
}
|
25
libultraship/libultraship/SDLGamepadController.h
Normal file
25
libultraship/libultraship/SDLGamepadController.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "SDLController.h"
|
||||
|
||||
|
||||
namespace Ship {
|
||||
class SDLGamepadController : public SDLController {
|
||||
public:
|
||||
SDLGamepadController(int32_t dwControllerNumber);
|
||||
~SDLGamepadController();
|
||||
|
||||
void ReadFromSource();
|
||||
void WriteToSource(ControllerCallback* controller);
|
||||
|
||||
|
||||
protected:
|
||||
std::string GetControllerType();
|
||||
void CreateDefaultBinding();
|
||||
|
||||
private:
|
||||
SDL_GameController* Cont;
|
||||
|
||||
bool Open();
|
||||
bool Close();
|
||||
};
|
||||
}
|
275
libultraship/libultraship/SDLJoystickController.cpp
Normal file
275
libultraship/libultraship/SDLJoystickController.cpp
Normal file
|
@ -0,0 +1,275 @@
|
|||
#include "SDLJoystickController.h"
|
||||
|
||||
#include "GameSettings.h"
|
||||
#include "GlobalCtx2.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "stox.h"
|
||||
#include "Window.h"
|
||||
|
||||
extern "C" uint8_t __osMaxControllers;
|
||||
float gyroDriftX;
|
||||
float gyroDriftY;
|
||||
|
||||
namespace Ship {
|
||||
|
||||
|
||||
SDLJoystickController::SDLJoystickController(int32_t dwControllerNumber) : SDLController(dwControllerNumber), Cont(nullptr), numButtons(0) {
|
||||
|
||||
}
|
||||
|
||||
SDLJoystickController::~SDLJoystickController() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool SDLJoystickController::Open() {
|
||||
std::string ConfSection = GetConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
for (int i = 0; i < SDL_NumJoysticks(); i++) {
|
||||
// This is for HID devices. So don't use the GameController API
|
||||
if (!SDL_IsGameController(i)) {
|
||||
// Get the GUID from SDL
|
||||
char GuidBuf[33];
|
||||
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(i), GuidBuf, sizeof(GuidBuf));
|
||||
auto NewGuid = std::string(GuidBuf);
|
||||
|
||||
// Invalid GUID read. Go to next.
|
||||
if (NewGuid.compare(INVALID_SDL_CONTROLLER_GUID) == 0) {
|
||||
SPDLOG_ERROR("SDL Controller returned invalid guid");
|
||||
continue;
|
||||
}
|
||||
|
||||
// The GUID is in use, we want to use a different physical controller. Go to next.
|
||||
if (IsGuidInUse(NewGuid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the GUID is blank from the config, OR if the config GUID matches, load the controller.
|
||||
if (Conf[ConfSection]["GUID"].compare("") == 0 || Conf[ConfSection]["GUID"].compare(INVALID_SDL_CONTROLLER_GUID) == 0 || Conf[ConfSection]["GUID"].compare(NewGuid) == 0) {
|
||||
auto NewCont = SDL_JoystickOpen(i);
|
||||
|
||||
// We failed to load the controller. Go to next.
|
||||
if (NewCont == nullptr) {
|
||||
SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
guid = NewGuid;
|
||||
Cont = NewCont;
|
||||
numButtons = SDL_JoystickNumButtons(Cont);
|
||||
|
||||
std::string BindingConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pBindingConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& BindingConf = *pBindingConf.get();
|
||||
|
||||
if (!BindingConf.has(BindingConfSection)) {
|
||||
CreateDefaultBinding();
|
||||
}
|
||||
|
||||
LoadBinding();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Cont != nullptr;
|
||||
}
|
||||
|
||||
bool SDLJoystickController::Close() {
|
||||
if (Cont != nullptr) {
|
||||
SDL_JoystickClose(Cont);
|
||||
}
|
||||
Cont = nullptr;
|
||||
guid = "";
|
||||
ButtonMapping.clear();
|
||||
dwPressedButtons = 0;
|
||||
wStickX = 0;
|
||||
wStickY = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SDLJoystickController::ReadFromSource() {
|
||||
std::string ConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
SDL_GameControllerUpdate();
|
||||
|
||||
// If the controller is disconnected, close it.
|
||||
if (Cont != nullptr && !SDL_JoystickGetAttached(Cont)) {
|
||||
Close();
|
||||
}
|
||||
|
||||
// Attempt to load the controller if it's not loaded
|
||||
if (Cont == nullptr) {
|
||||
// If we failed to load the controller, don't process it.
|
||||
if (!Open()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < numButtons; i++) {
|
||||
if (ButtonMapping.contains(i)) {
|
||||
if (SDL_JoystickGetButton(Cont, i)) {
|
||||
dwPressedButtons |= ButtonMapping[i];
|
||||
}
|
||||
else {
|
||||
dwPressedButtons &= ~ButtonMapping[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int StickAxisX = SDL_CONTROLLER_AXIS_INVALID;
|
||||
int StickAxisY = SDL_CONTROLLER_AXIS_INVALID;
|
||||
int32_t StickDeadzone = 0;
|
||||
|
||||
for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
|
||||
auto Axis = i;
|
||||
auto PosScancode = i + AXIS_SCANCODE_BIT;
|
||||
auto NegScancode = -PosScancode;
|
||||
auto AxisThreshold = ThresholdMapping[i];
|
||||
auto PosButton = ButtonMapping[PosScancode];
|
||||
auto NegButton = ButtonMapping[NegScancode];
|
||||
auto AxisValue = SDL_JoystickGetAxis(Cont, Axis);
|
||||
|
||||
|
||||
// If the axis is NOT mapped to the control stick.
|
||||
if (!(
|
||||
PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT ||
|
||||
PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN ||
|
||||
NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT ||
|
||||
NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) {
|
||||
if (AxisValue > AxisThreshold) {
|
||||
dwPressedButtons |= PosButton;
|
||||
dwPressedButtons &= ~NegButton;
|
||||
}
|
||||
else if (AxisValue < -AxisThreshold) {
|
||||
dwPressedButtons &= ~PosButton;
|
||||
dwPressedButtons |= NegButton;
|
||||
}
|
||||
else {
|
||||
dwPressedButtons &= ~PosButton;
|
||||
dwPressedButtons &= ~NegButton;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (PosButton == BTN_STICKLEFT || PosButton == BTN_STICKRIGHT) {
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
|
||||
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", StickAxisX, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisX = Axis;
|
||||
}
|
||||
|
||||
if (PosButton == BTN_STICKUP || PosButton == BTN_STICKDOWN) {
|
||||
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
|
||||
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", StickAxisY, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisY = Axis;
|
||||
}
|
||||
|
||||
if (NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT) {
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisX != Axis) {
|
||||
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", StickAxisX, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisX = Axis;
|
||||
}
|
||||
|
||||
if (NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN) {
|
||||
if (StickAxisY != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != Axis) {
|
||||
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", StickAxisY, Axis);
|
||||
}
|
||||
|
||||
if (StickDeadzone != 0 && StickDeadzone != AxisThreshold) {
|
||||
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", StickDeadzone, AxisThreshold);
|
||||
}
|
||||
|
||||
StickDeadzone = AxisThreshold;
|
||||
StickAxisY = Axis;
|
||||
}
|
||||
}
|
||||
|
||||
if (StickAxisX != SDL_CONTROLLER_AXIS_INVALID && StickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
|
||||
auto AxisValueX = SDL_JoystickGetAxis(Cont, StickAxisX);
|
||||
auto AxisValueY = SDL_JoystickGetAxis(Cont, StickAxisY);
|
||||
NormalizeStickAxis(AxisValueX, AxisValueY, StickDeadzone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDLJoystickController::WriteToSource(ControllerCallback* controller)
|
||||
{
|
||||
if (SDL_JoystickHasRumble(Cont)) {
|
||||
if (controller->rumble > 0) {
|
||||
SDL_JoystickRumble(Cont, 0xFFFF * Game::Settings.controller.rumble_strength, 0xFFFF * Game::Settings.controller.rumble_strength, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (SDL_JoystickHasLED(Cont)) {
|
||||
if (controller->ledColor == 1) {
|
||||
SDL_JoystickSetLED(Cont, 255, 0, 0);
|
||||
}
|
||||
else {
|
||||
SDL_JoystickSetLED(Cont, 0, 255, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SDLJoystickController::CreateDefaultBinding() {
|
||||
std::string ConfSection = GetBindingConfSection();
|
||||
std::shared_ptr<ConfigFile> pConf = GlobalCtx2::GetInstance()->GetConfig();
|
||||
ConfigFile& Conf = *pConf.get();
|
||||
|
||||
Conf[ConfSection][STR(BTN_CRIGHT)] = std::to_string(9);
|
||||
Conf[ConfSection][STR(BTN_CLEFT)] = std::to_string(8);
|
||||
Conf[ConfSection][STR(BTN_CDOWN)] = std::to_string(7);
|
||||
Conf[ConfSection][STR(BTN_CUP)] = std::to_string(6);
|
||||
Conf[ConfSection][STR(BTN_R)] = std::to_string(5);
|
||||
Conf[ConfSection][STR(BTN_L)] = std::to_string(4);
|
||||
Conf[ConfSection][STR(BTN_DRIGHT)] = std::to_string(13);
|
||||
Conf[ConfSection][STR(BTN_DLEFT)] = std::to_string(12);
|
||||
Conf[ConfSection][STR(BTN_DDOWN)] = std::to_string(11);
|
||||
Conf[ConfSection][STR(BTN_DUP)] = std::to_string(10);
|
||||
Conf[ConfSection][STR(BTN_START)] = std::to_string(3);
|
||||
Conf[ConfSection][STR(BTN_Z)] = std::to_string(2);
|
||||
Conf[ConfSection][STR(BTN_B)] = std::to_string(1);
|
||||
Conf[ConfSection][STR(BTN_A)] = std::to_string(0);
|
||||
Conf[ConfSection][STR(BTN_STICKRIGHT)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKLEFT)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKDOWN)] = std::to_string((SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
|
||||
Conf[ConfSection][STR(BTN_STICKUP)] = std::to_string(-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT));
|
||||
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTX) + "_threshold"] = std::to_string(16.0);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_LEFTY) + "_threshold"] = std::to_string(16.0);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTX) + "_threshold"] = std::to_string(0x4000);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_RIGHTY) + "_threshold"] = std::to_string(0x4000);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERLEFT) + "_threshold"] = std::to_string(0x1E00);
|
||||
Conf[ConfSection][STR(SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + "_threshold"] = std::to_string(0x1E00);
|
||||
|
||||
Conf.Save();
|
||||
}
|
||||
|
||||
std::string SDLJoystickController::GetControllerType() {
|
||||
return "Joystick";
|
||||
}
|
||||
}
|
25
libultraship/libultraship/SDLJoystickController.h
Normal file
25
libultraship/libultraship/SDLJoystickController.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "SDLController.h"
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace Ship {
|
||||
class SDLJoystickController : public SDLController {
|
||||
public:
|
||||
SDLJoystickController(int32_t dwControllerNumber);
|
||||
~SDLJoystickController();
|
||||
|
||||
void ReadFromSource();
|
||||
void WriteToSource(ControllerCallback* controller);
|
||||
|
||||
protected:
|
||||
std::string GetControllerType();
|
||||
void CreateDefaultBinding();
|
||||
|
||||
private:
|
||||
SDL_Joystick* Cont;
|
||||
int numButtons;
|
||||
|
||||
bool Open();
|
||||
bool Close();
|
||||
};
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
#include "Window.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "KeyboardController.h"
|
||||
#include "SDLController.h"
|
||||
#include "SDLGamepadController.h"
|
||||
#include "SDLJoystickController.h"
|
||||
#include "GlobalCtx2.h"
|
||||
#include "DisplayList.h"
|
||||
#include "Vertex.h"
|
||||
|
@ -39,12 +40,19 @@ extern "C" {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
if (SDL_Init(SDL_INIT_JOYSTICK) != 0) {
|
||||
SPDLOG_ERROR("Failed to initialize HID game controllers ({})", SDL_GetError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
const char* controllerDb = "gamecontrollerdb.txt";
|
||||
int mappingsAdded = SDL_GameControllerAddMappingsFromFile(controllerDb);
|
||||
if (mappingsAdded >= 0) {
|
||||
SPDLOG_INFO("Added SDL game controllers from \"{}\" ({})", controllerDb, mappingsAdded);
|
||||
} else {
|
||||
SPDLOG_ERROR("Failed add SDL game controller mappings from \"{}\" ({})", controllerDb, SDL_GetError());
|
||||
|
||||
}
|
||||
|
||||
// TODO: This for loop is debug. Burn it with fire.
|
||||
|
@ -66,11 +74,13 @@ extern "C" {
|
|||
|
||||
if (ControllerType == "auto") {
|
||||
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::KeyboardController>(i));
|
||||
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLController>(i));
|
||||
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLGamepadController>(i));
|
||||
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLJoystickController>(i));
|
||||
} else if (ControllerType == "keyboard") {
|
||||
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::KeyboardController>(i));
|
||||
} else if (ControllerType == "usb") {
|
||||
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLController>(i));
|
||||
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLGamepadController>(i));
|
||||
Ship::Window::Controllers[i].push_back(std::make_shared<Ship::SDLJoystickController>(i));
|
||||
} else if (ControllerType == "unplugged") {
|
||||
// Do nothing for unplugged controllers
|
||||
} else {
|
||||
|
|
|
@ -239,6 +239,8 @@
|
|||
<ClCompile Include="Cvar.cpp" />
|
||||
<ClCompile Include="Environment.cpp" />
|
||||
<ClCompile Include="GameSettings.cpp" />
|
||||
<ClCompile Include="SDLGamepadController.cpp" />
|
||||
<ClCompile Include="SDLJoystickController.cpp" />
|
||||
<ClCompile Include="Lib\ImGui\backends\imgui_impl_dx11.cpp" />
|
||||
<ClCompile Include="Lib\ImGui\backends\imgui_impl_win32.cpp" />
|
||||
<ClCompile Include="luslog.cpp" />
|
||||
|
@ -326,6 +328,8 @@
|
|||
<ClInclude Include="Cvar.h" />
|
||||
<ClInclude Include="Environment.h" />
|
||||
<ClInclude Include="GameSettings.h" />
|
||||
<ClInclude Include="SDLGamepadController.h" />
|
||||
<ClInclude Include="SDLJoystickController.h" />
|
||||
<ClInclude Include="Lib\ImGui\backends\imgui_impl_dx11.h" />
|
||||
<ClInclude Include="Lib\ImGui\backends\imgui_impl_win32.h" />
|
||||
<ClInclude Include="Lib\stb\stb_image_write.h" />
|
||||
|
|
|
@ -339,6 +339,12 @@
|
|||
<ClCompile Include="GameSettings.cpp">
|
||||
<Filter>Source Files\CustomImpl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SDLJoystickController.cpp">
|
||||
<Filter>Source Files\Controller</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SDLGamepadController.cpp">
|
||||
<Filter>Source Files\Controller</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Lib\tinyxml2\tinyxml2.h">
|
||||
|
@ -626,5 +632,11 @@
|
|||
<ClInclude Include="GameSettings.h">
|
||||
<Filter>Source Files\CustomImpl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SDLGamepadController.h">
|
||||
<Filter>Source Files\Controller</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SDLJoystickController.h">
|
||||
<Filter>Source Files\Controller</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Add table
Add a link
Reference in a new issue