input/qt: let user choose raw mouse device

This commit is contained in:
Megamouse 2024-05-20 14:01:20 +02:00
parent dae4eb2d0e
commit 5a08ae4f41
7 changed files with 118 additions and 13 deletions

View file

@ -12,6 +12,8 @@ struct raw_mouse_config : cfg::node
public:
using cfg::node::node;
cfg::string device{this, "Device", ""};
cfg::_float<10, 1000> mouse_acceleration{ this, "Mouse Acceleration", 100.0f, true };
cfg::string mouse_button_1{this, "Button 1", "Button 1"};

View file

@ -214,6 +214,12 @@ void raw_mouse::update_values(const RAWMOUSE& state)
}
#endif
raw_mouse_handler::raw_mouse_handler(bool ignore_config)
: MouseHandlerBase()
, m_ignore_config(ignore_config)
{
}
raw_mouse_handler::~raw_mouse_handler()
{
if (m_raw_mice.empty())
@ -253,7 +259,16 @@ void raw_mouse_handler::Init(const u32 max_connect)
m_mice.clear();
for (u32 i = 0; i < std::min(::size32(m_raw_mice), max_connect); i++)
// Get max device index
u32 now_connect = 0;
std::set<u32> connected_mice{};
for (const auto& [handle, mouse] : m_raw_mice)
{
now_connect = std::max(now_connect, mouse.index());
connected_mice.insert(mouse.index());
}
for (u32 i = 0; i < now_connect; i++)
{
m_mice.emplace_back(Mouse());
}
@ -265,7 +280,7 @@ void raw_mouse_handler::Init(const u32 max_connect)
for (u32 i = 0; i < m_info.now_connect; i++)
{
m_info.status[i] = CELL_MOUSE_STATUS_CONNECTED;
m_info.status[i] = connected_mice.contains(i) ? CELL_MOUSE_STATUS_CONNECTED : CELL_MOUSE_STATUS_DISCONNECTED;
m_info.mode[i] = CELL_MOUSE_INFO_TABLET_MOUSE_MODE;
m_info.tablet_is_supported[i] = CELL_MOUSE_INFO_TABLET_NOT_SUPPORTED;
m_info.vendor_id[0] = 0x1234;
@ -371,9 +386,24 @@ void raw_mouse_handler::enumerate_devices(u32 max_connect)
const std::string device_name = wchar_to_utf8(buf.data());
input_log.notice("raw_mouse_handler: adding device %d: '%s'", m_raw_mice.size(), device_name);
if (m_ignore_config)
{
input_log.notice("raw_mouse_handler: adding device %d: '%s'", m_raw_mice.size(), device_name);
m_raw_mice[device.hDevice] = raw_mouse(::size32(m_raw_mice), device_name, device.hDevice, this);
continue;
}
m_raw_mice[device.hDevice] = raw_mouse(::size32(m_raw_mice), device_name, device.hDevice, this);
for (u32 i = 0; i < std::min(max_connect, ::size32(g_cfg_raw_mouse.players)); i++)
{
const auto& player = ::at32(g_cfg_raw_mouse.players, i);
if (player && player->device.to_string() == device_name)
{
input_log.notice("raw_mouse_handler: adding device %d: '%s'", m_raw_mice.size(), device_name);
m_raw_mice[device.hDevice] = raw_mouse(i, device_name, device.hDevice, this);
break;
}
}
}
#endif

View file

@ -2,6 +2,7 @@
#include "Emu/Io/MouseHandler.h"
#include "Emu/RSX/display.h"
#include "Utilities/Config.h"
#ifdef _WIN32
#include <windows.h>
@ -37,6 +38,9 @@ public:
void update_values(const RAWMOUSE& state);
#endif
const std::string& device_name() const { return m_device_name; }
u32 index() const { return m_index; }
private:
static std::pair<int, int> get_mouse_button(const cfg::string& button);
@ -57,13 +61,14 @@ private:
class raw_mouse_handler final : public MouseHandlerBase
{
using MouseHandlerBase::MouseHandlerBase;
public:
raw_mouse_handler(bool ignore_config = false);
virtual ~raw_mouse_handler();
void Init(const u32 max_connect) override;
const std::map<void*, raw_mouse>& get_mice() const { return m_raw_mice; };
#ifdef _WIN32
void handle_native_event(const MSG& msg);
#endif
@ -71,5 +76,6 @@ public:
private:
void enumerate_devices(u32 max_connect);
bool m_ignore_config = false;
std::map<void*, raw_mouse> m_raw_mice;
};

View file

@ -1,3 +1,4 @@
#include "stdafx.h"
#include "gui_application.h"
#include "qt_utils.h"
@ -22,7 +23,6 @@
#include "Emu/vfs_config.h"
#include "util/init_mutex.hpp"
#include "util/console.h"
#include "Input/raw_mouse_handler.h"
#include "trophy_notification_helper.h"
#include "save_data_dialog.h"
#include "msg_dialog_frame.h"
@ -58,6 +58,8 @@
LOG_CHANNEL(gui_log, "GUI");
std::unique_ptr<raw_mouse_handler> g_raw_mouse_handler;
[[noreturn]] void report_fatal_error(std::string_view text, bool is_html = false, bool include_help_text = true);
gui_application::gui_application(int& argc, char** argv) : QApplication(argc, argv)
@ -1124,6 +1126,11 @@ bool gui_application::native_event_filter::nativeEventFilter([[maybe_unused]] co
{
static_cast<raw_mouse_handler*>(handler)->handle_native_event(*msg);
}
if (g_raw_mouse_handler)
{
g_raw_mouse_handler->handle_native_event(*msg);
}
}
}
#endif

View file

@ -13,6 +13,7 @@
#include "main_application.h"
#include "Emu/System.h"
#include "Input/raw_mouse_handler.h"
#include <memory>
#include <functional>
@ -24,6 +25,8 @@ class gui_settings;
class emu_settings;
class persistent_settings;
extern std::unique_ptr<raw_mouse_handler> g_raw_mouse_handler; // Only used for GUI
/** RPCS3 GUI Application Class
* The main point of this class is to do application initialization, to hold the main and game windows and to initialize callbacks.
*/

View file

@ -1,12 +1,12 @@
#include "stdafx.h"
#include "raw_mouse_settings_dialog.h"
#include "localized_emu.h"
#include "gui_application.h"
#include "Input/raw_mouse_config.h"
#include "Input/raw_mouse_handler.h"
#include "util/asm.hpp"
#include <QDialogButtonBox>
#include <QDoubleSpinBox>
#include <QGroupBox>
#include <QMessageBox>
#include <QPushButton>
@ -68,6 +68,9 @@ raw_mouse_settings_dialog::raw_mouse_settings_dialog(QWidget* parent)
cfg_log.notice("Could not load raw mouse config. Using defaults.");
}
g_raw_mouse_handler = std::make_unique<raw_mouse_handler>(true);
g_raw_mouse_handler->Init(::size32(g_cfg_raw_mouse.players));
add_tabs(tabs);
v_layout->addWidget(tabs);
@ -75,6 +78,11 @@ raw_mouse_settings_dialog::raw_mouse_settings_dialog(QWidget* parent)
setLayout(v_layout);
}
raw_mouse_settings_dialog::~raw_mouse_settings_dialog()
{
g_raw_mouse_handler.reset();
}
void raw_mouse_settings_dialog::add_tabs(QTabWidget* tabs)
{
ensure(!!tabs);
@ -92,6 +100,9 @@ void raw_mouse_settings_dialog::add_tabs(QTabWidget* tabs)
m_combos.resize(players);
ensure(g_raw_mouse_handler);
const auto& mice = g_raw_mouse_handler->get_mice();
for (usz player = 0; player < players; player++)
{
QWidget* widget = new QWidget(this);
@ -99,7 +110,38 @@ void raw_mouse_settings_dialog::add_tabs(QTabWidget* tabs)
auto& config = ::at32(g_cfg_raw_mouse.players, player);
for (int i = 0, row = 0, col = 0; i < static_cast<int>(button_count); i++, row++)
QHBoxLayout* h_layout = new QHBoxLayout(this);
QGroupBox* gb = new QGroupBox(tr("Device"), this);
QComboBox* combo = new QComboBox(this);
m_device_combos.push_back(combo);
combo->addItem(tr("Disabled"), QString());
for (const auto& [handle, mouse] : mice)
{
const QString name = QString::fromStdString(mouse.device_name());
const QString& pretty_name = name; // Same ugly device path for now
combo->addItem(pretty_name, name);
}
combo->setCurrentText(QString::fromStdString(config->device.to_string()));
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this, player, combo](int index)
{
if (index < 0 || !combo)
return;
const QVariant data = combo->itemData(index);
if (!data.isValid() || !data.canConvert<QString>())
return;
auto& config = ::at32(g_cfg_raw_mouse.players, player)->device;
config.from_string(data.toString().toStdString());
});
h_layout->addWidget(combo);
gb->setLayout(h_layout);
grid_layout->addWidget(gb, 0, 0, 1, 2);
const int first_row = grid_layout->rowCount();
for (int i = 0, row = first_row, col = 0; i < static_cast<int>(button_count); i++, row++)
{
const int cell_code = get_mouse_button_code(i);
const QString translated_cell_button = localized_emu::translated_mouse_button(cell_code);
@ -134,9 +176,9 @@ void raw_mouse_settings_dialog::add_tabs(QTabWidget* tabs)
::at32(g_cfg_raw_mouse.players, player)->get_button(cell_code).from_string(data.toString().toStdString());
});
if (row >= rows)
if (row >= rows + first_row)
{
row = 0;
row = first_row;
col++;
}
@ -146,9 +188,10 @@ void raw_mouse_settings_dialog::add_tabs(QTabWidget* tabs)
grid_layout->addWidget(gb, row, col);
}
QHBoxLayout* h_layout = new QHBoxLayout(this);
QGroupBox* gb = new QGroupBox(tr("Mouse Acceleration"), this);
h_layout = new QHBoxLayout(this);
gb = new QGroupBox(tr("Mouse Acceleration"), this);
QDoubleSpinBox* mouse_acceleration_spin_box = new QDoubleSpinBox(this);
m_accel_spin_boxes.push_back(mouse_acceleration_spin_box);
mouse_acceleration_spin_box->setRange(0.1, 10.0);
mouse_acceleration_spin_box->setValue(config->mouse_acceleration.get() / 100.0);
connect(mouse_acceleration_spin_box, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, [player](double value)
@ -188,5 +231,15 @@ void raw_mouse_settings_dialog::reset_config()
combo->setCurrentIndex(combo->findData(def_btn_id, button_role::button_name));
}
if (QComboBox* combo = ::at32(m_device_combos, player))
{
combo->setCurrentIndex(combo->findData(QString::fromStdString(config->device.to_string())));
}
if (QDoubleSpinBox* sb = ::at32(m_accel_spin_boxes, player))
{
sb->setValue(config->mouse_acceleration.get() / 100.0);
}
}
}

View file

@ -2,6 +2,7 @@
#include <QComboBox>
#include <QDialog>
#include <QDoubleSpinBox>
#include <QTabWidget>
#include <vector>
@ -12,11 +13,14 @@ class raw_mouse_settings_dialog : public QDialog
public:
raw_mouse_settings_dialog(QWidget* parent = nullptr);
virtual ~raw_mouse_settings_dialog();
private:
void add_tabs(QTabWidget* tabs);
void reset_config();
std::vector<QComboBox*> m_device_combos;
std::vector<QDoubleSpinBox*> m_accel_spin_boxes;
std::vector<std::vector<QComboBox*>> m_combos;
};