Cleans up Controllers

Renames VirtualController to DummyController.
Makes controller axis treated the same as buttons.
Made Controller class members private or protected
Made Controller class treat deadzones, sensitivities, and press thresholds consistently.
This commit is contained in:
Kenix3 2022-08-11 00:06:58 -04:00
parent 791f7774a5
commit 094388187f
13 changed files with 413 additions and 362 deletions

View File

@ -2,7 +2,7 @@
#include "Window.h"
#include "Controller.h"
#include "VirtualController.h"
#include "DummyController.h"
#include "KeyboardController.h"
#include "SDLController.h"
#include <Utils/StringHelper.h>
@ -28,9 +28,9 @@ namespace Ship {
}
}
physicalDevices.push_back(std::make_shared<VirtualController>("Auto", "Auto", true));
physicalDevices.push_back(std::make_shared<DummyController>("Auto", "Auto", true));
physicalDevices.push_back(std::make_shared<KeyboardController>());
physicalDevices.push_back(std::make_shared<VirtualController>("Disconnected", "None", false));
physicalDevices.push_back(std::make_shared<DummyController>("Disconnected", "None", false));
for (const auto& device : physicalDevices) {
for (int i = 0; i < MAXCONTROLLERS; i++) {
@ -77,7 +77,7 @@ namespace Ship {
}
}
#define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), slot, __VA_ARGS__)
#define NESTED(key, ...) StringHelper::Sprintf("Controllers.%s.Slot_%d." key, device->GetGuid().c_str(), virtualSlot, __VA_ARGS__)
void ControlDeck::LoadControllerSettings() {
std::shared_ptr<Mercury> Config = GlobalCtx2::GetInstance()->GetConfig();
@ -102,25 +102,40 @@ namespace Ship {
std::string guid = device->GetGuid();
for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
for (int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
if (!(Config->rjson["Controllers"].contains(guid) && Config->rjson["Controllers"][guid].contains(StringHelper::Sprintf("Slot_%d", slot)))) continue;
if (!(Config->rjson["Controllers"].contains(guid) && Config->rjson["Controllers"][guid].contains(StringHelper::Sprintf("Slot_%d", virtualSlot)))) continue;
auto& profile = device->profiles[slot];
auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", slot)];
auto profile = device->getProfile(virtualSlot);
auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", virtualSlot)];
profile.Mappings.clear();
profile.Thresholds.clear();
profile.UseRumble = Config->getBool(NESTED("Rumble.Enabled", ""));
profile.RumbleStrength = Config->getFloat(NESTED("Rumble.Strength", ""));
profile.UseGyro = Config->getBool(NESTED("Gyro.Enabled", ""));
profile->Mappings.clear();
profile->AxisDeadzones.clear();
profile->AxisSensitivities.clear();
profile->GyroData.clear();
profile->Version = Config->getInt(NESTED("Version", ""));
profile->UseRumble = Config->getBool(NESTED("Rumble.Enabled", ""));
profile->RumbleStrength = Config->getFloat(NESTED("Rumble.Strength", ""));
profile->UseGyro = Config->getBool(NESTED("Gyro.Enabled", ""));
for (auto const& val : rawProfile["Thresholds"].items()) {
profile.Thresholds[static_cast<ControllerThresholds>(std::stoi(val.key()))] = val.value();
for (auto const& val : rawProfile["AxisDeadzones"].items()) {
profile->AxisDeadzones[std::stoi(val.key())] = val.value();
}
for (auto const& val : rawProfile["AxisSensitivities"].items()) {
profile->AxisSensitivities[std::stoi(val.key())] = val.value();
}
for (auto const& val : rawProfile["AxisMinimumPress"].items()) {
profile->AxisMinimumPress[std::stoi(val.key())] = val.value();
}
for (auto const& val : rawProfile["GyroData"].items()) {
profile->GyroData[std::stoi(val.key())] = val.value();
}
for (auto const& val : rawProfile["Mappings"].items()) {
device->SetButtonMapping(slot, std::stoi(val.key().substr(4)), val.value());
device->SetButtonMapping(virtualSlot, std::stoi(val.key().substr(4)), val.value());
}
}
}
@ -136,31 +151,45 @@ namespace Ship {
for (const auto& device : physicalDevices) {
int slot = 0;
int32_t virtualSlot = 0;
std::string guid = device->GetGuid();
for (const auto& profile : device->profiles) {
for (int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
auto profile = device->getProfile(virtualSlot);
if (!device->Connected()) continue;
auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", slot)];
Config->setBool(NESTED("Rumble.Enabled", ""), profile.UseRumble);
Config->setFloat(NESTED("Rumble.Strength", ""), profile.RumbleStrength);
Config->setBool(NESTED("Gyro.Enabled", ""), profile.UseGyro);
auto rawProfile = Config->rjson["Controllers"][guid][StringHelper::Sprintf("Slot_%d", virtualSlot)];
Config->setInt(NESTED("Version", ""), profile->Version);
Config->setBool(NESTED("Rumble.Enabled", ""), profile->UseRumble);
Config->setFloat(NESTED("Rumble.Strength", ""), profile->RumbleStrength);
Config->setBool(NESTED("Gyro.Enabled", ""), profile->UseGyro);
for (auto const& val : rawProfile["Mappings"].items()) {
Config->setInt(NESTED("Mappings.%s", val.key().c_str()), -1);
}
for (auto const& [key, val] : profile.Thresholds) {
Config->setFloat(NESTED("Thresholds.%d", key), val);
for (auto const& [key, val] : profile->AxisDeadzones) {
Config->setFloat(NESTED("AxisDeadzones.%d", key), val);
}
for (auto const& [key, val] : profile.Mappings) {
for (auto const& [key, val] : profile->AxisSensitivities) {
Config->setFloat(NESTED("AxisSensitivities.%d", key), val);
}
for (auto const& [key, val] : profile->AxisMinimumPress) {
Config->setFloat(NESTED("AxisMinimumPress.%d", key), val);
}
for (auto const& [key, val] : profile->GyroData) {
Config->setFloat(NESTED("GyroData.%d", key), val);
}
for (auto const& [key, val] : profile->Mappings) {
Config->setInt(NESTED("Mappings.BTN_%d", val), key);
}
slot++;
virtualSlot++;
}
}

View File

@ -9,72 +9,105 @@
namespace Ship {
Controller::Controller() : isRumbling(false), wStickX(0), wStickY(0), wGyroX(0), wGyroY(0), wCamX(0), wCamY(0), dwPressedButtons(0){
Controller::Controller() : isRumbling(false) {
Attachment = nullptr;
profiles.resize(MAXCONTROLLERS);
for(int slot = 0; slot < MAXCONTROLLERS; slot++) {
dwPressedButtons.push_back(0);
for(int virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
profiles[virtualSlot] = std::make_shared<DeviceProfileV0>();
ButtonData[virtualSlot] = std::make_shared<Buttons>();
}
}
void Controller::Read(OSContPad* pad, int32_t slot) {
ReadFromSource(slot);
void Controller::Read(OSContPad* pad, int32_t virtualSlot) {
ReadFromSource(virtualSlot);
SDL_PumpEvents();
// Button Inputs
pad->button |= dwPressedButtons[slot] & 0xFFFF;
pad->button |= getPressedButtons(virtualSlot) & 0xFFFF;
// Stick Inputs
if (wStickX == 0) {
if (dwPressedButtons[slot] & BTN_STICKLEFT) {
if (getLeftStickX(virtualSlot) == 0) {
if (getPressedButtons(virtualSlot) & BTN_STICKLEFT) {
pad->stick_x = -128;
} else if (dwPressedButtons[slot] & BTN_STICKRIGHT) {
} else if (getPressedButtons(virtualSlot) & BTN_STICKRIGHT) {
pad->stick_x = 127;
}
} else {
pad->stick_x = wStickX;
pad->stick_x = getLeftStickX(virtualSlot);
}
if (wStickY == 0) {
if (dwPressedButtons[slot] & BTN_STICKDOWN) {
if (getLeftStickY(virtualSlot) == 0) {
if (getPressedButtons(virtualSlot) & BTN_STICKDOWN) {
pad->stick_y = -128;
} else if (dwPressedButtons[slot] & BTN_STICKUP) {
} else if (getPressedButtons(virtualSlot) & BTN_STICKUP) {
pad->stick_y = 127;
}
} else {
pad->stick_y = wStickY;
pad->stick_y = getLeftStickY(virtualSlot);
}
// Stick Inputs
if (wCamX == 0) {
if (dwPressedButtons[slot] & BTN_VSTICKLEFT) {
pad->cam_x = -128 * 10.0f;
} else if (dwPressedButtons[slot] & BTN_VSTICKRIGHT) {
pad->cam_x = 127 * 10.0f;
if (getRightStickX(virtualSlot) == 0) {
if (getPressedButtons(virtualSlot) & BTN_VSTICKLEFT) {
pad->right_stick_x = -128;
} else if (getPressedButtons(virtualSlot) & BTN_VSTICKRIGHT) {
pad->right_stick_x = 127;
}
} else {
pad->cam_x = wCamX;
pad->right_stick_x = getRightStickX(virtualSlot);
}
if (wCamY == 0) {
if (dwPressedButtons[slot] & BTN_VSTICKDOWN) {
pad->cam_y = -128 * 10.0f;
} else if (dwPressedButtons[slot] & BTN_VSTICKUP) {
pad->cam_y = 127 * 10.0f;
if (getRightStickY(virtualSlot) == 0) {
if (getPressedButtons(virtualSlot) & BTN_VSTICKDOWN) {
pad->right_stick_y = -128;
} else if (getPressedButtons(virtualSlot) & BTN_VSTICKUP) {
pad->right_stick_y = 127;
}
} else {
pad->cam_y = wCamY;
pad->right_stick_y = getRightStickY(virtualSlot);
}
// Gyro
pad->gyro_x = wGyroX;
pad->gyro_y = wGyroY;
pad->gyro_x = getGyroX(virtualSlot);
pad->gyro_y = getGyroY(virtualSlot);
}
void Controller::SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode) {
std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
void Controller::SetButtonMapping(int32_t virtualSlot, int32_t n64Button, int32_t dwScancode) {
std::map<int32_t, int32_t>& Mappings = getProfile(virtualSlot)->Mappings;
std::erase_if(Mappings, [n64Button](const std::pair<int32_t, int32_t>& bin) { return bin.second == n64Button; });
Mappings[dwScancode] = n64Button;
}
int8_t& Controller::getLeftStickX(int32_t virtualSlot) {
return ButtonData[virtualSlot]->leftStickX;
}
int8_t& Controller::getLeftStickY(int32_t virtualSlot) {
return ButtonData[virtualSlot]->leftStickY;
}
int8_t& Controller::getRightStickX(int32_t virtualSlot) {
return ButtonData[virtualSlot]->rightStickX;
}
int8_t& Controller::getRightStickY(int32_t virtualSlot) {
return ButtonData[virtualSlot]->rightStickY;
}
int32_t& Controller::getPressedButtons(int32_t virtualSlot) {
return ButtonData[virtualSlot]->pressedButtons;
}
float& Controller::getGyroX(int32_t virtualSlot) {
return ButtonData[virtualSlot]->gyroX;
}
float& Controller::getGyroY(int32_t virtualSlot) {
return ButtonData[virtualSlot]->gyroY;
}
std::shared_ptr<DeviceProfileV0> Controller::getProfile(int32_t virtualSlot) {
return profiles[virtualSlot];
}
}

View File

@ -3,10 +3,9 @@
#include <map>
#include <memory>
#include <string>
#include "stdint.h"
#include <cstdint>
#include "UltraController.h"
#include "ControllerAttachment.h"
#include <vector>
#include <unordered_map>
#define EXTENDED_SCANCODE_BIT (1 << 8)
@ -14,68 +13,73 @@
namespace Ship {
enum ControllerThresholds {
LEFT_STICK = 1,
RIGHT_STICK = 2,
LEFT_TRIGGER = 3,
RIGHT_TRIGGER = 4,
DRIFT_X = 5,
DRIFT_Y = 6,
SENSITIVITY = 7,
GYRO_SENSITIVITY = 8
enum GyroDataV0 {
DRIFT_X,
DRIFT_Y,
GYRO_SENSITIVITY
};
struct DeviceProfile {
struct DeviceProfileV0 {
int32_t Version = 0;
bool UseRumble = false;
bool UseGyro = false;
float RumbleStrength = 1.0f;
std::unordered_map<ControllerThresholds, float> Thresholds;
std::unordered_map<int32_t, float> AxisDeadzones;
std::unordered_map<int32_t, float> AxisMinimumPress;
std::unordered_map<int32_t, float> AxisSensitivities;
std::unordered_map<int32_t, float> GyroData;
std::map<int32_t, int32_t> Mappings;
};
class Controller {
public:
virtual ~Controller() = default;
Controller();
void Read(OSContPad* pad, int32_t slot);
virtual void ReadFromSource(int32_t slot) = 0;
virtual void WriteToSource(int32_t slot, ControllerCallback* controller) = 0;
virtual bool Connected() const = 0;
virtual bool CanRumble() const = 0;
virtual bool CanGyro() const = 0;
virtual void CreateDefaultBinding(int32_t slot) = 0;
bool isRumbling;
std::vector<DeviceProfile> profiles;
virtual void ClearRawPress() = 0;
virtual int32_t ReadRawPress() = 0;
void SetButtonMapping(int slot, int32_t n64Button, int32_t dwScancode);
std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; }
std::string GetGuid() { return GUID; }
virtual const char* GetButtonName(int slot, int n64Button) = 0;
virtual const char* GetControllerName() = 0;
int8_t wStickX;
int8_t wStickY;
float wGyroX;
float wGyroY;
float wCamX;
float wCamY;
public:
virtual ~Controller() = default;
Controller();
void Read(OSContPad* pad, int32_t virtualSlot);
virtual void ReadFromSource(int32_t virtualSlot) = 0;
virtual void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) = 0;
virtual bool Connected() const = 0;
virtual bool CanRumble() const = 0;
virtual bool CanGyro() const = 0;
virtual void CreateDefaultBinding(int32_t virtualSlot) = 0;
virtual void ClearRawPress() = 0;
virtual int32_t ReadRawPress() = 0;
void SetButtonMapping(int32_t virtualSlot, int32_t n64Button, int32_t dwScancode);
std::shared_ptr<ControllerAttachment> GetAttachment() { return Attachment; }
int8_t& getLeftStickX(int32_t virtualSlot);
int8_t& getLeftStickY(int32_t virtualSlot);
int8_t& getRightStickX(int32_t virtualSlot);
int8_t& getRightStickY(int32_t virtualSlot);
int32_t& getPressedButtons(int32_t virtualSlot);
float& getGyroX(int32_t virtualSlot);
float& getGyroY(int32_t virtualSlot);
std::shared_ptr<DeviceProfileV0> getProfile(int32_t virtualSlot);
bool IsRumbling() { return isRumbling; }
std::string GetGuid() { return GUID; }
virtual const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) = 0;
virtual const std::string GetControllerName() = 0;
protected:
std::vector<int32_t> dwPressedButtons;
std::shared_ptr<ControllerAttachment> Attachment;
std::string GUID;
bool isRumbling;
void LoadBinding();
private:
std::shared_ptr<ControllerAttachment> Attachment;
};
struct Buttons {
int32_t pressedButtons = 0;
int8_t leftStickX = 0;
int8_t leftStickY = 0;
int8_t rightStickX = 0;
int8_t rightStickY = 0;
float gyroX = 0.0f;
float gyroY = 0.0f;
};
struct ControllerEntry {
uint8_t* controllerBits;
Controller* entryIO;
std::unordered_map<int32_t, std::shared_ptr<DeviceProfileV0>> profiles;
std::unordered_map<int32_t, std::shared_ptr<Buttons>> ButtonData = {};
};
}

View File

@ -5,9 +5,9 @@
#include "Controller.h"
namespace Ship {
class VirtualController final : public Controller {
class DummyController final : public Controller {
public:
VirtualController(const std::string& CUID, const std::string& KeyName, bool Connected) {
DummyController(const std::string& CUID, const std::string& KeyName, bool Connected) {
GUID = CUID;
isConnected = Connected;
ButtonName = KeyName;
@ -15,8 +15,8 @@ namespace Ship {
std::map<std::vector<std::string>, int32_t> ReadButtonPress();
void ReadFromSource(int32_t slot) override {}
const char* GetControllerName() override { return GUID.c_str(); }
const char* GetButtonName(int slot, int n64Button) override { return ButtonName.c_str(); }
const std::string GetControllerName() override { return GUID; }
const std::string GetButtonName(int slot, int n64Button) override { return ButtonName; }
void WriteToSource(int32_t slot, ControllerCallback* controller) override { }
bool Connected() const override { return isConnected; }
bool CanRumble() const override { return false; }

View File

@ -48,9 +48,9 @@ namespace Ship {
}
}
const char* BtnName = backend->GetButtonName(CurrentPort, n64Btn);
const std::string BtnName = backend->GetButtonName(CurrentPort, n64Btn);
if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName, n64Btn).c_str())) {
if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName.c_str(), n64Btn).c_str())) {
BtnReading = n64Btn;
backend->ClearRawPress();
}
@ -84,18 +84,16 @@ namespace Ship {
void InputEditor::DrawControllerSchema() {
auto controlDeck = Ship::GlobalCtx2::GetInstance()->GetWindow()->GetControlDeck();
auto Backend = controlDeck->GetPhysicalDeviceFromVirtualSlot(CurrentPort);
DeviceProfile& profile = Backend->profiles[CurrentPort];
float sensitivity = profile.Thresholds[SENSITIVITY];
auto profile = Backend->getProfile(CurrentPort);
bool IsKeyboard = Backend->GetGuid() == "Keyboard" || Backend->GetGuid() == "Auto" || !Backend->Connected();
const char* ControllerName = Backend->GetControllerName();
std::string ControllerName = Backend->GetControllerName();
if (ControllerName != nullptr && ImGui::BeginCombo("##ControllerEntries", ControllerName)) {
if (ImGui::BeginCombo("##ControllerEntries", ControllerName.c_str())) {
for (uint8_t i = 0; i < controlDeck->GetNumPhysicalDevices(); i++) {
std::string DeviceName = controlDeck->GetPhysicalDevice(i)->GetControllerName();
if (DeviceName != "Keyboard" && DeviceName != "Auto") {
DeviceName+="##"+std::to_string(i);
if (ControllerName != "Keyboard" && ControllerName != "Auto") {
ControllerName += "##"+std::to_string(i);
}
if (ImGui::Selectable(DeviceName.c_str(), i == controlDeck->GetVirtualDevice(CurrentPort))) {
if (ImGui::Selectable(ControllerName.c_str(), i == controlDeck->GetVirtualDevice(CurrentPort))) {
controlDeck->SetPhysicalDevice(CurrentPort, i);
}
}
@ -142,7 +140,7 @@ namespace Ship {
if (!IsKeyboard) {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
DrawVirtualStick("##MainVirtualStick", ImVec2(Backend->wStickX, Backend->wStickY));
DrawVirtualStick("##MainVirtualStick", ImVec2(Backend->getLeftStickX(CurrentPort), Backend->getLeftStickY(CurrentPort)));
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
@ -150,7 +148,7 @@ namespace Ship {
ImGui::BeginChild("##MSInput", ImVec2(90, 50), false);
ImGui::Text("Deadzone");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##MDZone", &profile.Thresholds[LEFT_STICK], 1.0f, 0.0f, "%.0f");
ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[0] /* This is the SDL value for left stick X axis */, 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth();
ImGui::EndChild();
} else {
@ -172,18 +170,20 @@ namespace Ship {
DrawButton("Right", BTN_VSTICKRIGHT);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
DrawVirtualStick("##CameraVirtualStick", ImVec2(Backend->wCamX / sensitivity, Backend->wCamY / sensitivity));
// 2 is the SDL value for right stick X axis
// 3 is the SDL value for right stick Y axis.
DrawVirtualStick("##CameraVirtualStick", ImVec2(Backend->getRightStickX(CurrentPort) / profile->AxisSensitivities[2], Backend->getRightStickY(CurrentPort) / profile->AxisSensitivities[3]));
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::BeginChild("##CSInput", ImVec2(90, 85), false);
ImGui::Text("Deadzone");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##MDZone", &profile.Thresholds[RIGHT_STICK], 1.0f, 0.0f, "%.0f");
ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[2] /* This is the SDL value for left stick X axis */, 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth();
ImGui::Text("Sensitivity");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##MSensitivity", &profile.Thresholds[SENSITIVITY], 1.0f, 0.0f, "%.0f");
ImGui::InputFloat("##MSensitivity", &profile->AxisSensitivities[2] /* This is the SDL value for right stick X axis */, 1.0f, 0.0f, "%.0f");
ImGui::PopItemWidth();
ImGui::EndChild();
#ifdef __SWITCH__
@ -199,32 +199,32 @@ namespace Ship {
SohImGui::BeginGroupPanel("Gyro Options", ImVec2(175, 20));
float cursorX = ImGui::GetCursorPosX() + 5;
ImGui::SetCursorPosX(cursorX);
ImGui::Checkbox("Enable Gyro", &profile.UseGyro);
ImGui::Checkbox("Enable Gyro", &profile->UseGyro);
ImGui::SetCursorPosX(cursorX);
ImGui::Text("Gyro Sensitivity: %d%%", static_cast<int>(100.0f * profile.Thresholds[GYRO_SENSITIVITY]));
ImGui::Text("Gyro Sensitivity: %d%%", static_cast<int>(100.0f * profile->GyroData[GYRO_SENSITIVITY]));
ImGui::PushItemWidth(135.0f);
ImGui::SetCursorPosX(cursorX);
ImGui::SliderFloat("##GSensitivity", &profile.Thresholds[GYRO_SENSITIVITY], 0.0f, 1.0f, "");
ImGui::SliderFloat("##GSensitivity", &profile->GyroData[GYRO_SENSITIVITY], 0.0f, 1.0f, "");
ImGui::PopItemWidth();
ImGui::Dummy(ImVec2(0, 1));
ImGui::SetCursorPosX(cursorX);
if (ImGui::Button("Recalibrate Gyro##RGyro")) {
profile.Thresholds[DRIFT_X] = 0.0f;
profile.Thresholds[DRIFT_Y] = 0.0f;
profile->GyroData[DRIFT_X] = 0.0f;
profile->GyroData[DRIFT_Y] = 0.0f;
}
ImGui::SetCursorPosX(cursorX);
DrawVirtualStick("##GyroPreview", ImVec2(-10.0f * Backend->wGyroY, 10.0f * Backend->wGyroX));
DrawVirtualStick("##GyroPreview", ImVec2(-10.0f * Backend->getGyroY(CurrentPort), 10.0f * Backend->getGyroX(CurrentPort)));
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::BeginChild("##GyInput", ImVec2(90, 85), false);
ImGui::Text("Drift X");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##GDriftX", &profile.Thresholds[DRIFT_X], 1.0f, 0.0f, "%.1f");
ImGui::InputFloat("##GDriftX", &profile->GyroData[DRIFT_X], 1.0f, 0.0f, "%.1f");
ImGui::PopItemWidth();
ImGui::Text("Drift Y");
ImGui::PushItemWidth(80);
ImGui::InputFloat("##GDriftY", &profile.Thresholds[DRIFT_Y], 1.0f, 0.0f, "%.1f");
ImGui::InputFloat("##GDriftY", &profile->GyroData[DRIFT_Y], 1.0f, 0.0f, "%.1f");
ImGui::PopItemWidth();
ImGui::EndChild();
#ifdef __SWITCH__
@ -255,13 +255,13 @@ namespace Ship {
SohImGui::BeginGroupPanel("Options", ImVec2(158, 20));
float cursorX = ImGui::GetCursorPosX() + 5;
ImGui::SetCursorPosX(cursorX);
ImGui::Checkbox("Rumble Enabled", &profile.UseRumble);
ImGui::Checkbox("Rumble Enabled", &profile->UseRumble);
if (Backend->CanRumble()) {
ImGui::SetCursorPosX(cursorX);
ImGui::Text("Rumble Force: %d%%", static_cast<int>(100.0f * profile.RumbleStrength));
ImGui::Text("Rumble Force: %d%%", static_cast<int>(100.0f * profile->RumbleStrength));
ImGui::SetCursorPosX(cursorX);
ImGui::PushItemWidth(135.0f);
ImGui::SliderFloat("##RStrength", &profile.RumbleStrength, 0.0f, 1.0f, "");
ImGui::SliderFloat("##RStrength", &profile->RumbleStrength, 0.0f, 1.0f, "");
ImGui::PopItemWidth();
}
ImGui::Dummy(ImVec2(0, 5));

View File

@ -17,13 +17,12 @@ namespace Ship {
}
bool KeyboardController::PressButton(int32_t dwScancode) {
lastKey = dwScancode;
for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
for (int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
if (profiles[slot].Mappings.contains(dwScancode)) {
dwPressedButtons[slot] |= profiles[slot].Mappings[dwScancode];
if (getProfile(virtualSlot)->Mappings.contains(dwScancode)) {
getPressedButtons(virtualSlot) |= getProfile(virtualSlot)->Mappings[dwScancode];
return true;
}
}
@ -32,9 +31,9 @@ namespace Ship {
}
bool KeyboardController::ReleaseButton(int32_t dwScancode) {
for (int slot = 0; slot < MAXCONTROLLERS; slot++) {
if (profiles[slot].Mappings.contains(dwScancode)) {
dwPressedButtons[slot] &= ~profiles[slot].Mappings[dwScancode];
for (int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
if (getProfile(virtualSlot)->Mappings.contains(dwScancode)) {
getPressedButtons(virtualSlot) &= ~getProfile(virtualSlot)->Mappings[dwScancode];
return true;
}
}
@ -43,16 +42,16 @@ namespace Ship {
}
void KeyboardController::ReleaseAllButtons() {
for(int slot = 0; slot < MAXCONTROLLERS; slot++) {
dwPressedButtons[slot] = 0;
for(int32_t virtualSlot = 0; virtualSlot < MAXCONTROLLERS; virtualSlot++) {
getPressedButtons(virtualSlot) = 0;
}
}
void KeyboardController::ReadFromSource(int32_t slot) {
wStickX = 0;
wStickY = 0;
wCamX = 0;
wCamY = 0;
void KeyboardController::ReadFromSource(int32_t virtualSlot) {
getLeftStickX(virtualSlot) = 0;
getLeftStickY(virtualSlot) = 0;
getRightStickX(virtualSlot) = 0;
getRightStickY(virtualSlot) = 0;
}
int32_t KeyboardController::ReadRawPress() {
@ -60,13 +59,12 @@ namespace Ship {
}
void KeyboardController::WriteToSource(int32_t slot, ControllerCallback* controller)
{
void KeyboardController::WriteToSource(int32_t virtualSlot, ControllerCallback* controller) {
}
const char* KeyboardController::GetButtonName(int slot, int n64Button) {
std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
const std::string KeyboardController::GetButtonName(int32_t virtualSlot, int32_t n64Button) {
std::map<int32_t, int32_t>& Mappings = getProfile(virtualSlot)->Mappings;
const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) {
return pair.second == n64Button;
});
@ -77,29 +75,29 @@ namespace Ship {
}
void KeyboardController::CreateDefaultBinding(int32_t slot) {
DeviceProfile& profile = profiles[slot];
profile.Mappings[0x14D] = BTN_CRIGHT;
profile.Mappings[0x14B] = BTN_CLEFT;
profile.Mappings[0x150] = BTN_CDOWN;
profile.Mappings[0x148] = BTN_CUP;
profile.Mappings[0x13] = BTN_R;
profile.Mappings[0x12] = BTN_L;
profile.Mappings[0x023] = BTN_DRIGHT;
profile.Mappings[0x021] = BTN_DLEFT;
profile.Mappings[0x022] = BTN_DDOWN;
profile.Mappings[0x014] = BTN_DUP;
profile.Mappings[0x039] = BTN_START;
profile.Mappings[0x02C] = BTN_Z;
profile.Mappings[0x02E] = BTN_B;
profile.Mappings[0x02D] = BTN_A;
profile.Mappings[0x020] = BTN_STICKRIGHT;
profile.Mappings[0x01E] = BTN_STICKLEFT;
profile.Mappings[0x01F] = BTN_STICKDOWN;
profile.Mappings[0x011] = BTN_STICKUP;
void KeyboardController::CreateDefaultBinding(int32_t virtualSlot) {
auto profile = getProfile(virtualSlot);
profile->Mappings[0x14D] = BTN_CRIGHT;
profile->Mappings[0x14B] = BTN_CLEFT;
profile->Mappings[0x150] = BTN_CDOWN;
profile->Mappings[0x148] = BTN_CUP;
profile->Mappings[0x13] = BTN_R;
profile->Mappings[0x12] = BTN_L;
profile->Mappings[0x023] = BTN_DRIGHT;
profile->Mappings[0x021] = BTN_DLEFT;
profile->Mappings[0x022] = BTN_DDOWN;
profile->Mappings[0x014] = BTN_DUP;
profile->Mappings[0x039] = BTN_START;
profile->Mappings[0x02C] = BTN_Z;
profile->Mappings[0x02E] = BTN_B;
profile->Mappings[0x02D] = BTN_A;
profile->Mappings[0x020] = BTN_STICKRIGHT;
profile->Mappings[0x01E] = BTN_STICKLEFT;
profile->Mappings[0x01F] = BTN_STICKDOWN;
profile->Mappings[0x011] = BTN_STICKUP;
}
const char* KeyboardController::GetControllerName() {
const std::string KeyboardController::GetControllerName() {
return "Keyboard";
}
}

View File

@ -7,13 +7,13 @@ namespace Ship {
public:
KeyboardController();
void ReadFromSource(int32_t slot) override;
void WriteToSource(int32_t slot, ControllerCallback* controller) override;
void ReadFromSource(int32_t virtualSlot) override;
void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override;
bool Connected() const override { return true; }
bool CanRumble() const override { return false; }
bool CanGyro() const override { return false; }
const char* GetControllerName() override;
const char* GetButtonName(int slot, int n64Button) override;
const std::string GetControllerName() override;
const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override;
bool PressButton(int32_t dwScancode);
bool ReleaseButton(int32_t dwScancode);
@ -29,7 +29,7 @@ namespace Ship {
}
int32_t GetLastScancode() { return lastScancode; }
void CreateDefaultBinding(int32_t slot) override;
void CreateDefaultBinding(int32_t virtualSlot) override;
protected:
int32_t lastScancode;

View File

@ -13,7 +13,6 @@ extern "C" uint8_t __osMaxControllers;
namespace Ship {
bool SDLController::Open() {
const auto NewCont = SDL_GameControllerOpen(physicalSlot);
// We failed to load the controller. Go to next.
@ -30,8 +29,7 @@ namespace Ship {
char GuidBuf[33];
SDL_JoystickGetGUIDString(SDL_JoystickGetDeviceGUID(physicalSlot), GuidBuf, sizeof(GuidBuf));
Cont = NewCont;
wCamX = 0;
wCamY = 0;
#ifdef __SWITCH__
GUID = StringHelper::Sprintf("%s:%d", GuidBuf, physicalSlot);
ControllerName = StringHelper::Sprintf("%s #%d", SDL_GameControllerNameForIndex(physicalSlot), physicalSlot + 1);
@ -50,54 +48,58 @@ namespace Ship {
SDL_GameControllerClose(Cont);
}
Cont = nullptr;
wStickX = 0;
wStickY = 0;
return true;
}
void SDLController::NormalizeStickAxis(SDL_GameControllerAxis axisX, SDL_GameControllerAxis axisY, int16_t axisThreshold, int32_t virtualSlot) {
auto profile = getProfile(virtualSlot);
const auto axisValueX = SDL_GameControllerGetAxis(Cont, axisX);
const auto axisValueY = SDL_GameControllerGetAxis(Cont, axisY);
void SDLController::NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity) {
//scale {-32768 ... +32767} to {-84 ... +84}
auto ax = wAxisValueX * 85.0 / 32767.0;
auto ay = wAxisValueY * 85.0 / 32767.0;
auto ax = axisValueX * 85.0f / 32767.0f;
auto ay = axisValueY * 85.0f / 32767.0f;
//create scaled circular dead-zone in range {-15 ... +15}
auto len = sqrt(ax * ax + ay * ay);
if (len < wAxisThreshold) {
len = 0;
if (len < axisThreshold) {
len = 0.0f;
}
else if (len > 85.0) {
len = 85.0 / len;
len = 85.0f / len;
}
else {
len = (len - wAxisThreshold) * 85.0 / (85.0 - wAxisThreshold) / len;
len = (len - axisThreshold) * 85.0f / (85.0f - axisThreshold) / len;
}
ax *= len;
ay *= len;
//bound diagonals to an octagonal range {-68 ... +68}
if (ax != 0.0 && ay != 0.0) {
if (ax != 0.0f && ay != 0.0f) {
auto slope = ay / ax;
auto edgex = copysign(85.0 / (abs(slope) + 16.0 / 69.0), ax);
auto edgey = copysign(std::min(abs(edgex * slope), 85.0 / (1.0 / abs(slope) + 16.0 / 69.0)), ay);
auto edgex = copysign(85.0f / (abs(slope) + 16.0f / 69.0f), ax);
auto edgey = copysign(std::min(abs(edgex * slope), 85.0f / (1.0f / abs(slope) + 16.0f / 69.0f)), ay);
edgex = edgey / slope;
auto scale = sqrt(edgex * edgex + edgey * edgey) / 85.0;
auto scale = sqrt(edgex * edgex + edgey * edgey) / 85.0f;
ax *= scale;
ay *= scale;
}
if (!isRightStick) {
wStickX = +ax;
wStickY = -ay;
} else {
wCamX = +ax * sensitivity;
wCamY = -ay * sensitivity;
ax *= profile->AxisSensitivities[axisX];
ay *= profile->AxisSensitivities[axisY];
if (axisX == SDL_CONTROLLER_AXIS_LEFTX) {
getLeftStickX(virtualSlot) = +ax;
getLeftStickY(virtualSlot) = -ay;
} else if (axisX == SDL_CONTROLLER_AXIS_RIGHTX) {
getRightStickX(virtualSlot) = +ax;
getRightStickY(virtualSlot) = -ay;
}
}
int32_t SDLController::ReadRawPress() {
SDL_GameControllerUpdate();
@ -123,24 +125,8 @@ namespace Ship {
return -1;
}
ControllerThresholds SDLAxisToThreshold( uint32_t axis ){
switch(axis){
case SDL_CONTROLLER_AXIS_LEFTX:
case SDL_CONTROLLER_AXIS_LEFTY:
return LEFT_STICK;
case SDL_CONTROLLER_AXIS_RIGHTX:
case SDL_CONTROLLER_AXIS_RIGHTY:
return RIGHT_STICK;
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
return LEFT_TRIGGER;
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
return RIGHT_TRIGGER;
default: return DRIFT_X;
}
}
void SDLController::ReadFromSource(int32_t slot) {
DeviceProfile& profile = profiles[slot];
void SDLController::ReadFromSource(int32_t virtualSlot) {
auto profile = getProfile(virtualSlot);
SDL_GameControllerUpdate();
@ -157,14 +143,14 @@ namespace Ship {
}
}
if (supportsGyro && profile.UseGyro) {
if (supportsGyro && profile->UseGyro) {
float gyroData[3];
SDL_GameControllerGetSensorData(Cont, SDL_SENSOR_GYRO, gyroData, 3);
float gyro_drift_x = profile.Thresholds[DRIFT_X] / 100.0f;
float gyro_drift_y = profile.Thresholds[DRIFT_Y] / 100.0f;
const float gyro_sensitivity = profile.Thresholds[GYRO_SENSITIVITY];
float gyro_drift_x = profile->GyroData[DRIFT_X] / 100.0f;
float gyro_drift_y = profile->GyroData[DRIFT_Y] / 100.0f;
const float gyro_sensitivity = profile->GyroData[GYRO_SENSITIVITY];
if (gyro_drift_x == 0) {
gyro_drift_x = gyroData[0];
@ -174,25 +160,25 @@ namespace Ship {
gyro_drift_y = gyroData[1];
}
profile.Thresholds[DRIFT_X] = gyro_drift_x * 100.0f;
profile.Thresholds[DRIFT_Y] = gyro_drift_y * 100.0f;
profile->GyroData[DRIFT_X] = gyro_drift_x * 100.0f;
profile->GyroData[DRIFT_Y] = gyro_drift_y * 100.0f;
wGyroX = gyroData[0] - gyro_drift_x;
wGyroY = gyroData[1] - gyro_drift_y;
getGyroX(virtualSlot) = gyroData[0] - gyro_drift_x;
getGyroY(virtualSlot) = gyroData[1] - gyro_drift_y;
wGyroX *= gyro_sensitivity;
wGyroY *= gyro_sensitivity;
getGyroX(virtualSlot) *= gyro_sensitivity;
getGyroY(virtualSlot) *= gyro_sensitivity;
}
dwPressedButtons[slot] = 0;
getPressedButtons(virtualSlot) = 0;
for (int32_t i = SDL_CONTROLLER_BUTTON_A; i < SDL_CONTROLLER_BUTTON_MAX; i++) {
if (profile.Mappings.contains(i)) {
if (profile->Mappings.contains(i)) {
if (SDL_GameControllerGetButton(Cont, static_cast<SDL_GameControllerButton>(i))) {
dwPressedButtons[slot] |= profile.Mappings[i];
getPressedButtons(virtualSlot) |= profile->Mappings[i];
}
else {
dwPressedButtons[slot] &= ~profile.Mappings[i];
getPressedButtons(virtualSlot) &= ~profile->Mappings[i];
}
}
}
@ -209,9 +195,10 @@ namespace Ship {
const auto Axis = static_cast<SDL_GameControllerAxis>(i);
const auto PosScancode = i + AXIS_SCANCODE_BIT;
const auto NegScancode = -PosScancode;
const auto AxisThreshold = static_cast<int>(profile.Thresholds[SDLAxisToThreshold(i)]);
const auto PosButton = profile.Mappings[PosScancode];
const auto NegButton = profile.Mappings[NegScancode];
const auto AxisDeadzone = profile->AxisDeadzones[i];
const auto AxisMinimumPress = profile->AxisMinimumPress[i];
const auto PosButton = profile->Mappings[PosScancode];
const auto NegButton = profile->Mappings[NegScancode];
const auto AxisValue = SDL_GameControllerGetAxis(Cont, Axis);
#ifdef TARGET_WEB
@ -231,17 +218,17 @@ namespace Ship {
NegButton == BTN_STICKLEFT || NegButton == BTN_STICKRIGHT ||
NegButton == BTN_STICKUP || NegButton == BTN_STICKDOWN)) {
if (AxisValue > 0x1E00) {
dwPressedButtons[slot] |= PosButton;
dwPressedButtons[slot] &= ~NegButton;
if (AxisValue > AxisMinimumPress) {
getPressedButtons(virtualSlot) |= PosButton;
getPressedButtons(virtualSlot) &= ~NegButton;
}
else if (AxisValue < -0x1E00) {
dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons[slot] |= NegButton;
else if (AxisValue < -AxisMinimumPress) {
getPressedButtons(virtualSlot) &= ~PosButton;
getPressedButtons(virtualSlot) |= NegButton;
}
else {
dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons[slot] &= ~NegButton;
getPressedButtons(virtualSlot) &= ~PosButton;
getPressedButtons(virtualSlot) &= ~NegButton;
}
}
else {
@ -250,11 +237,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", LStickAxisX, Axis);
}
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", LStickDeadzone, AxisThreshold);
if (LStickDeadzone != 0 && LStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", LStickDeadzone, AxisDeadzone);
}
LStickDeadzone = AxisThreshold;
LStickDeadzone = AxisDeadzone;
LStickAxisX = Axis;
}
@ -263,11 +250,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", LStickAxisY, Axis);
}
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
if (LStickDeadzone != 0 && LStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisDeadzone);
}
LStickDeadzone = AxisThreshold;
LStickDeadzone = AxisDeadzone;
LStickAxisY = Axis;
}
@ -276,11 +263,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", LStickAxisX, Axis);
}
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
if (LStickDeadzone != 0 && LStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisDeadzone);
}
LStickDeadzone = AxisThreshold;
LStickDeadzone = AxisDeadzone;
LStickAxisX = Axis;
}
@ -289,21 +276,15 @@ namespace Ship {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", LStickAxisY, Axis);
}
if (LStickDeadzone != 0 && LStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisThreshold);
if (LStickDeadzone != 0 && LStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", LStickDeadzone, AxisDeadzone);
}
LStickDeadzone = AxisThreshold;
LStickDeadzone = AxisDeadzone;
LStickAxisY = Axis;
}
}
if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
const auto AxisValueX = SDL_GameControllerGetAxis(Cont, LStickAxisX);
const auto AxisValueY = SDL_GameControllerGetAxis(Cont, LStickAxisY);
NormalizeStickAxis(AxisValueX, AxisValueY, LStickDeadzone, false, profile.Thresholds[SENSITIVITY]);
}
// Right Stick
// If the axis is NOT mapped to the control stick.
if (!(
@ -312,17 +293,17 @@ namespace Ship {
NegButton == BTN_VSTICKLEFT || NegButton == BTN_VSTICKRIGHT ||
NegButton == BTN_VSTICKUP || NegButton == BTN_VSTICKDOWN)) {
if (AxisValue > 0x1E00) {
dwPressedButtons[slot] |= PosButton;
dwPressedButtons[slot] &= ~NegButton;
if (AxisValue > AxisMinimumPress) {
getPressedButtons(virtualSlot) |= PosButton;
getPressedButtons(virtualSlot) &= ~NegButton;
}
else if (AxisValue < -0x1E00) {
dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons[slot] |= NegButton;
else if (AxisValue < -AxisMinimumPress) {
getPressedButtons(virtualSlot) &= ~PosButton;
getPressedButtons(virtualSlot) |= NegButton;
}
else {
dwPressedButtons[slot] &= ~PosButton;
dwPressedButtons[slot] &= ~NegButton;
getPressedButtons(virtualSlot) &= ~PosButton;
getPressedButtons(virtualSlot) &= ~NegButton;
}
} else {
@ -331,11 +312,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid PosStickX configured. Neg was {} and Pos is {}", RStickAxisX, Axis);
}
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", RStickDeadzone, AxisThreshold);
if (RStickDeadzone != 0 && RStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Up/Down was {} and Left/Right is {}", RStickDeadzone, AxisDeadzone);
}
RStickDeadzone = AxisThreshold;
RStickDeadzone = AxisDeadzone;
RStickAxisX = Axis;
}
@ -344,11 +325,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid PosStickY configured. Neg was {} and Pos is {}", RStickAxisY, Axis);
}
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
if (RStickDeadzone != 0 && RStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisDeadzone);
}
RStickDeadzone = AxisThreshold;
RStickDeadzone = AxisDeadzone;
RStickAxisY = Axis;
}
@ -357,11 +338,11 @@ namespace Ship {
SPDLOG_TRACE("Invalid NegStickX configured. Pos was {} and Neg is {}", RStickAxisX, Axis);
}
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
if (RStickDeadzone != 0 && RStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone configured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisDeadzone);
}
RStickDeadzone = AxisThreshold;
RStickDeadzone = AxisDeadzone;
RStickAxisX = Axis;
}
@ -370,28 +351,30 @@ namespace Ship {
SPDLOG_TRACE("Invalid NegStickY configured. Pos was {} and Neg is {}", RStickAxisY, Axis);
}
if (RStickDeadzone != 0 && RStickDeadzone != AxisThreshold) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisThreshold);
if (RStickDeadzone != 0 && RStickDeadzone != AxisDeadzone) {
SPDLOG_TRACE("Invalid Deadzone misconfigured. Left/Right was {} and Up/Down is {}", RStickDeadzone, AxisDeadzone);
}
RStickDeadzone = AxisThreshold;
RStickDeadzone = AxisDeadzone;
RStickAxisY = Axis;
}
}
if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
const auto AxisValueX = SDL_GameControllerGetAxis(Cont, RStickAxisX);
const auto AxisValueY = SDL_GameControllerGetAxis(Cont, RStickAxisY);
NormalizeStickAxis(AxisValueX, AxisValueY, RStickDeadzone, true, profile.Thresholds[SENSITIVITY]);
if (LStickAxisX != SDL_CONTROLLER_AXIS_INVALID && LStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
NormalizeStickAxis(LStickAxisX, LStickAxisY, LStickDeadzone, virtualSlot);
}
if (RStickAxisX != SDL_CONTROLLER_AXIS_INVALID && RStickAxisY != SDL_CONTROLLER_AXIS_INVALID) {
NormalizeStickAxis(RStickAxisX, RStickAxisY, RStickDeadzone, virtualSlot);
}
}
}
}
void SDLController::WriteToSource(int32_t slot, ControllerCallback* controller)
void SDLController::WriteToSource(int32_t virtualSlot, ControllerCallback* controller)
{
if (CanRumble() && profiles[slot].UseRumble) {
if (CanRumble() && getProfile(virtualSlot)->UseRumble) {
if (controller->rumble > 0) {
float rumble_strength = profiles[slot].RumbleStrength;
float rumble_strength = getProfile(virtualSlot)->RumbleStrength;
SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0);
}
else {
@ -416,20 +399,11 @@ namespace Ship {
}
}
}
const std::string SDLController::GetButtonName(int32_t virtualSlot, int32_t n64Button) {
char buffer[50];
std::map<int32_t, int32_t>& Mappings = getProfile(virtualSlot)->Mappings;
const char* AxisNames[] = {
"Left Stick X",
"Left Stick Y",
"Right Stick X",
"Right Stick Y",
"Left Trigger",
"Right Trigger",
"Start Button"
};
char buffer[50];
const char* SDLController::GetButtonName(int slot, int n64Button) {
std::map<int32_t, int32_t>& Mappings = profiles[slot].Mappings;
const auto find = std::find_if(Mappings.begin(), Mappings.end(), [n64Button](const std::pair<int32_t, int32_t>& pair) {
return pair.second == n64Button;
});
@ -449,42 +423,45 @@ namespace Ship {
return buffer;
}
const char* SDLController::GetControllerName() {
return strdup(ControllerName.c_str());
const std::string SDLController::GetControllerName() {
return ControllerName;
}
void SDLController::CreateDefaultBinding(int32_t slot) {
DeviceProfile& profile = profiles[slot];
profile.Mappings.clear();
void SDLController::CreateDefaultBinding(int32_t virtualSlot) {
auto profile = getProfile(virtualSlot);
profile->Mappings.clear();
profile.UseRumble = true;
profile.RumbleStrength = 1.0f;
profile.UseGyro = false;
profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT] = BTN_CRIGHT;
profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT)] = BTN_CLEFT;
profile.Mappings[ SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT] = BTN_CDOWN;
profile.Mappings[-(SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT)] = BTN_CUP;
profile.Mappings[SDL_CONTROLLER_AXIS_TRIGGERRIGHT + AXIS_SCANCODE_BIT] = BTN_R;
profile.Mappings[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = BTN_L;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_RIGHT] = BTN_DRIGHT;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_LEFT] = BTN_DLEFT;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_DOWN] = BTN_DDOWN;
profile.Mappings[SDL_CONTROLLER_BUTTON_DPAD_UP] = BTN_DUP;
profile.Mappings[SDL_CONTROLLER_BUTTON_START] = BTN_START;
profile.Mappings[SDL_CONTROLLER_AXIS_TRIGGERLEFT + AXIS_SCANCODE_BIT] = BTN_Z;
profile.Mappings[SDL_CONTROLLER_BUTTON_B] = BTN_B;
profile.Mappings[SDL_CONTROLLER_BUTTON_A] = BTN_A;
profile.Mappings[(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT)] = BTN_STICKRIGHT;
profile.Mappings[-(SDL_CONTROLLER_AXIS_LEFTX + AXIS_SCANCODE_BIT)] = BTN_STICKLEFT;
profile.Mappings[SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT] = BTN_STICKDOWN;
profile.Mappings[-(SDL_CONTROLLER_AXIS_LEFTY + AXIS_SCANCODE_BIT)] = BTN_STICKUP;
profile.Thresholds[LEFT_STICK] = 16.0f;
profile.Thresholds[RIGHT_STICK] = 16.0f;
profile.Thresholds[LEFT_TRIGGER] = 0x1E00;
profile.Thresholds[RIGHT_TRIGGER] = 0x1E00;
profile.Thresholds[DRIFT_X] = 0.0f;
profile.Thresholds[DRIFT_Y] = 0.0f;
profile.Thresholds[SENSITIVITY] = 16.0f;
profile.Thresholds[GYRO_SENSITIVITY] = 1.0f;
profile->UseRumble = true;
profile->RumbleStrength = 1.0f;
profile->UseGyro = false;
profile->Mappings[SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT] = BTN_CRIGHT;
profile->Mappings[-(SDL_CONTROLLER_AXIS_RIGHTX | AXIS_SCANCODE_BIT)] = BTN_CLEFT;
profile->Mappings[SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT] = BTN_CDOWN;
profile->Mappings[-(SDL_CONTROLLER_AXIS_RIGHTY | AXIS_SCANCODE_BIT)] = BTN_CUP;
profile->Mappings[SDL_CONTROLLER_AXIS_LEFTX | AXIS_SCANCODE_BIT] = BTN_STICKRIGHT;
profile->Mappings[-(SDL_CONTROLLER_AXIS_LEFTX | AXIS_SCANCODE_BIT)] = BTN_STICKLEFT;
profile->Mappings[SDL_CONTROLLER_AXIS_LEFTY | AXIS_SCANCODE_BIT] = BTN_STICKDOWN;
profile->Mappings[-(SDL_CONTROLLER_AXIS_LEFTY | AXIS_SCANCODE_BIT)] = BTN_STICKUP;
profile->Mappings[SDL_CONTROLLER_AXIS_TRIGGERRIGHT | AXIS_SCANCODE_BIT] = BTN_R;
profile->Mappings[SDL_CONTROLLER_AXIS_TRIGGERLEFT | AXIS_SCANCODE_BIT] = BTN_Z;
profile->Mappings[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = BTN_L;
profile->Mappings[SDL_CONTROLLER_BUTTON_DPAD_RIGHT] = BTN_DRIGHT;
profile->Mappings[SDL_CONTROLLER_BUTTON_DPAD_LEFT] = BTN_DLEFT;
profile->Mappings[SDL_CONTROLLER_BUTTON_DPAD_DOWN] = BTN_DDOWN;
profile->Mappings[SDL_CONTROLLER_BUTTON_DPAD_UP] = BTN_DUP;
profile->Mappings[SDL_CONTROLLER_BUTTON_START] = BTN_START;
profile->Mappings[SDL_CONTROLLER_BUTTON_B] = BTN_B;
profile->Mappings[SDL_CONTROLLER_BUTTON_A] = BTN_A;
for (int32_t i = SDL_CONTROLLER_AXIS_LEFTX; i < SDL_CONTROLLER_AXIS_MAX; i++) {
profile->AxisSensitivities[i] = 1.0f;
profile->AxisDeadzones[i] = 16.0f;
profile->AxisMinimumPress[i] = 7680.0f;
}
profile->GyroData[DRIFT_X] = 0.0f;
profile->GyroData[DRIFT_Y] = 0.0f;
profile->GyroData[GYRO_SENSITIVITY] = 1.0f;
}
}

View File

@ -5,18 +5,28 @@
namespace Ship {
class SDLController : public Controller {
public:
SDLController(int slot) : Controller(), Cont(nullptr), physicalSlot(slot) { }
void ReadFromSource(int32_t slot) override;
const char* GetControllerName() override;
const char* GetButtonName(int slot, int n64Button) override;
void WriteToSource(int32_t slot, ControllerCallback* controller) override;
inline static const char* AxisNames[] = {
"Left Stick X",
"Left Stick Y",
"Right Stick X",
"Right Stick Y",
"Left Trigger",
"Right Trigger",
"Start Button"
};
SDLController(int32_t physicalSlot) : Controller(), Cont(nullptr), physicalSlot(physicalSlot) { }
void ReadFromSource(int32_t virtualSlot) override;
const std::string GetControllerName() override;
const std::string GetButtonName(int32_t virtualSlot, int32_t n64Button) override;
void WriteToSource(int32_t virtualSlot, ControllerCallback* controller) override;
bool Connected() const override { return Cont != nullptr; }
bool CanGyro() const override { return supportsGyro; }
bool CanRumble() const override {
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
return SDL_GameControllerHasRumble(Cont);
#endif
return true;
return false;
}
bool Open();
@ -24,14 +34,14 @@ namespace Ship {
int32_t ReadRawPress() override;
protected:
void CreateDefaultBinding(int32_t slot) override;
void CreateDefaultBinding(int32_t virtualSlot) override;
private:
std::string ControllerName = "Unknown";
SDL_GameController* Cont;
int physicalSlot;
int32_t physicalSlot;
bool supportsGyro;
void NormalizeStickAxis(int16_t wAxisValueX, int16_t wAxisValueY, int16_t wAxisThreshold, bool isRightStick, float sensitivity);
void NormalizeStickAxis(SDL_GameControllerAxis axisX, SDL_GameControllerAxis axisY, int16_t axisThreshold, int32_t virtualSlot);
bool Close();
};
}

View File

@ -124,8 +124,8 @@ typedef struct {
/* 0x04 */ uint8_t err_no;
/* 0x05 */ float gyro_x;
/* 0x09 */ float gyro_y;
/* 0x1C */ float cam_x;
/* 0x20 */ float cam_y;
/* 0x1C */ int8_t right_stick_x;
/* 0x20 */ int8_t right_stick_y;
} OSContPad; // size = 0x24
typedef struct {

View File

@ -61,8 +61,8 @@ extern "C" {
pad->button = 0;
pad->stick_x = 0;
pad->stick_y = 0;
pad->cam_x = 0;
pad->cam_y = 0;
pad->right_stick_x = 0;
pad->right_stick_y = 0;
pad->err_no = 0;
pad->gyro_x = 0;
pad->gyro_y = 0;

View File

@ -1410,8 +1410,8 @@ s32 Camera_Noop(Camera* camera) {
}
s32 SetCameraManual(Camera* camera) {
f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x;
f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y;
f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x * 10.0f;
f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y * 10.0f;
if ((fabsf(newCamX) >= 15.0f || fabsf(newCamY) >= 15.0f) && camera->globalCtx->manualCamera == false) {
camera->globalCtx->manualCamera = true;
@ -1479,8 +1479,8 @@ s32 Camera_Free(Camera* camera) {
camera->animState = 1;
f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x;
f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y;
f32 newCamX = -D_8015BD7C->state.input[0].cur.cam_x * 10.0f;
f32 newCamY = D_8015BD7C->state.input[0].cur.cam_y * 10.0f;
camera->globalCtx->camX += newCamX;
camera->globalCtx->camY += newCamY;

View File

@ -128,8 +128,8 @@ void KaleidoScope_DrawPlayerWork(GlobalContext* globalCtx) {
} else if ((AllowDPadRotation && CHECK_BTN_ALL(input->cur.button, BTN_DRIGHT)) ||
(AllowCRotation && CHECK_BTN_ALL(input->cur.button, BTN_CRIGHT))) {
link_kaleido_rot.y = link_kaleido_rot.y + RotationSpeed;
} else if(AllowStickRotation && input->cur.cam_x != 0){
link_kaleido_rot.y = link_kaleido_rot.y + (input->cur.cam_x*(((f32)RotationSpeed)/600.0f));
} else if(AllowStickRotation && input->cur.cam_x*10.0f != 0){
link_kaleido_rot.y = link_kaleido_rot.y + (input->cur.cam_x*10.0f*(((f32)RotationSpeed)/600.0f));
}
if ((AllowDPadRotation && CHECK_BTN_ALL(input->press.button, BTN_DUP)) || // reset rotation
@ -138,13 +138,13 @@ void KaleidoScope_DrawPlayerWork(GlobalContext* globalCtx) {
} else if ((AllowCRotation && CHECK_BTN_ALL(input->press.button, BTN_CUP)) ||
(AllowCRotation && CHECK_BTN_ALL(input->press.button, BTN_CDOWN))) {
link_kaleido_rot.y = 32300;
} else if (AllowStickRotation && input->cur.cam_y < -1200) {
} else if (AllowStickRotation && input->cur.cam_y * 10.0f < -1200) {
link_kaleido_rot.y = 32300;
}
if (AllowStickRotation && input->cur.cam_y>0) { // Zoom in
scale = scale + input->cur.cam_y*.00005;
pos.y = pos.y - input->cur.cam_y*.25;
if (AllowStickRotation && input->cur.cam_y * 10.0f > 0) { // Zoom in
scale = scale + input->cur.cam_y*10.0f*.00005f;
pos.y = pos.y - input->cur.cam_y*10.0f*0.25f;
}