Skip to content

Commit

Permalink
Controller now stores the scancode as the key in the mapping. (#290)
Browse files Browse the repository at this point in the history
* Controller now stores the scancode as the key in the mapping.

This allows us to support multiple physical buttons going to a single N64 button.

* Runs clang-format

* SetButtonMapping takes the physical button id as the first argument

* Comments need to release all buttons in InputEditorWindow.

* Erases all one controller to many json blocks.

* Runs clang-format
  • Loading branch information
Kenix3 committed May 25, 2023
1 parent c946c2c commit a3f18f7
Show file tree
Hide file tree
Showing 14 changed files with 91 additions and 40 deletions.
62 changes: 48 additions & 14 deletions src/controller/ControlDeck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@ void ControlDeck::LoadSettings() {
profile->AxisMinimumPress.clear();
profile->GyroData.clear();

profile->Version = config->GetInt(NESTED("Version", ""), DEVICE_PROFILE_VERSION_V0);
profile->Version = config->GetInt(NESTED("Version", ""), DEVICE_PROFILE_VERSION_0);

switch (profile->Version) {

case DEVICE_PROFILE_VERSION_V0:
case DEVICE_PROFILE_VERSION_0:

// Load up defaults for the things we can't load.
device->CreateDefaultBinding(virtualSlot);
Expand All @@ -175,12 +175,12 @@ void ControlDeck::LoadSettings() {
profile->UseGyro = config->GetBool(NESTED("Gyro.Enabled", ""));

for (auto const& val : rawProfile["Mappings"].items()) {
device->SetButtonMapping(virtualSlot, std::stoi(val.key().substr(4)), val.value());
device->SetButtonMapping(virtualSlot, val.value(), std::stoi(val.key().substr(4)));
}

break;

case DEVICE_PROFILE_VERSION_V1:
case DEVICE_PROFILE_VERSION_1:
profile->UseRumble = config->GetBool(NESTED("Rumble.Enabled", ""));
profile->RumbleStrength = config->GetFloat(NESTED("Rumble.Strength", ""));
profile->UseGyro = config->GetBool(NESTED("Gyro.Enabled", ""));
Expand All @@ -199,7 +199,31 @@ void ControlDeck::LoadSettings() {
}

for (auto const& val : rawProfile["Mappings"].items()) {
device->SetButtonMapping(virtualSlot, std::stoi(val.key().substr(4)), val.value());
device->SetButtonMapping(virtualSlot, val.value(), std::stoi(val.key().substr(4)));
}

break;

case DEVICE_PROFILE_VERSION_2:
profile->UseRumble = config->GetBool(NESTED("Rumble.Enabled", ""));
profile->RumbleStrength = config->GetFloat(NESTED("Rumble.Strength", ""));
profile->UseGyro = config->GetBool(NESTED("Gyro.Enabled", ""));
profile->NotchProximityThreshold = config->GetInt(NESTED("Notches.ProximityThreshold", ""));

for (auto const& val : rawProfile["AxisDeadzones"].items()) {
profile->AxisDeadzones[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(virtualSlot, std::stoi(val.key()), val.value());
}

break;
Expand All @@ -218,7 +242,7 @@ void ControlDeck::SaveSettings() {

for (size_t i = 0; i < mPortList.size(); i++) {
std::shared_ptr<Controller> backend = mDevices[mPortList[i]];
config->SetString(StringHelper::Sprintf("Controllers.Deck.Slot_%d", (int)i), backend->GetGuid());
config->SetString(StringHelper::Sprintf("Controllers.Deck.Slot_%d", (int32_t)i), backend->GetGuid());
}

for (const auto& device : mDevices) {
Expand All @@ -231,16 +255,30 @@ void ControlDeck::SaveSettings() {
continue;
}

auto rawProfile =
config->GetNestedJson()["Controllers"][guid][StringHelper::Sprintf("Slot_%d", virtualSlot)];
// We always save to the most recent version.
profile->Version = DEVICE_PROFILE_CURRENT_VERSION;

auto conf = config->GetNestedJson()["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);
config->SetInt(NESTED("Notches.ProximityThreshold", ""), profile->NotchProximityThreshold);

for (auto const& val : rawProfile["Mappings"].items()) {
config->SetInt(NESTED("Mappings.%s", val.key().c_str()), -1);
// Clear all sections with a one controller to many relationship.
const static std::vector<std::string> sClearSections = { "Mappings", "AxisDeadzones", "AxisMinimumPress",
"GyroData" };
for (auto const& section : sClearSections) {
if (conf.contains(section)) {
for (auto const& val : conf[section].items()) {
config->Erase(NESTED("%s.%s", section.c_str(), val.key().c_str()));
}
}
}

for (auto const& [key, val] : profile->Mappings) {
config->SetInt(NESTED("Mappings.%d", key), val);
}

for (auto const& [key, val] : profile->AxisDeadzones) {
Expand All @@ -255,10 +293,6 @@ void ControlDeck::SaveSettings() {
config->SetFloat(NESTED("GyroData.%d", key), val);
}

for (auto const& [key, val] : profile->Mappings) {
config->SetInt(NESTED("Mappings.BTN_%d", val), key);
}

virtualSlot++;
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/controller/Controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,8 @@ void Controller::ReadToPad(OSContPad* pad, int32_t portIndex) {
}
}

void Controller::SetButtonMapping(int32_t portIndex, int32_t n64Button, int32_t scancode) {
std::map<int32_t, int32_t>& mappings = GetProfile(portIndex)->Mappings;
std::erase_if(mappings, [n64Button](const std::pair<int32_t, int32_t>& bin) { return bin.second == n64Button; });
mappings[scancode] = n64Button;
void Controller::SetButtonMapping(int32_t portIndex, int32_t deviceButtonId, int32_t n64bitmask) {
GetProfile(portIndex)->Mappings[deviceButtonId] = n64bitmask;
}

int8_t& Controller::GetLeftStickX(int32_t portIndex) {
Expand Down
14 changes: 5 additions & 9 deletions src/controller/Controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ namespace LUS {
enum GyroData { DRIFT_X, DRIFT_Y, GYRO_SENSITIVITY };
enum Stick { LEFT, RIGHT };
enum Axis { X, Y };
enum DeviceProfileVersion { DEVICE_PROFILE_VERSION_V0 = 0, DEVICE_PROFILE_VERSION_V1 = 1 };
enum DeviceProfileVersion { DEVICE_PROFILE_VERSION_0 = 0, DEVICE_PROFILE_VERSION_1 = 1, DEVICE_PROFILE_VERSION_2 = 2 };

#define DEVICE_PROFILE_CURRENT_VERSION DEVICE_PROFILE_VERSION_V1
#define DEVICE_PROFILE_CURRENT_VERSION DEVICE_PROFILE_VERSION_2

struct DeviceProfile {
int32_t Version = 0;
Expand All @@ -33,8 +33,6 @@ struct DeviceProfile {
std::map<int32_t, int32_t> Mappings;
};

class ControlDeck;

class Controller {
public:
Controller(int32_t deviceIndex);
Expand All @@ -47,13 +45,13 @@ class Controller {
virtual void CreateDefaultBinding(int32_t portIndex) = 0;
virtual void ClearRawPress() = 0;
virtual int32_t ReadRawPress() = 0;
virtual const std::string GetButtonName(int32_t portIndex, int32_t n64Button) = 0;
virtual const std::string GetButtonName(int32_t portIndex, int32_t n64bitmask) = 0;
virtual int32_t SetRumble(int32_t portIndex, bool rumble) = 0;
virtual int32_t SetLedColor(int32_t portIndex, Color_RGB8 color) = 0;

std::string GetControllerName();
void ReadToPad(OSContPad* pad, int32_t portIndex);
void SetButtonMapping(int32_t portIndex, int32_t n64Button, int32_t scancode);
void SetButtonMapping(int32_t portIndex, int32_t deviceButtonId, int32_t n64bitmask);

std::shared_ptr<DeviceProfile> GetProfile(int32_t portIndex);
int8_t& GetLeftStickX(int32_t portIndex);
Expand All @@ -74,9 +72,9 @@ class Controller {
int32_t mDeviceIndex;
std::string mControllerName = "Unknown";

void LoadBinding();
int8_t ReadStick(int32_t portIndex, Stick stick, Axis axis);
void ProcessStick(int8_t& x, int8_t& y, float deadzoneX, float deadzoneY, int32_t notchProxmityThreshold);
double GetClosestNotch(double angle, double approximationThreshold);

private:
struct Buttons {
Expand All @@ -92,7 +90,5 @@ class Controller {
std::unordered_map<int32_t, std::shared_ptr<DeviceProfile>> mProfiles;
std::unordered_map<int32_t, std::shared_ptr<Buttons>> mButtonData = {};
std::deque<OSContPad> mPadBuffer;

double GetClosestNotch(double angle, double approximationThreshold);
};
} // namespace LUS
2 changes: 1 addition & 1 deletion src/controller/DummyController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ DummyController::DummyController(int32_t deviceIndex, const std::string& guid, c
void DummyController::ReadDevice(int32_t portIndex) {
}

const std::string DummyController::GetButtonName(int32_t portIndex, int32_t n64Button) {
const std::string DummyController::GetButtonName(int32_t portIndex, int32_t n64bitmask) {
return mButtonName;
}

Expand Down
2 changes: 1 addition & 1 deletion src/controller/DummyController.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class DummyController final : public Controller {
public:
DummyController(int32_t deviceIndex, const std::string& guid, const std::string& keyName, bool connected);
void ReadDevice(int32_t portIndex) override;
const std::string GetButtonName(int32_t portIndex, int32_t n64Button) override;
const std::string GetButtonName(int32_t portIndex, int32_t n64bitmask) override;
bool Connected() const override;
bool CanRumble() const override;
bool CanSetLed() const override;
Expand Down
15 changes: 13 additions & 2 deletions src/controller/KeyboardController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,12 @@ int32_t KeyboardController::ReadRawPress() {
return mLastKey;
}

const std::string KeyboardController::GetButtonName(int32_t portIndex, int32_t n64Button) {
const std::string KeyboardController::GetButtonName(int32_t portIndex, int32_t n64bitmask) {
std::map<int32_t, int32_t>& mappings = GetProfile(portIndex)->Mappings;
// OTRTODO: This should get the scancode of all bits in the mask.
const auto find =
std::find_if(mappings.begin(), mappings.end(),
[n64Button](const std::pair<int32_t, int32_t>& pair) { return pair.second == n64Button; });
[n64bitmask](const std::pair<int32_t, int32_t>& pair) { return pair.second == n64bitmask; });

if (find == mappings.end()) {
return "Unknown";
Expand All @@ -74,6 +75,16 @@ const std::string KeyboardController::GetButtonName(int32_t portIndex, int32_t n

void KeyboardController::CreateDefaultBinding(int32_t portIndex) {
auto profile = GetProfile(portIndex);
profile->Mappings.clear();
profile->AxisDeadzones.clear();
profile->AxisMinimumPress.clear();
profile->GyroData.clear();

profile->Version = DEVICE_PROFILE_CURRENT_VERSION;
profile->UseRumble = false;
profile->RumbleStrength = 1.0f;
profile->UseGyro = false;

profile->Mappings[0x14D] = BTN_CRIGHT;
profile->Mappings[0x14B] = BTN_CLEFT;
profile->Mappings[0x150] = BTN_CDOWN;
Expand Down
2 changes: 1 addition & 1 deletion src/controller/KeyboardController.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class KeyboardController : public Controller {
KeyboardController(int32_t deviceIndex);

void ReadDevice(int32_t portIndex) override;
const std::string GetButtonName(int32_t portIndex, int32_t n64Button) override;
const std::string GetButtonName(int32_t portIndex, int32_t n64bitmask) override;
bool PressButton(int32_t scancode);
bool ReleaseButton(int32_t scancode);
bool Connected() const override;
Expand Down
5 changes: 3 additions & 2 deletions src/controller/SDLController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,13 +315,14 @@ int32_t SDLController::SetLedColor(int32_t portIndex, Color_RGB8 color) {
return SDL_JoystickSetLED(SDL_GameControllerGetJoystick(mController), mLedColor.r, mLedColor.g, mLedColor.b);
}

const std::string SDLController::GetButtonName(int32_t portIndex, int32_t n64Button) {
const std::string SDLController::GetButtonName(int32_t portIndex, int32_t n64bitmask) {
char buffer[50];
// OTRTODO: This should get the scancode of all bits in the mask.
std::map<int32_t, int32_t>& mappings = GetProfile(portIndex)->Mappings;

const auto find =
std::find_if(mappings.begin(), mappings.end(),
[n64Button](const std::pair<int32_t, int32_t>& pair) { return pair.second == n64Button; });
[n64bitmask](const std::pair<int32_t, int32_t>& pair) { return pair.second == n64bitmask; });

if (find == mappings.end()) {
return "Unknown";
Expand Down
2 changes: 1 addition & 1 deletion src/controller/SDLController.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class SDLController : public Controller {
public:
SDLController(int32_t deviceIndex);
void ReadDevice(int32_t portIndex) override;
const std::string GetButtonName(int32_t portIndex, int32_t n64Button) override;
const std::string GetButtonName(int32_t portIndex, int32_t n64bitmask) override;
int32_t SetRumble(int32_t portIndex, bool rumble) override;
int32_t SetLedColor(int32_t portIndex, Color_RGB8 color) override;
bool Connected() const override;
Expand Down
2 changes: 1 addition & 1 deletion src/port/wiiu/WiiUController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ int32_t WiiUController::ReadRawPress() {
return -1;
}

const std::string WiiUController::GetButtonName(int32_t portIndex, int n64Button) {
const std::string WiiUController::GetButtonName(int32_t portIndex, int32_t n64bitmask) {
std::map<int32_t, int32_t>& Mappings = GetProfile(portIndex)->Mappings;
const auto find =
std::find_if(Mappings.begin(), Mappings.end(),
Expand Down
2 changes: 1 addition & 1 deletion src/port/wiiu/WiiUController.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class WiiUController : public Controller {
int32_t ReadRawPress() override;
int32_t SetRumble(int32_t portIndex, bool rumble) override;
int32_t SetLedColor(int32_t portIndex, Color_RGB8 color) override;
const std::string GetButtonName(int32_t portIndex, int n64Button) override;
const std::string GetButtonName(int32_t portIndex, int32_t n64bitmask) override;

protected:
void CreateDefaultBinding(int32_t portIndex) override;
Expand Down
2 changes: 1 addition & 1 deletion src/port/wiiu/WiiUGamepad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ int32_t WiiUGamepad::ReadRawPress() {
return -1;
}

const std::string WiiUGamepad::GetButtonName(int32_t portIndex, int n64Button) {
const std::string WiiUGamepad::GetButtonName(int32_t portIndex, int32_t n64bitmask) {
std::map<int32_t, int32_t>& mappings = GetProfile(portIndex)->Mappings;
const auto find =
std::find_if(mappings.begin(), mappings.end(),
Expand Down
2 changes: 1 addition & 1 deletion src/port/wiiu/WiiUGamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class WiiUGamepad : public Controller {
int32_t ReadRawPress() override;
int32_t SetRumble(int32_t portIndex, bool rumble) override;
int32_t SetLedColor(int32_t portIndex, Color_RGB8 color) override;
const std::string GetButtonName(int32_t portIndex, int n64Button) override;
const std::string GetButtonName(int32_t portIndex, int32_t n64bitmask) override;

protected:
void CreateDefaultBinding(int32_t portIndex) override;
Expand Down
13 changes: 12 additions & 1 deletion src/window/gui/InputEditorWindow.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "InputEditorWindow.h"
#include "controller/Controller.h"
#include "controller/KeyboardController.h"
#include "Context.h"
#include "Gui.h"
#include <Utils/StringHelper.h>
Expand Down Expand Up @@ -48,7 +49,17 @@ void InputEditorWindow::DrawButton(const char* label, int32_t n64Btn, int32_t cu
Context::GetInstance()->GetControlDeck()->BlockGameInput(mGameInputBlockId);

if (btn != -1) {
backend->SetButtonMapping(currentPort, n64Btn, btn);
auto profile = backend->GetProfile(currentPort);
// Remove other mappings that include the n64 bitmask. Note that the n64 button is really a mask and is not
// unique, but the UI as-is needs a way to unset the old n64 button.
std::erase_if(profile->Mappings,
[n64Btn](const std::pair<int32_t, int32_t>& bin) { return bin.second == n64Btn; });
backend->SetButtonMapping(currentPort, btn, n64Btn);
auto keyboardBackend = dynamic_pointer_cast<KeyboardController>(backend);
if (keyboardBackend != nullptr) {
// Window backend has not called release on the scancode and thus we need to release all buttons.
keyboardBackend->ReleaseAllButtons();
}
Context::GetInstance()->GetControlDeck()->SaveSettings();

*btnReading = -1;
Expand Down

0 comments on commit a3f18f7

Please sign in to comment.