mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-29 00:33:01 +00:00
Qt: use dedicated thread for getting input in the pad settings
This fixes the slow motion and rubber banding in the pad settings dialog while using HID handlers. Previously everything was running on the main thread including the UI updates. This meant that the poll rate was simply too slow and we were never up to date with the current data.
This commit is contained in:
parent
16381929ba
commit
c4459dff40
@ -104,7 +104,7 @@ main_window::~main_window()
|
||||
/* An init method is used so that RPCS3App can create the necessary connects before calling init (specifically the stylesheet connect).
|
||||
* Simplifies logic a bit.
|
||||
*/
|
||||
bool main_window::Init(bool with_cli_boot)
|
||||
bool main_window::Init([[maybe_unused]] bool with_cli_boot)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "Input/product_info.h"
|
||||
#include "Input/keyboard_pad_handler.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
LOG_CHANNEL(cfg_log, "CFG");
|
||||
|
||||
inline std::string sstr(const QString& _in) { return _in.toStdString(); }
|
||||
@ -206,6 +208,14 @@ pad_settings_dialog::pad_settings_dialog(std::shared_ptr<gui_settings> gui_setti
|
||||
|
||||
pad_settings_dialog::~pad_settings_dialog()
|
||||
{
|
||||
if (m_input_thread)
|
||||
{
|
||||
m_input_thread_state = input_thread_state::pausing;
|
||||
auto& thread = *m_input_thread;
|
||||
thread = thread_state::aborting;
|
||||
thread();
|
||||
}
|
||||
|
||||
m_gui_settings->SetValue(gui::pads_geometry, saveGeometry());
|
||||
|
||||
if (!Emu.IsStopped())
|
||||
@ -440,17 +450,27 @@ void pad_settings_dialog::InitButtons()
|
||||
}
|
||||
};
|
||||
|
||||
// Use timer to get button input
|
||||
// Use timer to display button input
|
||||
connect(&m_timer_input, &QTimer::timeout, this, [this, callback, fail_callback]()
|
||||
{
|
||||
const std::vector<std::string> buttons =
|
||||
input_callback_data data;
|
||||
{
|
||||
m_cfg_entries[button_ids::id_pad_l2].key, m_cfg_entries[button_ids::id_pad_r2].key, m_cfg_entries[button_ids::id_pad_lstick_left].key,
|
||||
m_cfg_entries[button_ids::id_pad_lstick_right].key, m_cfg_entries[button_ids::id_pad_lstick_down].key, m_cfg_entries[button_ids::id_pad_lstick_up].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_handler->get_next_button_press(m_device_name, callback, fail_callback, false, buttons);
|
||||
std::lock_guard lock(m_input_mutex);
|
||||
data = m_input_callback_data;
|
||||
m_input_callback_data.has_new_data = false;
|
||||
}
|
||||
|
||||
if (data.has_new_data)
|
||||
{
|
||||
if (data.success)
|
||||
{
|
||||
callback(data.val, std::move(data.name), std::move(data.pad_name), data.battery_level, std::move(data.preview_values));
|
||||
}
|
||||
else
|
||||
{
|
||||
fail_callback(data.pad_name);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Use timer to refresh pad connection status
|
||||
@ -463,18 +483,73 @@ void pad_settings_dialog::InitButtons()
|
||||
cfg_log.fatal("Cannot convert itemData for index %d and itemText %s", i, sstr(ui->chooseDevice->itemText(i)));
|
||||
continue;
|
||||
}
|
||||
|
||||
const pad_device_info info = ui->chooseDevice->itemData(i).value<pad_device_info>();
|
||||
|
||||
std::lock_guard lock(m_handler_mutex);
|
||||
|
||||
m_handler->get_next_button_press(info.name,
|
||||
[this](u16, std::string, std::string pad_name, u32, pad_preview_values) { SwitchPadInfo(pad_name, true); },
|
||||
[this](std::string pad_name) { SwitchPadInfo(pad_name, false); }, false);
|
||||
}
|
||||
});
|
||||
|
||||
// Use thread to get button input
|
||||
m_input_thread = std::make_unique<named_thread<std::function<void()>>>("Pad Settings Thread", [this]()
|
||||
{
|
||||
while (thread_ctrl::state() != thread_state::aborting)
|
||||
{
|
||||
thread_ctrl::wait_for(1000);
|
||||
|
||||
if (m_input_thread_state != input_thread_state::active)
|
||||
{
|
||||
if (m_input_thread_state == input_thread_state::pausing)
|
||||
{
|
||||
m_input_thread_state = input_thread_state::paused;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
std::lock_guard lock(m_handler_mutex);
|
||||
|
||||
const std::vector<std::string> buttons =
|
||||
{
|
||||
m_cfg_entries[button_ids::id_pad_l2].key, m_cfg_entries[button_ids::id_pad_r2].key, m_cfg_entries[button_ids::id_pad_lstick_left].key,
|
||||
m_cfg_entries[button_ids::id_pad_lstick_right].key, m_cfg_entries[button_ids::id_pad_lstick_down].key, m_cfg_entries[button_ids::id_pad_lstick_up].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_handler->get_next_button_press(m_device_name,
|
||||
[this](u16 val, std::string name, std::string pad_name, u32 battery_level, pad_preview_values preview_values)
|
||||
{
|
||||
std::lock_guard lock(m_input_mutex);
|
||||
m_input_callback_data.val = val;
|
||||
m_input_callback_data.name = std::move(name);
|
||||
m_input_callback_data.pad_name = std::move(pad_name);
|
||||
m_input_callback_data.battery_level = battery_level;
|
||||
m_input_callback_data.preview_values = std::move(preview_values);
|
||||
m_input_callback_data.has_new_data = true;
|
||||
m_input_callback_data.success = true;
|
||||
},
|
||||
[this](std::string pad_name)
|
||||
{
|
||||
std::lock_guard lock(m_input_mutex);
|
||||
m_input_callback_data.pad_name = std::move(pad_name);
|
||||
m_input_callback_data.has_new_data = true;
|
||||
m_input_callback_data.success = false;
|
||||
},
|
||||
false, buttons);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void pad_settings_dialog::SetPadData(u32 large_motor, u32 small_motor, bool led_battery_indicator)
|
||||
{
|
||||
ensure(m_handler);
|
||||
const auto& cfg = GetPlayerConfig();
|
||||
|
||||
std::lock_guard lock(m_handler_mutex);
|
||||
m_handler->SetPadData(m_device_name, GetPlayerIndex(), large_motor, small_motor, cfg.colorR, cfg.colorG, cfg.colorB, led_battery_indicator, cfg.led_battery_indicator_brightness);
|
||||
}
|
||||
|
||||
@ -1082,8 +1157,11 @@ void pad_settings_dialog::OnPadButtonClicked(int id)
|
||||
UpdateLabels(true);
|
||||
return;
|
||||
case button_ids::id_blacklist:
|
||||
{
|
||||
std::lock_guard lock(m_handler_mutex);
|
||||
m_handler->get_next_button_press(m_device_name, nullptr, nullptr, true);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1131,6 +1209,9 @@ void pad_settings_dialog::OnTabChanged(int index)
|
||||
|
||||
void pad_settings_dialog::ChangeHandler()
|
||||
{
|
||||
// Pause input thread. This means we don't have to lock the handler mutex here.
|
||||
pause_input_thread();
|
||||
|
||||
bool force_enable = false; // enable configs even with disconnected devices
|
||||
const u32 player = GetPlayerIndex();
|
||||
const bool is_ldd_pad = GetIsLddPad(player);
|
||||
@ -1351,6 +1432,7 @@ void pad_settings_dialog::ChangeHandler()
|
||||
// Re-enable input timer
|
||||
if (ui->chooseDevice->isEnabled() && ui->chooseDevice->currentIndex() >= 0)
|
||||
{
|
||||
start_input_thread();
|
||||
m_timer_input.start(1);
|
||||
m_timer_pad_refresh.start(1000);
|
||||
}
|
||||
@ -1769,3 +1851,21 @@ void pad_settings_dialog::SubscribeTooltips()
|
||||
SubscribeTooltip(ui->gb_mouse_dz, tooltips.gamepad_settings.mouse_deadzones);
|
||||
SubscribeTooltip(ui->gb_mouse_movement, tooltips.gamepad_settings.mouse_movement);
|
||||
}
|
||||
|
||||
void pad_settings_dialog::start_input_thread()
|
||||
{
|
||||
m_input_thread_state = input_thread_state::active;
|
||||
}
|
||||
|
||||
void pad_settings_dialog::pause_input_thread()
|
||||
{
|
||||
if (m_input_thread)
|
||||
{
|
||||
m_input_thread_state = input_thread_state::pausing;
|
||||
|
||||
while (m_input_thread_state != input_thread_state::paused)
|
||||
{
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,11 @@
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "Emu/Io/pad_config.h"
|
||||
#include "Emu/GameInfo.h"
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
class gui_settings;
|
||||
class PadHandlerBase;
|
||||
@ -145,6 +148,7 @@ private:
|
||||
|
||||
// Pad Handlers
|
||||
std::shared_ptr<PadHandlerBase> m_handler;
|
||||
std::mutex m_handler_mutex;
|
||||
std::string m_device_name;
|
||||
std::string m_profile;
|
||||
QTimer m_timer_pad_refresh;
|
||||
@ -158,8 +162,27 @@ private:
|
||||
// Mouse Move
|
||||
QPoint m_last_pos;
|
||||
|
||||
// Input timer. Its Callback handles the input
|
||||
// Input timer. Updates the GUI with input values
|
||||
QTimer m_timer_input;
|
||||
std::mutex m_input_mutex;
|
||||
struct input_callback_data
|
||||
{
|
||||
bool success = false;
|
||||
bool has_new_data = false;
|
||||
u16 val = 0;
|
||||
std::string name;
|
||||
std::string pad_name;
|
||||
u32 battery_level = 0;
|
||||
std::array<int, 6> preview_values{};
|
||||
} m_input_callback_data;
|
||||
|
||||
// Input thread. Its Callback handles the input
|
||||
std::unique_ptr<named_thread<std::function<void()>>> m_input_thread;
|
||||
enum class input_thread_state { paused, pausing, active };
|
||||
atomic_t<input_thread_state> m_input_thread_state{input_thread_state::paused};
|
||||
|
||||
void start_input_thread();
|
||||
void pause_input_thread();
|
||||
|
||||
void SaveExit();
|
||||
void CancelExit();
|
||||
|
Loading…
x
Reference in New Issue
Block a user