Merge branch 'master' into stdc++-auto-checker

This commit is contained in:
Ani 2018-12-23 21:49:57 +00:00 committed by GitHub
commit fc25df84f8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 392 additions and 104 deletions

View file

@ -316,7 +316,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
// * Installed // * Installed
// We will go with the easy path of Installed, and that's it. // We will go with the easy path of Installed, and that's it.
auto statuses = {SCE_NP_TROPHY_STATUS_NOT_INSTALLED, auto statuses = {SCE_NP_TROPHY_STATUS_INSTALLED,
SCE_NP_TROPHY_STATUS_PROCESSING_SETUP, SCE_NP_TROPHY_STATUS_PROCESSING_SETUP,
SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS, SCE_NP_TROPHY_STATUS_PROCESSING_PROGRESS,
SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE, SCE_NP_TROPHY_STATUS_PROCESSING_FINALIZE,

View file

@ -448,7 +448,7 @@ public:
PadHandlerBase(pad_handler type = pad_handler::null); PadHandlerBase(pad_handler type = pad_handler::null);
virtual ~PadHandlerBase() = default; virtual ~PadHandlerBase() = default;
//Sets window to config the controller(optional) //Sets window to config the controller(optional)
virtual void GetNextButtonPress(const std::string& /*padId*/, const std::function<void(u16, std::string, int[])>& /*callback*/, bool /*get_blacklist*/ = false, std::vector<std::string> /*buttons*/ = {}) {}; virtual void GetNextButtonPress(const std::string& /*padId*/, const std::function<void(u16, std::string, std::string, int[])>& /*callback*/, const std::function<void(std::string)>& /*fail_callback*/, bool /*get_blacklist*/ = false, std::vector<std::string> /*buttons*/ = {}) {};
virtual void TestVibration(const std::string& /*padId*/, u32 /*largeMotor*/, u32 /*smallMotor*/) {}; virtual void TestVibration(const std::string& /*padId*/, u32 /*largeMotor*/, u32 /*smallMotor*/) {};
//Return list of devices for that handler //Return list of devices for that handler
virtual std::vector<std::string> ListDevices() = 0; virtual std::vector<std::string> ListDevices() = 0;

View file

@ -494,8 +494,85 @@ bool Emulator::BootRsxCapture(const std::string& path)
return true; return true;
} }
void Emulator::LimitCacheSize()
{
const std::string cache_location = Emulator::GetHdd1Dir() + "/cache";
if (!fs::is_dir(cache_location))
{
LOG_WARNING(GENERAL, "Cache does not exist (%s)", cache_location);
return;
}
const u64 size = fs::get_dir_size(cache_location);
const u64 max_size = static_cast<u64>(g_cfg.vfs.cache_max_size) * 1024 * 1024;
if (max_size == 0) // Everything must go, so no need to do checks
{
fs::remove_all(cache_location, false);
LOG_SUCCESS(GENERAL, "Cleared disk cache");
return;
}
if (size <= max_size)
{
LOG_TRACE(GENERAL, "Cache size below limit: %llu/%llu", size, max_size);
return;
}
LOG_SUCCESS(GENERAL, "Cleaning disk cache...");
std::vector<fs::dir_entry> file_list{};
fs::dir cache_dir{};
if (!cache_dir.open(cache_location))
{
LOG_ERROR(GENERAL, "Could not open cache directory");
return;
}
// retrieve items to delete
for (const auto &item : cache_dir)
{
if (item.name != "." && item.name != "..")
file_list.push_back(item);
}
cache_dir.close();
// sort oldest first
std::sort(file_list.begin(), file_list.end(), [](auto left, auto right)
{
return left.mtime < right.mtime;
});
// keep removing until cache is empty or enough bytes have been cleared
// cache is cleared down to 80% of limit to increase interval between clears
const u64 to_remove = static_cast<u64>(size - max_size * 0.8);
u64 removed = 0;
for (const auto &item : file_list)
{
const std::string &name = cache_location + "/" + item.name;
const u64 item_size = fs::is_dir(name) ? fs::get_dir_size(name) : item.size;
if (fs::is_dir(name))
{
fs::remove_all(name, true);
}
else
{
fs::remove_file(name);
}
removed += item_size;
if (removed >= to_remove)
break;
}
LOG_SUCCESS(GENERAL, "Cleaned disk cache, removed %.2f MB", size / 1024.0 / 1024.0);
}
bool Emulator::BootGame(const std::string& path, bool direct, bool add_only) bool Emulator::BootGame(const std::string& path, bool direct, bool add_only)
{ {
if (g_cfg.vfs.limit_cache_size)
LimitCacheSize();
static const char* boot_list[] = static const char* boot_list[] =
{ {
"/PS3_GAME/USRDIR/EBOOT.BIN", "/PS3_GAME/USRDIR/EBOOT.BIN",
@ -571,6 +648,11 @@ std::string Emulator::GetHddDir()
return fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", GetEmuDir()); return fmt::replace_all(g_cfg.vfs.dev_hdd0, "$(EmulatorDir)", GetEmuDir());
} }
std::string Emulator::GetHdd1Dir()
{
return fmt::replace_all(g_cfg.vfs.dev_hdd1, "$(EmulatorDir)", GetEmuDir());
}
std::string Emulator::GetSfoDirFromGamePath(const std::string& game_path, const std::string& user) std::string Emulator::GetSfoDirFromGamePath(const std::string& game_path, const std::string& user)
{ {
if (fs::is_file(game_path + "/PS3_DISC.SFB")) if (fs::is_file(game_path + "/PS3_DISC.SFB"))

View file

@ -189,6 +189,7 @@ struct EmuCallbacks
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()> reset_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;
@ -317,6 +318,9 @@ public:
private: private:
static std::string GetEmuDir(); static std::string GetEmuDir();
static std::string GetHdd1Dir();
void LimitCacheSize();
public: public:
static std::string GetHddDir(); static std::string GetHddDir();
static std::string GetSfoDirFromGamePath(const std::string& game_path, const std::string& user); static std::string GetSfoDirFromGamePath(const std::string& game_path, const std::string& user);
@ -404,6 +408,9 @@ struct cfg_root : cfg::node
cfg::_bool host_root{this, "Enable /host_root/"}; cfg::_bool host_root{this, "Enable /host_root/"};
cfg::_bool init_dirs{this, "Initialize Directories", true}; cfg::_bool init_dirs{this, "Initialize Directories", true};
cfg::_bool limit_cache_size{this, "Limit disk cache size", false};
cfg::_int<0, 10240> cache_max_size{this, "Disk cache maximum size (MB)", 5120};
} vfs{this}; } vfs{this};
struct node_video : cfg::node struct node_video : cfg::node

View file

@ -140,6 +140,7 @@
"system": { "system": {
"sysLangBox": "Some games may fail to boot if the system language is not available in the game itself.\nOther games will switch language automatically to what is selected here.\nIt is recommended leaving this on a language supported by the game.", "sysLangBox": "Some games may fail to boot if the system language is not available in the game itself.\nOther games will switch language automatically to what is selected here.\nIt is recommended leaving this on a language supported by the game.",
"enterButtonAssignment": "The button used for enter/accept/confirm in system dialogs.\nChange this to use the circle button instead, which is the default configuration on japanese systems and in many japanese games.\nIn these cases having the cross button assigned can often lead to confusion.", "enterButtonAssignment": "The button used for enter/accept/confirm in system dialogs.\nChange this to use the circle button instead, which is the default configuration on japanese systems and in many japanese games.\nIn these cases having the cross button assigned can often lead to confusion.",
"enableHostRoot": "Required for some Homebrew.\nIf unsure, don't use this option." "enableHostRoot": "Required for some Homebrew.\nIf unsure, don't use this option.",
"limitCacheSize": "Automatically removes older files from disk cache on boot if it grows larger than the specified value.\nGames can use the cache folder to temporarily store data outside of system memory. It is not used for long term storage."
} }
} }

View file

@ -96,7 +96,8 @@ ds4_pad_handler::ds4_pad_handler() : PadHandlerBase(pad_handler::ds4)
b_has_rumble = true; b_has_rumble = true;
b_has_deadzones = true; b_has_deadzones = true;
m_name_string = "Ds4 Pad #"; m_name_string = "DS4 Pad #";
m_max_devices = CELL_PAD_MAX_PORT_NUM;
m_trigger_threshold = trigger_max / 2; m_trigger_threshold = trigger_max / 2;
m_thumb_threshold = thumb_max / 2; m_thumb_threshold = thumb_max / 2;
@ -150,14 +151,14 @@ void ds4_pad_handler::init_config(pad_config* cfg, const std::string& name)
cfg->from_default(); cfg->from_default();
} }
void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons) void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, std::vector<std::string> buttons)
{ {
if (get_blacklist) if (get_blacklist)
blacklist.clear(); blacklist.clear();
std::shared_ptr<DS4Device> device = GetDevice(padId); std::shared_ptr<DS4Device> device = GetDevice(padId, true);
if (device == nullptr || device->hidDevice == nullptr) if (device == nullptr || device->hidDevice == nullptr)
return; return fail_callback(padId);
// Now that we have found a device, get its status // Now that we have found a device, get its status
DS4DataStatus status = GetRawData(device); DS4DataStatus status = GetRawData(device);
@ -167,7 +168,7 @@ void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::fu
// this also can mean disconnected, either way deal with it on next loop and reconnect // this also can mean disconnected, either way deal with it on next loop and reconnect
hid_close(device->hidDevice); hid_close(device->hidDevice);
device->hidDevice = nullptr; device->hidDevice = nullptr;
return; return fail_callback(padId);
} }
// return if nothing new has happened. ignore this to get the current state for blacklist // return if nothing new has happened. ignore this to get the current state for blacklist
@ -215,9 +216,9 @@ void ds4_pad_handler::GetNextButtonPress(const std::string& padId, const std::fu
int preview_values[6] = { data[L2], data[R2], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] }; int preview_values[6] = { data[L2], data[R2], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] };
if (pressed_button.first > 0) if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, preview_values); return callback(pressed_button.first, pressed_button.second, padId, preview_values);
else else
return callback(0, "", preview_values); return callback(0, "", padId, preview_values);
} }
void ds4_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) void ds4_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor)
@ -249,7 +250,7 @@ void ds4_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u3
SendVibrateData(device); SendVibrateData(device);
} }
std::shared_ptr<ds4_pad_handler::DS4Device> ds4_pad_handler::GetDevice(const std::string& padId) std::shared_ptr<ds4_pad_handler::DS4Device> ds4_pad_handler::GetDevice(const std::string& padId, bool try_reconnect)
{ {
if (!Init()) if (!Init())
return nullptr; return nullptr;
@ -261,11 +262,22 @@ std::shared_ptr<ds4_pad_handler::DS4Device> ds4_pad_handler::GetDevice(const std
std::string pad_serial = padId.substr(pos + 9); std::string pad_serial = padId.substr(pos + 9);
std::shared_ptr<DS4Device> device = nullptr; std::shared_ptr<DS4Device> device = nullptr;
int i = 0; // Controllers 1-n in GUI
for (auto& cur_control : controllers) for (auto& cur_control : controllers)
{ {
if (pad_serial == cur_control.first) if (pad_serial == std::to_string(++i) || pad_serial == cur_control.first)
{ {
device = cur_control.second; device = cur_control.second;
if (try_reconnect && device && !device->hidDevice)
{
device->hidDevice = hid_open_path(device->path.c_str());
if (device->hidDevice)
{
hid_set_nonblocking(device->hidDevice, 1);
LOG_NOTICE(HLE, "DS4 device %d reconnected", i);
}
}
break; break;
} }
} }
@ -768,9 +780,9 @@ std::vector<std::string> ds4_pad_handler::ListDevices()
if (!Init()) if (!Init())
return ds4_pads_list; return ds4_pads_list;
for (auto& pad : controllers) for (size_t i = 1; i <= controllers.size(); ++i) // Controllers 1-n in GUI
{ {
ds4_pads_list.emplace_back(m_name_string + pad.first); ds4_pads_list.emplace_back(m_name_string + std::to_string(i));
} }
return ds4_pads_list; return ds4_pads_list;

View file

@ -142,7 +142,7 @@ public:
std::vector<std::string> ListDevices() override; std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override; bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override; void ThreadProc() override;
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& buttonCallback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override; void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& buttonCallback, const std::function<void(std::string)>& fail_callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override;
void init_config(pad_config* cfg, const std::string& name) override; void init_config(pad_config* cfg, const std::string& name) override;
@ -154,7 +154,7 @@ private:
std::shared_ptr<DS4Device> m_dev; std::shared_ptr<DS4Device> m_dev;
private: private:
std::shared_ptr<DS4Device> GetDevice(const std::string& padId); std::shared_ptr<DS4Device> GetDevice(const std::string& padId, bool try_reconnect = false);
void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override; void TranslateButtonPress(u64 keyCode, bool& pressed, u16& val, bool ignore_threshold = false) override;
void ProcessDataToPad(const std::shared_ptr<DS4Device>& ds4Device, const std::shared_ptr<Pad>& pad); void ProcessDataToPad(const std::shared_ptr<DS4Device>& ds4Device, const std::shared_ptr<Pad>& pad);
// Copies data into padData if status is NewData, otherwise buffer is untouched // Copies data into padData if status is NewData, otherwise buffer is untouched

View file

@ -257,7 +257,7 @@ evdev_joystick_handler::EvdevDevice* evdev_joystick_handler::get_device(const st
return &dev; return &dev;
} }
void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons) void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, std::vector<std::string> buttons)
{ {
if (get_blacklist) if (get_blacklist)
blacklist.clear(); blacklist.clear();
@ -265,7 +265,7 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const
// Get our evdev device // Get our evdev device
EvdevDevice* device = get_device(padId); EvdevDevice* device = get_device(padId);
if (device == nullptr || device->device == nullptr) if (device == nullptr || device->device == nullptr)
return; return fail_callback(padId);
libevdev* dev = device->device; libevdev* dev = device->device;
// Try to query the latest event from the joystick. // Try to query the latest event from the joystick.
@ -381,20 +381,21 @@ void evdev_joystick_handler::GetNextButtonPress(const std::string& padId, const
return it != data.end() && dir == it->second.second ? it->second.first : 0; return it != data.end() && dir == it->second.second ? it->second.first : 0;
}; };
int preview_values[6] = int preview_values[6] = { 0, 0, 0, 0, 0, 0 };
if (buttons.size() == 10)
{ {
find_value(buttons[0]), // Left Trigger preview_values[0] = find_value(buttons[0]); // Left Trigger
find_value(buttons[1]), // Right Trigger preview_values[1] = find_value(buttons[1]); // Right Trigger
find_value(buttons[3]) - find_value(buttons[2]), // Left Stick X preview_values[2] = find_value(buttons[3]) - find_value(buttons[2]); // Left Stick X
find_value(buttons[5]) - find_value(buttons[4]), // Left Stick Y preview_values[3] = find_value(buttons[5]) - find_value(buttons[4]); // Left Stick Y
find_value(buttons[7]) - find_value(buttons[6]), // Right Stick X preview_values[4] = find_value(buttons[7]) - find_value(buttons[6]); // Right Stick X
find_value(buttons[9]) - find_value(buttons[8]), // Right Stick Y preview_values[5] = find_value(buttons[9]) - find_value(buttons[8]); // Right Stick Y
}; }
if (pressed_button.first > 0) if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, preview_values); return callback(pressed_button.first, pressed_button.second, padId, preview_values);
else else
return callback(0, "", preview_values); return callback(0, "", padId, preview_values);
} }
// https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp // https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp

View file

@ -338,7 +338,7 @@ public:
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override; bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override; void ThreadProc() override;
void Close(); void Close();
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override; void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override;
private: private:

View file

@ -94,12 +94,8 @@ int main(int argc, char** argv)
{ {
logs::set_init(); logs::set_init();
#ifdef _WIN32 #if defined(_WIN32) || defined(__APPLE__)
// use this instead of SetProcessDPIAware if Qt ever fully supports this on windows QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
// at the moment it can't display QCombobox frames for example
// I think there was an issue with gsframe if I recall correctly, so look out for that
//QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
SetProcessDPIAware();
#else #else
qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1"); qputenv("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
#endif #endif

View file

@ -283,13 +283,13 @@ void mm_joystick_handler::ThreadProc()
} }
} }
void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons) void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, std::vector<std::string> buttons)
{ {
if (get_blacklist) if (get_blacklist)
blacklist.clear(); blacklist.clear();
if (!Init()) if (!Init())
return; return fail_callback(padId);
static std::string cur_pad = ""; static std::string cur_pad = "";
static int id = -1; static int id = -1;
@ -301,7 +301,7 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std
if (id < 0) if (id < 0)
{ {
LOG_ERROR(GENERAL, "MMJOY GetNextButtonPress for device [%s] failed with id = %d", padId, id); LOG_ERROR(GENERAL, "MMJOY GetNextButtonPress for device [%s] failed with id = %d", padId, id);
return; return fail_callback(padId);
} }
} }
@ -316,7 +316,7 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std
switch (status) switch (status)
{ {
case JOYERR_UNPLUGGED: case JOYERR_UNPLUGGED:
break; return fail_callback(padId);
case JOYERR_NOERROR: case JOYERR_NOERROR:
auto data = GetButtonValues(js_info, js_caps); auto data = GetButtonValues(js_info, js_caps);
@ -403,20 +403,21 @@ void mm_joystick_handler::GetNextButtonPress(const std::string& padId, const std
return static_cast<u64>(key); return static_cast<u64>(key);
}; };
int preview_values[6] = int preview_values[6] = { 0, 0, 0, 0, 0, 0 };
if (buttons.size() == 10)
{ {
data[find_key(buttons[0])], preview_values[0] = data[find_key(buttons[0])];
data[find_key(buttons[1])], preview_values[1] = data[find_key(buttons[1])];
data[find_key(buttons[3])] - data[find_key(buttons[2])], preview_values[2] = data[find_key(buttons[3])] - data[find_key(buttons[2])];
data[find_key(buttons[5])] - data[find_key(buttons[4])], preview_values[3] = data[find_key(buttons[5])] - data[find_key(buttons[4])];
data[find_key(buttons[7])] - data[find_key(buttons[6])], preview_values[4] = data[find_key(buttons[7])] - data[find_key(buttons[6])];
data[find_key(buttons[9])] - data[find_key(buttons[8])], preview_values[5] = data[find_key(buttons[9])] - data[find_key(buttons[8])];
}; }
if (pressed_button.first > 0) if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, preview_values); return callback(pressed_button.first, pressed_button.second, padId, preview_values);
else else
return callback(0, "", preview_values); return callback(0, "", padId, preview_values);
break; break;
} }
@ -579,7 +580,7 @@ bool mm_joystick_handler::GetMMJOYDevice(int index, MMJOYDevice* dev)
LOG_NOTICE(GENERAL, "Joystick nr.%d found. Driver: %s", index, drv); LOG_NOTICE(GENERAL, "Joystick nr.%d found. Driver: %s", index, drv);
dev->device_id = index; dev->device_id = index;
dev->device_name = m_name_string + std::to_string(index); dev->device_name = m_name_string + std::to_string(index + 1); // Controllers 1-n in GUI
dev->device_info = js_info; dev->device_info = js_info;
dev->device_caps = js_caps; dev->device_caps = js_caps;

View file

@ -108,7 +108,7 @@ public:
std::vector<std::string> ListDevices() override; std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override; bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override; void ThreadProc() override;
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override; void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void init_config(pad_config* cfg, const std::string& name) override; void init_config(pad_config* cfg, const std::string& name) override;
private: private:

View file

@ -142,11 +142,21 @@ void pad_thread::Reset()
reset = active.load(); reset = active.load();
} }
void pad_thread::SetEnabled(bool enabled)
{
is_enabled = enabled;
}
void pad_thread::ThreadFunc() void pad_thread::ThreadFunc()
{ {
active = true; active = true;
while (active) while (active)
{ {
if (!is_enabled)
{
std::this_thread::sleep_for(1ms);
continue;
}
if (reset && reset.exchange(false)) if (reset && reset.exchange(false))
{ {
Init(); Init();

View file

@ -24,6 +24,7 @@ public:
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();
void SetEnabled(bool enabled);
protected: protected:
void ThreadFunc(); void ThreadFunc();
@ -40,6 +41,7 @@ protected:
atomic_t<bool> active{ false }; atomic_t<bool> active{ false };
atomic_t<bool> reset{ false }; atomic_t<bool> reset{ false };
atomic_t<bool> is_enabled{ true };
std::shared_ptr<std::thread> thread; std::shared_ptr<std::thread> thread;
}; };

View file

@ -146,6 +146,10 @@ void rpcs3_app::InitializeCallbacks()
{ {
pad::get_current_handler()->Reset(); pad::get_current_handler()->Reset();
}; };
callbacks.enable_pads = [this](bool enable)
{
pad::get_current_handler()->SetEnabled(enable);
};
callbacks.get_kb_handler = [=]() -> std::shared_ptr<KeyboardHandlerBase> callbacks.get_kb_handler = [=]() -> std::shared_ptr<KeyboardHandlerBase>
{ {

View file

@ -128,6 +128,8 @@ public:
Language, Language,
EnterButtonAssignment, EnterButtonAssignment,
EnableHostRoot, EnableHostRoot,
LimitCacheSize,
MaximumCacheSize,
// Virtual File System // Virtual File System
emulatorLocation, emulatorLocation,
@ -330,6 +332,8 @@ private:
{ Language, { "System", "Language"}}, { Language, { "System", "Language"}},
{ EnterButtonAssignment, { "System", "Enter button assignment"}}, { EnterButtonAssignment, { "System", "Enter button assignment"}},
{ EnableHostRoot, { "VFS", "Enable /host_root/"}}, { EnableHostRoot, { "VFS", "Enable /host_root/"}},
{ LimitCacheSize, { "VFS", "Limit disk cache size"}},
{ MaximumCacheSize, { "VFS", "Disk cache maximum size (MB)"}},
// Virtual File System // Virtual File System
{ emulatorLocation, { "VFS", "$(EmulatorDir)"}}, { emulatorLocation, { "VFS", "$(EmulatorDir)"}},

View file

@ -67,6 +67,8 @@ gs_frame::gs_frame(const QString& title, const QRect& geometry, QIcon appIcon, b
setSurfaceType(QSurface::VulkanSurface); setSurfaceType(QSurface::VulkanSurface);
#endif #endif
setMinimumWidth(160);
setMinimumHeight(90);
setGeometry(geometry); setGeometry(geometry);
setTitle(m_windowTitle); setTitle(m_windowTitle);
setVisibility(Hidden); setVisibility(Hidden);
@ -252,20 +254,26 @@ void gs_frame::delete_context(draw_context_t ctx)
int gs_frame::client_width() int gs_frame::client_width()
{ {
#if defined(_WIN32) || defined(__APPLE__) #ifdef _WIN32
return size().width(); RECT rect;
#else if (GetClientRect(HWND(winId()), &rect))
return size().width() * devicePixelRatio(); {
#endif return rect.right - rect.left;
}
#endif // _WIN32
return width() * devicePixelRatio();
} }
int gs_frame::client_height() int gs_frame::client_height()
{ {
#if defined(_WIN32) || defined(__APPLE__) #ifdef _WIN32
return size().height(); RECT rect;
#else if (GetClientRect(HWND(winId()), &rect))
return size().height() * devicePixelRatio(); {
#endif return rect.bottom - rect.top;
}
#endif // _WIN32
return height() * devicePixelRatio();
} }
void gs_frame::flip(draw_context_t, bool /*skip_frame*/) void gs_frame::flip(draw_context_t, bool /*skip_frame*/)

View file

@ -1252,8 +1252,25 @@ void main_window::CreateConnects()
auto openPadSettings = [this] auto openPadSettings = [this]
{ {
auto resetPadHandlers = [this]
{
if (Emu.IsStopped())
{
return;
}
Emu.GetCallbacks().reset_pads();
};
if (!Emu.IsStopped())
{
Emu.GetCallbacks().enable_pads(false);
}
pad_settings_dialog dlg(this); pad_settings_dialog dlg(this);
connect(&dlg, &QDialog::accepted, resetPadHandlers);
dlg.exec(); dlg.exec();
if (!Emu.IsStopped())
{
Emu.GetCallbacks().enable_pads(true);
}
}; };
connect(ui->confPadsAct, &QAction::triggered, openPadSettings); connect(ui->confPadsAct, &QAction::triggered, openPadSettings);

View file

@ -90,13 +90,14 @@ pad_settings_dialog::pad_settings_dialog(QWidget *parent)
connect(ui->chooseHandler, &QComboBox::currentTextChanged, this, &pad_settings_dialog::ChangeInputType); connect(ui->chooseHandler, &QComboBox::currentTextChanged, this, &pad_settings_dialog::ChangeInputType);
// Combobox: Devices // Combobox: Devices
connect(ui->chooseDevice, &QComboBox::currentTextChanged, [this](const QString& dev) connect(ui->chooseDevice, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index)
{ {
if (dev.isEmpty()) if (index < 0)
{ {
return; return;
} }
m_device_name = sstr(dev); const pad_info info = ui->chooseDevice->itemData(index).value<pad_info>();
m_device_name = info.name;
if (!g_cfg_input.player[m_tabs->currentIndex()]->device.from_string(m_device_name)) if (!g_cfg_input.player[m_tabs->currentIndex()]->device.from_string(m_device_name))
{ {
// Something went wrong // Something went wrong
@ -316,8 +317,14 @@ void pad_settings_dialog::InitButtons()
}); });
// Enable Button Remapping // Enable Button Remapping
const auto& callback = [=](u16 val, std::string name, int preview_values[6]) const auto& callback = [=](u16 val, std::string name, std::string pad_name, int preview_values[6])
{ {
SwitchPadInfo(pad_name, true);
if (!m_enable_buttons && !m_timer.isActive())
{
SwitchButtons(true);
}
if (m_handler->has_deadzones()) if (m_handler->has_deadzones())
{ {
ui->preview_trigger_left->setValue(preview_values[0]); ui->preview_trigger_left->setValue(preview_values[0]);
@ -349,8 +356,18 @@ void pad_settings_dialog::InitButtons()
} }
}; };
// Disable Button Remapping
const auto& fail_callback = [this](const std::string& pad_name)
{
SwitchPadInfo(pad_name, false);
if (m_enable_buttons)
{
SwitchButtons(false);
}
};
// Use timer to get button input // Use timer to get button input
connect(&m_timer_input, &QTimer::timeout, [this, callback]() connect(&m_timer_input, &QTimer::timeout, [this, callback, fail_callback]()
{ {
std::vector<std::string> buttons = std::vector<std::string> buttons =
{ {
@ -359,8 +376,45 @@ void pad_settings_dialog::InitButtons()
m_cfg_entries[button_ids::id_pad_rstick_left].key, m_cfg_entries[button_ids::id_pad_rstick_right].key, m_cfg_entries[button_ids::id_pad_rstick_down].key, m_cfg_entries[button_ids::id_pad_rstick_left].key, m_cfg_entries[button_ids::id_pad_rstick_right].key, m_cfg_entries[button_ids::id_pad_rstick_down].key,
m_cfg_entries[button_ids::id_pad_rstick_up].key m_cfg_entries[button_ids::id_pad_rstick_up].key
}; };
m_handler->GetNextButtonPress(m_device_name, callback, false, buttons); m_handler->GetNextButtonPress(m_device_name, callback, fail_callback, false, buttons);
}); });
// Use timer to refresh pad connection status
connect(&m_timer_pad_refresh, &QTimer::timeout, [this]()
{
for (int i = 0; i < ui->chooseDevice->count(); i++)
{
if (!ui->chooseDevice->itemData(i).canConvert<pad_info>())
{
LOG_FATAL(GENERAL, "Cannot convert itemData for index %d and itemText %s", i, sstr(ui->chooseDevice->itemText(i)));
continue;
}
const pad_info info = ui->chooseDevice->itemData(i).value<pad_info>();
m_handler->GetNextButtonPress(info.name, [=](u16 val, std::string name, std::string pad_name, int preview_values[6]) { SwitchPadInfo(pad_name, true); }, [=](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false);
}
});
}
void pad_settings_dialog::SwitchPadInfo(const std::string& pad_name, bool is_connected)
{
for (int i = 0; i < ui->chooseDevice->count(); i++)
{
const pad_info info = ui->chooseDevice->itemData(i).value<pad_info>();
if (info.name == pad_name)
{
if (info.is_connected != is_connected)
{
ui->chooseDevice->setItemData(i, QVariant::fromValue(pad_info{ pad_name, is_connected }));
ui->chooseDevice->setItemText(i, is_connected ? qstr(pad_name) : (qstr(pad_name) + Disconnected_suffix));
}
if (!is_connected && m_timer.isActive() && ui->chooseDevice->currentIndex() == i)
{
ReactivateButtons();
}
break;
}
}
} }
void pad_settings_dialog::ReloadButtons() void pad_settings_dialog::ReloadButtons()
@ -406,9 +460,6 @@ void pad_settings_dialog::ReloadButtons()
updateButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg.rs_right); updateButton(button_ids::id_pad_rstick_right, ui->b_rstick_right, &m_handler_cfg.rs_right);
updateButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg.rs_up); updateButton(button_ids::id_pad_rstick_up, ui->b_rstick_up, &m_handler_cfg.rs_up);
// Enable Vibration Checkboxes
ui->gb_vibration->setEnabled(m_handler->has_rumble());
ui->chb_vibration_large->setChecked((bool)m_handler_cfg.enable_vibration_motor_large); 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_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_switch->setChecked((bool)m_handler_cfg.switch_vibration_motors);
@ -416,11 +467,11 @@ void pad_settings_dialog::ReloadButtons()
m_min_force = m_handler->vibration_min; m_min_force = m_handler->vibration_min;
m_max_force = m_handler->vibration_max; m_max_force = m_handler->vibration_max;
// Enable Deadzone Settings // Enable Vibration Checkboxes
const bool enable_deadzones = m_handler->has_deadzones(); m_enable_rumble = m_handler->has_rumble();
ui->gb_sticks->setEnabled(enable_deadzones); // Enable Deadzone Settings
ui->gb_triggers->setEnabled(enable_deadzones); m_enable_deadzones = m_handler->has_deadzones();
// Enable Trigger Thresholds // Enable Trigger Thresholds
ui->slider_trigger_left->setRange(0, m_handler->trigger_max); ui->slider_trigger_left->setRange(0, m_handler->trigger_max);
@ -652,6 +703,12 @@ void pad_settings_dialog::UpdateLabel(bool is_reset)
void pad_settings_dialog::SwitchButtons(bool is_enabled) void pad_settings_dialog::SwitchButtons(bool is_enabled)
{ {
m_enable_buttons = is_enabled;
ui->gb_vibration->setEnabled(is_enabled && m_enable_rumble);
ui->gb_sticks->setEnabled(is_enabled && m_enable_deadzones);
ui->gb_triggers->setEnabled(is_enabled && m_enable_deadzones);
for (int i = button_ids::id_pad_begin + 1; i < button_ids::id_pad_end; i++) for (int i = button_ids::id_pad_begin + 1; i < button_ids::id_pad_end; i++)
{ {
m_padButtons->button(i)->setEnabled(is_enabled); m_padButtons->button(i)->setEnabled(is_enabled);
@ -675,7 +732,7 @@ void pad_settings_dialog::OnPadButtonClicked(int id)
UpdateLabel(true); UpdateLabel(true);
return; return;
case button_ids::id_blacklist: case button_ids::id_blacklist:
m_handler->GetNextButtonPress(m_device_name, nullptr, true); m_handler->GetNextButtonPress(m_device_name, nullptr, nullptr, true);
return; return;
default: default:
break; break;
@ -769,18 +826,20 @@ void pad_settings_dialog::ChangeInputType()
// Get this player's current handler and it's currently available devices // Get this player's current handler and it's currently available devices
m_handler = GetHandler(g_cfg_input.player[player]->handler); m_handler = GetHandler(g_cfg_input.player[player]->handler);
const std::vector<std::string> list_devices = m_handler->ListDevices(); const auto device_list = m_handler->ListDevices();
// Refill the device combobox with currently available devices // Refill the device combobox with currently available devices
switch (m_handler->m_type) switch (m_handler->m_type)
{ {
#ifdef _WIN32 #ifdef _WIN32
case pad_handler::ds4:
case pad_handler::xinput: case pad_handler::xinput:
{ {
const QString name_string = qstr(m_handler->name_string()); const QString name_string = qstr(m_handler->name_string());
for (int i = 0; i < m_handler->max_devices(); i++) for (int i = 1; i <= m_handler->max_devices(); i++) // Controllers 1-n in GUI
{ {
ui->chooseDevice->addItem(name_string + QString::number(i), i); const QString device_name = name_string + QString::number(i);
ui->chooseDevice->addItem(device_name, QVariant::fromValue(pad_info{ sstr(device_name), true }));
} }
force_enable = true; force_enable = true;
break; break;
@ -788,21 +847,34 @@ void pad_settings_dialog::ChangeInputType()
#endif #endif
default: default:
{ {
for (int i = 0; i < list_devices.size(); i++) for (int i = 0; i < device_list.size(); i++)
{ {
ui->chooseDevice->addItem(qstr(list_devices[i]), i); ui->chooseDevice->addItem(qstr(device_list[i]), QVariant::fromValue(pad_info{ device_list[i], true }));
} }
break; break;
} }
} }
// Handle empty device list // Handle empty device list
bool config_enabled = force_enable || (m_handler->m_type != pad_handler::null && list_devices.size() > 0); bool config_enabled = force_enable || (m_handler->m_type != pad_handler::null && ui->chooseDevice->count() > 0);
ui->chooseDevice->setEnabled(config_enabled); ui->chooseDevice->setEnabled(config_enabled);
if (config_enabled) if (config_enabled)
{ {
ui->chooseDevice->setCurrentText(qstr(device)); for (int i = 0; i < ui->chooseDevice->count(); i++)
{
if (!ui->chooseDevice->itemData(i).canConvert<pad_info>())
{
LOG_FATAL(GENERAL, "Cannot convert itemData for index %d and itemText %s", i, sstr(ui->chooseDevice->itemText(i)));
continue;
}
const pad_info info = ui->chooseDevice->itemData(i).value<pad_info>();
m_handler->GetNextButtonPress(info.name, [=](u16 val, std::string name, std::string pad_name, int preview_values[6]) { SwitchPadInfo(pad_name, true); }, [=](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false);
if (info.name == device)
{
ui->chooseDevice->setCurrentIndex(i);
}
}
QString profile_dir = qstr(PadHandlerBase::get_config_dir(m_handler->m_type)); QString profile_dir = qstr(PadHandlerBase::get_config_dir(m_handler->m_type));
QStringList profiles = gui::utils::get_dir_entries(QDir(profile_dir), QStringList() << "*.yml"); QStringList profiles = gui::utils::get_dir_entries(QDir(profile_dir), QStringList() << "*.yml");
@ -835,7 +907,7 @@ void pad_settings_dialog::ChangeInputType()
} }
// enable configuration and profile list if possible // enable configuration and profile list if possible
SwitchButtons(config_enabled); SwitchButtons(config_enabled && m_handler->m_type == pad_handler::keyboard);
ui->b_addProfile->setEnabled(config_enabled); ui->b_addProfile->setEnabled(config_enabled);
ui->chooseProfile->setEnabled(config_enabled); ui->chooseProfile->setEnabled(config_enabled);
} }
@ -856,6 +928,10 @@ void pad_settings_dialog::ChangeProfile()
{ {
m_timer_input.stop(); m_timer_input.stop();
} }
if (m_timer_pad_refresh.isActive())
{
m_timer_pad_refresh.stop();
}
// 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_profile + ".yml";
@ -900,6 +976,7 @@ void pad_settings_dialog::ChangeProfile()
if (ui->chooseDevice->isEnabled() && ui->chooseDevice->currentIndex() >= 0) if (ui->chooseDevice->isEnabled() && ui->chooseDevice->currentIndex() >= 0)
{ {
m_timer_input.start(1); m_timer_input.start(1);
m_timer_pad_refresh.start(1000);
} }
} }
@ -944,16 +1021,6 @@ void pad_settings_dialog::SaveProfile()
m_handler_cfg.save(); m_handler_cfg.save();
} }
void pad_settings_dialog::ResetPadHandler()
{
if (Emu.IsStopped())
{
return;
}
Emu.GetCallbacks().reset_pads();
}
void pad_settings_dialog::SaveExit() void pad_settings_dialog::SaveExit()
{ {
SaveProfile(); SaveProfile();
@ -970,8 +1037,6 @@ void pad_settings_dialog::SaveExit()
g_cfg_input.save(); g_cfg_input.save();
ResetPadHandler();
QDialog::accept(); QDialog::accept();
} }

View file

@ -14,6 +14,14 @@ namespace Ui
class pad_settings_dialog; class pad_settings_dialog;
} }
struct pad_info
{
std::string name;
bool is_connected;
};
Q_DECLARE_METATYPE(pad_info);
class pad_settings_dialog : public QDialog class pad_settings_dialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
@ -73,6 +81,8 @@ class pad_settings_dialog : public QDialog
QString text; QString text;
}; };
const QString Disconnected_suffix = tr(" (disconnected)");
public: public:
explicit pad_settings_dialog(QWidget *parent = nullptr); explicit pad_settings_dialog(QWidget *parent = nullptr);
~pad_settings_dialog(); ~pad_settings_dialog();
@ -93,6 +103,11 @@ private:
// TabWidget // TabWidget
QTabWidget* m_tabs; QTabWidget* m_tabs;
// Capabilities
bool m_enable_buttons{ false };
bool m_enable_rumble{ false };
bool m_enable_deadzones{ false };
// Button Mapping // Button Mapping
QButtonGroup* m_padButtons; QButtonGroup* m_padButtons;
u32 m_button_id = id_pad_begin; u32 m_button_id = id_pad_begin;
@ -116,6 +131,7 @@ private:
pad_config m_handler_cfg; pad_config m_handler_cfg;
std::string m_device_name; std::string m_device_name;
std::string m_profile; std::string m_profile;
QTimer m_timer_pad_refresh;
// Remap Timer // Remap Timer
const int MAX_SECONDS = 5; const int MAX_SECONDS = 5;
@ -130,6 +146,7 @@ private:
/** Update all the Button Labels with current button mapping */ /** Update all the Button Labels with current button mapping */
void UpdateLabel(bool is_reset = false); void UpdateLabel(bool is_reset = false);
void SwitchPadInfo(const std::string& name, bool is_connected);
/** Enable/Disable Buttons while trying to remap an other */ /** Enable/Disable Buttons while trying to remap an other */
void SwitchButtons(bool is_enabled); void SwitchButtons(bool is_enabled);
@ -141,7 +158,6 @@ private:
void ReloadButtons(); void ReloadButtons();
void ChangeProfile(); void ChangeProfile();
void ResetPadHandler();
/** Repaints a stick deadzone preview label */ /** Repaints a stick deadzone preview label */
void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y); void RepaintPreviewLabel(QLabel* l, int dz, int w, int x, int y);

View file

@ -2,6 +2,9 @@
<ui version="4.0"> <ui version="4.0">
<class>pad_settings_dialog</class> <class>pad_settings_dialog</class>
<widget class="QDialog" name="pad_settings_dialog"> <widget class="QDialog" name="pad_settings_dialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>

View file

@ -784,6 +784,16 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> guiSettings, std:
xemu_settings->EnhanceCheckBox(ui->enableHostRoot, emu_settings::EnableHostRoot); xemu_settings->EnhanceCheckBox(ui->enableHostRoot, emu_settings::EnableHostRoot);
SubscribeTooltip(ui->enableHostRoot, json_sys["enableHostRoot"].toString()); SubscribeTooltip(ui->enableHostRoot, json_sys["enableHostRoot"].toString());
xemu_settings->EnhanceCheckBox(ui->enableCacheClearing, emu_settings::LimitCacheSize);
SubscribeTooltip(ui->enableCacheClearing, json_sys["limitCacheSize"].toString());
connect(ui->enableCacheClearing, &QCheckBox::stateChanged, ui->maximumCacheSize, &QSlider::setEnabled);
// Sliders
EnhanceSlider(emu_settings::MaximumCacheSize, ui->maximumCacheSize, ui->maximumCacheSizeLabel, tr("Maximum size: %0 MB"));
SubscribeTooltip(ui->maximumCacheSize, json_sys["limitCacheSize"].toString());
ui->maximumCacheSize->setEnabled(ui->enableCacheClearing->isChecked());
// Radio Buttons // Radio Buttons
SubscribeTooltip(ui->gb_enterButtonAssignment, json_sys["enterButtonAssignment"].toString()); SubscribeTooltip(ui->gb_enterButtonAssignment, json_sys["enterButtonAssignment"].toString());

View file

@ -1149,6 +1149,55 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="1,1,1">
<item>
<widget class="QGroupBox" name="gb_DiskCacheClearing">
<property name="title">
<string>Disk cache</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_73">
<item>
<widget class="QCheckBox" name="enableCacheClearing">
<property name="text">
<string>Clear cache automatically</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="maximumCacheSizeLabel">
<property name="text">
<string>Cache size: 3072 MB</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="maximumCacheSize">
<property name="pageStep">
<number>512</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1024</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_14" native="true"/>
</item>
<item>
<widget class="QWidget" name="widget_15" native="true"/>
</item>
</layout>
</item>
<item> <item>
<spacer name="verticalSpacer_8"> <spacer name="verticalSpacer_8">
<property name="orientation"> <property name="orientation">

View file

@ -74,14 +74,14 @@ void xinput_pad_handler::init_config(pad_config* cfg, const std::string& name)
cfg->from_default(); cfg->from_default();
} }
void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist, std::vector<std::string> buttons) void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist, std::vector<std::string> buttons)
{ {
if (get_blacklist) if (get_blacklist)
blacklist.clear(); blacklist.clear();
int device_number = GetDeviceNumber(padId); int device_number = GetDeviceNumber(padId);
if (device_number < 0) if (device_number < 0)
return; return fail_callback(padId);
DWORD dwResult; DWORD dwResult;
XINPUT_STATE state; XINPUT_STATE state;
@ -90,7 +90,7 @@ void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std:
// Simply get the state of the controller from XInput. // Simply get the state of the controller from XInput.
dwResult = (*xinputGetState)(static_cast<u32>(device_number), &state); dwResult = (*xinputGetState)(static_cast<u32>(device_number), &state);
if (dwResult != ERROR_SUCCESS) if (dwResult != ERROR_SUCCESS)
return; return fail_callback(padId);
// Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed. // Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed.
// Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold) // Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold)
@ -131,9 +131,9 @@ void xinput_pad_handler::GetNextButtonPress(const std::string& padId, const std:
int preview_values[6] = { data[LT], data[RT], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] }; int preview_values[6] = { data[LT], data[RT], data[LSXPos] - data[LSXNeg], data[LSYPos] - data[LSYNeg], data[RSXPos] - data[RSXNeg], data[RSYPos] - data[RSYNeg] };
if (pressed_button.first > 0) if (pressed_button.first > 0)
return callback(pressed_button.first, pressed_button.second, preview_values); return callback(pressed_button.first, pressed_button.second, padId, preview_values);
else else
return callback(0, "", preview_values); return callback(0, "", padId, preview_values);
} }
void xinput_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) void xinput_pad_handler::TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor)
@ -197,7 +197,7 @@ int xinput_pad_handler::GetDeviceNumber(const std::string& padId)
if (pos == std::string::npos) if (pos == std::string::npos)
return -1; return -1;
int device_number = std::stoul(padId.substr(pos + 12)); int device_number = std::stoul(padId.substr(pos + 12)) - 1; // Controllers 1-n in GUI
if (device_number >= XUSER_MAX_COUNT) if (device_number >= XUSER_MAX_COUNT)
return -1; return -1;
@ -455,7 +455,7 @@ std::vector<std::string> xinput_pad_handler::ListDevices()
XINPUT_STATE state; XINPUT_STATE state;
DWORD result = (*xinputGetState)(i, &state); DWORD result = (*xinputGetState)(i, &state);
if (result == ERROR_SUCCESS) if (result == ERROR_SUCCESS)
xinput_pads_list.push_back(m_name_string + std::to_string(i)); xinput_pads_list.push_back(m_name_string + std::to_string(i + 1)); // Controllers 1-n in GUI
} }
return xinput_pads_list; return xinput_pads_list;
} }

View file

@ -107,7 +107,7 @@ public:
std::vector<std::string> ListDevices() override; std::vector<std::string> ListDevices() override;
bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override; bool bindPadToDevice(std::shared_ptr<Pad> pad, const std::string& device) override;
void ThreadProc() override; void ThreadProc() override;
void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, int[])>& callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override; void GetNextButtonPress(const std::string& padId, const std::function<void(u16, std::string, std::string, int[])>& callback, const std::function<void(std::string)>& fail_callback, bool get_blacklist = false, std::vector<std::string> buttons = {}) override;
void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override; void TestVibration(const std::string& padId, u32 largeMotor, u32 smallMotor) override;
void init_config(pad_config* cfg, const std::string& name) override; void init_config(pad_config* cfg, const std::string& name) override;