From a123b260a9932d6ea8a8c384e141b976c9241117 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 23 Dec 2017 22:25:51 +0100 Subject: [PATCH] Qt/Input: Introduce profiles --- rpcs3/Emu/Io/Null/NullPadHandler.h | 5 +- rpcs3/Emu/Io/PadHandler.h | 59 ++++- rpcs3/ds4_pad_handler.cpp | 257 +++++++++++---------- rpcs3/ds4_pad_handler.h | 5 +- rpcs3/evdev_joystick_handler.cpp | 205 ++++++++-------- rpcs3/evdev_joystick_handler.h | 4 +- rpcs3/keyboard_pad_handler.cpp | 133 ++++++----- rpcs3/keyboard_pad_handler.h | 1 + rpcs3/mm_joystick_handler.cpp | 185 ++++++++------- rpcs3/mm_joystick_handler.h | 2 + rpcs3/pad_thread.cpp | 8 +- rpcs3/rpcs3qt/gamepads_settings_dialog.cpp | 166 +++++++++++-- rpcs3/rpcs3qt/gamepads_settings_dialog.h | 46 +--- rpcs3/rpcs3qt/gui_settings.cpp | 11 + rpcs3/rpcs3qt/gui_settings.h | 1 + rpcs3/rpcs3qt/pad_settings_dialog.cpp | 142 ++++++------ rpcs3/rpcs3qt/pad_settings_dialog.h | 21 +- rpcs3/xinput_pad_handler.cpp | 205 ++++++++-------- rpcs3/xinput_pad_handler.h | 3 + 19 files changed, 867 insertions(+), 592 deletions(-) diff --git a/rpcs3/Emu/Io/Null/NullPadHandler.h b/rpcs3/Emu/Io/Null/NullPadHandler.h index 7fb25a487fac..a2a06cc373cc 100644 --- a/rpcs3/Emu/Io/Null/NullPadHandler.h +++ b/rpcs3/Emu/Io/Null/NullPadHandler.h @@ -10,6 +10,10 @@ class NullPadHandler final : public PadHandlerBase return true; } + void init_config(pad_config* cfg, const std::string& name) override + { + } + std::vector ListDevices() override { std::vector nulllist; @@ -25,5 +29,4 @@ class NullPadHandler final : public PadHandlerBase void ThreadProc() override { } - }; diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index c5a9e8cd1a6e..4884cb466696 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -6,6 +6,7 @@ #include "stdafx.h" #include "../../Utilities/Config.h" #include "../../Utilities/types.h" +#include "Emu/System.h" // TODO: HLE info (constants, structs, etc.) should not be available here @@ -248,9 +249,53 @@ struct Pad } }; -struct pad_config : cfg::node +struct player_config final : cfg::node +{ + pad_handler def_handler = pad_handler::null; + player_config(node* owner, const std::string& name, pad_handler type) : cfg::node(owner, name), def_handler(type) {}; + + cfg::_enum handler{ this, "Handler", def_handler }; + cfg::string device{ this, "Device", handler.to_string() }; + cfg::string profile{ this, "Profile", "Default Profile" }; +}; + +struct input_config final : cfg::node +{ + const std::string cfg_name = fs::get_config_dir() + "/config_input.yml"; + + player_config player1{ this, "Player 1 Input", pad_handler::keyboard }; + player_config player2{ this, "Player 2 Input", pad_handler::null }; + player_config player3{ this, "Player 3 Input", pad_handler::null }; + player_config player4{ this, "Player 4 Input", pad_handler::null }; + player_config player5{ this, "Player 5 Input", pad_handler::null }; + player_config player6{ this, "Player 6 Input", pad_handler::null }; + player_config player7{ this, "Player 7 Input", pad_handler::null }; + + player_config *player[7]{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc! + + bool load() + { + if (fs::file cfg_file{ cfg_name, fs::read }) + { + return from_string(cfg_file.to_string()); + } + + return false; + } + + void save() + { + fs::file(cfg_name, fs::rewrite).write(to_string()); + } + + bool exist() + { + return fs::is_file(cfg_name); + } +}; + +struct pad_config final : cfg::node { - std::string cfg_type = ""; std::string cfg_name = ""; cfg::string ls_left { this, "Left Stick Left", "" }; @@ -314,6 +359,8 @@ struct pad_config : cfg::node } }; +static input_config input_cfg; + class PadHandlerBase { protected: @@ -327,7 +374,7 @@ class PadHandlerBase bool b_has_deadzones = false; bool b_has_rumble = false; bool b_has_config = false; - pad_config m_pad_config; + std::array m_pad_configs; template T lerp(T v0, T v1, T t) { @@ -584,6 +631,8 @@ class PadHandlerBase s32 vibration_max = 255; u32 connected = 0; + pad_handler m_type = pad_handler::null; + virtual bool Init() { return true; }; virtual ~PadHandlerBase() = default; @@ -591,7 +640,8 @@ class PadHandlerBase bool has_config() { return b_has_config; }; bool has_rumble() { return b_has_rumble; }; bool has_deadzones() { return b_has_deadzones; }; - pad_config* GetConfig() { return &m_pad_config; }; + static std::string get_config_dir(pad_handler type) { return fs::get_config_dir() + "/InputConfigs/" + fmt::format("%s", type) + "/"; }; + static std::string get_config_filename(const input_config& cfg, int i) { return fs::get_config_dir() + "/InputConfigs/" + cfg.player[i]->handler.to_string() + "/" + cfg.player[i]->profile.to_string() + ".yml"; }; //Sets window to config the controller(optional) virtual void GetNextButtonPress(const std::string& padId, const std::function& callback, bool get_blacklist = false, std::vector buttons = {}) {}; virtual void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) {}; @@ -601,6 +651,7 @@ class PadHandlerBase virtual void ThreadProc() = 0; //Binds a Pad to a device virtual bool bindPadToDevice(std::shared_ptr pad, const std::string& device) = 0; + virtual void init_config(pad_config* cfg, const std::string& name) = 0; private: virtual void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) {}; diff --git a/rpcs3/ds4_pad_handler.cpp b/rpcs3/ds4_pad_handler.cpp index 17cad5b5dc77..584cb07a7293 100644 --- a/rpcs3/ds4_pad_handler.cpp +++ b/rpcs3/ds4_pad_handler.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "Emu/System.h" #include "ds4_pad_handler.h" -#include "rpcs3qt/pad_settings_dialog.h" #include @@ -92,51 +91,20 @@ ds4_pad_handler::ds4_pad_handler() : is_init(false) vibration_min = 0; vibration_max = 255; - // Set this handler's type and save location - m_pad_config.cfg_type = "ds4"; - m_pad_config.cfg_name = fs::get_config_dir() + "/config_ds4.yml"; + m_type = pad_handler::ds4; - // Set default button mapping - m_pad_config.ls_left.def = button_list.at(DS4KeyCodes::LSXNeg); - m_pad_config.ls_down.def = button_list.at(DS4KeyCodes::LSYNeg); - m_pad_config.ls_right.def = button_list.at(DS4KeyCodes::LSXPos); - m_pad_config.ls_up.def = button_list.at(DS4KeyCodes::LSYPos); - m_pad_config.rs_left.def = button_list.at(DS4KeyCodes::RSXNeg); - m_pad_config.rs_down.def = button_list.at(DS4KeyCodes::RSYNeg); - m_pad_config.rs_right.def = button_list.at(DS4KeyCodes::RSXPos); - m_pad_config.rs_up.def = button_list.at(DS4KeyCodes::RSYPos); - m_pad_config.start.def = button_list.at(DS4KeyCodes::Options); - m_pad_config.select.def = button_list.at(DS4KeyCodes::Share); - m_pad_config.ps.def = button_list.at(DS4KeyCodes::PSButton); - m_pad_config.square.def = button_list.at(DS4KeyCodes::Square); - m_pad_config.cross.def = button_list.at(DS4KeyCodes::Cross); - m_pad_config.circle.def = button_list.at(DS4KeyCodes::Circle); - m_pad_config.triangle.def = button_list.at(DS4KeyCodes::Triangle); - m_pad_config.left.def = button_list.at(DS4KeyCodes::Left); - m_pad_config.down.def = button_list.at(DS4KeyCodes::Down); - m_pad_config.right.def = button_list.at(DS4KeyCodes::Right); - m_pad_config.up.def = button_list.at(DS4KeyCodes::Up); - m_pad_config.r1.def = button_list.at(DS4KeyCodes::R1); - m_pad_config.r2.def = button_list.at(DS4KeyCodes::R2); - m_pad_config.r3.def = button_list.at(DS4KeyCodes::R3); - m_pad_config.l1.def = button_list.at(DS4KeyCodes::L1); - m_pad_config.l2.def = button_list.at(DS4KeyCodes::L2); - m_pad_config.l3.def = button_list.at(DS4KeyCodes::L3); - - // Set default misc variables - m_pad_config.lstickdeadzone.def = 40; // between 0 and 255 - m_pad_config.rstickdeadzone.def = 40; // between 0 and 255 - m_pad_config.ltriggerthreshold.def = 0; // between 0 and 255 - m_pad_config.rtriggerthreshold.def = 0; // between 0 and 255 - m_pad_config.padsquircling.def = 8000; + input_cfg.from_default(); + input_cfg.load(); - // Set color value - m_pad_config.colorR.def = 0; - m_pad_config.colorG.def = 0; - m_pad_config.colorB.def = 20; - - // apply defaults - m_pad_config.from_default(); + int index = 0; + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (input_cfg.player[i]->handler == pad_handler::ds4) + { + init_config(&m_pad_configs[index], get_config_filename(input_cfg, i)); + index++; + } + } // set capabilities b_has_config = true; @@ -147,6 +115,54 @@ ds4_pad_handler::ds4_pad_handler() : is_init(false) m_thumb_threshold = thumb_max / 2; } +void ds4_pad_handler::init_config(pad_config* cfg, const std::string& name) +{ + // Set this profile's save location + cfg->cfg_name = name; + + // Set default button mapping + cfg->ls_left.def = button_list.at(DS4KeyCodes::LSXNeg); + cfg->ls_down.def = button_list.at(DS4KeyCodes::LSYNeg); + cfg->ls_right.def = button_list.at(DS4KeyCodes::LSXPos); + cfg->ls_up.def = button_list.at(DS4KeyCodes::LSYPos); + cfg->rs_left.def = button_list.at(DS4KeyCodes::RSXNeg); + cfg->rs_down.def = button_list.at(DS4KeyCodes::RSYNeg); + cfg->rs_right.def = button_list.at(DS4KeyCodes::RSXPos); + cfg->rs_up.def = button_list.at(DS4KeyCodes::RSYPos); + cfg->start.def = button_list.at(DS4KeyCodes::Options); + cfg->select.def = button_list.at(DS4KeyCodes::Share); + cfg->ps.def = button_list.at(DS4KeyCodes::PSButton); + cfg->square.def = button_list.at(DS4KeyCodes::Square); + cfg->cross.def = button_list.at(DS4KeyCodes::Cross); + cfg->circle.def = button_list.at(DS4KeyCodes::Circle); + cfg->triangle.def = button_list.at(DS4KeyCodes::Triangle); + cfg->left.def = button_list.at(DS4KeyCodes::Left); + cfg->down.def = button_list.at(DS4KeyCodes::Down); + cfg->right.def = button_list.at(DS4KeyCodes::Right); + cfg->up.def = button_list.at(DS4KeyCodes::Up); + cfg->r1.def = button_list.at(DS4KeyCodes::R1); + cfg->r2.def = button_list.at(DS4KeyCodes::R2); + cfg->r3.def = button_list.at(DS4KeyCodes::R3); + cfg->l1.def = button_list.at(DS4KeyCodes::L1); + cfg->l2.def = button_list.at(DS4KeyCodes::L2); + cfg->l3.def = button_list.at(DS4KeyCodes::L3); + + // Set default misc variables + cfg->lstickdeadzone.def = 40; // between 0 and 255 + cfg->rstickdeadzone.def = 40; // between 0 and 255 + cfg->ltriggerthreshold.def = 0; // between 0 and 255 + cfg->rtriggerthreshold.def = 0; // between 0 and 255 + cfg->padsquircling.def = 8000; + + // Set color value + cfg->colorR.def = 0; + cfg->colorG.def = 0; + cfg->colorB.def = 20; + + // apply defaults + cfg->from_default(); +} + void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::function& callback, bool get_blacklist, std::vector buttons) { if (get_blacklist) @@ -259,29 +275,30 @@ void ds4_pad_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, { // Update the pad button values based on their type and thresholds. // With this you can use axis or triggers as buttons or vice versa + auto p_profile = m_dev->config; switch (keyCode) { case DS4KeyCodes::L2: - pressed = val > m_pad_config.ltriggerthreshold; - val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0; + pressed = val > p_profile->ltriggerthreshold; + val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0; break; case DS4KeyCodes::R2: - pressed = val > m_pad_config.rtriggerthreshold; - val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0; + pressed = val > p_profile->rtriggerthreshold; + val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0; break; case DS4KeyCodes::LSXNeg: case DS4KeyCodes::LSXPos: case DS4KeyCodes::LSYNeg: case DS4KeyCodes::LSYPos: - pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone); - val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0; + pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone); + val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, ignore_threshold) : 0; break; case DS4KeyCodes::RSXNeg: case DS4KeyCodes::RSXPos: case DS4KeyCodes::RSYNeg: case DS4KeyCodes::RSYPos: - pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone); - val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0; + pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone); + val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0; break; default: // normal button (should in theory also support sensitive buttons) pressed = val > 0; @@ -406,8 +423,8 @@ void ds4_pad_handler::ProcessDataToPad(const std::shared_ptr& device, pad->m_cable_state = device->cableState; auto buf = device->padData; - auto button_values = GetButtonValues(device); + auto p_profile = device->config; // Translate any corresponding keycodes to our normal DS3 buttons and triggers for (auto & btn : pad->m_buttons) @@ -452,13 +469,13 @@ void ds4_pad_handler::ProcessDataToPad(const std::shared_ptr& device, u16 lx, ly, rx, ry; // Normalize our two stick's axis based on the thresholds - std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], m_pad_config.lstickdeadzone); - std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone); + std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], p_profile->lstickdeadzone); + std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], p_profile->rstickdeadzone); - if (m_pad_config.padsquircling != 0) + if (p_profile->padsquircling != 0) { - std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, m_pad_config.padsquircling); - std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling); + std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, p_profile->padsquircling); + std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, p_profile->padsquircling); } ly = 255 - ly; @@ -654,6 +671,8 @@ ds4_pad_handler::~ds4_pad_handler() int ds4_pad_handler::SendVibrateData(const std::shared_ptr& device) { + auto p_profile = device->config; + std::array outputBuf{0}; // write rumble state if (device->btCon) @@ -663,9 +682,9 @@ int ds4_pad_handler::SendVibrateData(const std::shared_ptr& device) outputBuf[3] = 0x07; outputBuf[6] = device->smallVibrate; outputBuf[7] = device->largeVibrate; - outputBuf[8] = m_pad_config.colorR; // red - outputBuf[9] = m_pad_config.colorG; // green - outputBuf[10] = m_pad_config.colorB; // blue + outputBuf[8] = p_profile->colorR; // red + outputBuf[9] = p_profile->colorG; // green + outputBuf[10] = p_profile->colorB; // blue // alternating blink states with values 0-255: only setting both to zero disables blinking // 255 is roughly 2 seconds, so setting both values to 255 results in a 4 second interval @@ -690,9 +709,9 @@ int ds4_pad_handler::SendVibrateData(const std::shared_ptr& device) outputBuf[1] = 0x07; outputBuf[4] = device->smallVibrate; outputBuf[5] = device->largeVibrate; - outputBuf[6] = m_pad_config.colorR; // red - outputBuf[7] = m_pad_config.colorG; // green - outputBuf[8] = m_pad_config.colorB; // blue + outputBuf[6] = p_profile->colorR; // red + outputBuf[7] = p_profile->colorG; // green + outputBuf[8] = p_profile->colorB; // blue outputBuf[9] = device->led_delay_on; outputBuf[10] = device->led_delay_off; @@ -734,10 +753,6 @@ bool ds4_pad_handler::Init() else LOG_SUCCESS(HLE, "[DS4] Controllers found: %d", controllers.size()); - m_pad_config.load(); - if (!m_pad_config.exist()) - m_pad_config.save(); - is_init = true; return true; } @@ -763,7 +778,12 @@ bool ds4_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::strin if (ds4device == nullptr || ds4device->hidDevice == nullptr) return false; - m_pad_config.load(); + int index = static_cast(bindings.size()); + m_pad_configs[index].load(); + ds4device->config = &m_pad_configs[index]; + pad_config* p_profile = ds4device->config; + if (p_profile == nullptr) + return false; pad->Init ( @@ -774,34 +794,34 @@ bool ds4_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::strin ); // 'keycode' here is just 0 as we have to manually calculate this - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.l2), CELL_PAD_CTRL_L2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.r2), CELL_PAD_CTRL_R2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.right), CELL_PAD_CTRL_RIGHT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l2), CELL_PAD_CTRL_L2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r2), CELL_PAD_CTRL_R2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->up), CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->down), CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->left), CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->right), CELL_PAD_CTRL_RIGHT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->square), CELL_PAD_CTRL_SQUARE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->cross), CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->circle), CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l1), CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r1), CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->select), CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->start), CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->l3), CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->r3), CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 512); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, m_pad_config.ls_left), FindKeyCode(button_list, m_pad_config.ls_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, m_pad_config.ls_down), FindKeyCode(button_list, m_pad_config.ls_up)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, m_pad_config.rs_left), FindKeyCode(button_list, m_pad_config.rs_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, m_pad_config.rs_down), FindKeyCode(button_list, m_pad_config.rs_up)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, p_profile->ls_left), FindKeyCode(button_list, p_profile->ls_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, p_profile->ls_down), FindKeyCode(button_list, p_profile->ls_up)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, p_profile->rs_left), FindKeyCode(button_list, p_profile->rs_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, p_profile->rs_down), FindKeyCode(button_list, p_profile->rs_up)); pad->m_vibrateMotors.emplace_back(true, 0); pad->m_vibrateMotors.emplace_back(false, 0); @@ -815,13 +835,14 @@ void ds4_pad_handler::ThreadProc() { for (int i = 0; i < static_cast(bindings.size()); i++) { - std::shared_ptr device = bindings[i].first; + m_dev = bindings[i].first; auto thepad = bindings[i].second; + auto profile = m_dev->config; - if (device->hidDevice == nullptr) + if (m_dev->hidDevice == nullptr) { // try to reconnect - hid_device* dev = hid_open_path(device->path.c_str()); + hid_device* dev = hid_open_path(m_dev->path.c_str()); if (dev) { if (last_connection_status[i] == false) @@ -831,10 +852,10 @@ void ds4_pad_handler::ThreadProc() connected++; } hid_set_nonblocking(dev, 1); - device->hidDevice = dev; + m_dev->hidDevice = dev; thepad->m_port_status = CELL_PAD_STATUS_CONNECTED|CELL_PAD_STATUS_ASSIGN_CHANGES; - if (!device->hasCalibData) - device->hasCalibData = GetCalibrationData(device); + if (!m_dev->hasCalibData) + m_dev->hasCalibData = GetCalibrationData(m_dev); } else { @@ -856,53 +877,53 @@ void ds4_pad_handler::ThreadProc() connected++; } - DS4DataStatus status = GetRawData(device); + DS4DataStatus status = GetRawData(m_dev); if (status == DS4DataStatus::ReadError) { // this also can mean disconnected, either way deal with it on next loop and reconnect - hid_close(device->hidDevice); - device->hidDevice = nullptr; + hid_close(m_dev->hidDevice); + m_dev->hidDevice = nullptr; continue; } // Attempt to send rumble no matter what - int idx_l = m_pad_config.switch_vibration_motors ? 1 : 0; - int idx_s = m_pad_config.switch_vibration_motors ? 0 : 1; + int idx_l = profile->switch_vibration_motors ? 1 : 0; + int idx_s = profile->switch_vibration_motors ? 0 : 1; - int speed_large = m_pad_config.enable_vibration_motor_large ? thepad->m_vibrateMotors[idx_l].m_value : vibration_min; - int speed_small = m_pad_config.enable_vibration_motor_small ? thepad->m_vibrateMotors[idx_s].m_value : vibration_min; + int speed_large = profile->enable_vibration_motor_large ? thepad->m_vibrateMotors[idx_l].m_value : vibration_min; + int speed_small = profile->enable_vibration_motor_small ? thepad->m_vibrateMotors[idx_s].m_value : vibration_min; - bool wireless = device->cableState < 1; - bool lowBattery = device->batteryLevel < 2; - bool isBlinking = device->led_delay_on > 0 || device->led_delay_off > 0; + bool wireless = m_dev->cableState < 1; + bool lowBattery = m_dev->batteryLevel < 2; + bool isBlinking = m_dev->led_delay_on > 0 || m_dev->led_delay_off > 0; bool newBlinkData = false; // we are now wired or have okay battery level -> stop blinking if (isBlinking && !(wireless && lowBattery)) { - device->led_delay_on = 0; - device->led_delay_off = 0; + m_dev->led_delay_on = 0; + m_dev->led_delay_off = 0; newBlinkData = true; } // we are now wireless and low on battery -> blink if (!isBlinking && wireless && lowBattery) { - device->led_delay_on = 100; - device->led_delay_off = 100; + m_dev->led_delay_on = 100; + m_dev->led_delay_off = 100; newBlinkData = true; } - device->newVibrateData = device->newVibrateData || device->largeVibrate != speed_large || device->smallVibrate != speed_small || newBlinkData; + m_dev->newVibrateData = m_dev->newVibrateData || m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small || newBlinkData; - device->largeVibrate = speed_large; - device->smallVibrate = speed_small; + m_dev->largeVibrate = speed_large; + m_dev->smallVibrate = speed_small; - if (device->newVibrateData) + if (m_dev->newVibrateData) { - if (SendVibrateData(device) >= 0) + if (SendVibrateData(m_dev) >= 0) { - device->newVibrateData = false; + m_dev->newVibrateData = false; } } @@ -911,7 +932,7 @@ void ds4_pad_handler::ThreadProc() continue; else if (status == DS4DataStatus::NewData) - ProcessDataToPad(device, thepad); + ProcessDataToPad(m_dev, thepad); } } diff --git a/rpcs3/ds4_pad_handler.h b/rpcs3/ds4_pad_handler.h index 196a2ffcf9f6..639e2eb8b926 100644 --- a/rpcs3/ds4_pad_handler.h +++ b/rpcs3/ds4_pad_handler.h @@ -109,6 +109,7 @@ class ds4_pad_handler final : public PadHandlerBase struct DS4Device { hid_device* hidDevice{ nullptr }; + pad_config* config{ nullptr }; std::string path{ "" }; bool btCon{ false }; bool hasCalibData{ false }; @@ -143,12 +144,14 @@ class ds4_pad_handler final : public PadHandlerBase void ThreadProc() override; void GetNextButtonPress(const std::string& padId, const std::function& buttonCallback, bool get_blacklist = false, std::vector buttons = {}) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; + void init_config(pad_config* cfg, const std::string& name) override; private: - bool is_init; + bool is_init = false; std::vector blacklist; std::vector, std::shared_ptr>> bindings; + std::shared_ptr m_dev; private: std::shared_ptr GetDevice(const std::string& padId); diff --git a/rpcs3/evdev_joystick_handler.cpp b/rpcs3/evdev_joystick_handler.cpp index 701ba7655609..5382f45157eb 100644 --- a/rpcs3/evdev_joystick_handler.cpp +++ b/rpcs3/evdev_joystick_handler.cpp @@ -27,46 +27,20 @@ evdev_joystick_handler::evdev_joystick_handler() vibration_min = 0; vibration_max = 65535; - // Set this handler's type and save location - m_pad_config.cfg_type = "evdev"; - m_pad_config.cfg_name = fs::get_config_dir() + "/config_evdev.yml"; + m_type = pad_handler::evdev; - // Set default button mapping - m_pad_config.ls_left.def = rev_axis_list.at(ABS_X); - m_pad_config.ls_down.def = axis_list.at(ABS_Y); - m_pad_config.ls_right.def = axis_list.at(ABS_X); - m_pad_config.ls_up.def = rev_axis_list.at(ABS_Y); - m_pad_config.rs_left.def = rev_axis_list.at(ABS_RX); - m_pad_config.rs_down.def = axis_list.at(ABS_RY); - m_pad_config.rs_right.def = axis_list.at(ABS_RX); - m_pad_config.rs_up.def = rev_axis_list.at(ABS_RY); - m_pad_config.start.def = button_list.at(BTN_START); - m_pad_config.select.def = button_list.at(BTN_SELECT); - m_pad_config.ps.def = button_list.at(BTN_MODE); - m_pad_config.square.def = button_list.at(BTN_X); - m_pad_config.cross.def = button_list.at(BTN_A); - m_pad_config.circle.def = button_list.at(BTN_B); - m_pad_config.triangle.def = button_list.at(BTN_Y); - m_pad_config.left.def = rev_axis_list.at(ABS_HAT0X); - m_pad_config.down.def = axis_list.at(ABS_HAT0Y); - m_pad_config.right.def = axis_list.at(ABS_HAT0X); - m_pad_config.up.def = rev_axis_list.at(ABS_HAT0Y); - m_pad_config.r1.def = button_list.at(BTN_TR); - m_pad_config.r2.def = axis_list.at(ABS_RZ); - m_pad_config.r3.def = button_list.at(BTN_THUMBR); - m_pad_config.l1.def = button_list.at(BTN_TL); - m_pad_config.l2.def = axis_list.at(ABS_Z); - m_pad_config.l3.def = button_list.at(BTN_THUMBL); - - // Set default misc variables - m_pad_config.lstickdeadzone.def = 30; // between 0 and 255 - m_pad_config.rstickdeadzone.def = 30; // between 0 and 255 - m_pad_config.ltriggerthreshold.def = 0; // between 0 and 255 - m_pad_config.rtriggerthreshold.def = 0; // between 0 and 255 - m_pad_config.padsquircling.def = 5000; + input_cfg.from_default(); + input_cfg.load(); - // apply defaults - m_pad_config.from_default(); + int index = 0; + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (input_cfg.player_input[i] == pad_handler::evdev) + { + init_config(&m_pad_configs[index], get_config_filename(input_cfg, i)); + index++; + } + } // set capabilities b_has_config = true; @@ -82,12 +56,54 @@ evdev_joystick_handler::~evdev_joystick_handler() Close(); } +void evdev_joystick_handler::init_config(pad_config* cfg, const std::string& name) +{ + // Set this profile's save location + cfg->cfg_name = name; + + // Set default button mapping + cfg->ls_left.def = rev_axis_list.at(ABS_X); + cfg->ls_down.def = axis_list.at(ABS_Y); + cfg->ls_right.def = axis_list.at(ABS_X); + cfg->ls_up.def = rev_axis_list.at(ABS_Y); + cfg->rs_left.def = rev_axis_list.at(ABS_RX); + cfg->rs_down.def = axis_list.at(ABS_RY); + cfg->rs_right.def = axis_list.at(ABS_RX); + cfg->rs_up.def = rev_axis_list.at(ABS_RY); + cfg->start.def = button_list.at(BTN_START); + cfg->select.def = button_list.at(BTN_SELECT); + cfg->ps.def = button_list.at(BTN_MODE); + cfg->square.def = button_list.at(BTN_X); + cfg->cross.def = button_list.at(BTN_A); + cfg->circle.def = button_list.at(BTN_B); + cfg->triangle.def = button_list.at(BTN_Y); + cfg->left.def = rev_axis_list.at(ABS_HAT0X); + cfg->down.def = axis_list.at(ABS_HAT0Y); + cfg->right.def = axis_list.at(ABS_HAT0X); + cfg->up.def = rev_axis_list.at(ABS_HAT0Y); + cfg->r1.def = button_list.at(BTN_TR); + cfg->r2.def = axis_list.at(ABS_RZ); + cfg->r3.def = button_list.at(BTN_THUMBR); + cfg->l1.def = button_list.at(BTN_TL); + cfg->l2.def = axis_list.at(ABS_Z); + cfg->l3.def = button_list.at(BTN_THUMBL); + + // Set default misc variables + cfg->lstickdeadzone.def = 30; // between 0 and 255 + cfg->rstickdeadzone.def = 30; // between 0 and 255 + cfg->ltriggerthreshold.def = 0; // between 0 and 255 + cfg->rtriggerthreshold.def = 0; // between 0 and 255 + cfg->padsquircling.def = 5000; + + // apply defaults + cfg->from_default(); +} + bool evdev_joystick_handler::Init() { if (m_is_init) return true; - m_pad_config.load(); m_pos_axis_config.load(); if (!m_pos_axis_config.exist()) @@ -498,6 +514,7 @@ void evdev_joystick_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u1 { // Update the pad button values based on their type and thresholds. // With this you can use axis or triggers as buttons or vice versa + auto profile = m_dev.config; u32 code = static_cast(keyCode); auto checkButton = [&](const EvdevButton& b) { @@ -510,23 +527,23 @@ void evdev_joystick_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u1 if (checkButton(m_dev.trigger_left)) { - pressed = value > m_pad_config.ltriggerthreshold; - value = pressed ? NormalizeTriggerInput(value, m_pad_config.ltriggerthreshold) : 0; + pressed = value > profile->ltriggerthreshold; + value = pressed ? NormalizeTriggerInput(value, profile->ltriggerthreshold) : 0; } else if (checkButton(m_dev.trigger_right)) { - pressed = value > m_pad_config.rtriggerthreshold; - value = pressed ? NormalizeTriggerInput(value, m_pad_config.rtriggerthreshold) : 0; + pressed = value > profile->rtriggerthreshold; + value = pressed ? NormalizeTriggerInput(value, profile->rtriggerthreshold) : 0; } else if (checkButtons(m_dev.axis_left)) { - pressed = value > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone); - value = pressed ? NormalizeStickInput(value, m_pad_config.lstickdeadzone, ignore_threshold) : 0; + pressed = value > (ignore_threshold ? 0 : profile->lstickdeadzone); + value = pressed ? NormalizeStickInput(value, profile->lstickdeadzone, ignore_threshold) : 0; } else if (checkButtons(m_dev.axis_right)) { - pressed = value > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone); - value = pressed ? NormalizeStickInput(value, m_pad_config.rstickdeadzone, ignore_threshold) : 0; + pressed = value > (ignore_threshold ? 0 : profile->rstickdeadzone); + value = pressed ? NormalizeStickInput(value, profile->rstickdeadzone, ignore_threshold) : 0; } else // normal button (should in theory also support sensitive buttons) { @@ -608,7 +625,7 @@ std::vector evdev_joystick_handler::ListDevices() libevdev_has_event_code(dev, EV_ABS, ABS_Y)) { // It's a joystick. - evdev_joystick_list.push_back(libevdev_get_name(dev)); + evdev_joystick_list.push_back(et.name + ": " + libevdev_get_name(dev)); } libevdev_free(dev); close(fd); @@ -643,7 +660,7 @@ int evdev_joystick_handler::add_device(const std::string& device, bool in_settin close(fd); continue; } - const std::string name = libevdev_get_name(dev); + const std::string name = et.name + ": " + libevdev_get_name(dev); if (libevdev_has_event_type(dev, EV_KEY) && libevdev_has_event_code(dev, EV_ABS, ABS_X) && libevdev_has_event_code(dev, EV_ABS, ABS_Y) && @@ -680,6 +697,7 @@ void evdev_joystick_handler::ThreadProc() for (auto& device : devices) { m_dev = device; + auto profile = device.config; auto pad = device.pad; auto axis_orientations = device.axis_orientations; auto& dev = device.device; @@ -704,10 +722,10 @@ void evdev_joystick_handler::ThreadProc() padnum++; // Handle vibration - int idx_l = m_pad_config.switch_vibration_motors ? 1 : 0; - int idx_s = m_pad_config.switch_vibration_motors ? 0 : 1; - u16 force_large = m_pad_config.enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min; - u16 force_small = m_pad_config.enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min; + int idx_l = profile->switch_vibration_motors ? 1 : 0; + int idx_s = profile->switch_vibration_motors ? 0 : 1; + u16 force_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min; + u16 force_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min; SetRumble(&device, force_large, force_small); // Try to query the latest event from the joystick. @@ -832,13 +850,13 @@ void evdev_joystick_handler::ThreadProc() u16 lx, ly, rx, ry; // Normalize our two stick's axis based on the thresholds - std::tie(lx, ly) = NormalizeStickDeadzone(device.stick_val[0], device.stick_val[1], m_pad_config.lstickdeadzone); - std::tie(rx, ry) = NormalizeStickDeadzone(device.stick_val[2], device.stick_val[3], m_pad_config.rstickdeadzone); + std::tie(lx, ly) = NormalizeStickDeadzone(device.stick_val[0], device.stick_val[1], profile->lstickdeadzone); + std::tie(rx, ry) = NormalizeStickDeadzone(device.stick_val[2], device.stick_val[3], profile->rstickdeadzone); - if (m_pad_config.padsquircling != 0) + if (profile->padsquircling != 0) { - std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, m_pad_config.padsquircling); - std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling); + std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling); + std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling); } pad->m_sticks[0].m_value = lx; @@ -866,6 +884,13 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std int i = 0; // increment to know the axis location (17-24). Be careful if you ever add more find_key() calls in here (BUTTON_COUNT = 17) int last_type = EV_ABS; + int index = static_cast(bindings.size()); + m_pad_configs[index].load(); + m_dev.config = &m_pad_configs[index]; + pad_config* p_profile = m_dev.config; + if (p_profile == nullptr) + return false; + auto find_key = [&](const cfg::string& name) { int type = EV_ABS; @@ -909,38 +934,38 @@ bool evdev_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std CELL_PAD_DEV_TYPE_STANDARD ); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.square), CELL_PAD_CTRL_SQUARE); - - m_dev.trigger_left = evdevbutton(m_pad_config.l2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_left.code, CELL_PAD_CTRL_L2); - - m_dev.trigger_right = evdevbutton(m_pad_config.r2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_right.code, CELL_PAD_CTRL_R2); - - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.right), CELL_PAD_CTRL_RIGHT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved - - m_dev.axis_left[0] = evdevbutton(m_pad_config.ls_right); - m_dev.axis_left[1] = evdevbutton(m_pad_config.ls_left); - m_dev.axis_left[2] = evdevbutton(m_pad_config.ls_up); - m_dev.axis_left[3] = evdevbutton(m_pad_config.ls_down); - m_dev.axis_right[0] = evdevbutton(m_pad_config.rs_right); - m_dev.axis_right[1] = evdevbutton(m_pad_config.rs_left); - m_dev.axis_right[2] = evdevbutton(m_pad_config.rs_up); - m_dev.axis_right[3] = evdevbutton(m_pad_config.rs_down); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->circle), CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE); + + m_dev.trigger_left = evdevbutton(p_profile->l2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_left.code, CELL_PAD_CTRL_L2); + + m_dev.trigger_right = evdevbutton(p_profile->r2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, m_dev.trigger_right.code, CELL_PAD_CTRL_R2); + + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->start), CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->select), CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->l3), CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->r3), CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->up), CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->down), CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved + + m_dev.axis_left[0] = evdevbutton(p_profile->ls_right); + m_dev.axis_left[1] = evdevbutton(p_profile->ls_left); + m_dev.axis_left[2] = evdevbutton(p_profile->ls_up); + m_dev.axis_left[3] = evdevbutton(p_profile->ls_down); + m_dev.axis_right[0] = evdevbutton(p_profile->rs_right); + m_dev.axis_right[1] = evdevbutton(p_profile->rs_left); + m_dev.axis_right[2] = evdevbutton(p_profile->rs_up); + m_dev.axis_right[3] = evdevbutton(p_profile->rs_down); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, m_dev.axis_left[1].code, m_dev.axis_left[0].code); pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, m_dev.axis_left[3].code, m_dev.axis_left[2].code); diff --git a/rpcs3/evdev_joystick_handler.h b/rpcs3/evdev_joystick_handler.h index 4e554ba94757..72e4a4e66899 100644 --- a/rpcs3/evdev_joystick_handler.h +++ b/rpcs3/evdev_joystick_handler.h @@ -302,7 +302,8 @@ class evdev_joystick_handler final : public PadHandlerBase struct EvdevDevice { - libevdev* device = nullptr; + libevdev* device{ nullptr }; + pad_config* config{ nullptr }; std::string path; std::shared_ptr pad; std::unordered_map axis_orientations; // value is true if key was found in rev_axis_list @@ -328,6 +329,7 @@ class evdev_joystick_handler final : public PadHandlerBase evdev_joystick_handler(); ~evdev_joystick_handler(); + void init_config(pad_config* cfg, const std::string& name) override; bool Init() override; std::vector ListDevices() override; bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; diff --git a/rpcs3/keyboard_pad_handler.cpp b/rpcs3/keyboard_pad_handler.cpp index 073b0e170ed5..9075125a0f2a 100644 --- a/rpcs3/keyboard_pad_handler.cpp +++ b/rpcs3/keyboard_pad_handler.cpp @@ -4,8 +4,6 @@ #include -#include "rpcs3qt/pad_settings_dialog.h" - inline std::string sstr(const QString& _in) { return _in.toStdString(); } constexpr auto qstr = QString::fromStdString; @@ -16,44 +14,61 @@ bool keyboard_pad_handler::Init() keyboard_pad_handler::keyboard_pad_handler() : QObject() { - // Set this handler's type and save location - m_pad_config.cfg_type = "keyboard"; - m_pad_config.cfg_name = fs::get_config_dir() + "/config_kbpad_qt.yml"; + m_type = pad_handler::keyboard; - // Set default button mapping - m_pad_config.ls_left.def = GetKeyName(Qt::Key_A); - m_pad_config.ls_down.def = GetKeyName(Qt::Key_S); - m_pad_config.ls_right.def = GetKeyName(Qt::Key_D); - m_pad_config.ls_up.def = GetKeyName(Qt::Key_W); - m_pad_config.rs_left.def = GetKeyName(Qt::Key_Home); - m_pad_config.rs_down.def = GetKeyName(Qt::Key_PageDown); - m_pad_config.rs_right.def = GetKeyName(Qt::Key_End); - m_pad_config.rs_up.def = GetKeyName(Qt::Key_PageUp); - m_pad_config.start.def = GetKeyName(Qt::Key_Return); - m_pad_config.select.def = GetKeyName(Qt::Key_Space); - m_pad_config.ps.def = GetKeyName(Qt::Key_Backspace); - m_pad_config.square.def = GetKeyName(Qt::Key_Z); - m_pad_config.cross.def = GetKeyName(Qt::Key_X); - m_pad_config.circle.def = GetKeyName(Qt::Key_C); - m_pad_config.triangle.def = GetKeyName(Qt::Key_V); - m_pad_config.left.def = GetKeyName(Qt::Key_Left); - m_pad_config.down.def = GetKeyName(Qt::Key_Down); - m_pad_config.right.def = GetKeyName(Qt::Key_Right); - m_pad_config.up.def = GetKeyName(Qt::Key_Up); - m_pad_config.r1.def = GetKeyName(Qt::Key_E); - m_pad_config.r2.def = GetKeyName(Qt::Key_T); - m_pad_config.r3.def = GetKeyName(Qt::Key_G); - m_pad_config.l1.def = GetKeyName(Qt::Key_Q); - m_pad_config.l2.def = GetKeyName(Qt::Key_R); - m_pad_config.l3.def = GetKeyName(Qt::Key_F); + input_cfg.from_default(); + input_cfg.load(); - // apply defaults - m_pad_config.from_default(); + int index = 0; + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (input_cfg.player[i]->handler == pad_handler::keyboard) + { + init_config(&m_pad_configs[index], get_config_filename(input_cfg, i)); + index++; + } + } // set capabilities b_has_config = true; } +void keyboard_pad_handler::init_config(pad_config* cfg, const std::string& name) +{ + // Set this profile's save location + cfg->cfg_name = name; + + // Set default button mapping + cfg->ls_left.def = GetKeyName(Qt::Key_A); + cfg->ls_down.def = GetKeyName(Qt::Key_S); + cfg->ls_right.def = GetKeyName(Qt::Key_D); + cfg->ls_up.def = GetKeyName(Qt::Key_W); + cfg->rs_left.def = GetKeyName(Qt::Key_Home); + cfg->rs_down.def = GetKeyName(Qt::Key_PageDown); + cfg->rs_right.def = GetKeyName(Qt::Key_End); + cfg->rs_up.def = GetKeyName(Qt::Key_PageUp); + cfg->start.def = GetKeyName(Qt::Key_Return); + cfg->select.def = GetKeyName(Qt::Key_Space); + cfg->ps.def = GetKeyName(Qt::Key_Backspace); + cfg->square.def = GetKeyName(Qt::Key_Z); + cfg->cross.def = GetKeyName(Qt::Key_X); + cfg->circle.def = GetKeyName(Qt::Key_C); + cfg->triangle.def = GetKeyName(Qt::Key_V); + cfg->left.def = GetKeyName(Qt::Key_Left); + cfg->down.def = GetKeyName(Qt::Key_Down); + cfg->right.def = GetKeyName(Qt::Key_Right); + cfg->up.def = GetKeyName(Qt::Key_Up); + cfg->r1.def = GetKeyName(Qt::Key_E); + cfg->r2.def = GetKeyName(Qt::Key_T); + cfg->r3.def = GetKeyName(Qt::Key_G); + cfg->l1.def = GetKeyName(Qt::Key_Q); + cfg->l2.def = GetKeyName(Qt::Key_R); + cfg->l3.def = GetKeyName(Qt::Key_F); + + // apply defaults + cfg->from_default(); +} + void keyboard_pad_handler::Key(const u32 code, bool pressed, u16 value) { value = Clamp0To255(value); @@ -386,7 +401,11 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std:: if (device != "Keyboard") return false; - m_pad_config.load(); + int index = static_cast(bindings.size()); + m_pad_configs[index].load(); + pad_config* p_profile = &m_pad_configs[index]; + if (p_profile == nullptr) + return false; auto find_key = [&](const cfg::string& name) { @@ -407,29 +426,29 @@ bool keyboard_pad_handler::bindPadToDevice(std::shared_ptr pad, const std:: CELL_PAD_DEV_TYPE_STANDARD ); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.right), CELL_PAD_CTRL_RIGHT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.r2), CELL_PAD_CTRL_R2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.l2), CELL_PAD_CTRL_L2); - - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_key(m_pad_config.ls_left), find_key(m_pad_config.ls_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_key(m_pad_config.ls_up), find_key(m_pad_config.ls_down)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_key(m_pad_config.rs_left), find_key(m_pad_config.rs_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_key(m_pad_config.rs_up), find_key(m_pad_config.rs_down)); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->down), CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->up), CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->start), CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->r3), CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->l3), CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->select), CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->circle), CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r2), CELL_PAD_CTRL_R2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l2), CELL_PAD_CTRL_L2); + + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, find_key(p_profile->ls_left), find_key(p_profile->ls_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, find_key(p_profile->ls_up), find_key(p_profile->ls_down)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, find_key(p_profile->rs_left), find_key(p_profile->rs_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, find_key(p_profile->rs_up), find_key(p_profile->rs_down)); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); diff --git a/rpcs3/keyboard_pad_handler.h b/rpcs3/keyboard_pad_handler.h index 79d213ae6a39..dcb6d77c6e11 100644 --- a/rpcs3/keyboard_pad_handler.h +++ b/rpcs3/keyboard_pad_handler.h @@ -57,6 +57,7 @@ class keyboard_pad_handler final : public QObject, public PadHandlerBase bool eventFilter(QObject* obj, QEvent* ev) override; + void init_config(pad_config* cfg, const std::string& name) override; std::vector ListDevices() override; bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; void ThreadProc() override; diff --git a/rpcs3/mm_joystick_handler.cpp b/rpcs3/mm_joystick_handler.cpp index 1e8929823242..563ecfd67399 100644 --- a/rpcs3/mm_joystick_handler.cpp +++ b/rpcs3/mm_joystick_handler.cpp @@ -12,46 +12,20 @@ mm_joystick_handler::mm_joystick_handler() : is_init(false) vibration_min = 0; vibration_max = 65535; - // Set this handler's type and save location - m_pad_config.cfg_type = "mmjoystick"; - m_pad_config.cfg_name = fs::get_config_dir() + "/config_mmjoystick.yml"; + m_type = pad_handler::mm; - // Set default button mapping - m_pad_config.ls_left.def = axis_list.at(mmjoy_axis::joy_x_neg); - m_pad_config.ls_down.def = axis_list.at(mmjoy_axis::joy_y_neg); - m_pad_config.ls_right.def = axis_list.at(mmjoy_axis::joy_x_pos); - m_pad_config.ls_up.def = axis_list.at(mmjoy_axis::joy_y_pos); - m_pad_config.rs_left.def = axis_list.at(mmjoy_axis::joy_z_neg); - m_pad_config.rs_down.def = axis_list.at(mmjoy_axis::joy_r_neg); - m_pad_config.rs_right.def = axis_list.at(mmjoy_axis::joy_z_pos); - m_pad_config.rs_up.def = axis_list.at(mmjoy_axis::joy_r_pos); - m_pad_config.start.def = button_list.at(JOY_BUTTON9); - m_pad_config.select.def = button_list.at(JOY_BUTTON10); - m_pad_config.ps.def = button_list.at(JOY_BUTTON17); - m_pad_config.square.def = button_list.at(JOY_BUTTON4); - m_pad_config.cross.def = button_list.at(JOY_BUTTON3); - m_pad_config.circle.def = button_list.at(JOY_BUTTON2); - m_pad_config.triangle.def = button_list.at(JOY_BUTTON1); - m_pad_config.left.def = pov_list.at(JOY_POVLEFT); - m_pad_config.down.def = pov_list.at(JOY_POVBACKWARD); - m_pad_config.right.def = pov_list.at(JOY_POVRIGHT); - m_pad_config.up.def = pov_list.at(JOY_POVFORWARD); - m_pad_config.r1.def = button_list.at(JOY_BUTTON8); - m_pad_config.r2.def = button_list.at(JOY_BUTTON6); - m_pad_config.r3.def = button_list.at(JOY_BUTTON12); - m_pad_config.l1.def = button_list.at(JOY_BUTTON7); - m_pad_config.l2.def = button_list.at(JOY_BUTTON5); - m_pad_config.l3.def = button_list.at(JOY_BUTTON11); - - // Set default misc variables - m_pad_config.lstickdeadzone.def = 0; // between 0 and 255 - m_pad_config.rstickdeadzone.def = 0; // between 0 and 255 - m_pad_config.ltriggerthreshold.def = 0; // between 0 and 255 - m_pad_config.rtriggerthreshold.def = 0; // between 0 and 255 - m_pad_config.padsquircling.def = 8000; + input_cfg.from_default(); + input_cfg.load(); - // apply defaults - m_pad_config.from_default(); + int index = 0; + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (input_cfg.player[i]->handler == pad_handler::mm) + { + init_config(&m_pad_configs[index], get_config_filename(input_cfg, i)); + index++; + } + } // set capabilities b_has_config = true; @@ -66,6 +40,49 @@ mm_joystick_handler::~mm_joystick_handler() { } +void mm_joystick_handler::init_config(pad_config* cfg, const std::string& name) +{ + // Set this profile's save location + cfg->cfg_name = name; + + // Set default button mapping + cfg->ls_left.def = axis_list.at(mmjoy_axis::joy_x_neg); + cfg->ls_down.def = axis_list.at(mmjoy_axis::joy_y_neg); + cfg->ls_right.def = axis_list.at(mmjoy_axis::joy_x_pos); + cfg->ls_up.def = axis_list.at(mmjoy_axis::joy_y_pos); + cfg->rs_left.def = axis_list.at(mmjoy_axis::joy_z_neg); + cfg->rs_down.def = axis_list.at(mmjoy_axis::joy_r_neg); + cfg->rs_right.def = axis_list.at(mmjoy_axis::joy_z_pos); + cfg->rs_up.def = axis_list.at(mmjoy_axis::joy_r_pos); + cfg->start.def = button_list.at(JOY_BUTTON9); + cfg->select.def = button_list.at(JOY_BUTTON10); + cfg->ps.def = button_list.at(JOY_BUTTON17); + cfg->square.def = button_list.at(JOY_BUTTON4); + cfg->cross.def = button_list.at(JOY_BUTTON3); + cfg->circle.def = button_list.at(JOY_BUTTON2); + cfg->triangle.def = button_list.at(JOY_BUTTON1); + cfg->left.def = pov_list.at(JOY_POVLEFT); + cfg->down.def = pov_list.at(JOY_POVBACKWARD); + cfg->right.def = pov_list.at(JOY_POVRIGHT); + cfg->up.def = pov_list.at(JOY_POVFORWARD); + cfg->r1.def = button_list.at(JOY_BUTTON8); + cfg->r2.def = button_list.at(JOY_BUTTON6); + cfg->r3.def = button_list.at(JOY_BUTTON12); + cfg->l1.def = button_list.at(JOY_BUTTON7); + cfg->l2.def = button_list.at(JOY_BUTTON5); + cfg->l3.def = button_list.at(JOY_BUTTON11); + + // Set default misc variables + cfg->lstickdeadzone.def = 0; // between 0 and 255 + cfg->rstickdeadzone.def = 0; // between 0 and 255 + cfg->ltriggerthreshold.def = 0; // between 0 and 255 + cfg->rtriggerthreshold.def = 0; // between 0 and 255 + cfg->padsquircling.def = 8000; + + // apply defaults + cfg->from_default(); +} + bool mm_joystick_handler::Init() { if (is_init) return true; @@ -93,7 +110,6 @@ bool mm_joystick_handler::Init() m_devices.emplace(i, dev); } - m_pad_config.load(); is_init = true; return true; } @@ -123,6 +139,13 @@ bool mm_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std::s std::shared_ptr joy_device = std::make_shared(m_devices.at(id)); + int index = static_cast(bindings.size()); + m_pad_configs[index].load(); + joy_device->config = &m_pad_configs[index]; + pad_config* p_profile = joy_device->config; + if (p_profile == nullptr) + return false; + auto find_key = [=](const cfg::string& name) { long key = FindKeyCode(button_list, name, false); @@ -141,34 +164,34 @@ bool mm_joystick_handler::bindPadToDevice(std::shared_ptr pad, const std::s CELL_PAD_DEV_TYPE_STANDARD ); - joy_device->trigger_left = find_key(m_pad_config.l2); - joy_device->trigger_right = find_key(m_pad_config.r2); - joy_device->axis_left[0] = find_key(m_pad_config.ls_left); - joy_device->axis_left[1] = find_key(m_pad_config.ls_right); - joy_device->axis_left[2] = find_key(m_pad_config.ls_down); - joy_device->axis_left[3] = find_key(m_pad_config.ls_up); - joy_device->axis_right[0] = find_key(m_pad_config.rs_left); - joy_device->axis_right[1] = find_key(m_pad_config.rs_right); - joy_device->axis_right[2] = find_key(m_pad_config.rs_down); - joy_device->axis_right[3] = find_key(m_pad_config.rs_up); - - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, joy_device->trigger_left, CELL_PAD_CTRL_L2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, joy_device->trigger_right, CELL_PAD_CTRL_R2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(m_pad_config.right), CELL_PAD_CTRL_RIGHT); + joy_device->trigger_left = find_key(p_profile->l2); + joy_device->trigger_right = find_key(p_profile->r2); + joy_device->axis_left[0] = find_key(p_profile->ls_left); + joy_device->axis_left[1] = find_key(p_profile->ls_right); + joy_device->axis_left[2] = find_key(p_profile->ls_down); + joy_device->axis_left[3] = find_key(p_profile->ls_up); + joy_device->axis_right[0] = find_key(p_profile->rs_left); + joy_device->axis_right[1] = find_key(p_profile->rs_right); + joy_device->axis_right[2] = find_key(p_profile->rs_down); + joy_device->axis_right[3] = find_key(p_profile->rs_up); + + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->circle), CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->cross), CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->square), CELL_PAD_CTRL_SQUARE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, joy_device->trigger_left, CELL_PAD_CTRL_L2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, joy_device->trigger_right, CELL_PAD_CTRL_R2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->l1), CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->r1), CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->start), CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->select), CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->l3), CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->r3), CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, find_key(p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->up), CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->down), CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->left), CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, find_key(p_profile->right), CELL_PAD_CTRL_RIGHT); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, joy_device->axis_left[0], joy_device->axis_left[1]); @@ -197,6 +220,7 @@ void mm_joystick_handler::ThreadProc() { m_dev = bindings[i].first; auto pad = bindings[i].second; + auto profile = m_dev->config; status = joyGetPosEx(m_dev->device_id, &m_dev->device_info); if (status != JOYERR_NOERROR) @@ -256,13 +280,13 @@ void mm_joystick_handler::ThreadProc() u16 lx, ly, rx, ry; // Normalize our two stick's axis based on the thresholds - std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], m_pad_config.lstickdeadzone); - std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone); + std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone); + std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], profile->rstickdeadzone); - if (m_pad_config.padsquircling != 0) + if (profile->padsquircling != 0) { - std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, m_pad_config.padsquircling); - std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling); + std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling); + std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling); } pad->m_sticks[0].m_value = lx; @@ -415,26 +439,27 @@ void mm_joystick_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& { // Update the pad button values based on their type and thresholds. // With this you can use axis or triggers as buttons or vice versa + auto p_profile = m_dev->config; if (keyCode == m_dev->trigger_left) { - pressed = val > (ignore_threshold ? 0 : m_pad_config.ltriggerthreshold); - val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0; + pressed = val > (ignore_threshold ? 0 : p_profile->ltriggerthreshold); + val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0; } else if (keyCode == m_dev->trigger_right) { - pressed = val > (ignore_threshold ? 0 : m_pad_config.rtriggerthreshold); - val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0; + pressed = val > (ignore_threshold ? 0 : p_profile->rtriggerthreshold); + val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0; } else if (std::find(m_dev->axis_left.begin(), m_dev->axis_left.end(), keyCode) != m_dev->axis_left.end()) { - pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone); - val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0; + pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone); + val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, ignore_threshold) : 0; } else if (std::find(m_dev->axis_right.begin(), m_dev->axis_right.end(), keyCode) != m_dev->axis_right.end()) { - pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone); - val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0; + pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone); + val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0; } else // normal button (should in theory also support sensitive buttons) { diff --git a/rpcs3/mm_joystick_handler.h b/rpcs3/mm_joystick_handler.h index c397706c77a8..5fc926a957b9 100644 --- a/rpcs3/mm_joystick_handler.h +++ b/rpcs3/mm_joystick_handler.h @@ -90,6 +90,7 @@ class mm_joystick_handler final : public PadHandlerBase { u32 device_id{ 0 }; std::string device_name{ "" }; + pad_config* config{ nullptr }; JOYINFOEX device_info; JOYCAPS device_caps; u64 trigger_left = 0; @@ -108,6 +109,7 @@ class mm_joystick_handler final : public PadHandlerBase bool bindPadToDevice(std::shared_ptr pad, const std::string& device) override; void ThreadProc() override; void GetNextButtonPress(const std::string& padId, const std::function& callback, bool get_blacklist = false, std::vector buttons = {}) override; + void init_config(pad_config* cfg, const std::string& name) override; private: void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override; diff --git a/rpcs3/pad_thread.cpp b/rpcs3/pad_thread.cpp index df648892ffb5..7a616134f3b0 100644 --- a/rpcs3/pad_thread.cpp +++ b/rpcs3/pad_thread.cpp @@ -42,7 +42,7 @@ void pad_thread::Init(const u32 max_connect) { std::shared_ptr cur_pad_handler; - const auto &handler_type = input_cfg.player_input[i]; + const auto &handler_type = input_cfg.player[i]->handler; if (handlers.count(handler_type) != 0) { @@ -87,11 +87,11 @@ void pad_thread::Init(const u32 max_connect) CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR, CELL_PAD_DEV_TYPE_STANDARD)); - if (cur_pad_handler->bindPadToDevice(m_pads.back(), input_cfg.player_device[i]->to_string()) == false) + if (cur_pad_handler->bindPadToDevice(m_pads.back(), input_cfg.player[i]->device.to_string()) == false) { //Failed to bind the device to cur_pad_handler so binds to NullPadHandler - LOG_ERROR(GENERAL, "Failed to bind device %s to handler %s", input_cfg.player_device[i]->to_string(), handler_type.to_string()); - nullpad->bindPadToDevice(m_pads.back(), input_cfg.player_device[i]->to_string()); + LOG_ERROR(GENERAL, "Failed to bind device %s to handler %s", input_cfg.player[i]->device.to_string(), handler_type.to_string()); + nullpad->bindPadToDevice(m_pads.back(), input_cfg.player[i]->device.to_string()); } } diff --git a/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp b/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp index c69789064377..944a6da804c1 100644 --- a/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/gamepads_settings_dialog.cpp @@ -14,12 +14,39 @@ #include #include - -input_config input_cfg; +#include +#include inline std::string sstr(const QString& _in) { return _in.toStdString(); } constexpr auto qstr = QString::fromStdString; +inline bool CreateConfigFile(const QString& dir, const QString& name) +{ + QString input_dir = qstr(fs::get_config_dir()) + "/InputConfigs/"; + if (!QDir().mkdir(input_dir) && !QDir().exists(input_dir)) + { + LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(input_dir)); + return false; + } + if (!QDir().mkdir(dir) && !QDir().exists(dir)) + { + LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(dir)); + return false; + } + + QString filename = dir + name + ".yml"; + QFile new_file(filename); + + if (!new_file.open(QIODevice::WriteOnly)) + { + LOG_ERROR(GENERAL, "Failed to create file %s", sstr(filename)); + return false; + } + + new_file.close(); + return true; +}; + // taken from https://stackoverflow.com/a/30818424/8353754 // because size policies won't work as expected (see similar bugs in Qt bugtracker) inline void resizeComboBoxView(QComboBox* combo) @@ -80,20 +107,27 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent) co_deviceID[i]->view()->setTextElideMode(Qt::ElideNone); ppad_layout->addWidget(co_deviceID[i]); + co_profile[i] = new QComboBox(); + co_profile[i]->setEnabled(false); + co_profile[i]->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); + co_profile[i]->view()->setTextElideMode(Qt::ElideNone); + ppad_layout->addWidget(co_profile[i]); + QHBoxLayout *button_layout = new QHBoxLayout(); - bu_config[i] = new QPushButton(tr("Config")); + bu_new_profile[i] = new QPushButton(tr("Add Profile")); + bu_new_profile[i]->setEnabled(false); + bu_config[i] = new QPushButton(tr("Configure")); bu_config[i]->setEnabled(false); - bu_config[i]->setFixedSize(bu_config[i]->sizeHint()); - button_layout->addSpacing(bu_config[i]->sizeHint().width()*0.50f); + button_layout->setContentsMargins(0,0,0,0); button_layout->addWidget(bu_config[i]); - button_layout->addSpacing(bu_config[i]->sizeHint().width()*0.50f); + button_layout->addWidget(bu_new_profile[i]); ppad_layout->addLayout(button_layout); grp_player->setLayout(ppad_layout); grp_player->setFixedSize(grp_player->sizeHint()); // fill comboboxes after setting the groupbox's size to prevent stretch - std::vector str_inputs = input_cfg.player_input[0].to_list(); + std::vector str_inputs = input_cfg.player[0]->handler.to_list(); for (int index = 0; index < str_inputs.size(); index++) { co_inputtype[i]->addItem(qstr(str_inputs[index])); @@ -132,7 +166,7 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent) for (int i = 0; i < MAX_PLAYERS; i++) { // No extra loops are necessary because setCurrentText does it for us - co_inputtype[i]->setCurrentText(qstr(input_cfg.player_input[i].to_string())); + co_inputtype[i]->setCurrentText(qstr(input_cfg.player[i]->handler.to_string())); // Device will be empty on some rare occasions, so fill them by force ChangeInputType(i); } @@ -140,18 +174,67 @@ gamepads_settings_dialog::gamepads_settings_dialog(QWidget* parent) for (int i = 0; i < MAX_PLAYERS; i++) { - connect(co_inputtype[i], &QComboBox::currentTextChanged, [=] { ChangeInputType(i); }); + connect(co_inputtype[i], &QComboBox::currentTextChanged, [=] + { + ChangeInputType(i); + }); connect(co_deviceID[i], &QComboBox::currentTextChanged, [=](const QString& dev) { std::string device = sstr(dev); - if (!input_cfg.player_device[i]->from_string(device)) + if (!input_cfg.player[i]->device.from_string(device)) { //Something went wrong LOG_ERROR(GENERAL, "Failed to convert device string: %s", device); return; } }); - connect(bu_config[i], &QAbstractButton::clicked, [=] { ClickConfigButton(i); }); + connect(co_profile[i], &QComboBox::currentTextChanged, [=](const QString& prof) + { + std::string profile = sstr(prof); + if (!input_cfg.player[i]->profile.from_string(profile)) + { + //Something went wrong + LOG_ERROR(GENERAL, "Failed to convert profile string: %s", profile); + return; + } + }); + connect(bu_config[i], &QAbstractButton::clicked, [=] + { + ClickConfigButton(i); + }); + connect(bu_new_profile[i], &QAbstractButton::clicked, [=] + { + QInputDialog* dialog = new QInputDialog(this); + dialog->setWindowTitle(tr("Choose a unique name")); + dialog->setLabelText(tr("Profile Name: ")); + dialog->setFixedSize(500, 100); + + while (dialog->exec() != QDialog::Rejected) + { + QString friendlyName = dialog->textValue(); + if (friendlyName == "") + { + QMessageBox::warning(this, tr("Error"), tr("Name cannot be empty")); + continue; + } + if (friendlyName.contains(".")) + { + QMessageBox::warning(this, tr("Error"), tr("Must choose a name without '.'")); + continue; + } + if (co_profile[i]->findText(friendlyName) != -1) + { + QMessageBox::warning(this, tr("Error"), tr("Please choose a non-existing name")); + continue; + } + if (CreateConfigFile(qstr(PadHandlerBase::get_config_dir(input_cfg.player[i]->handler)), friendlyName)) + { + co_profile[i]->addItem(friendlyName); + co_profile[i]->setCurrentText(friendlyName); + } + break; + } + }); } connect(ok_button, &QPushButton::pressed, this, &gamepads_settings_dialog::SaveExit); connect(cancel_button, &QPushButton::pressed, this, &gamepads_settings_dialog::CancelExit); @@ -167,8 +250,9 @@ void gamepads_settings_dialog::SaveExit() { if (co_deviceID[i]->currentData() == -1) { - input_cfg.player_input[i].from_default(); - input_cfg.player_device[i]->from_default(); + input_cfg.player[i]->handler.from_default(); + input_cfg.player[i]->device.from_default(); + input_cfg.player[i]->profile.from_default(); } } @@ -224,10 +308,11 @@ std::shared_ptr gamepads_settings_dialog::GetHandler(pad_handler void gamepads_settings_dialog::ChangeInputType(int player) { std::string handler = sstr(co_inputtype[player]->currentText()); - std::string device = input_cfg.player_device[player]->to_string(); + std::string device = input_cfg.player[player]->device.to_string(); + std::string profile = input_cfg.player[player]->profile.to_string(); // Change this player's current handler - if (!input_cfg.player_input[player].from_string(handler)) + if (!input_cfg.player[player]->handler.from_string(handler)) { //Something went wrong LOG_ERROR(GENERAL, "Failed to convert input string:%s", handler); @@ -235,7 +320,7 @@ void gamepads_settings_dialog::ChangeInputType(int player) } // Get this player's current handler and it's currently available devices - std::shared_ptr cur_pad_handler = GetHandler(input_cfg.player_input[player]); + std::shared_ptr cur_pad_handler = GetHandler(input_cfg.player[player]->handler); std::vector list_devices = cur_pad_handler->ListDevices(); // Refill the device combobox with currently available devices @@ -258,19 +343,60 @@ void gamepads_settings_dialog::ChangeInputType(int player) co_deviceID[player]->addItem(tr("No Device Detected"), -1); } - // Update view and enable configuration if possible + bool config_enabled = device_found && cur_pad_handler->has_config(); + co_profile[player]->clear(); + + // update profile list if possible + if (config_enabled) + { + QString s_profile_dir = qstr(PadHandlerBase::get_config_dir(cur_pad_handler->m_type)); + QStringList profiles = gui_settings::GetDirEntries(QDir(s_profile_dir), QStringList() << "*.yml"); + + if (profiles.isEmpty()) + { + QString def_name = "Default Profile"; + if (!CreateConfigFile(s_profile_dir, def_name)) + { + config_enabled = false; + } + else + { + co_profile[player]->addItem(def_name); + co_profile[player]->setCurrentText(def_name); + } + } + else + { + for (const auto& prof : profiles) + { + co_profile[player]->addItem(prof); + } + co_profile[player]->setCurrentText(qstr(profile)); + } + } + + if (!config_enabled) + co_profile[player]->addItem(tr("No Profiles")); + + // enable configuration and profile list if possible + bu_config[player]->setEnabled(config_enabled); + bu_new_profile[player]->setEnabled(config_enabled); + co_profile[player]->setEnabled(config_enabled); + + // update view resizeComboBoxView(co_deviceID[player]); - bu_config[player]->setEnabled(device_found && cur_pad_handler->has_config()); + resizeComboBoxView(co_profile[player]); } void gamepads_settings_dialog::ClickConfigButton(int player) { // Get this player's current handler and open its pad settings dialog - std::shared_ptr cur_pad_handler = GetHandler(input_cfg.player_input[player]); + std::shared_ptr cur_pad_handler = GetHandler(input_cfg.player[player]->handler); if (cur_pad_handler->has_config()) { std::string device = sstr(co_deviceID[player]->currentText()); - pad_settings_dialog dlg(device, cur_pad_handler); + std::string profile = sstr(co_profile[player]->currentText()); + pad_settings_dialog dlg(device, profile, cur_pad_handler); dlg.exec(); } } diff --git a/rpcs3/rpcs3qt/gamepads_settings_dialog.h b/rpcs3/rpcs3qt/gamepads_settings_dialog.h index 08ff5c7e85c0..5581e4343c2f 100644 --- a/rpcs3/rpcs3qt/gamepads_settings_dialog.h +++ b/rpcs3/rpcs3qt/gamepads_settings_dialog.h @@ -12,50 +12,6 @@ #include "../../Utilities/File.h" #include "../Emu/Io/PadHandler.h" -struct input_config final : cfg::node -{ - const std::string cfg_name = fs::get_config_dir() + "/config_input.yml"; - - cfg::_enum player_input[7]{ - { this, "Player 1 Input", pad_handler::keyboard }, - { this, "Player 2 Input", pad_handler::null }, - { this, "Player 3 Input", pad_handler::null }, - { this, "Player 4 Input", pad_handler::null }, - { this, "Player 5 Input", pad_handler::null }, - { this, "Player 6 Input", pad_handler::null }, - { this, "Player 7 Input", pad_handler::null } }; - - cfg::string player1{ this, "Player 1 Device", "Keyboard" }; - cfg::string player2{ this, "Player 2 Device", "Default Null Device" }; - cfg::string player3{ this, "Player 3 Device", "Default Null Device" }; - cfg::string player4{ this, "Player 4 Device", "Default Null Device" }; - cfg::string player5{ this, "Player 5 Device", "Default Null Device" }; - cfg::string player6{ this, "Player 6 Device", "Default Null Device" }; - cfg::string player7{ this, "Player 7 Device", "Default Null Device" }; - - cfg::string *player_device[7]{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc! - - bool load() - { - if (fs::file cfg_file{ cfg_name, fs::read }) - { - return from_string(cfg_file.to_string()); - } - - return false; - } - - void save() - { - fs::file(cfg_name, fs::rewrite).write(to_string()); - } - - bool exist() - { - return fs::is_file(cfg_name); - } -}; - extern input_config input_cfg; class gamepads_settings_dialog : public QDialog @@ -72,7 +28,9 @@ class gamepads_settings_dialog : public QDialog protected: QComboBox *co_inputtype[7]; QComboBox *co_deviceID[7]; + QComboBox *co_profile[7]; QPushButton *bu_config[7]; + QPushButton *bu_new_profile[7]; public: gamepads_settings_dialog(QWidget* parent); diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp index c5d708aae0bf..ec32dcada857 100644 --- a/rpcs3/rpcs3qt/gui_settings.cpp +++ b/rpcs3/rpcs3qt/gui_settings.cpp @@ -321,6 +321,17 @@ QStringList gui_settings::GetConfigEntries() return res; } +QStringList gui_settings::GetDirEntries(const QDir& dir, const QStringList& nameFilters) +{ + QFileInfoList entries = dir.entryInfoList(nameFilters, QDir::Files); + QStringList res; + for (const QFileInfo &entry : entries) + { + res.append(entry.baseName()); + } + return res; +} + void gui_settings::BackupSettingsToTarget(const QString& friendlyName) { QSettings target(ComputeSettingsDir() + friendlyName + ".ini", QSettings::Format::IniFormat); diff --git a/rpcs3/rpcs3qt/gui_settings.h b/rpcs3/rpcs3qt/gui_settings.h index 364a3b0e6b1d..95e0f0de0c5f 100644 --- a/rpcs3/rpcs3qt/gui_settings.h +++ b/rpcs3/rpcs3qt/gui_settings.h @@ -230,6 +230,7 @@ class gui_settings : public QObject bool GetGamelistColVisibility(int col); QColor GetCustomColor(int col); QStringList GetConfigEntries(); + static QStringList GetDirEntries(const QDir& dir, const QStringList& nameFilters); QString GetCurrentStylesheetPath(); QStringList GetStylesheetEntries(); QStringList GetGameListCategoryFilters(); diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index 22d816164921..1d52907e91c4 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -13,11 +13,9 @@ inline std::string sstr(const QString& _in) { return _in.toStdString(); } constexpr auto qstr = QString::fromStdString; -pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_ptr handler, QWidget *parent) - : QDialog(parent), ui(new Ui::pad_settings_dialog), m_handler_cfg(handler->GetConfig()), m_device_name(device), m_handler(handler) +pad_settings_dialog::pad_settings_dialog(const std::string& device, const std::string& profile, std::shared_ptr handler, QWidget *parent) + : QDialog(parent), ui(new Ui::pad_settings_dialog), m_device_name(device), m_handler(handler), m_handler_type(handler->m_type) { - m_handler_cfg->load(); - ui->setupUi(this); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); @@ -28,37 +26,47 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_ m_padButtons = new QButtonGroup(this); m_palette = ui->b_left->palette(); // save normal palette - ui->chb_vibration_large->setChecked((bool)m_handler_cfg->enable_vibration_motor_large); - ui->chb_vibration_small->setChecked((bool)m_handler_cfg->enable_vibration_motor_small); - ui->chb_vibration_switch->setChecked((bool)m_handler_cfg->switch_vibration_motors); + std::string cfg_name = PadHandlerBase::get_config_dir(m_handler_type) + profile + ".yml"; // Adjust to the different pad handlers - if (m_handler_cfg->cfg_type == "keyboard") + if (m_handler_type == pad_handler::keyboard) { setWindowTitle(tr("Configure Keyboard")); - m_handler_type = handler_type::handler_type_keyboard; ui->b_blacklist->setEnabled(false); + ((keyboard_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); } - else if (m_handler_cfg->cfg_type == "xinput") + else if (m_handler_type == pad_handler::ds4) { - setWindowTitle(tr("Configure XInput")); - m_handler_type = handler_type::handler_type_xinput; + setWindowTitle(tr("Configure DS4")); + ((ds4_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); } - else if (m_handler_cfg->cfg_type == "ds4") +#ifdef _MSC_VER + else if (m_handler_type == pad_handler::xinput) { - setWindowTitle(tr("Configure DS4")); - m_handler_type = handler_type::handler_type_ds4; + setWindowTitle(tr("Configure XInput")); + ((xinput_pad_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); } - else if (m_handler_cfg->cfg_type == "mmjoystick") +#endif +#ifdef _WIN32 + else if (m_handler_type == pad_handler::mm) { setWindowTitle(tr("Configure MMJoystick")); - m_handler_type = handler_type::handler_type_mmjoy; + ((mm_joystick_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); } - else if (m_handler_cfg->cfg_type == "evdev") +#endif +#ifdef HAVE_LIBEVDEV + else if (m_handler_type == pad_handler::evdev) { setWindowTitle(tr("Configure evdev")); - m_handler_type = handler_type::handler_type_evdev; + ((evdev_joystick_handler*)m_handler.get())->init_config(&m_handler_cfg, cfg_name); } +#endif + + m_handler_cfg.load(); + + ui->chb_vibration_large->setChecked((bool)m_handler_cfg.enable_vibration_motor_large); + ui->chb_vibration_small->setChecked((bool)m_handler_cfg.enable_vibration_motor_small); + ui->chb_vibration_switch->setChecked((bool)m_handler_cfg.switch_vibration_motors); // Enable Button Remapping if (m_handler->has_config()) @@ -85,7 +93,7 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_ if (val <= 0) return; - LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_handler_cfg->cfg_type, name, val); + LOG_NOTICE(HLE, "GetNextButtonPress: %s button %s pressed with value %d", m_handler_type, name, val); if (m_button_id > button_ids::id_pad_begin && m_button_id < button_ids::id_pad_end) { m_cfg_entries[m_button_id].key = name; @@ -185,14 +193,14 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_ }; // Enable Trigger Thresholds - initSlider(ui->slider_trigger_left, m_handler_cfg->ltriggerthreshold, 0, m_handler->trigger_max); - initSlider(ui->slider_trigger_right, m_handler_cfg->rtriggerthreshold, 0, m_handler->trigger_max); + initSlider(ui->slider_trigger_left, m_handler_cfg.ltriggerthreshold, 0, m_handler->trigger_max); + initSlider(ui->slider_trigger_right, m_handler_cfg.rtriggerthreshold, 0, m_handler->trigger_max); ui->preview_trigger_left->setRange(0, m_handler->trigger_max); ui->preview_trigger_right->setRange(0, m_handler->trigger_max); // Enable Stick Deadzones - initSlider(ui->slider_stick_left, m_handler_cfg->lstickdeadzone, 0, m_handler->thumb_max); - initSlider(ui->slider_stick_right, m_handler_cfg->rstickdeadzone, 0, m_handler->thumb_max); + initSlider(ui->slider_stick_left, m_handler_cfg.lstickdeadzone, 0, m_handler->thumb_max); + initSlider(ui->slider_stick_right, m_handler_cfg.rstickdeadzone, 0, m_handler->thumb_max); RepaintPreviewLabel(ui->preview_stick_left, ui->slider_stick_left->value(), ui->slider_stick_left->sizeHint().width(), lx, ly); connect(ui->slider_stick_left, &QSlider::valueChanged, [&](int value) @@ -224,37 +232,37 @@ pad_settings_dialog::pad_settings_dialog(const std::string& device, std::shared_ button->installEventFilter(this); }; - insertButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &m_handler_cfg->ls_left); - insertButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &m_handler_cfg->ls_down); - insertButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &m_handler_cfg->ls_right); - insertButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &m_handler_cfg->ls_up); + insertButton(button_ids::id_pad_lstick_left, ui->b_lstick_left, &m_handler_cfg.ls_left); + insertButton(button_ids::id_pad_lstick_down, ui->b_lstick_down, &m_handler_cfg.ls_down); + insertButton(button_ids::id_pad_lstick_right, ui->b_lstick_right, &m_handler_cfg.ls_right); + insertButton(button_ids::id_pad_lstick_up, ui->b_lstick_up, &m_handler_cfg.ls_up); - insertButton(button_ids::id_pad_left, ui->b_left, &m_handler_cfg->left); - insertButton(button_ids::id_pad_down, ui->b_down, &m_handler_cfg->down); - insertButton(button_ids::id_pad_right, ui->b_right, &m_handler_cfg->right); - insertButton(button_ids::id_pad_up, ui->b_up, &m_handler_cfg->up); + insertButton(button_ids::id_pad_left, ui->b_left, &m_handler_cfg.left); + insertButton(button_ids::id_pad_down, ui->b_down, &m_handler_cfg.down); + insertButton(button_ids::id_pad_right, ui->b_right, &m_handler_cfg.right); + insertButton(button_ids::id_pad_up, ui->b_up, &m_handler_cfg.up); - insertButton(button_ids::id_pad_l1, ui->b_shift_l1, &m_handler_cfg->l1); - insertButton(button_ids::id_pad_l2, ui->b_shift_l2, &m_handler_cfg->l2); - insertButton(button_ids::id_pad_l3, ui->b_shift_l3, &m_handler_cfg->l3); + insertButton(button_ids::id_pad_l1, ui->b_shift_l1, &m_handler_cfg.l1); + insertButton(button_ids::id_pad_l2, ui->b_shift_l2, &m_handler_cfg.l2); + insertButton(button_ids::id_pad_l3, ui->b_shift_l3, &m_handler_cfg.l3); - insertButton(button_ids::id_pad_start, ui->b_start, &m_handler_cfg->start); - insertButton(button_ids::id_pad_select, ui->b_select, &m_handler_cfg->select); - insertButton(button_ids::id_pad_ps, ui->b_ps, &m_handler_cfg->ps); + insertButton(button_ids::id_pad_start, ui->b_start, &m_handler_cfg.start); + insertButton(button_ids::id_pad_select, ui->b_select, &m_handler_cfg.select); + insertButton(button_ids::id_pad_ps, ui->b_ps, &m_handler_cfg.ps); - insertButton(button_ids::id_pad_r1, ui->b_shift_r1, &m_handler_cfg->r1); - insertButton(button_ids::id_pad_r2, ui->b_shift_r2, &m_handler_cfg->r2); - insertButton(button_ids::id_pad_r3, ui->b_shift_r3, &m_handler_cfg->r3); + insertButton(button_ids::id_pad_r1, ui->b_shift_r1, &m_handler_cfg.r1); + insertButton(button_ids::id_pad_r2, ui->b_shift_r2, &m_handler_cfg.r2); + insertButton(button_ids::id_pad_r3, ui->b_shift_r3, &m_handler_cfg.r3); - insertButton(button_ids::id_pad_square, ui->b_square, &m_handler_cfg->square); - insertButton(button_ids::id_pad_cross, ui->b_cross, &m_handler_cfg->cross); - insertButton(button_ids::id_pad_circle, ui->b_circle, &m_handler_cfg->circle); - insertButton(button_ids::id_pad_triangle, ui->b_triangle, &m_handler_cfg->triangle); + insertButton(button_ids::id_pad_square, ui->b_square, &m_handler_cfg.square); + insertButton(button_ids::id_pad_cross, ui->b_cross, &m_handler_cfg.cross); + insertButton(button_ids::id_pad_circle, ui->b_circle, &m_handler_cfg.circle); + insertButton(button_ids::id_pad_triangle, ui->b_triangle, &m_handler_cfg.triangle); - insertButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &m_handler_cfg->rs_left); - insertButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &m_handler_cfg->rs_down); - insertButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg->rs_right); - insertButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg->rs_up); + insertButton(button_ids::id_pad_rstick_left, ui->b_rstick_left, &m_handler_cfg.rs_left); + insertButton(button_ids::id_pad_rstick_down, ui->b_rstick_down, &m_handler_cfg.rs_down); + insertButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg.rs_right); + insertButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg.rs_up); m_padButtons->addButton(ui->b_reset, button_ids::id_reset_parameters); m_padButtons->addButton(ui->b_blacklist, button_ids::id_blacklist); @@ -345,7 +353,7 @@ void pad_settings_dialog::RepaintPreviewLabel(QLabel* l, int dz, int w, int x, i void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) { - if (m_handler_type != handler_type::handler_type_keyboard) + if (m_handler_type != pad_handler::keyboard) { return; } @@ -370,7 +378,7 @@ void pad_settings_dialog::keyPressEvent(QKeyEvent *keyEvent) void pad_settings_dialog::mousePressEvent(QMouseEvent* event) { - if (m_handler_type != handler_type::handler_type_keyboard) + if (m_handler_type != pad_handler::keyboard) { return; } @@ -407,17 +415,17 @@ void pad_settings_dialog::UpdateLabel(bool is_reset) { if (m_handler->has_rumble()) { - ui->chb_vibration_large->setChecked((bool)m_handler_cfg->enable_vibration_motor_large); - ui->chb_vibration_small->setChecked((bool)m_handler_cfg->enable_vibration_motor_small); - ui->chb_vibration_switch->setChecked((bool)m_handler_cfg->switch_vibration_motors); + ui->chb_vibration_large->setChecked((bool)m_handler_cfg.enable_vibration_motor_large); + ui->chb_vibration_small->setChecked((bool)m_handler_cfg.enable_vibration_motor_small); + ui->chb_vibration_switch->setChecked((bool)m_handler_cfg.switch_vibration_motors); } if (m_handler->has_deadzones()) { - ui->slider_trigger_left->setValue(m_handler_cfg->ltriggerthreshold); - ui->slider_trigger_right->setValue(m_handler_cfg->rtriggerthreshold); - ui->slider_stick_left->setValue(m_handler_cfg->lstickdeadzone); - ui->slider_stick_right->setValue(m_handler_cfg->rstickdeadzone); + ui->slider_trigger_left->setValue(m_handler_cfg.ltriggerthreshold); + ui->slider_trigger_right->setValue(m_handler_cfg.rtriggerthreshold); + ui->slider_stick_left->setValue(m_handler_cfg.lstickdeadzone); + ui->slider_stick_right->setValue(m_handler_cfg.rstickdeadzone); } } @@ -450,20 +458,20 @@ void pad_settings_dialog::SaveConfig() if (m_handler->has_rumble()) { - m_handler_cfg->enable_vibration_motor_large.set(ui->chb_vibration_large->isChecked()); - m_handler_cfg->enable_vibration_motor_small.set(ui->chb_vibration_small->isChecked()); - m_handler_cfg->switch_vibration_motors.set(ui->chb_vibration_switch->isChecked()); + m_handler_cfg.enable_vibration_motor_large.set(ui->chb_vibration_large->isChecked()); + m_handler_cfg.enable_vibration_motor_small.set(ui->chb_vibration_small->isChecked()); + m_handler_cfg.switch_vibration_motors.set(ui->chb_vibration_switch->isChecked()); } if (m_handler->has_deadzones()) { - m_handler_cfg->ltriggerthreshold.set(ui->slider_trigger_left->value()); - m_handler_cfg->rtriggerthreshold.set(ui->slider_trigger_right->value()); - m_handler_cfg->lstickdeadzone.set(ui->slider_stick_left->value()); - m_handler_cfg->rstickdeadzone.set(ui->slider_stick_right->value()); + m_handler_cfg.ltriggerthreshold.set(ui->slider_trigger_left->value()); + m_handler_cfg.rtriggerthreshold.set(ui->slider_trigger_right->value()); + m_handler_cfg.lstickdeadzone.set(ui->slider_stick_left->value()); + m_handler_cfg.rstickdeadzone.set(ui->slider_stick_right->value()); } - m_handler_cfg->save(); + m_handler_cfg.save(); } void pad_settings_dialog::OnPadButtonClicked(int id) @@ -476,7 +484,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id) return; case button_ids::id_reset_parameters: ReactivateButtons(); - m_handler_cfg->from_default(); + m_handler_cfg.from_default(); UpdateLabel(true); return; case button_ids::id_blacklist: diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 1f767388d515..8b683576d3fb 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -17,6 +17,12 @@ #ifdef _WIN32 #include "xinput_pad_handler.h" #endif +#ifdef _MSC_VER +#include "mm_joystick_handler.h" +#endif +#ifdef HAVE_LIBEVDEV +#include "evdev_joystick_handler.h" +#endif #include "ds4_pad_handler.h" namespace Ui @@ -72,15 +78,6 @@ class pad_settings_dialog : public QDialog id_cancel }; - enum handler_type - { - handler_type_keyboard, - handler_type_xinput, - handler_type_ds4, - handler_type_mmjoy, - handler_type_evdev - }; - struct pad_button { cfg::string* cfg_name; @@ -109,9 +106,9 @@ private Q_SLOTS: QPalette m_palette; // Pad Handlers + pad_handler m_handler_type; std::shared_ptr m_handler; - handler_type m_handler_type; - pad_config* m_handler_cfg; + pad_config m_handler_cfg; std::string m_device_name; // Remap Timer @@ -129,7 +126,7 @@ private Q_SLOTS: void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y); public: - explicit pad_settings_dialog(const std::string& device, std::shared_ptr handler, QWidget *parent = nullptr); + explicit pad_settings_dialog(const std::string& device, const std::string& profile, std::shared_ptr handler, QWidget *parent = nullptr); ~pad_settings_dialog(); /** Handle keyboard handler input */ diff --git a/rpcs3/xinput_pad_handler.cpp b/rpcs3/xinput_pad_handler.cpp index 3f81f5be35bf..bdc3bac3d9c5 100644 --- a/rpcs3/xinput_pad_handler.cpp +++ b/rpcs3/xinput_pad_handler.cpp @@ -1,7 +1,6 @@ #ifdef _MSC_VER #include "xinput_pad_handler.h" -#include "rpcs3qt/pad_settings_dialog.h" xinput_pad_handler::xinput_pad_handler() : library(nullptr), xinputGetState(nullptr), xinputEnable(nullptr), @@ -15,46 +14,20 @@ xinput_pad_handler::xinput_pad_handler() : vibration_min = 0; vibration_max = 65535; - // Set this handler's type and save location - m_pad_config.cfg_type = "xinput"; - m_pad_config.cfg_name = fs::get_config_dir() + "/config_xinput.yml"; + m_type = pad_handler::xinput; - // Set default button mapping - m_pad_config.ls_left.def = button_list.at(XInputKeyCodes::LSXNeg); - m_pad_config.ls_down.def = button_list.at(XInputKeyCodes::LSYNeg); - m_pad_config.ls_right.def = button_list.at(XInputKeyCodes::LSXPos); - m_pad_config.ls_up.def = button_list.at(XInputKeyCodes::LSYPos); - m_pad_config.rs_left.def = button_list.at(XInputKeyCodes::RSXNeg); - m_pad_config.rs_down.def = button_list.at(XInputKeyCodes::RSYNeg); - m_pad_config.rs_right.def = button_list.at(XInputKeyCodes::RSXPos); - m_pad_config.rs_up.def = button_list.at(XInputKeyCodes::RSYPos); - m_pad_config.start.def = button_list.at(XInputKeyCodes::Start); - m_pad_config.select.def = button_list.at(XInputKeyCodes::Back); - m_pad_config.ps.def = button_list.at(XInputKeyCodes::Guide); - m_pad_config.square.def = button_list.at(XInputKeyCodes::X); - m_pad_config.cross.def = button_list.at(XInputKeyCodes::A); - m_pad_config.circle.def = button_list.at(XInputKeyCodes::B); - m_pad_config.triangle.def = button_list.at(XInputKeyCodes::Y); - m_pad_config.left.def = button_list.at(XInputKeyCodes::Left); - m_pad_config.down.def = button_list.at(XInputKeyCodes::Down); - m_pad_config.right.def = button_list.at(XInputKeyCodes::Right); - m_pad_config.up.def = button_list.at(XInputKeyCodes::Up); - m_pad_config.r1.def = button_list.at(XInputKeyCodes::RB); - m_pad_config.r2.def = button_list.at(XInputKeyCodes::RT); - m_pad_config.r3.def = button_list.at(XInputKeyCodes::RS); - m_pad_config.l1.def = button_list.at(XInputKeyCodes::LB); - m_pad_config.l2.def = button_list.at(XInputKeyCodes::LT); - m_pad_config.l3.def = button_list.at(XInputKeyCodes::LS); - - // Set default misc variables - m_pad_config.lstickdeadzone.def = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; // between 0 and 32767 - m_pad_config.rstickdeadzone.def = XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; // between 0 and 32767 - m_pad_config.ltriggerthreshold.def = XINPUT_GAMEPAD_TRIGGER_THRESHOLD; // between 0 and 255 - m_pad_config.rtriggerthreshold.def = XINPUT_GAMEPAD_TRIGGER_THRESHOLD; // between 0 and 255 - m_pad_config.padsquircling.def = 8000; + input_cfg.from_default(); + input_cfg.load(); - // apply defaults - m_pad_config.from_default(); + int index = 0; + for (int i = 0; i < MAX_GAMEPADS; i++) + { + if (input_cfg.player[i]->handler == pad_handler::xinput) + { + init_config(&m_pad_configs[index], get_config_filename(input_cfg, i)); + index++; + } + } // set capabilities b_has_config = true; @@ -70,6 +43,49 @@ xinput_pad_handler::~xinput_pad_handler() Close(); } +void xinput_pad_handler::init_config(pad_config* cfg, const std::string& name) +{ + // Set this profile's save location + cfg->cfg_name = name; + + // Set default button mapping + cfg->ls_left.def = button_list.at(XInputKeyCodes::LSXNeg); + cfg->ls_down.def = button_list.at(XInputKeyCodes::LSYNeg); + cfg->ls_right.def = button_list.at(XInputKeyCodes::LSXPos); + cfg->ls_up.def = button_list.at(XInputKeyCodes::LSYPos); + cfg->rs_left.def = button_list.at(XInputKeyCodes::RSXNeg); + cfg->rs_down.def = button_list.at(XInputKeyCodes::RSYNeg); + cfg->rs_right.def = button_list.at(XInputKeyCodes::RSXPos); + cfg->rs_up.def = button_list.at(XInputKeyCodes::RSYPos); + cfg->start.def = button_list.at(XInputKeyCodes::Start); + cfg->select.def = button_list.at(XInputKeyCodes::Back); + cfg->ps.def = button_list.at(XInputKeyCodes::Guide); + cfg->square.def = button_list.at(XInputKeyCodes::X); + cfg->cross.def = button_list.at(XInputKeyCodes::A); + cfg->circle.def = button_list.at(XInputKeyCodes::B); + cfg->triangle.def = button_list.at(XInputKeyCodes::Y); + cfg->left.def = button_list.at(XInputKeyCodes::Left); + cfg->down.def = button_list.at(XInputKeyCodes::Down); + cfg->right.def = button_list.at(XInputKeyCodes::Right); + cfg->up.def = button_list.at(XInputKeyCodes::Up); + cfg->r1.def = button_list.at(XInputKeyCodes::RB); + cfg->r2.def = button_list.at(XInputKeyCodes::RT); + cfg->r3.def = button_list.at(XInputKeyCodes::RS); + cfg->l1.def = button_list.at(XInputKeyCodes::LB); + cfg->l2.def = button_list.at(XInputKeyCodes::LT); + cfg->l3.def = button_list.at(XInputKeyCodes::LS); + + // Set default misc variables + cfg->lstickdeadzone.def = XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE; // between 0 and 32767 + cfg->rstickdeadzone.def = XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE; // between 0 and 32767 + cfg->ltriggerthreshold.def = XINPUT_GAMEPAD_TRIGGER_THRESHOLD; // between 0 and 255 + cfg->rtriggerthreshold.def = XINPUT_GAMEPAD_TRIGGER_THRESHOLD; // between 0 and 255 + cfg->padsquircling.def = 8000; + + // apply defaults + cfg->from_default(); +} + void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function& callback, bool get_blacklist, std::vector buttons) { if (get_blacklist) @@ -152,29 +168,30 @@ void xinput_pad_handler::TranslateButtonPress(u64 keyCode, bool& pressed, u16& v { // Update the pad button values based on their type and thresholds. // With this you can use axis or triggers as buttons or vice versa + auto p_profile = m_dev->config; switch (keyCode) { case XInputKeyCodes::LT: - pressed = val > m_pad_config.ltriggerthreshold; - val = pressed ? NormalizeTriggerInput(val, m_pad_config.ltriggerthreshold) : 0; + pressed = val > p_profile->ltriggerthreshold; + val = pressed ? NormalizeTriggerInput(val, p_profile->ltriggerthreshold) : 0; break; case XInputKeyCodes::RT: - pressed = val > m_pad_config.rtriggerthreshold; - val = pressed ? NormalizeTriggerInput(val, m_pad_config.rtriggerthreshold) : 0; + pressed = val > p_profile->rtriggerthreshold; + val = pressed ? NormalizeTriggerInput(val, p_profile->rtriggerthreshold) : 0; break; case XInputKeyCodes::LSXNeg: case XInputKeyCodes::LSXPos: case XInputKeyCodes::LSYPos: case XInputKeyCodes::LSYNeg: - pressed = val > (ignore_threshold ? 0 : m_pad_config.lstickdeadzone); - val = pressed ? NormalizeStickInput(val, m_pad_config.lstickdeadzone, ignore_threshold) : 0; + pressed = val > (ignore_threshold ? 0 : p_profile->lstickdeadzone); + val = pressed ? NormalizeStickInput(val, p_profile->lstickdeadzone, ignore_threshold) : 0; break; case XInputKeyCodes::RSXNeg: case XInputKeyCodes::RSXPos: case XInputKeyCodes::RSYPos: case XInputKeyCodes::RSYNeg: - pressed = val > (ignore_threshold ? 0 : m_pad_config.rstickdeadzone); - val = pressed ? NormalizeStickInput(val, m_pad_config.rstickdeadzone, ignore_threshold) : 0; + pressed = val > (ignore_threshold ? 0 : p_profile->rstickdeadzone); + val = pressed ? NormalizeStickInput(val, p_profile->rstickdeadzone, ignore_threshold) : 0; break; default: // normal button (should in theory also support sensitive buttons) pressed = val > 0; @@ -293,10 +310,6 @@ bool xinput_pad_handler::Init() if (!is_init) return false; - m_pad_config.load(); - if (!m_pad_config.exist()) - m_pad_config.save(); - return true; } @@ -316,8 +329,9 @@ void xinput_pad_handler::ThreadProc() { for (auto &bind : bindings) { - auto device = bind.first; - auto padnum = device->deviceNumber; + m_dev = bind.first; + auto padnum = m_dev->deviceNumber; + auto profile = m_dev->config; auto pad = bind.second; result = (*xinputGetState)(padnum, &state); @@ -388,13 +402,13 @@ void xinput_pad_handler::ThreadProc() u16 lx, ly, rx, ry; // Normalize our two stick's axis based on the thresholds - std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], m_pad_config.lstickdeadzone); - std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], m_pad_config.rstickdeadzone); + std::tie(lx, ly) = NormalizeStickDeadzone(stick_val[0], stick_val[1], profile->lstickdeadzone); + std::tie(rx, ry) = NormalizeStickDeadzone(stick_val[2], stick_val[3], profile->rstickdeadzone); - if (m_pad_config.padsquircling != 0) + if (profile->padsquircling != 0) { - std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, m_pad_config.padsquircling); - std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, m_pad_config.padsquircling); + std::tie(lx, ly) = ConvertToSquirclePoint(lx, ly, profile->padsquircling); + std::tie(rx, ry) = ConvertToSquirclePoint(rx, ry, profile->padsquircling); } pad->m_sticks[0].m_value = lx; @@ -410,19 +424,19 @@ void xinput_pad_handler::ThreadProc() // The left motor is the low-frequency rumble motor. The right motor is the high-frequency rumble motor. // The two motors are not the same, and they create different vibration effects. Values range between 0 to 65535. - int idx_l = m_pad_config.switch_vibration_motors ? 1 : 0; - int idx_s = m_pad_config.switch_vibration_motors ? 0 : 1; + int idx_l = profile->switch_vibration_motors ? 1 : 0; + int idx_s = profile->switch_vibration_motors ? 0 : 1; - int speed_large = m_pad_config.enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min; - int speed_small = m_pad_config.enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min; + int speed_large = profile->enable_vibration_motor_large ? pad->m_vibrateMotors[idx_l].m_value * 257 : vibration_min; + int speed_small = profile->enable_vibration_motor_small ? pad->m_vibrateMotors[idx_s].m_value * 257 : vibration_min; - device->newVibrateData = device->newVibrateData || device->largeVibrate != speed_large || device->smallVibrate != speed_small; + m_dev->newVibrateData = m_dev->newVibrateData || m_dev->largeVibrate != speed_large || m_dev->smallVibrate != speed_small; - device->largeVibrate = speed_large; - device->smallVibrate = speed_small; + m_dev->largeVibrate = speed_large; + m_dev->smallVibrate = speed_small; // XBox One Controller can't handle faster vibration updates than ~10ms. Elite is even worse. So I'll use 20ms to be on the safe side. No lag was noticable. - if (device->newVibrateData && (clock() - device->last_vibration > 20)) + if (m_dev->newVibrateData && (clock() - m_dev->last_vibration > 20)) { XINPUT_VIBRATION vibrate; vibrate.wLeftMotorSpeed = speed_large; @@ -430,8 +444,8 @@ void xinput_pad_handler::ThreadProc() if ((*xinputSetState)(padnum, &vibrate) == ERROR_SUCCESS) { - device->newVibrateData = false; - device->last_vibration = clock(); + m_dev->newVibrateData = false; + m_dev->last_vibration = clock(); } } @@ -464,10 +478,15 @@ bool xinput_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::st if (device_number < 0) return false; - std::shared_ptr device_id = std::make_shared(); - device_id->deviceNumber = static_cast(device_number); + std::shared_ptr x_device = std::make_shared(); + x_device->deviceNumber = static_cast(device_number); - m_pad_config.load(); + int index = static_cast(bindings.size()); + m_pad_configs[index].load(); + x_device->config = &m_pad_configs[index]; + pad_config* p_profile = x_device->config; + if (p_profile == nullptr) + return false; pad->Init ( @@ -477,29 +496,29 @@ bool xinput_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::st CELL_PAD_DEV_TYPE_STANDARD ); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.up), CELL_PAD_CTRL_UP); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.down), CELL_PAD_CTRL_DOWN); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.left), CELL_PAD_CTRL_LEFT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.right), CELL_PAD_CTRL_RIGHT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.start), CELL_PAD_CTRL_START); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.select), CELL_PAD_CTRL_SELECT); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.l3), CELL_PAD_CTRL_L3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, m_pad_config.r3), CELL_PAD_CTRL_R3); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.l1), CELL_PAD_CTRL_L1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.r1), CELL_PAD_CTRL_R1); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.cross), CELL_PAD_CTRL_CROSS); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.circle), CELL_PAD_CTRL_CIRCLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.square), CELL_PAD_CTRL_SQUARE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.triangle), CELL_PAD_CTRL_TRIANGLE); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.l2), CELL_PAD_CTRL_L2); - pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, m_pad_config.r2), CELL_PAD_CTRL_R2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->up), CELL_PAD_CTRL_UP); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->down), CELL_PAD_CTRL_DOWN); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->left), CELL_PAD_CTRL_LEFT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->right), CELL_PAD_CTRL_RIGHT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->start), CELL_PAD_CTRL_START); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->select), CELL_PAD_CTRL_SELECT); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->l3), CELL_PAD_CTRL_L3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, FindKeyCode(button_list, p_profile->r3), CELL_PAD_CTRL_R3); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l1), CELL_PAD_CTRL_L1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r1), CELL_PAD_CTRL_R1); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->ps), 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->cross), CELL_PAD_CTRL_CROSS); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->circle), CELL_PAD_CTRL_CIRCLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->square), CELL_PAD_CTRL_SQUARE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->triangle), CELL_PAD_CTRL_TRIANGLE); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->l2), CELL_PAD_CTRL_L2); + pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, FindKeyCode(button_list, p_profile->r2), CELL_PAD_CTRL_R2); pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, m_pad_config.ls_left), FindKeyCode(button_list, m_pad_config.ls_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, m_pad_config.ls_down), FindKeyCode(button_list, m_pad_config.ls_up)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, m_pad_config.rs_left), FindKeyCode(button_list, m_pad_config.rs_right)); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, m_pad_config.rs_down), FindKeyCode(button_list, m_pad_config.rs_up)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, FindKeyCode(button_list, p_profile->ls_left), FindKeyCode(button_list, p_profile->ls_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, FindKeyCode(button_list, p_profile->ls_down), FindKeyCode(button_list, p_profile->ls_up)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, FindKeyCode(button_list, p_profile->rs_left), FindKeyCode(button_list, p_profile->rs_right)); + pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, FindKeyCode(button_list, p_profile->rs_down), FindKeyCode(button_list, p_profile->rs_up)); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 512); pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 399); @@ -509,7 +528,7 @@ bool xinput_pad_handler::bindPadToDevice(std::shared_ptr pad, const std::st pad->m_vibrateMotors.emplace_back(true, 0); pad->m_vibrateMotors.emplace_back(false, 0); - bindings.emplace_back(device_id, pad); + bindings.emplace_back(x_device, pad); return true; } diff --git a/rpcs3/xinput_pad_handler.h b/rpcs3/xinput_pad_handler.h index 93ddead64382..472fdebd8f1e 100644 --- a/rpcs3/xinput_pad_handler.h +++ b/rpcs3/xinput_pad_handler.h @@ -95,6 +95,7 @@ class xinput_pad_handler final : public PadHandlerBase u8 largeVibrate{ 0 }; u8 smallVibrate{ 0 }; clock_t last_vibration{ 0 }; + pad_config* config{ nullptr }; }; public: @@ -109,6 +110,7 @@ class xinput_pad_handler final : public PadHandlerBase void ThreadProc() override; void GetNextButtonPress(const std::string& padId, const std::function& callback, bool get_blacklist = false, std::vector buttons = {}) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; + void init_config(pad_config* cfg, const std::string& name) override; private: typedef void (WINAPI * PFN_XINPUTENABLE)(BOOL); @@ -130,6 +132,7 @@ class xinput_pad_handler final : public PadHandlerBase std::vector blacklist; std::vector, std::shared_ptr>> bindings; + std::shared_ptr m_dev; // holds internal controller state change XINPUT_STATE state;