Qt: Add custom pad configs

Add a custom pad config for every game.
This commit is contained in:
gidan80 2018-11-20 16:35:06 +01:00 committed by Megamouse
parent cb78522620
commit 9aa08313e3
17 changed files with 332 additions and 105 deletions

View File

@ -1,4 +1,4 @@
#pragma once #pragma once
#include "Utilities/types.h" #include "Utilities/types.h"
#include "Utilities/mutex.h" #include "Utilities/mutex.h"
@ -633,8 +633,8 @@ public:
} }
// Emplace the object returned by provider() and return it if no object exists // Emplace the object returned by provider() and return it if no object exists
template <typename T, typename F> template <typename T, typename F, typename... Args>
static auto import(F&& provider) -> decltype(static_cast<std::shared_ptr<T>>(provider())) static auto import(F&& provider, Args&&... args) -> decltype(static_cast<std::shared_ptr<T>>(provider(std::forward<Args>(args)...)))
{ {
std::shared_ptr<T> ptr; std::shared_ptr<T> ptr;
{ {
@ -644,7 +644,7 @@ public:
if (!cur) if (!cur)
{ {
ptr = provider(); ptr = provider(std::forward<Args>(args)...);
if (ptr) if (ptr)
{ {
@ -662,8 +662,8 @@ public:
} }
// Emplace the object return by provider() (old object will be removed if it exists) // Emplace the object return by provider() (old object will be removed if it exists)
template <typename T, typename F> template <typename T, typename F, typename... Args>
static auto import_always(F&& provider) -> decltype(static_cast<std::shared_ptr<T>>(provider())) static auto import_always(F&& provider, Args&&... args) -> decltype(static_cast<std::shared_ptr<T>>(provider(std::forward<Args>(args)...)))
{ {
std::shared_ptr<T> ptr; std::shared_ptr<T> ptr;
std::shared_ptr<void> old; std::shared_ptr<void> old;
@ -672,7 +672,7 @@ public:
auto& cur = g_vec[get_type<T>()]; auto& cur = g_vec[get_type<T>()];
ptr = provider(); ptr = provider(std::forward<Args>(args)...);
if (ptr) if (ptr)
{ {

View File

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "PadHandler.h" #include "PadHandler.h"
#include "pad_thread.h"
cfg_input g_cfg_input; cfg_input g_cfg_input;
@ -268,13 +269,25 @@ bool PadHandlerBase::has_led()
return b_has_led; return b_has_led;
} }
std::string PadHandlerBase::get_config_dir(pad_handler type) std::string PadHandlerBase::get_config_dir(pad_handler type, const std::string& title_id)
{ {
if (!title_id.empty())
{
return Emu.GetCustomInputConfigDir(title_id) + fmt::format("%s", type) + "/";
}
return fs::get_config_dir() + "/InputConfigs/" + fmt::format("%s", type) + "/"; return fs::get_config_dir() + "/InputConfigs/" + fmt::format("%s", type) + "/";
} }
std::string PadHandlerBase::get_config_filename(int i) std::string PadHandlerBase::get_config_filename(int i, const std::string& title_id)
{ {
if (!title_id.empty() && fs::is_file(Emu.GetCustomInputConfigPath(title_id)))
{
const std::string path = Emu.GetCustomInputConfigDir(title_id) + g_cfg_input.player[i]->handler.to_string() + "/" + g_cfg_input.player[i]->profile.to_string() + ".yml";
if (fs::is_file(path))
{
return path;
}
}
return fs::get_config_dir() + "/InputConfigs/" + g_cfg_input.player[i]->handler.to_string() + "/" + g_cfg_input.player[i]->profile.to_string() + ".yml"; return fs::get_config_dir() + "/InputConfigs/" + g_cfg_input.player[i]->handler.to_string() + "/" + g_cfg_input.player[i]->profile.to_string() + ".yml";
} }
@ -286,7 +299,7 @@ void PadHandlerBase::init_configs()
{ {
if (g_cfg_input.player[i]->handler == m_type) if (g_cfg_input.player[i]->handler == m_type)
{ {
init_config(&m_pad_configs[index], get_config_filename(i)); init_config(&m_pad_configs[index], get_config_filename(i, pad::g_title_id));
index++; index++;
} }
} }

View File

@ -7,6 +7,7 @@
#include "Utilities/Config.h" #include "Utilities/Config.h"
#include "Utilities/types.h" #include "Utilities/types.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/GameInfo.h"
// TODO: HLE info (constants, structs, etc.) should not be available here // TODO: HLE info (constants, structs, etc.) should not be available here
@ -268,7 +269,7 @@ struct cfg_player final : cfg::node
struct cfg_input final : cfg::node struct cfg_input final : cfg::node
{ {
const std::string cfg_name = fs::get_config_dir() + "/config_input.yml"; std::string cfg_name = fs::get_config_dir() + "/config_input.yml";
cfg_player player1{ this, "Player 1 Input", pad_handler::keyboard }; cfg_player player1{ this, "Player 1 Input", pad_handler::keyboard };
cfg_player player2{ this, "Player 2 Input", pad_handler::null }; cfg_player player2{ this, "Player 2 Input", pad_handler::null };
@ -280,18 +281,32 @@ struct cfg_input final : cfg::node
cfg_player *player[7]{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc! cfg_player *player[7]{ &player1, &player2, &player3, &player4, &player5, &player6, &player7 }; // Thanks gcc!
bool load() bool load(const std::string& title_id = "")
{ {
if (fs::file cfg_file{ cfg_name, fs::read }) cfg_name = Emu.GetCustomInputConfigPath(title_id);
if (!fs::is_file(cfg_name))
{
cfg_name = fs::get_config_dir() + "/config_input.yml";
}
if (fs::file cfg_file{cfg_name, fs::read})
{ {
return from_string(cfg_file.to_string()); return from_string(cfg_file.to_string());
} }
return false; return false;
} }
void save() void save(const std::string& title_id = "")
{ {
if (title_id.empty())
{
cfg_name = fs::get_config_dir() + "/config_input.yml";
}
else
{
cfg_name = Emu.GetCustomInputConfigPath(title_id);
}
fs::file(cfg_name, fs::rewrite).write(to_string()); fs::file(cfg_name, fs::rewrite).write(to_string());
} }
}; };
@ -460,8 +475,8 @@ public:
bool has_deadzones(); bool has_deadzones();
bool has_led(); bool has_led();
static std::string get_config_dir(pad_handler type); static std::string get_config_dir(pad_handler type, const std::string& title_id = "");
static std::string get_config_filename(int i); static std::string get_config_filename(int i, const std::string& title_id = "");
virtual bool Init() { return true; } virtual bool Init() { return true; }
PadHandlerBase(pad_handler type = pad_handler::null); PadHandlerBase(pad_handler type = pad_handler::null);

View File

@ -39,7 +39,6 @@
#include "Utilities/GDBDebugServer.h" #include "Utilities/GDBDebugServer.h"
#include "Utilities/sysinfo.h"
#include "Utilities/JIT.h" #include "Utilities/JIT.h"
#if defined(_WIN32) || defined(HAVE_VULKAN) #if defined(_WIN32) || defined(HAVE_VULKAN)
@ -303,31 +302,31 @@ void Emulator::Init()
if (g_cfg.vfs.init_dirs) if (g_cfg.vfs.init_dirs)
{ {
fs::create_path(dev_hdd0); fs::create_path(dev_hdd0);
fs::create_path(dev_hdd1); fs::create_path(dev_hdd1);
fs::create_path(dev_usb); fs::create_path(dev_usb);
fs::create_dir(dev_hdd0 + "game/"); fs::create_dir(dev_hdd0 + "game/");
fs::create_dir(dev_hdd0 + "game/TEST12345/"); fs::create_dir(dev_hdd0 + "game/TEST12345/");
fs::create_dir(dev_hdd0 + "game/TEST12345/USRDIR/"); fs::create_dir(dev_hdd0 + "game/TEST12345/USRDIR/");
fs::create_dir(dev_hdd0 + "game/.locks/"); fs::create_dir(dev_hdd0 + "game/.locks/");
fs::create_dir(dev_hdd0 + "home/"); fs::create_dir(dev_hdd0 + "home/");
fs::create_dir(dev_hdd0 + "home/" + m_usr + "/"); fs::create_dir(dev_hdd0 + "home/" + m_usr + "/");
fs::create_dir(dev_hdd0 + "home/" + m_usr + "/exdata/"); fs::create_dir(dev_hdd0 + "home/" + m_usr + "/exdata/");
fs::create_dir(dev_hdd0 + "home/" + m_usr + "/savedata/"); fs::create_dir(dev_hdd0 + "home/" + m_usr + "/savedata/");
fs::create_dir(dev_hdd0 + "home/" + m_usr + "/trophy/"); fs::create_dir(dev_hdd0 + "home/" + m_usr + "/trophy/");
fs::write_file(dev_hdd0 + "home/" + m_usr + "/localusername", fs::create + fs::excl + fs::write, "User"s); fs::write_file(dev_hdd0 + "home/" + m_usr + "/localusername", fs::create + fs::excl + fs::write, "User"s);
fs::create_dir(dev_hdd0 + "disc/"); fs::create_dir(dev_hdd0 + "disc/");
fs::create_dir(dev_hdd0 + "savedata/"); fs::create_dir(dev_hdd0 + "savedata/");
fs::create_dir(dev_hdd0 + "savedata/vmc/"); fs::create_dir(dev_hdd0 + "savedata/vmc/");
fs::create_dir(dev_hdd1 + "cache/"); fs::create_dir(dev_hdd1 + "cache/");
fs::create_dir(dev_hdd1 + "game/"); fs::create_dir(dev_hdd1 + "game/");
} }
fs::create_path(fs::get_cache_dir() + "shaderlog/"); fs::create_path(fs::get_cache_dir() + "shaderlog/");
fs::create_path(fs::get_config_dir() + "captures/"); fs::create_path(fs::get_config_dir() + "captures/");
#ifdef WITH_GDB_DEBUGGER #ifdef WITH_GDB_DEBUGGER
LOG_SUCCESS(GENERAL, "GDB debug server will be started and listening on %d upon emulator boot", (int) g_cfg.misc.gdb_server_port); LOG_SUCCESS(GENERAL, "GDB debug server will be started and listening on %d upon emulator boot", (int)g_cfg.misc.gdb_server_port);
#endif #endif
// Initialize patch engine // Initialize patch engine
@ -506,7 +505,7 @@ bool Emulator::BootRsxCapture(const std::string& path)
GetCallbacks().on_ready(); GetCallbacks().on_ready();
auto gsrender = fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); auto gsrender = fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render);
auto padhandler = fxm::import<pad_thread>(Emu.GetCallbacks().get_pad_handler); auto padhandler = fxm::import<pad_thread>(Emu.GetCallbacks().get_pad_handler, "");
if (gsrender.get() == nullptr || padhandler.get() == nullptr) if (gsrender.get() == nullptr || padhandler.get() == nullptr)
return false; return false;
@ -727,6 +726,22 @@ std::string Emulator::GetCustomConfigPath(const std::string& title_id, bool get_
return path; return path;
} }
std::string Emulator::GetCustomInputConfigDir(const std::string& title_id)
{
// Notice: the extra folder for each title id may be removed at a later stage
// Warning: make sure to change any function that removes this directory as well
#ifdef _WIN32
return fs::get_config_dir() + "config/custom_input_configs/" + title_id + "/";
#else
return fs::get_config_dir() + "custom_input_configs/" + title_id + "/";
#endif
}
std::string Emulator::GetCustomInputConfigPath(const std::string& title_id)
{
return GetCustomInputConfigDir(title_id) + "/config_input_" + title_id + ".yml";
}
void Emulator::SetForceBoot(bool force_boot) void Emulator::SetForceBoot(bool force_boot)
{ {
m_force_boot = force_boot; m_force_boot = force_boot;
@ -1343,7 +1358,7 @@ void Emulator::Load(bool add_only, bool force_global_config)
} }
fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall fxm::import<GSRender>(Emu.GetCallbacks().get_gs_render); // TODO: must be created in appropriate sys_rsx syscall
fxm::import<pad_thread>(Emu.GetCallbacks().get_pad_handler); fxm::import<pad_thread>(Emu.GetCallbacks().get_pad_handler, m_title_id);
network_thread_init(); network_thread_init();
} }
else if (ppu_prx.open(elf_file) == elf_error::ok) else if (ppu_prx.open(elf_file) == elf_error::ok)

View File

@ -189,12 +189,12 @@ struct EmuCallbacks
std::function<void()> on_stop; std::function<void()> on_stop;
std::function<void()> on_ready; std::function<void()> on_ready;
std::function<void()> exit; std::function<void()> exit;
std::function<void()> reset_pads; std::function<void(const std::string&)> reset_pads;
std::function<void(bool)> enable_pads; std::function<void(bool)> enable_pads;
std::function<void(s32, s32)> handle_taskbar_progress; // (type, value) type: 0 for reset, 1 for increment, 2 for set_limit std::function<void(s32, s32)> handle_taskbar_progress; // (type, value) type: 0 for reset, 1 for increment, 2 for set_limit
std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler; std::function<std::shared_ptr<class KeyboardHandlerBase>()> get_kb_handler;
std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler; std::function<std::shared_ptr<class MouseHandlerBase>()> get_mouse_handler;
std::function<std::shared_ptr<class pad_thread>()> get_pad_handler; std::function<std::shared_ptr<class pad_thread>(const std::string&)> get_pad_handler;
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame; std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
std::function<std::shared_ptr<class GSRender>()> get_gs_render; std::function<std::shared_ptr<class GSRender>()> get_gs_render;
std::function<std::shared_ptr<class AudioBackend>()> get_audio; std::function<std::shared_ptr<class AudioBackend>()> get_audio;
@ -326,6 +326,8 @@ public:
static std::string GetCustomConfigDir(); static std::string GetCustomConfigDir();
static std::string GetCustomConfigPath(const std::string& title_id, bool get_deprecated_path = false); static std::string GetCustomConfigPath(const std::string& title_id, bool get_deprecated_path = false);
static std::string GetCustomInputConfigDir(const std::string& title_id);
static std::string GetCustomInputConfigPath(const std::string& title_id);
void SetForceBoot(bool force_boot); void SetForceBoot(bool force_boot);

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -14,6 +14,7 @@ namespace pad
{ {
atomic_t<pad_thread*> g_current = nullptr; atomic_t<pad_thread*> g_current = nullptr;
std::recursive_mutex g_pad_mutex; std::recursive_mutex g_pad_mutex;
std::string g_title_id;
} }
struct pad_setting struct pad_setting
@ -23,8 +24,9 @@ struct pad_setting
u32 device_type; u32 device_type;
}; };
pad_thread::pad_thread(void *_curthread, void *_curwindow) : curthread(_curthread), curwindow(_curwindow) pad_thread::pad_thread(void *_curthread, void *_curwindow, const std::string& title_id) : curthread(_curthread), curwindow(_curwindow)
{ {
pad::g_title_id = title_id;
Init(); Init();
thread = std::make_shared<std::thread>(&pad_thread::ThreadFunc, this); thread = std::make_shared<std::thread>(&pad_thread::ThreadFunc, this);
@ -65,7 +67,7 @@ void pad_thread::Init()
handlers.clear(); handlers.clear();
g_cfg_input.load(); g_cfg_input.load(pad::g_title_id);
std::shared_ptr<keyboard_pad_handler> keyptr; std::shared_ptr<keyboard_pad_handler> keyptr;
@ -142,8 +144,9 @@ void pad_thread::SetRumble(const u32 pad, u8 largeMotor, bool smallMotor)
} }
} }
void pad_thread::Reset() void pad_thread::Reset(const std::string& title_id)
{ {
pad::g_title_id = title_id;
reset = active.load(); reset = active.load();
} }

View File

@ -1,4 +1,4 @@
#pragma once #pragma once
#include <map> #include <map>
#include <thread> #include <thread>
@ -16,14 +16,14 @@ struct PadInfo
class pad_thread class pad_thread
{ {
public: public:
pad_thread(void *_curthread, void *_curwindow); // void * instead of QThread * and QWindow * because of include in emucore pad_thread(void* _curthread, void* _curwindow, const std::string& title_id = ""); // void * instead of QThread * and QWindow * because of include in emucore
~pad_thread(); ~pad_thread();
PadInfo& GetInfo() { return m_info; } PadInfo& GetInfo() { return m_info; }
auto& GetPads() { return m_pads; } auto& GetPads() { return m_pads; }
void SetRumble(const u32 pad, u8 largeMotor, bool smallMotor); void SetRumble(const u32 pad, u8 largeMotor, bool smallMotor);
void Init(); void Init();
void Reset(); void Reset(const std::string& title_id = "");
void SetEnabled(bool enabled); void SetEnabled(bool enabled);
void SetIntercepted(bool intercepted); void SetIntercepted(bool intercepted);
@ -50,6 +50,7 @@ namespace pad
{ {
extern atomic_t<pad_thread*> g_current; extern atomic_t<pad_thread*> g_current;
extern std::recursive_mutex g_pad_mutex; extern std::recursive_mutex g_pad_mutex;
extern std::string g_title_id;
static inline class pad_thread* get_current_handler() static inline class pad_thread* get_current_handler()
{ {

View File

@ -18,5 +18,7 @@
<file>Icons/open.png</file> <file>Icons/open.png</file>
<file>Icons/custom_config.png</file> <file>Icons/custom_config.png</file>
<file>Icons/custom_config_2.png</file> <file>Icons/custom_config_2.png</file>
<file>Icons/controllers_2.png</file>
<file>Icons/combo_config_bordered.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -142,9 +142,9 @@ void rpcs3_app::InitializeCallbacks()
RequestCallAfter(std::move(func)); RequestCallAfter(std::move(func));
}; };
callbacks.reset_pads = [this]() callbacks.reset_pads = [this](const std::string& title_id = "")
{ {
pad::get_current_handler()->Reset(); pad::get_current_handler()->Reset(title_id);
}; };
callbacks.enable_pads = [this](bool enable) callbacks.enable_pads = [this](bool enable)
{ {
@ -183,9 +183,9 @@ void rpcs3_app::InitializeCallbacks()
} }
}; };
callbacks.get_pad_handler = [this]() -> std::shared_ptr<pad_thread> callbacks.get_pad_handler = [this](const std::string& title_id) -> std::shared_ptr<pad_thread>
{ {
return std::make_shared<pad_thread>(thread(), gameWindow); return std::make_shared<pad_thread>(thread(), gameWindow, title_id);
}; };
callbacks.get_gs_frame = [this]() -> std::unique_ptr<GSFrameBase> callbacks.get_gs_frame = [this]() -> std::unique_ptr<GSFrameBase>

View File

@ -1,6 +1,7 @@
#include "game_list_frame.h" #include "game_list_frame.h"
#include "qt_utils.h" #include "qt_utils.h"
#include "settings_dialog.h" #include "settings_dialog.h"
#include "pad_settings_dialog.h"
#include "table_item_delegate.h" #include "table_item_delegate.h"
#include "custom_table_widget_item.h" #include "custom_table_widget_item.h"
#include "input_dialog.h" #include "input_dialog.h"
@ -114,6 +115,10 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> guiSettings, std:
QMenu* configure = new QMenu(this); QMenu* configure = new QMenu(this);
configure->addActions(m_columnActs); configure->addActions(m_columnActs);
configure->exec(mapToGlobal(pos)); configure->exec(mapToGlobal(pos));
QMenu* pad_configure = new QMenu(this);
pad_configure->addActions(m_columnActs);
pad_configure->exec(mapToGlobal(pos));
}); });
connect(m_xgrid, &QTableWidget::itemDoubleClicked, this, &game_list_frame::doubleClickedSlot); connect(m_xgrid, &QTableWidget::itemDoubleClicked, this, &game_list_frame::doubleClickedSlot);
@ -471,12 +476,14 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter)
} }
const auto compat = m_game_compat->GetCompatibility(game.serial); const auto compat = m_game_compat->GetCompatibility(game.serial);
const bool hasCustomConfig = fs::is_file(Emu.GetCustomConfigPath(game.serial)) || fs::is_file(Emu.GetCustomConfigPath(game.serial, true)); const bool hasCustomConfig = fs::is_file(Emu.GetCustomConfigPath(game.serial)) || fs::is_file(Emu.GetCustomConfigPath(game.serial, true));
const bool hasCustomPadConfig = fs::is_file(Emu.GetCustomInputConfigPath(game.serial));
const QColor color = getGridCompatibilityColor(compat.color); const QColor color = getGridCompatibilityColor(compat.color);
const QPixmap pxmap = PaintedPixmap(img, hasCustomConfig, color); const QPixmap pxmap = PaintedPixmap(img, hasCustomConfig, hasCustomPadConfig, color);
m_game_data.push_back(game_info(new gui_game_info{ game, compat, img, pxmap, hasCustomConfig })); m_game_data.push_back(game_info(new gui_game_info{game, compat, img, pxmap, hasCustomConfig, hasCustomPadConfig}));
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -695,6 +702,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
} }
myMenu.addAction(boot); myMenu.addAction(boot);
QAction* configure = myMenu.addAction(tr("&Configure")); QAction* configure = myMenu.addAction(tr("&Configure"));
QAction* pad_configure = myMenu.addAction(tr("&Configure pads"));
QAction* createPPUCache = myMenu.addAction(tr("&Create PPU Cache")); QAction* createPPUCache = myMenu.addAction(tr("&Create PPU Cache"));
myMenu.addSeparator(); myMenu.addSeparator();
QAction* renameTitle = myMenu.addAction(tr("&Rename In Game List")); QAction* renameTitle = myMenu.addAction(tr("&Rename In Game List"));
@ -709,9 +717,20 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
QAction* remove_custom_config = remove_menu->addAction(tr("&Remove Custom Configuration")); QAction* remove_custom_config = remove_menu->addAction(tr("&Remove Custom Configuration"));
connect(remove_custom_config, &QAction::triggered, [=]() connect(remove_custom_config, &QAction::triggered, [=]()
{ {
if (RemoveCustomConfiguration(currGame.serial, true)) if (RemoveCustomConfiguration(currGame.serial, gameinfo, true))
{ {
ShowCustomConfigIcon(item, false); ShowCustomConfigIcon(item, config::type::emu);
}
});
}
if (gameinfo->hasCustomPadConfig)
{
QAction* remove_custom_pad_config = remove_menu->addAction(tr("&Remove Custom Pad Configuration"));
connect(remove_custom_pad_config, &QAction::triggered, [=]()
{
if (RemoveCustomPadConfiguration(currGame.serial, gameinfo, true))
{
ShowCustomConfigIcon(item, config::type::pad);
} }
}); });
} }
@ -775,7 +794,33 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
settings_dialog dlg(m_gui_settings, m_emu_settings, 0, this, &currGame); settings_dialog dlg(m_gui_settings, m_emu_settings, 0, this, &currGame);
if (dlg.exec() == QDialog::Accepted && !gameinfo->hasCustomConfig) if (dlg.exec() == QDialog::Accepted && !gameinfo->hasCustomConfig)
{ {
ShowCustomConfigIcon(item, true); gameinfo->hasCustomConfig = true;
ShowCustomConfigIcon(item, config::type::emu);
}
});
connect(pad_configure, &QAction::triggered, [=]
{
if (!Emu.IsStopped())
{
Emu.GetCallbacks().enable_pads(false);
}
pad_settings_dialog dlg(this, &currGame);
connect(&dlg, &QDialog::finished, [this](int/* result*/)
{
if (Emu.IsStopped())
{
return;
}
Emu.GetCallbacks().reset_pads(Emu.GetTitleID());
});
if (dlg.exec() == QDialog::Accepted && !gameinfo->hasCustomPadConfig)
{
gameinfo->hasCustomPadConfig = true;
ShowCustomConfigIcon(item, config::type::pad);
}
if (!Emu.IsStopped())
{
Emu.GetCallbacks().enable_pads(true);
} }
}); });
connect(hide_serial, &QAction::triggered, [=](bool checked) connect(hide_serial, &QAction::triggered, [=](bool checked)
@ -801,7 +846,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
} }
QMessageBox* mb = new QMessageBox(QMessageBox::Question, tr("Confirm %1 Removal").arg(qstr(currGame.category)), tr("Permanently remove %0 from drive?\nPath: %1").arg(name).arg(qstr(currGame.path)), QMessageBox::Yes | QMessageBox::No, this); QMessageBox* mb = new QMessageBox(QMessageBox::Question, tr("Confirm %1 Removal").arg(qstr(currGame.category)), tr("Permanently remove %0 from drive?\nPath: %1").arg(name).arg(qstr(currGame.path)), QMessageBox::Yes | QMessageBox::No, this);
mb->setCheckBox(new QCheckBox(tr("Remove caches and custom config"))); mb->setCheckBox(new QCheckBox(tr("Remove caches and custom configs")));
mb->deleteLater(); mb->deleteLater();
if (mb->exec() == QMessageBox::Yes) if (mb->exec() == QMessageBox::Yes)
{ {
@ -811,6 +856,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
RemovePPUCache(cache_base_dir); RemovePPUCache(cache_base_dir);
RemoveSPUCache(cache_base_dir); RemoveSPUCache(cache_base_dir);
RemoveCustomConfiguration(currGame.serial); RemoveCustomConfiguration(currGame.serial);
RemoveCustomPadConfiguration(currGame.serial);
} }
fs::remove_all(currGame.path); fs::remove_all(currGame.path);
m_game_data.erase(std::remove(m_game_data.begin(), m_game_data.end(), gameinfo), m_game_data.end()); m_game_data.erase(std::remove(m_game_data.begin(), m_game_data.end(), gameinfo), m_game_data.end());
@ -933,7 +979,7 @@ bool game_list_frame::CreatePPUCache(const std::string& path)
return success; return success;
} }
bool game_list_frame::RemoveCustomConfiguration(const std::string& title_id, bool is_interactive) bool game_list_frame::RemoveCustomConfiguration(const std::string& title_id, game_info game, bool is_interactive)
{ {
const std::string config_path_new = Emu.GetCustomConfigPath(title_id); const std::string config_path_new = Emu.GetCustomConfigPath(title_id);
const std::string config_path_old = Emu.GetCustomConfigPath(title_id, true); const std::string config_path_old = Emu.GetCustomConfigPath(title_id, true);
@ -954,6 +1000,10 @@ bool game_list_frame::RemoveCustomConfiguration(const std::string& title_id, boo
} }
if (fs::remove_file(path)) if (fs::remove_file(path))
{ {
if (game)
{
game->hasCustomConfig = false;
}
LOG_SUCCESS(GENERAL, "Removed configuration file: %s", path); LOG_SUCCESS(GENERAL, "Removed configuration file: %s", path);
} }
else else
@ -971,6 +1021,41 @@ bool game_list_frame::RemoveCustomConfiguration(const std::string& title_id, boo
return result; return result;
} }
bool game_list_frame::RemoveCustomPadConfiguration(const std::string& title_id, game_info game, bool is_interactive)
{
const std::string config_dir = Emu.GetCustomInputConfigDir(title_id);
if (!fs::is_dir(config_dir))
return true;
if (is_interactive && QMessageBox::question(this, tr("Confirm Removal"), (!Emu.IsStopped() && Emu.GetTitleID() == title_id)
? tr("Remove custom pad configuration?\nYour configuration will revert to the global pad settings.")
: tr("Remove custom pad configuration?")) != QMessageBox::Yes)
return true;
if (QDir(qstr(config_dir)).removeRecursively())
{
if (game)
{
game->hasCustomPadConfig = false;
}
if (!Emu.IsStopped() && Emu.GetTitleID() == title_id)
{
Emu.GetCallbacks().enable_pads(false);
Emu.GetCallbacks().reset_pads(title_id);
Emu.GetCallbacks().enable_pads(true);
}
LOG_NOTICE(GENERAL, "Removed pad configuration directory: %s", config_dir);
return true;
}
else if (is_interactive)
{
QMessageBox::warning(this, tr("Warning!"), tr("Failed to completely remove pad configuration directory!"));
LOG_FATAL(GENERAL, "Failed to completely remove pad configuration directory: %s\nError: %s", config_dir, fs::g_tls_error);
}
return false;
}
bool game_list_frame::RemoveShadersCache(const std::string& base_dir, bool is_interactive) bool game_list_frame::RemoveShadersCache(const std::string& base_dir, bool is_interactive)
{ {
if (!fs::is_dir(base_dir)) if (!fs::is_dir(base_dir))
@ -1260,6 +1345,52 @@ void game_list_frame::BatchRemoveCustomConfigurations()
Refresh(true); Refresh(true);
} }
void game_list_frame::BatchRemoveCustomPadConfigurations()
{
std::set<std::string> serials;
for (const auto& game : m_game_data)
{
if (game->hasCustomPadConfig && !serials.count(game->info.serial))
{
serials.emplace(game->info.serial);
}
}
const u32 total = serials.size();
if (total == 0)
{
QMessageBox::information(this, tr("Custom Pad Configuration Batch Removal"), tr("No files found"), QMessageBox::Ok);
return;
}
progress_dialog* pdlg = new progress_dialog(tr("Removing all custom pad configurations"), tr("Cancel"), 0, total, this);
pdlg->setWindowTitle(tr("Custom Pad Configuration Batch Removal"));
pdlg->setAutoClose(false);
pdlg->setAutoReset(false);
pdlg->show();
u32 removed = 0;
for (const auto& serial : serials)
{
if (pdlg->wasCanceled())
{
LOG_NOTICE(GENERAL, "Custom Pad Configuration Batch Removal was canceled. %d/%d custom pad configurations cleared", removed, total);
break;
}
QApplication::processEvents();
if (RemoveCustomPadConfiguration(serial))
{
pdlg->SetValue(++removed);
}
}
pdlg->setLabelText(tr("%0/%1 custom pad configurations cleared").arg(removed).arg(total));
pdlg->setCancelButtonText(tr("OK"));
QApplication::beep();
Refresh(true);
}
void game_list_frame::BatchRemoveShaderCaches() void game_list_frame::BatchRemoveShaderCaches()
{ {
std::set<std::string> serials; std::set<std::string> serials;
@ -1302,7 +1433,7 @@ void game_list_frame::BatchRemoveShaderCaches()
QApplication::beep(); QApplication::beep();
} }
QPixmap game_list_frame::PaintedPixmap(const QImage& img, bool paint_config_icon, const QColor& compatibility_color) QPixmap game_list_frame::PaintedPixmap(const QImage& img, bool paint_config_icon, bool paint_pad_config_icon, const QColor& compatibility_color)
{ {
const int device_pixel_ratio = devicePixelRatio(); const int device_pixel_ratio = devicePixelRatio();
const QSize original_size = img.size(); const QSize original_size = img.size();
@ -1318,11 +1449,26 @@ QPixmap game_list_frame::PaintedPixmap(const QImage& img, bool paint_config_icon
painter.drawImage(QPoint(0, 0), img); painter.drawImage(QPoint(0, 0), img);
} }
if (paint_config_icon && !m_isListLayout) if (!m_isListLayout && (paint_config_icon || paint_pad_config_icon))
{ {
const int width = original_size.width() * 0.2; const int width = original_size.width() * 0.2;
const QPoint origin = QPoint(original_size.width() - width, 0); const QPoint origin = QPoint(original_size.width() - width, 0);
QImage custom_config_icon(":/Icons/custom_config_2.png"); QString icon_path;
if (paint_config_icon && paint_pad_config_icon)
{
icon_path = ":/Icons/combo_config_bordered.png";
}
else if (paint_config_icon)
{
icon_path = ":/Icons/custom_config_2.png";
}
else if (paint_pad_config_icon)
{
icon_path = ":/Icons/controllers_2.png";
}
QImage custom_config_icon(icon_path);
custom_config_icon.setDevicePixelRatio(device_pixel_ratio); custom_config_icon.setDevicePixelRatio(device_pixel_ratio);
painter.drawImage(origin, custom_config_icon.scaled(QSize(width, width) * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation)); painter.drawImage(origin, custom_config_icon.scaled(QSize(width, width) * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation));
} }
@ -1342,7 +1488,7 @@ QPixmap game_list_frame::PaintedPixmap(const QImage& img, bool paint_config_icon
return QPixmap::fromImage(image.scaled(m_Icon_Size * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation)); return QPixmap::fromImage(image.scaled(m_Icon_Size * device_pixel_ratio, Qt::KeepAspectRatio, Qt::TransformationMode::SmoothTransformation));
} }
void game_list_frame::ShowCustomConfigIcon(QTableWidgetItem* item, bool enabled) void game_list_frame::ShowCustomConfigIcon(QTableWidgetItem* item, config::type type)
{ {
auto game = GetGameInfoFromItem(item); auto game = GetGameInfoFromItem(item);
if (game == nullptr) if (game == nullptr)
@ -1350,24 +1496,22 @@ void game_list_frame::ShowCustomConfigIcon(QTableWidgetItem* item, bool enabled)
return; return;
} }
game->hasCustomConfig = enabled;
const QColor color = getGridCompatibilityColor(game->compat.color);
game->pxmap = PaintedPixmap(game->icon, enabled, color);
if (!m_isListLayout) if (!m_isListLayout)
{ {
const QColor color = getGridCompatibilityColor(game->compat.color);
game->pxmap = PaintedPixmap(game->icon, game->hasCustomConfig, game->hasCustomPadConfig, color);
int r = m_xgrid->currentItem()->row(), c = m_xgrid->currentItem()->column(); int r = m_xgrid->currentItem()->row(), c = m_xgrid->currentItem()->column();
m_xgrid->addItem(game->pxmap, qstr(game->info.name).simplified(), r, c); m_xgrid->addItem(game->pxmap, qstr(game->info.name).simplified(), r, c);
m_xgrid->item(r, c)->setData(gui::game_role, QVariant::fromValue(game)); m_xgrid->item(r, c)->setData(gui::game_role, QVariant::fromValue(game));
} }
else if (enabled) else if (game->hasCustomConfig && game->hasCustomPadConfig)
{ m_gameList->item(item->row(), gui::column_name)->setIcon(QIcon(":/Icons/combo_config_bordered.png"));
else if (game->hasCustomConfig)
m_gameList->item(item->row(), gui::column_name)->setIcon(QIcon(":/Icons/custom_config.png")); m_gameList->item(item->row(), gui::column_name)->setIcon(QIcon(":/Icons/custom_config.png"));
} else if (game->hasCustomPadConfig)
m_gameList->item(item->row(), gui::column_name)->setIcon(QIcon(":/Icons/controllers.png"));
else else
{
m_gameList->setItem(item->row(), gui::column_name, new custom_table_widget_item(game->info.name)); m_gameList->setItem(item->row(), gui::column_name, new custom_table_widget_item(game->info.name));
}
} }
void game_list_frame::ResizeIcons(const int& sliderPos) void game_list_frame::ResizeIcons(const int& sliderPos)
@ -1395,7 +1539,7 @@ void game_list_frame::RepaintIcons(const bool& fromSettings)
for (auto& game : m_game_data) for (auto& game : m_game_data)
{ {
QColor color = getGridCompatibilityColor(game->compat.color); QColor color = getGridCompatibilityColor(game->compat.color);
game->pxmap = PaintedPixmap(game->icon, game->hasCustomConfig, color); game->pxmap = PaintedPixmap(game->icon, game->hasCustomConfig, game->hasCustomPadConfig, color);
} }
Refresh(); Refresh();
@ -1560,10 +1704,18 @@ int game_list_frame::PopulateGameList()
// Title // Title
custom_table_widget_item* title_item = new custom_table_widget_item(title); custom_table_widget_item* title_item = new custom_table_widget_item(title);
if (game->hasCustomConfig) if (game->hasCustomConfig && game->hasCustomPadConfig)
{
title_item->setIcon(QIcon(":/Icons/combo_config_bordered.png"));
}
else if (game->hasCustomConfig)
{ {
title_item->setIcon(QIcon(":/Icons/custom_config.png")); title_item->setIcon(QIcon(":/Icons/custom_config.png"));
} }
else if (game->hasCustomPadConfig)
{
title_item->setIcon(QIcon(":/Icons/controllers.png"));
}
// Serial // Serial
custom_table_widget_item* serial_item = new custom_table_widget_item(game->info.serial); custom_table_widget_item* serial_item = new custom_table_widget_item(game->info.serial);

View File

@ -31,6 +31,15 @@ enum Category
Others, Others,
}; };
namespace config
{
enum class type
{
emu,
pad
};
}
namespace category // (see PARAM.SFO in psdevwiki.com) TODO: Disc Categories namespace category // (see PARAM.SFO in psdevwiki.com) TODO: Disc Categories
{ {
// PS3 bootable // PS3 bootable
@ -171,6 +180,7 @@ struct gui_game_info
QImage icon; QImage icon;
QPixmap pxmap; QPixmap pxmap;
bool hasCustomConfig; bool hasCustomConfig;
bool hasCustomPadConfig;
}; };
typedef std::shared_ptr<gui_game_info> game_info; typedef std::shared_ptr<gui_game_info> game_info;
@ -215,6 +225,7 @@ public Q_SLOTS:
void BatchRemovePPUCaches(); void BatchRemovePPUCaches();
void BatchRemoveSPUCaches(); void BatchRemoveSPUCaches();
void BatchRemoveCustomConfigurations(); void BatchRemoveCustomConfigurations();
void BatchRemoveCustomPadConfigurations();
void BatchRemoveShaderCaches(); void BatchRemoveShaderCaches();
void SetListMode(const bool& isList); void SetListMode(const bool& isList);
void SetSearchText(const QString& text); void SetSearchText(const QString& text);
@ -234,9 +245,9 @@ protected:
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
bool eventFilter(QObject *object, QEvent *event) override; bool eventFilter(QObject *object, QEvent *event) override;
private: private:
QPixmap PaintedPixmap(const QImage& img, bool paint_config_icon = false, const QColor& color = QColor()); QPixmap PaintedPixmap(const QImage& img, bool paint_config_icon = false, bool paint_pad_config_icon = false, const QColor& color = QColor());
QColor getGridCompatibilityColor(const QString& string); QColor getGridCompatibilityColor(const QString& string);
void ShowCustomConfigIcon(QTableWidgetItem* item, bool enabled); void ShowCustomConfigIcon(QTableWidgetItem* item, config::type type);
void PopulateGameGrid(int maxCols, const QSize& image_size, const QColor& image_color); void PopulateGameGrid(int maxCols, const QSize& image_size, const QColor& image_color);
bool IsEntryVisible(const game_info& game); bool IsEntryVisible(const game_info& game);
void SortGameList(); void SortGameList();
@ -244,7 +255,8 @@ private:
int PopulateGameList(); int PopulateGameList();
bool SearchMatchesApp(const std::string& name, const std::string& serial); bool SearchMatchesApp(const std::string& name, const std::string& serial);
bool RemoveCustomConfiguration(const std::string& base_dir, bool is_interactive = false); bool RemoveCustomConfiguration(const std::string& title_id, game_info game = nullptr, bool is_interactive = false);
bool RemoveCustomPadConfiguration(const std::string& title_id, game_info game = nullptr, bool is_interactive = false);
bool RemoveShadersCache(const std::string& base_dir, bool is_interactive = false); bool RemoveShadersCache(const std::string& base_dir, bool is_interactive = false);
bool RemovePPUCache(const std::string& base_dir, bool is_interactive = false); bool RemovePPUCache(const std::string& base_dir, bool is_interactive = false);
bool RemoveSPUCache(const std::string& base_dir, bool is_interactive = false); bool RemoveSPUCache(const std::string& base_dir, bool is_interactive = false);

View File

@ -1247,6 +1247,7 @@ void main_window::CreateConnects()
connect(ui->batchRemoveSPUCachesAct, &QAction::triggered, m_gameListFrame, &game_list_frame::BatchRemoveSPUCaches); connect(ui->batchRemoveSPUCachesAct, &QAction::triggered, m_gameListFrame, &game_list_frame::BatchRemoveSPUCaches);
connect(ui->batchRemoveShaderCachesAct, &QAction::triggered, m_gameListFrame, &game_list_frame::BatchRemoveShaderCaches); connect(ui->batchRemoveShaderCachesAct, &QAction::triggered, m_gameListFrame, &game_list_frame::BatchRemoveShaderCaches);
connect(ui->batchRemoveCustomConfigurationsAct, &QAction::triggered, m_gameListFrame, &game_list_frame::BatchRemoveCustomConfigurations); connect(ui->batchRemoveCustomConfigurationsAct, &QAction::triggered, m_gameListFrame, &game_list_frame::BatchRemoveCustomConfigurations);
connect(ui->batchRemoveCustomPadConfigurationsAct, &QAction::triggered, m_gameListFrame, &game_list_frame::BatchRemoveCustomPadConfigurations);
connect(ui->sysPauseAct, &QAction::triggered, this, &main_window::OnPlayOrPause); connect(ui->sysPauseAct, &QAction::triggered, this, &main_window::OnPlayOrPause);
connect(ui->sysStopAct, &QAction::triggered, [=]() { Emu.Stop(); }); connect(ui->sysStopAct, &QAction::triggered, [=]() { Emu.Stop(); });
@ -1282,20 +1283,19 @@ void main_window::CreateConnects()
auto openPadSettings = [this] auto openPadSettings = [this]
{ {
auto resetPadHandlers = [this](int/* result*/)
{
if (Emu.IsStopped())
{
return;
}
Emu.GetCallbacks().reset_pads();
};
if (!Emu.IsStopped()) if (!Emu.IsStopped())
{ {
Emu.GetCallbacks().enable_pads(false); Emu.GetCallbacks().enable_pads(false);
} }
pad_settings_dialog dlg(this); pad_settings_dialog dlg(this);
connect(&dlg, &QDialog::finished, resetPadHandlers); connect(&dlg, &QDialog::finished, [this](int/* result*/)
{
if (Emu.IsStopped())
{
return;
}
Emu.GetCallbacks().reset_pads(Emu.GetTitleID());
});
dlg.exec(); dlg.exec();
if (!Emu.IsStopped()) if (!Emu.IsStopped())
{ {

View File

@ -141,7 +141,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1058</width> <width>1058</width>
<height>21</height> <height>22</height>
</rect> </rect>
</property> </property>
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
@ -172,6 +172,7 @@
<addaction name="batchCreatePPUCachesAct"/> <addaction name="batchCreatePPUCachesAct"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="batchRemoveCustomConfigurationsAct"/> <addaction name="batchRemoveCustomConfigurationsAct"/>
<addaction name="batchRemoveCustomPadConfigurationsAct"/>
<addaction name="batchRemovePPUCachesAct"/> <addaction name="batchRemovePPUCachesAct"/>
<addaction name="batchRemoveSPUCachesAct"/> <addaction name="batchRemoveSPUCachesAct"/>
<addaction name="batchRemoveShaderCachesAct"/> <addaction name="batchRemoveShaderCachesAct"/>
@ -995,6 +996,11 @@
<string>Remove Shader Caches</string> <string>Remove Shader Caches</string>
</property> </property>
</action> </action>
<action name="batchRemoveCustomPadConfigurationsAct">
<property name="text">
<string>Remove Custom Pad Configurations</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources> <resources>

View File

@ -1,4 +1,4 @@
#include <QCheckBox> #include <QCheckBox>
#include <QGroupBox> #include <QGroupBox>
#include <QPushButton> #include <QPushButton>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -29,19 +29,13 @@ constexpr auto qstr = QString::fromStdString;
inline bool CreateConfigFile(const QString& dir, const QString& name) inline bool CreateConfigFile(const QString& dir, const QString& name)
{ {
QString input_dir = qstr(fs::get_config_dir()) + "/InputConfigs/"; if (!QDir().mkpath(dir))
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)); LOG_ERROR(GENERAL, "Failed to create dir %s", sstr(dir));
return false; return false;
} }
QString filename = dir + name + ".yml"; const QString filename = dir + name + ".yml";
QFile new_file(filename); QFile new_file(filename);
if (!new_file.open(QIODevice::WriteOnly)) if (!new_file.open(QIODevice::WriteOnly))
@ -54,16 +48,25 @@ inline bool CreateConfigFile(const QString& dir, const QString& name)
return true; return true;
}; };
pad_settings_dialog::pad_settings_dialog(QWidget *parent) pad_settings_dialog::pad_settings_dialog(QWidget *parent, const GameInfo *game)
: QDialog(parent), ui(new Ui::pad_settings_dialog) : QDialog(parent), ui(new Ui::pad_settings_dialog)
{ {
ui->setupUi(this); ui->setupUi(this);
setWindowTitle(tr("Gamepads Settings"));
// load input config // load input config
g_cfg_input.from_default(); g_cfg_input.from_default();
g_cfg_input.load();
if (game)
{
m_title_id = game->serial;
g_cfg_input.load(game->serial);
setWindowTitle(tr("Gamepads Settings: [%0] %1").arg(qstr(game->serial)).arg(qstr(game->name).simplified()));
}
else
{
g_cfg_input.load();
setWindowTitle(tr("Gamepads Settings"));
}
// Create tab widget for 7 players // Create tab widget for 7 players
m_tabs = new QTabWidget; m_tabs = new QTabWidget;
@ -153,7 +156,7 @@ pad_settings_dialog::pad_settings_dialog(QWidget *parent)
QMessageBox::warning(this, tr("Error"), tr("Please choose a non-existing name")); QMessageBox::warning(this, tr("Error"), tr("Please choose a non-existing name"));
continue; continue;
} }
if (CreateConfigFile(qstr(PadHandlerBase::get_config_dir(g_cfg_input.player[i]->handler)), friendlyName)) if (CreateConfigFile(qstr(PadHandlerBase::get_config_dir(g_cfg_input.player[i]->handler, m_title_id)), friendlyName))
{ {
ui->chooseProfile->addItem(friendlyName); ui->chooseProfile->addItem(friendlyName);
ui->chooseProfile->setCurrentText(friendlyName); ui->chooseProfile->setCurrentText(friendlyName);
@ -839,6 +842,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id)
void pad_settings_dialog::OnTabChanged(int index) void pad_settings_dialog::OnTabChanged(int index)
{ {
// TODO: Do not save yet! But keep all profile changes until the dialog was saved.
// Save old profile // Save old profile
SaveProfile(); SaveProfile();
@ -898,7 +902,7 @@ void pad_settings_dialog::ChangeInputType()
if (!g_cfg_input.player[player]->handler.from_string(handler)) if (!g_cfg_input.player[player]->handler.from_string(handler))
{ {
// Something went wrong // Something went wrong
LOG_ERROR(GENERAL, "Failed to convert input string:%s", handler); LOG_ERROR(GENERAL, "Failed to convert input string: %s", handler);
return; return;
} }
@ -963,7 +967,7 @@ void pad_settings_dialog::ChangeInputType()
} }
} }
QString profile_dir = qstr(PadHandlerBase::get_config_dir(m_handler->m_type)); QString profile_dir = qstr(PadHandlerBase::get_config_dir(m_handler->m_type, m_title_id));
QStringList profiles = gui::utils::get_dir_entries(QDir(profile_dir), QStringList() << "*.yml"); QStringList profiles = gui::utils::get_dir_entries(QDir(profile_dir), QStringList() << "*.yml");
if (profiles.isEmpty()) if (profiles.isEmpty())
@ -1021,7 +1025,7 @@ void pad_settings_dialog::ChangeProfile()
} }
// Change handler // Change handler
const std::string cfg_name = PadHandlerBase::get_config_dir(m_handler->m_type) + m_profile + ".yml"; const std::string cfg_name = PadHandlerBase::get_config_dir(m_handler->m_type, m_title_id) + m_profile + ".yml";
// Adjust to the different pad handlers // Adjust to the different pad handlers
switch (m_handler->m_type) switch (m_handler->m_type)
@ -1145,7 +1149,7 @@ void pad_settings_dialog::SaveExit()
g_cfg_input.player[i]->profile.from_default(); g_cfg_input.player[i]->profile.from_default();
} }
g_cfg_input.save(); g_cfg_input.save(m_title_id);
QDialog::accept(); QDialog::accept();
} }

View File

@ -8,6 +8,7 @@
#include <QTimer> #include <QTimer>
#include "Emu/Io/PadHandler.h" #include "Emu/Io/PadHandler.h"
#include "Emu/GameInfo.h"
namespace Ui namespace Ui
{ {
@ -85,7 +86,7 @@ class pad_settings_dialog : public QDialog
const QString Disconnected_suffix = tr(" (disconnected)"); const QString Disconnected_suffix = tr(" (disconnected)");
public: public:
explicit pad_settings_dialog(QWidget *parent = nullptr); explicit pad_settings_dialog(QWidget *parent = nullptr, const GameInfo *game = nullptr);
~pad_settings_dialog(); ~pad_settings_dialog();
private Q_SLOTS: private Q_SLOTS:
@ -100,6 +101,7 @@ private Q_SLOTS:
private: private:
Ui::pad_settings_dialog *ui; Ui::pad_settings_dialog *ui;
std::string m_title_id;
// TabWidget // TabWidget
QTabWidget* m_tabs; QTabWidget* m_tabs;