From eb8ab8ef155e3d55ff477568e10b3f9e19549796 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 24 Dec 2020 13:48:22 +0100 Subject: [PATCH] implement mouse handler config --- rpcs3/CMakeLists.txt | 1 + rpcs3/Emu/CMakeLists.txt | 1 + rpcs3/Emu/Cell/Modules/cellGem.cpp | 2 - rpcs3/Emu/Io/GunCon3.cpp | 2 +- rpcs3/Emu/Io/MouseHandler.h | 25 ++- rpcs3/Emu/Io/mouse_config.cpp | 45 +++++ rpcs3/Emu/Io/mouse_config.h | 28 +++ rpcs3/Input/basic_mouse_handler.cpp | 56 ++++-- rpcs3/Input/basic_mouse_handler.h | 40 ++++ rpcs3/Input/raw_mouse_config.cpp | 73 +++++++ rpcs3/Input/raw_mouse_config.h | 66 ++----- rpcs3/Input/raw_mouse_handler.cpp | 46 ++++- rpcs3/Input/raw_mouse_handler.h | 15 ++ rpcs3/emucore.vcxproj | 3 +- rpcs3/emucore.vcxproj.filters | 9 +- rpcs3/rpcs3.vcxproj | 38 +++- rpcs3/rpcs3.vcxproj.filters | 32 ++- rpcs3/rpcs3qt/CMakeLists.txt | 2 + rpcs3/rpcs3qt/basic_mouse_settings_dialog.cpp | 149 ++++++++++++++ rpcs3/rpcs3qt/basic_mouse_settings_dialog.h | 19 ++ .../rpcs3qt/emulated_pad_settings_dialog.cpp | 2 +- rpcs3/rpcs3qt/localized_emu.cpp | 17 ++ rpcs3/rpcs3qt/localized_emu.h | 1 + rpcs3/rpcs3qt/main_window.cpp | 18 ++ rpcs3/rpcs3qt/main_window.ui | 20 +- rpcs3/rpcs3qt/pad_settings_dialog.cpp | 32 +-- rpcs3/rpcs3qt/pad_settings_dialog.h | 4 +- rpcs3/rpcs3qt/raw_mouse_settings_dialog.cpp | 187 ++++++++++++++++++ rpcs3/rpcs3qt/raw_mouse_settings_dialog.h | 22 +++ 29 files changed, 850 insertions(+), 105 deletions(-) create mode 100644 rpcs3/Emu/Io/mouse_config.cpp create mode 100644 rpcs3/Emu/Io/mouse_config.h create mode 100644 rpcs3/Input/raw_mouse_config.cpp create mode 100644 rpcs3/rpcs3qt/basic_mouse_settings_dialog.cpp create mode 100644 rpcs3/rpcs3qt/basic_mouse_settings_dialog.h create mode 100644 rpcs3/rpcs3qt/raw_mouse_settings_dialog.cpp create mode 100644 rpcs3/rpcs3qt/raw_mouse_settings_dialog.h diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index 4be00dca2f..7ee5e005ea 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -77,6 +77,7 @@ target_sources(rpcs3 Input/mm_joystick_handler.cpp Input/pad_thread.cpp Input/product_info.cpp + Input/raw_mouse_config.cpp Input/raw_mouse_handler.cpp Input/sdl_pad_handler.cpp Input/skateboard_pad_handler.cpp diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index f394055bd0..5613e49a6e 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -404,6 +404,7 @@ target_sources(rpcs3_emu PRIVATE Io/interception.cpp Io/KeyboardHandler.cpp Io/midi_config_types.cpp + Io/mouse_config.cpp Io/pad_config.cpp Io/pad_config_types.cpp Io/pad_types.cpp diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index c71e356cab..870b98da92 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -864,8 +864,6 @@ static void ds3_input_to_ext(const u32 gem_num, const gem_config::gem_controller /** * \brief Maps Move controller data (digital buttons, and analog Trigger data) to mouse input. - * Move Button: Mouse1 - * Trigger: Mouse2 * \param mouse_no Mouse index number to use * \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values * \param analog_t Analog value of Move's Trigger. diff --git a/rpcs3/Emu/Io/GunCon3.cpp b/rpcs3/Emu/Io/GunCon3.cpp index 5e46404c4d..9dcbee9aaf 100644 --- a/rpcs3/Emu/Io/GunCon3.cpp +++ b/rpcs3/Emu/Io/GunCon3.cpp @@ -15,7 +15,7 @@ void fmt_class_string::format(std::string& out, u64 arg) format_enum(out, arg, [](guncon3_btn value) { switch (value) - { + { case guncon3_btn::trigger: return "Trigger"; case guncon3_btn::a1: return "A1"; case guncon3_btn::a2: return "A2"; diff --git a/rpcs3/Emu/Io/MouseHandler.h b/rpcs3/Emu/Io/MouseHandler.h index 1ff3097418..7d9b1eaac9 100644 --- a/rpcs3/Emu/Io/MouseHandler.h +++ b/rpcs3/Emu/Io/MouseHandler.h @@ -3,6 +3,7 @@ #include #include #include +#include "Utilities/StrFmt.h" #include "Utilities/mutex.h" #include "util/init_mutex.hpp" #include "Emu/system_config_types.h" @@ -49,6 +50,22 @@ enum CELL_MOUSE_INFO_INTERCEPTED = 1 }; +static inline MouseButtonCodes get_mouse_button_code(int i) +{ + switch (i) + { + case 0: return CELL_MOUSE_BUTTON_1; + case 1: return CELL_MOUSE_BUTTON_2; + case 2: return CELL_MOUSE_BUTTON_3; + case 3: return CELL_MOUSE_BUTTON_4; + case 4: return CELL_MOUSE_BUTTON_5; + case 5: return CELL_MOUSE_BUTTON_6; + case 6: return CELL_MOUSE_BUTTON_7; + case 7: return CELL_MOUSE_BUTTON_8; + default: fmt::throw_exception("get_mouse_button_code: Invalid index %d", i); + } +} + static const u32 MAX_MICE = 127; static const u32 MOUSE_MAX_DATA_LIST_NUM = 8; static const u32 MOUSE_MAX_CODES = 64; @@ -191,7 +208,7 @@ public: MouseData new_data; new_data.update = CELL_MOUSE_DATA_UPDATE; - new_data.wheel = std::clamp(rotation / 120, -128, 127); //120=event.GetWheelDelta() + new_data.wheel = std::clamp(rotation / 120, -128, 127); // 120=event.GetWheelDelta() new_data.buttons = mouse.buttons; datalist.push_back(new_data); @@ -236,9 +253,9 @@ public: mouse.x_pos = x_pos_new; mouse.y_pos = y_pos_new; - /*CellMouseRawData& rawdata = GetRawData(p); - rawdata.data[rawdata.len % CELL_MOUSE_MAX_CODES] = 0; // (TODO) - rawdata.len++;*/ + //CellMouseRawData& rawdata = GetRawData(p); + //rawdata.data[rawdata.len % CELL_MOUSE_MAX_CODES] = 0; // (TODO) + //rawdata.len++; datalist.push_back(new_data); } diff --git a/rpcs3/Emu/Io/mouse_config.cpp b/rpcs3/Emu/Io/mouse_config.cpp new file mode 100644 index 0000000000..6e4cbf28f7 --- /dev/null +++ b/rpcs3/Emu/Io/mouse_config.cpp @@ -0,0 +1,45 @@ +#include "stdafx.h" +#include "mouse_config.h" +#include "MouseHandler.h" +#include "Utilities/File.h" + +mouse_config::mouse_config() + : cfg_name(fs::get_config_dir() + "/config_mouse.yml") +{ +} + +bool mouse_config::exist() const +{ + return fs::is_file(cfg_name); +} + +bool mouse_config::load() +{ + if (fs::file cfg_file{cfg_name, fs::read}) + { + return from_string(cfg_file.to_string()); + } + + return false; +} + +void mouse_config::save() const +{ + fs::file(cfg_name, fs::rewrite).write(to_string()); +} + +cfg::string& mouse_config::get_button(int code) +{ + switch (code) + { + case CELL_MOUSE_BUTTON_1: return mouse_button_1; + case CELL_MOUSE_BUTTON_2: return mouse_button_2; + case CELL_MOUSE_BUTTON_3: return mouse_button_3; + case CELL_MOUSE_BUTTON_4: return mouse_button_4; + case CELL_MOUSE_BUTTON_5: return mouse_button_5; + case CELL_MOUSE_BUTTON_6: return mouse_button_6; + case CELL_MOUSE_BUTTON_7: return mouse_button_7; + case CELL_MOUSE_BUTTON_8: return mouse_button_8; + default: fmt::throw_exception("Invalid code %d", code); + } +} diff --git a/rpcs3/Emu/Io/mouse_config.h b/rpcs3/Emu/Io/mouse_config.h new file mode 100644 index 0000000000..ac1df023cc --- /dev/null +++ b/rpcs3/Emu/Io/mouse_config.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Utilities/Config.h" + +// For simplicity's sake, there is only one config instead of 127 for MAX_MICE +struct mouse_config final : cfg::node +{ + mouse_config(); + + const std::string cfg_name; + + cfg::string mouse_button_1{this, "Button 1", "LeftButton"}; + cfg::string mouse_button_2{this, "Button 2", "RightButton"}; + cfg::string mouse_button_3{this, "Button 3", "MiddleButton"}; + cfg::string mouse_button_4{this, "Button 4", "NoButton"}; + cfg::string mouse_button_5{this, "Button 5", "NoButton"}; + cfg::string mouse_button_6{this, "Button 6", "NoButton"}; + cfg::string mouse_button_7{this, "Button 7", "NoButton"}; + cfg::string mouse_button_8{this, "Button 8", "NoButton"}; + + bool exist() const; + bool load(); + void save() const; + + cfg::string& get_button(int code); +}; + +extern mouse_config g_cfg_mouse; diff --git a/rpcs3/Input/basic_mouse_handler.cpp b/rpcs3/Input/basic_mouse_handler.cpp index cfe287d037..71e91d0eb4 100644 --- a/rpcs3/Input/basic_mouse_handler.cpp +++ b/rpcs3/Input/basic_mouse_handler.cpp @@ -7,9 +7,12 @@ #include "basic_mouse_handler.h" #include "rpcs3qt/gs_frame.h" #include "Emu/Io/interception.h" +#include "Emu/Io/mouse_config.h" LOG_CHANNEL(input_log, "Input"); +mouse_config g_cfg_mouse; + void basic_mouse_handler::Init(const u32 max_connect) { if (m_info.max_connect > 0) @@ -18,8 +21,21 @@ void basic_mouse_handler::Init(const u32 max_connect) return; } + g_cfg_mouse.from_default(); + g_cfg_mouse.load(); + + m_buttons[CELL_MOUSE_BUTTON_1] = get_mouse_button(g_cfg_mouse.mouse_button_1); + m_buttons[CELL_MOUSE_BUTTON_2] = get_mouse_button(g_cfg_mouse.mouse_button_2); + m_buttons[CELL_MOUSE_BUTTON_3] = get_mouse_button(g_cfg_mouse.mouse_button_3); + m_buttons[CELL_MOUSE_BUTTON_4] = get_mouse_button(g_cfg_mouse.mouse_button_4); + m_buttons[CELL_MOUSE_BUTTON_5] = get_mouse_button(g_cfg_mouse.mouse_button_5); + m_buttons[CELL_MOUSE_BUTTON_6] = get_mouse_button(g_cfg_mouse.mouse_button_6); + m_buttons[CELL_MOUSE_BUTTON_7] = get_mouse_button(g_cfg_mouse.mouse_button_7); + m_buttons[CELL_MOUSE_BUTTON_8] = get_mouse_button(g_cfg_mouse.mouse_button_8); + m_mice.clear(); m_mice.emplace_back(Mouse()); + m_info = {}; m_info.max_connect = max_connect; m_info.now_connect = std::min(::size32(m_mice), max_connect); @@ -88,28 +104,20 @@ bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev) void basic_mouse_handler::MouseButtonDown(QMouseEvent* event) { - if (event->button() == Qt::LeftButton) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_1, true); - else if (event->button() == Qt::RightButton) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_2, true); - else if (event->button() == Qt::MiddleButton) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_3, true); - // TODO: verify these - else if (event->button() == Qt::ExtraButton1) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_4, true); - else if (event->button() == Qt::ExtraButton2) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_5, true); - else if (event->button() == Qt::ExtraButton3) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_6, true); - else if (event->button() == Qt::ExtraButton4) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_7, true); - else if (event->button() == Qt::ExtraButton5) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_8, true); + if (const auto it = std::find_if(m_buttons.cbegin(), m_buttons.cend(), [event](const auto& entry){ return entry.second == event->button(); }); + it != m_buttons.cend()) + { + MouseHandlerBase::Button(0, it->first, true); + } } void basic_mouse_handler::MouseButtonUp(QMouseEvent* event) { - if (event->button() == Qt::LeftButton) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_1, false); - else if (event->button() == Qt::RightButton) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_2, false); - else if (event->button() == Qt::MiddleButton) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_3, false); - // TODO: verify these - else if (event->button() == Qt::ExtraButton1) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_4, false); - else if (event->button() == Qt::ExtraButton2) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_5, false); - else if (event->button() == Qt::ExtraButton3) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_6, false); - else if (event->button() == Qt::ExtraButton4) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_7, false); - else if (event->button() == Qt::ExtraButton5) MouseHandlerBase::Button(0, CELL_MOUSE_BUTTON_8, false); + if (const auto it = std::find_if(m_buttons.cbegin(), m_buttons.cend(), [event](const auto& entry){ return entry.second == event->button(); }); + it != m_buttons.cend()) + { + MouseHandlerBase::Button(0, it->first, false); + } } void basic_mouse_handler::MouseScroll(QWheelEvent* event) @@ -124,6 +132,18 @@ bool basic_mouse_handler::get_mouse_lock_state() const return false; } +Qt::MouseButton basic_mouse_handler::get_mouse_button(const cfg::string& button) +{ + const std::string value = button.to_string(); + + if (const auto it = qt_mouse_button_map.find(value); it != qt_mouse_button_map.cend()) + { + return it->second; + } + + return Qt::MouseButton::NoButton; +} + void basic_mouse_handler::MouseMove(QMouseEvent* event) { if (is_time_for_update()) diff --git a/rpcs3/Input/basic_mouse_handler.h b/rpcs3/Input/basic_mouse_handler.h index b308bb5412..1e4a168acb 100644 --- a/rpcs3/Input/basic_mouse_handler.h +++ b/rpcs3/Input/basic_mouse_handler.h @@ -7,6 +7,43 @@ #include #include +namespace cfg +{ + class string; +} + +static const std::map qt_mouse_button_map +{ + { "NoButton", Qt::MouseButton::NoButton }, + { "LeftButton", Qt::MouseButton::LeftButton }, + { "RightButton", Qt::MouseButton::RightButton }, + { "MiddleButton", Qt::MouseButton::MiddleButton }, + { "BackButton", Qt::MouseButton::BackButton }, + { "ForwardButton", Qt::MouseButton::ForwardButton }, + { "TaskButton", Qt::MouseButton::TaskButton }, + { "ExtraButton4", Qt::MouseButton::ExtraButton4 }, + { "ExtraButton5", Qt::MouseButton::ExtraButton5 }, + { "ExtraButton6", Qt::MouseButton::ExtraButton6 }, + { "ExtraButton7", Qt::MouseButton::ExtraButton7 }, + { "ExtraButton8", Qt::MouseButton::ExtraButton8 }, + { "ExtraButton9", Qt::MouseButton::ExtraButton9 }, + { "ExtraButton10", Qt::MouseButton::ExtraButton10 }, + { "ExtraButton11", Qt::MouseButton::ExtraButton11 }, + { "ExtraButton12", Qt::MouseButton::ExtraButton12 }, + { "ExtraButton13", Qt::MouseButton::ExtraButton13 }, + { "ExtraButton14", Qt::MouseButton::ExtraButton14 }, + { "ExtraButton15", Qt::MouseButton::ExtraButton15 }, + { "ExtraButton16", Qt::MouseButton::ExtraButton16 }, + { "ExtraButton17", Qt::MouseButton::ExtraButton17 }, + { "ExtraButton18", Qt::MouseButton::ExtraButton18 }, + { "ExtraButton19", Qt::MouseButton::ExtraButton19 }, + { "ExtraButton20", Qt::MouseButton::ExtraButton20 }, + { "ExtraButton21", Qt::MouseButton::ExtraButton21 }, + { "ExtraButton22", Qt::MouseButton::ExtraButton22 }, + { "ExtraButton23", Qt::MouseButton::ExtraButton23 }, + { "ExtraButton24", Qt::MouseButton::ExtraButton24 } +}; + class basic_mouse_handler final : public MouseHandlerBase, public QObject { using MouseHandlerBase::MouseHandlerBase; @@ -24,4 +61,7 @@ public: private: QWindow* m_target = nullptr; bool get_mouse_lock_state() const; + static Qt::MouseButton get_mouse_button(const cfg::string& button); + + std::map m_buttons; }; diff --git a/rpcs3/Input/raw_mouse_config.cpp b/rpcs3/Input/raw_mouse_config.cpp new file mode 100644 index 0000000000..d7c6a583c8 --- /dev/null +++ b/rpcs3/Input/raw_mouse_config.cpp @@ -0,0 +1,73 @@ +#include "stdafx.h" +#include "raw_mouse_config.h" +#include "Emu/Io/MouseHandler.h" + +cfg::string& raw_mouse_config::get_button(int code) +{ + switch (code) + { + case CELL_MOUSE_BUTTON_1: return mouse_button_1; + case CELL_MOUSE_BUTTON_2: return mouse_button_2; + case CELL_MOUSE_BUTTON_3: return mouse_button_3; + case CELL_MOUSE_BUTTON_4: return mouse_button_4; + case CELL_MOUSE_BUTTON_5: return mouse_button_5; + case CELL_MOUSE_BUTTON_6: return mouse_button_6; + case CELL_MOUSE_BUTTON_7: return mouse_button_7; + case CELL_MOUSE_BUTTON_8: return mouse_button_8; + default: fmt::throw_exception("Invalid code %d", code); + } +} + +raw_mice_config::raw_mice_config() +{ + for (u32 i = 0; i < ::size32(players); i++) + { + players.at(i) = std::make_shared(this, fmt::format("Player %d", i + 1)); + } +} + +bool raw_mice_config::load() +{ + m_mutex.lock(); + + bool result = false; + const std::string cfg_name = fmt::format("%sconfig/%s.yml", fs::get_config_dir(), cfg_id); + cfg_log.notice("Loading %s config: %s", cfg_id, cfg_name); + + from_default(); + + if (fs::file cfg_file{ cfg_name, fs::read }) + { + if (std::string content = cfg_file.to_string(); !content.empty()) + { + result = from_string(content); + } + + m_mutex.unlock(); + } + else + { + m_mutex.unlock(); + save(); + } + + return result; +} + +void raw_mice_config::save() +{ + std::lock_guard lock(m_mutex); + + const std::string cfg_name = fmt::format("%sconfig/%s.yml", fs::get_config_dir(), cfg_id); + cfg_log.notice("Saving %s config to '%s'", cfg_id, cfg_name); + + if (!fs::create_path(fs::get_parent_dir(cfg_name))) + { + cfg_log.fatal("Failed to create path: %s (%s)", cfg_name, fs::g_tls_error); + } + + if (!cfg::node::save(cfg_name)) + { + cfg_log.error("Failed to save %s config to '%s' (error=%s)", cfg_id, cfg_name, fs::g_tls_error); + } +} diff --git a/rpcs3/Input/raw_mouse_config.h b/rpcs3/Input/raw_mouse_config.h index 1bb872fa6c..eb9b5f5a69 100644 --- a/rpcs3/Input/raw_mouse_config.h +++ b/rpcs3/Input/raw_mouse_config.h @@ -13,67 +13,29 @@ public: using cfg::node::node; cfg::_float<10, 1000> mouse_acceleration{ this, "Mouse Acceleration", 100.0f, true }; + + cfg::string mouse_button_1{this, "Button 1", "Button 1"}; + cfg::string mouse_button_2{this, "Button 2", "Button 2"}; + cfg::string mouse_button_3{this, "Button 3", "Button 3"}; + cfg::string mouse_button_4{this, "Button 4", "Button 4"}; + cfg::string mouse_button_5{this, "Button 5", "Button 5"}; + cfg::string mouse_button_6{this, "Button 6", "No Button"}; + cfg::string mouse_button_7{this, "Button 7", "No Button"}; + cfg::string mouse_button_8{this, "Button 8", "No Button"}; + + cfg::string& get_button(int code); }; struct raw_mice_config : cfg::node { - raw_mice_config() - { - for (u32 i = 0; i < ::size32(players); i++) - { - players.at(i) = std::make_shared(this, fmt::format("Player %d", i + 1)); - } - } + raw_mice_config(); shared_mutex m_mutex; static constexpr std::string_view cfg_id = "raw_mouse"; std::array, 4> players; - bool load() - { - m_mutex.lock(); - - bool result = false; - const std::string cfg_name = fmt::format("%sconfig/%s.yml", fs::get_config_dir(), cfg_id); - cfg_log.notice("Loading %s config: %s", cfg_id, cfg_name); - - from_default(); - - if (fs::file cfg_file{ cfg_name, fs::read }) - { - if (std::string content = cfg_file.to_string(); !content.empty()) - { - result = from_string(content); - } - - m_mutex.unlock(); - } - else - { - m_mutex.unlock(); - save(); - } - - return result; - } - - void save() - { - std::lock_guard lock(m_mutex); - - const std::string cfg_name = fmt::format("%sconfig/%s.yml", fs::get_config_dir(), cfg_id); - cfg_log.notice("Saving %s config to '%s'", cfg_id, cfg_name); - - if (!fs::create_path(fs::get_parent_dir(cfg_name))) - { - cfg_log.fatal("Failed to create path: %s (%s)", cfg_name, fs::g_tls_error); - } - - if (!cfg::node::save(cfg_name)) - { - cfg_log.error("Failed to save %s config to '%s' (error=%s)", cfg_id, cfg_name, fs::g_tls_error); - } - } + bool load(); + void save(); }; extern raw_mice_config g_cfg_raw_mouse; diff --git a/rpcs3/Input/raw_mouse_handler.cpp b/rpcs3/Input/raw_mouse_handler.cpp index f8536fb716..8dd487e359 100644 --- a/rpcs3/Input/raw_mouse_handler.cpp +++ b/rpcs3/Input/raw_mouse_handler.cpp @@ -38,6 +38,15 @@ raw_mouse::raw_mouse(u32 index, const std::string& device_name, void* handle, ra if (const auto& player = ::at32(g_cfg_raw_mouse.players, m_index)) { m_mouse_acceleration = static_cast(player->mouse_acceleration.get()) / 100.0f; + + m_buttons[CELL_MOUSE_BUTTON_1] = get_mouse_button(player->mouse_button_1); + m_buttons[CELL_MOUSE_BUTTON_2] = get_mouse_button(player->mouse_button_2); + m_buttons[CELL_MOUSE_BUTTON_3] = get_mouse_button(player->mouse_button_3); + m_buttons[CELL_MOUSE_BUTTON_4] = get_mouse_button(player->mouse_button_4); + m_buttons[CELL_MOUSE_BUTTON_5] = get_mouse_button(player->mouse_button_5); + m_buttons[CELL_MOUSE_BUTTON_6] = get_mouse_button(player->mouse_button_6); + m_buttons[CELL_MOUSE_BUTTON_7] = get_mouse_button(player->mouse_button_7); + m_buttons[CELL_MOUSE_BUTTON_8] = get_mouse_button(player->mouse_button_8); } } } @@ -46,6 +55,29 @@ raw_mouse::~raw_mouse() { } +std::pair raw_mouse::get_mouse_button(const cfg::string& button) +{ + const std::string value = button.to_string(); + +#ifdef _WIN32 + static const std::unordered_map> btn_pairs + { + { RI_MOUSE_BUTTON_1_UP, { RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP }}, + { RI_MOUSE_BUTTON_2_UP, { RI_MOUSE_BUTTON_2_DOWN, RI_MOUSE_BUTTON_2_UP }}, + { RI_MOUSE_BUTTON_3_UP, { RI_MOUSE_BUTTON_3_DOWN, RI_MOUSE_BUTTON_3_UP }}, + { RI_MOUSE_BUTTON_4_UP, { RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP }}, + { RI_MOUSE_BUTTON_5_UP, { RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP }}, + }; + + if (const auto it = raw_mouse_button_map.find(value); it != raw_mouse_button_map.cend()) + { + return ::at32(btn_pairs, it->second); + } +#endif + + return {}; +} + void raw_mouse::update_window_handle() { #ifdef _WIN32 @@ -89,8 +121,10 @@ void raw_mouse::update_values(const RAWMOUSE& state) return; } - const auto get_button_pressed = [this](u8 button, int button_flags, int down, int up) + const auto get_button_pressed = [this](u8 button, int button_flags) { + const auto& [down, up] = ::at32(m_buttons, button); + // Only update the value if either down or up flags are present if ((button_flags & down)) { @@ -103,11 +137,11 @@ void raw_mouse::update_values(const RAWMOUSE& state) }; // Get mouse buttons - get_button_pressed(CELL_MOUSE_BUTTON_1, state.usButtonFlags, RI_MOUSE_BUTTON_1_DOWN, RI_MOUSE_BUTTON_1_UP); - get_button_pressed(CELL_MOUSE_BUTTON_2, state.usButtonFlags, RI_MOUSE_BUTTON_2_DOWN, RI_MOUSE_BUTTON_2_UP); - get_button_pressed(CELL_MOUSE_BUTTON_3, state.usButtonFlags, RI_MOUSE_BUTTON_3_DOWN, RI_MOUSE_BUTTON_3_UP); - get_button_pressed(CELL_MOUSE_BUTTON_4, state.usButtonFlags, RI_MOUSE_BUTTON_4_DOWN, RI_MOUSE_BUTTON_4_UP); - get_button_pressed(CELL_MOUSE_BUTTON_5, state.usButtonFlags, RI_MOUSE_BUTTON_5_DOWN, RI_MOUSE_BUTTON_5_UP); + get_button_pressed(CELL_MOUSE_BUTTON_1, state.usButtonFlags); + get_button_pressed(CELL_MOUSE_BUTTON_2, state.usButtonFlags); + get_button_pressed(CELL_MOUSE_BUTTON_3, state.usButtonFlags); + get_button_pressed(CELL_MOUSE_BUTTON_4, state.usButtonFlags); + get_button_pressed(CELL_MOUSE_BUTTON_5, state.usButtonFlags); // Get vertical mouse wheel if ((state.usButtonFlags & RI_MOUSE_WHEEL)) diff --git a/rpcs3/Input/raw_mouse_handler.h b/rpcs3/Input/raw_mouse_handler.h index f154b60e1d..e2af43a9e2 100644 --- a/rpcs3/Input/raw_mouse_handler.h +++ b/rpcs3/Input/raw_mouse_handler.h @@ -7,6 +7,18 @@ #include #endif +static const std::map raw_mouse_button_map +{ + { "No Button", 0 }, +#ifdef _WIN32 + { "Button 1", RI_MOUSE_BUTTON_1_UP }, + { "Button 2", RI_MOUSE_BUTTON_2_UP }, + { "Button 3", RI_MOUSE_BUTTON_3_UP }, + { "Button 4", RI_MOUSE_BUTTON_4_UP }, + { "Button 5", RI_MOUSE_BUTTON_5_UP }, +#endif +}; + class raw_mouse_handler; class raw_mouse @@ -26,6 +38,8 @@ public: #endif private: + static std::pair get_mouse_button(const cfg::string& button); + u32 m_index = 0; std::string m_device_name; void* m_handle{}; @@ -38,6 +52,7 @@ private: int m_pos_y{}; float m_mouse_acceleration = 1.0f; raw_mouse_handler* m_handler{}; + std::map> m_buttons; }; class raw_mouse_handler final : public MouseHandlerBase diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 405a59a13b..cdb7b8c134 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -88,6 +88,7 @@ + @@ -557,6 +558,7 @@ + @@ -663,7 +665,6 @@ - diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 3ae64c354a..3131397bea 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1249,6 +1249,9 @@ Emu\GPU\RSX\NV47\FW + + Emu\Io + @@ -2488,9 +2491,6 @@ Emu\Io - - Emu\Io - Emu\GPU\RSX\Program @@ -2542,6 +2542,9 @@ Emu\GPU\RSX\NV47\FW + + Emu\Io + diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 6ede5df310..5c89b29a0d 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -179,6 +179,7 @@ + @@ -445,6 +446,12 @@ true + + true + + + true + @@ -709,7 +716,14 @@ true + + true + + + true + + @@ -754,6 +768,7 @@ + @@ -931,6 +946,7 @@ $(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath) $(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath) + @@ -1408,6 +1424,26 @@ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\debug" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing %(Identity)... + .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) @@ -1945,4 +1981,4 @@ - + \ No newline at end of file diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 65fbb3d3b0..7df94e5d64 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -285,6 +285,18 @@ Generated Files\Release + + Generated Files\Debug + + + Generated Files\Release + + + Generated Files\Debug + + + Generated Files\Release + Generated Files\Debug @@ -1065,6 +1077,15 @@ rpcs3 + + Gui\settings + + + Gui\settings + + + Io\raw + @@ -1247,6 +1268,15 @@ rpcs3 + + Gui\settings + + + Gui\settings + + + Io\raw + @@ -1636,4 +1666,4 @@ Scripts - + \ No newline at end of file diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt index 9bb2e8fd8a..fcc4e0ec0f 100644 --- a/rpcs3/rpcs3qt/CMakeLists.txt +++ b/rpcs3/rpcs3qt/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(rpcs3_ui STATIC about_dialog.cpp auto_pause_settings_dialog.cpp + basic_mouse_settings_dialog.cpp breakpoint_handler.cpp breakpoint_list.cpp call_stack_list.cpp @@ -67,6 +68,7 @@ add_library(rpcs3_ui STATIC qt_camera_video_sink.cpp qt_music_handler.cpp qt_utils.cpp + raw_mouse_settings_dialog.cpp register_editor_dialog.cpp recvmessage_dialog_frame.cpp render_creator.cpp diff --git a/rpcs3/rpcs3qt/basic_mouse_settings_dialog.cpp b/rpcs3/rpcs3qt/basic_mouse_settings_dialog.cpp new file mode 100644 index 0000000000..a9b8753d49 --- /dev/null +++ b/rpcs3/rpcs3qt/basic_mouse_settings_dialog.cpp @@ -0,0 +1,149 @@ +#include "stdafx.h" +#include "basic_mouse_settings_dialog.h" +#include "localized_emu.h" +#include "Input/basic_mouse_handler.h" +#include "Emu/Io/mouse_config.h" +#include "Emu/Io/MouseHandler.h" +#include "util/asm.hpp" + +#include +#include +#include +#include +#include + +LOG_CHANNEL(cfg_log, "CFG"); + +enum button_role +{ + button_name = Qt::UserRole, + button_code +}; + +basic_mouse_settings_dialog::basic_mouse_settings_dialog(QWidget* parent) + : QDialog(parent) +{ + setObjectName("basic_mouse_settings_dialog"); + setWindowTitle(tr("Configure Basic Mouse Handler")); + setAttribute(Qt::WA_DeleteOnClose); + setAttribute(Qt::WA_StyledBackground); + setModal(true); + + QVBoxLayout* v_layout = new QVBoxLayout(this); + + QDialogButtonBox* buttons = new QDialogButtonBox(this); + buttons->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Save | QDialogButtonBox::RestoreDefaults); + + connect(buttons, &QDialogButtonBox::clicked, this, [this, buttons](QAbstractButton* button) + { + if (button == buttons->button(QDialogButtonBox::Apply)) + { + g_cfg_mouse.save(); + } + else if (button == buttons->button(QDialogButtonBox::Save)) + { + g_cfg_mouse.save(); + accept(); + } + else if (button == buttons->button(QDialogButtonBox::RestoreDefaults)) + { + if (QMessageBox::question(this, tr("Confirm Reset"), tr("Reset all settings?")) != QMessageBox::Yes) + return; + reset_config(); + } + else if (button == buttons->button(QDialogButtonBox::Cancel)) + { + reject(); + } + }); + + if (!g_cfg_mouse.load()) + { + cfg_log.notice("Could not load basic mouse config. Using defaults."); + } + + constexpr u32 button_count = 8; + constexpr u32 max_items_per_column = 4; + int rows = button_count; + + for (u32 cols = 1; utils::aligned_div(button_count, cols) > max_items_per_column;) + { + rows = utils::aligned_div(button_count, ++cols); + } + + QWidget* widget = new QWidget(this); + QGridLayout* grid_layout = new QGridLayout(this); + + for (int i = 0, row = 0, col = 0; i < static_cast(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); + + QHBoxLayout* h_layout = new QHBoxLayout(this); + QGroupBox* gb = new QGroupBox(translated_cell_button, this); + QComboBox* combo = new QComboBox; + + for (const auto& [name, btn] : qt_mouse_button_map) + { + const QString id = QString::fromStdString(name); + const QString translated_id = id; // We could localize the id, but I am too lazy at the moment + combo->addItem(translated_id); + const int index = combo->findText(translated_id); + combo->setItemData(index, id, button_role::button_name); + combo->setItemData(index, cell_code, button_role::button_code); + } + + const std::string saved_btn = g_cfg_mouse.get_button(cell_code); + + combo->setCurrentIndex(combo->findData(QString::fromStdString(saved_btn), button_role::button_name)); + + connect(combo, QOverload::of(&QComboBox::currentIndexChanged), this, [this, cell_code, combo](int index) + { + if (index < 0 || !combo) + return; + + const QVariant data = combo->itemData(index, button_role::button_name); + if (!data.isValid() || !data.canConvert()) + return; + + g_cfg_mouse.get_button(cell_code).from_string(data.toString().toStdString()); + }); + + if (row >= rows) + { + row = 0; + col++; + } + + m_combos.push_back(combo); + h_layout->addWidget(combo); + gb->setLayout(h_layout); + grid_layout->addWidget(gb, row, col); + } + + widget->setLayout(grid_layout); + + v_layout->addWidget(widget); + v_layout->addWidget(buttons); + setLayout(v_layout); +} + +void basic_mouse_settings_dialog::reset_config() +{ + g_cfg_mouse.from_default(); + + for (QComboBox* combo : m_combos) + { + if (!combo) + continue; + + const QVariant data = combo->itemData(0, button_role::button_code); + if (!data.isValid() || !data.canConvert()) + continue; + + const int cell_code = data.toInt(); + const QString def_btn_id = QString::fromStdString(g_cfg_mouse.get_button(cell_code).def); + + combo->setCurrentIndex(combo->findData(def_btn_id, button_role::button_name)); + } +} diff --git a/rpcs3/rpcs3qt/basic_mouse_settings_dialog.h b/rpcs3/rpcs3qt/basic_mouse_settings_dialog.h new file mode 100644 index 0000000000..532bbafc35 --- /dev/null +++ b/rpcs3/rpcs3qt/basic_mouse_settings_dialog.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include + +class basic_mouse_settings_dialog : public QDialog +{ + Q_OBJECT + +public: + basic_mouse_settings_dialog(QWidget* parent = nullptr); + +private: + void reset_config(); + + std::vector m_combos; +}; diff --git a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp index a962670c21..fc510aab12 100644 --- a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp @@ -34,7 +34,7 @@ emulated_pad_settings_dialog::emulated_pad_settings_dialog(pad_type type, QWidge QTabWidget* tabs = new QTabWidget(); tabs->setUsesScrollButtons(false); - QDialogButtonBox* buttons =new QDialogButtonBox(this); + QDialogButtonBox* buttons = new QDialogButtonBox(this); buttons->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Save | QDialogButtonBox::RestoreDefaults); connect(buttons, &QDialogButtonBox::clicked, this, [this, buttons](QAbstractButton* button) diff --git a/rpcs3/rpcs3qt/localized_emu.cpp b/rpcs3/rpcs3qt/localized_emu.cpp index 003171ba75..443b1dbdcb 100644 --- a/rpcs3/rpcs3qt/localized_emu.cpp +++ b/rpcs3/rpcs3qt/localized_emu.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "localized_emu.h" +#include "Emu/Io/MouseHandler.h" QString localized_emu::translated_pad_button(pad_button btn) { @@ -38,3 +39,19 @@ QString localized_emu::translated_pad_button(pad_button btn) } return ""; } + +QString localized_emu::translated_mouse_button(int btn) +{ + switch (btn) + { + case CELL_MOUSE_BUTTON_1: return tr("Button 1"); + case CELL_MOUSE_BUTTON_2: return tr("Button 2"); + case CELL_MOUSE_BUTTON_3: return tr("Button 3"); + case CELL_MOUSE_BUTTON_4: return tr("Button 4"); + case CELL_MOUSE_BUTTON_5: return tr("Button 5"); + case CELL_MOUSE_BUTTON_6: return tr("Button 6"); + case CELL_MOUSE_BUTTON_7: return tr("Button 7"); + case CELL_MOUSE_BUTTON_8: return tr("Button 8"); + } + return ""; +} diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index 5d884422f5..eff8602ff8 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -18,6 +18,7 @@ public: localized_emu() = default; static QString translated_pad_button(pad_button btn); + static QString translated_mouse_button(int btn); template static std::string get_string(localized_string_id id, Args&&... args) diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 4bccb4abdc..e6ebcc72ae 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -35,6 +35,8 @@ #include "shortcut_dialog.h" #include "system_cmd_dialog.h" #include "emulated_pad_settings_dialog.h" +#include "basic_mouse_settings_dialog.h" +#include "raw_mouse_settings_dialog.h" #include "welcome_dialog.h" #include @@ -2757,6 +2759,22 @@ void main_window::CreateConnects() dlg->show(); }); + connect(ui->actionBasic_Mouse, &QAction::triggered, this, [this] + { + basic_mouse_settings_dialog* dlg = new basic_mouse_settings_dialog(this); + dlg->show(); + }); + +#ifndef _WIN32 + ui->actionRaw_Mouse->setVisible(false); +#else + connect(ui->actionRaw_Mouse, &QAction::triggered, this, [this] + { + raw_mouse_settings_dialog* dlg = new raw_mouse_settings_dialog(this); + dlg->show(); + }); +#endif + connect(ui->confCamerasAct, &QAction::triggered, this, [this]() { camera_settings_dialog dlg(this); diff --git a/rpcs3/rpcs3qt/main_window.ui b/rpcs3/rpcs3qt/main_window.ui index 6f37b7cee8..117521987a 100644 --- a/rpcs3/rpcs3qt/main_window.ui +++ b/rpcs3/rpcs3qt/main_window.ui @@ -242,10 +242,18 @@ + + + Mice + + + + + @@ -1195,7 +1203,7 @@ Create Savestate - + false @@ -1330,6 +1338,16 @@ GunCon 3 + + + Basic Mouse + + + + + Raw Mouse + + diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.cpp b/rpcs3/rpcs3qt/pad_settings_dialog.cpp index e7e760cc72..f3154661e8 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/pad_settings_dialog.cpp @@ -322,7 +322,10 @@ void pad_settings_dialog::InitButtons() ReactivateButtons(); return; } - m_pad_buttons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(m_seconds)); + if (auto button = m_pad_buttons->button(m_button_id)) + { + button->setText(tr("[ Waiting %1 ]").arg(m_seconds)); + } }); connect(ui->chb_vibration_large, &QCheckBox::clicked, this, [this](bool checked) @@ -731,10 +734,10 @@ void pad_settings_dialog::ReactivateButtons() return; } - if (m_pad_buttons->button(m_button_id)) + if (auto button = m_pad_buttons->button(m_button_id)) { - m_pad_buttons->button(m_button_id)->setPalette(m_palette); - m_pad_buttons->button(m_button_id)->releaseMouse(); + button->setPalette(m_palette); + button->releaseMouse(); } m_button_id = button_ids::id_pad_begin; @@ -1209,7 +1212,10 @@ void pad_settings_dialog::UpdateLabels(bool is_reset) } // The button has to contain at least one character, because it would be square'ish otherwise - m_pad_buttons->button(id)->setText(button.text.isEmpty() ? QStringLiteral("-") : button.text); + if (auto btn = m_pad_buttons->button(id)) + { + btn->setText(button.text.isEmpty() ? QStringLiteral("-") : button.text); + } } } @@ -1243,7 +1249,10 @@ void pad_settings_dialog::SwitchButtons(bool is_enabled) for (int i = button_ids::id_pad_begin + 1; i < button_ids::id_pad_end; i++) { - m_pad_buttons->button(i)->setEnabled(is_enabled); + if (auto button = m_pad_buttons->button(i)) + { + button->setEnabled(is_enabled); + } } } @@ -1256,8 +1265,6 @@ void pad_settings_dialog::OnPadButtonClicked(int id) case button_ids::id_pad_end: case button_ids::id_add_config_file: case button_ids::id_refresh: - case button_ids::id_ok: - case button_ids::id_cancel: return; case button_ids::id_reset_parameters: ReactivateButtons(); @@ -1302,9 +1309,12 @@ void pad_settings_dialog::OnPadButtonClicked(int id) m_last_pos = QCursor::pos(); m_button_id = id; - m_pad_buttons->button(m_button_id)->setText(tr("[ Waiting %1 ]").arg(MAX_SECONDS)); - m_pad_buttons->button(m_button_id)->setPalette(QPalette(Qt::blue)); - m_pad_buttons->button(m_button_id)->grabMouse(); + if (auto button = m_pad_buttons->button(m_button_id)) + { + button->setText(tr("[ Waiting %1 ]").arg(MAX_SECONDS)); + button->setPalette(QPalette(Qt::blue)); + button->grabMouse(); + } SwitchButtons(false); // disable all buttons, needed for using Space, Enter and other specific buttons m_remap_timer.start(1000); } diff --git a/rpcs3/rpcs3qt/pad_settings_dialog.h b/rpcs3/rpcs3qt/pad_settings_dialog.h index 23e4d59a91..a795e0d0a9 100644 --- a/rpcs3/rpcs3qt/pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/pad_settings_dialog.h @@ -72,9 +72,7 @@ class pad_settings_dialog : public QDialog id_reset_parameters, id_blacklist, id_refresh, - id_add_config_file, - id_ok, - id_cancel + id_add_config_file }; struct pad_button diff --git a/rpcs3/rpcs3qt/raw_mouse_settings_dialog.cpp b/rpcs3/rpcs3qt/raw_mouse_settings_dialog.cpp new file mode 100644 index 0000000000..5609214440 --- /dev/null +++ b/rpcs3/rpcs3qt/raw_mouse_settings_dialog.cpp @@ -0,0 +1,187 @@ +#include "stdafx.h" +#include "raw_mouse_settings_dialog.h" +#include "localized_emu.h" +#include "Input/raw_mouse_config.h" +#include "Input/raw_mouse_handler.h" +#include "util/asm.hpp" + +#include +#include +#include +#include +#include +#include + +enum button_role +{ + button_name = Qt::UserRole, + button_code +}; + +raw_mouse_settings_dialog::raw_mouse_settings_dialog(QWidget* parent) + : QDialog(parent) +{ + setObjectName("raw_mouse_settings_dialog"); + setWindowTitle(tr("Configure Raw Mouse Handler")); + setAttribute(Qt::WA_DeleteOnClose); + setAttribute(Qt::WA_StyledBackground); + setModal(true); + + QVBoxLayout* v_layout = new QVBoxLayout(this); + + QTabWidget* tabs = new QTabWidget(); + tabs->setUsesScrollButtons(false); + + QDialogButtonBox* buttons = new QDialogButtonBox(this); + buttons->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Save | QDialogButtonBox::RestoreDefaults); + + connect(buttons, &QDialogButtonBox::clicked, this, [this, buttons](QAbstractButton* button) + { + if (button == buttons->button(QDialogButtonBox::Apply)) + { + g_cfg_raw_mouse.save(); + } + else if (button == buttons->button(QDialogButtonBox::Save)) + { + g_cfg_raw_mouse.save(); + accept(); + } + else if (button == buttons->button(QDialogButtonBox::RestoreDefaults)) + { + if (QMessageBox::question(this, tr("Confirm Reset"), tr("Reset settings of all players?")) != QMessageBox::Yes) + return; + reset_config(); + } + else if (button == buttons->button(QDialogButtonBox::Cancel)) + { + reject(); + } + }); + + if (!g_cfg_raw_mouse.load()) + { + cfg_log.notice("Could not load raw mouse config. Using defaults."); + } + + add_tabs(tabs); + + v_layout->addWidget(tabs); + v_layout->addWidget(buttons); + setLayout(v_layout); +} + +void raw_mouse_settings_dialog::add_tabs(QTabWidget* tabs) +{ + ensure(!!tabs); + + constexpr u32 button_count = 8; + constexpr u32 max_items_per_column = 6; + int rows = button_count; + + for (u32 cols = 1; utils::aligned_div(button_count, cols) > max_items_per_column;) + { + rows = utils::aligned_div(button_count, ++cols); + } + + const usz players = g_cfg_raw_mouse.players.size(); + + m_combos.resize(players); + + for (usz player = 0; player < players; player++) + { + QWidget* widget = new QWidget(this); + QGridLayout* grid_layout = new QGridLayout(this); + + auto& config = ::at32(g_cfg_raw_mouse.players, player); + + for (int i = 0, row = 0, col = 0; i < static_cast(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); + + QHBoxLayout* h_layout = new QHBoxLayout(this); + QGroupBox* gb = new QGroupBox(translated_cell_button, this); + QComboBox* combo = new QComboBox; + + for (const auto& [name, btn] : raw_mouse_button_map) + { + const QString id = QString::fromStdString(name); + const QString translated_id = id; // We could localize the id, but I am too lazy at the moment + combo->addItem(translated_id); + const int index = combo->findText(translated_id); + combo->setItemData(index, id, button_role::button_name); + combo->setItemData(index, cell_code, button_role::button_code); + } + + const std::string saved_btn = config->get_button(cell_code); + + combo->setCurrentIndex(combo->findData(QString::fromStdString(saved_btn), button_role::button_name)); + + connect(combo, QOverload::of(&QComboBox::currentIndexChanged), this, [this, player, cell_code, combo](int index) + { + if (index < 0 || !combo) + return; + + const QVariant data = combo->itemData(index, button_role::button_name); + if (!data.isValid() || !data.canConvert()) + return; + + ::at32(g_cfg_raw_mouse.players, player)->get_button(cell_code).from_string(data.toString().toStdString()); + }); + + if (row >= rows) + { + row = 0; + col++; + } + + ::at32(m_combos, player).push_back(combo); + h_layout->addWidget(combo); + gb->setLayout(h_layout); + grid_layout->addWidget(gb, row, col); + } + + QHBoxLayout* h_layout = new QHBoxLayout(this); + QGroupBox* gb = new QGroupBox(tr("Mouse Acceleration"), this); + QDoubleSpinBox* mouse_acceleration_spin_box = new QDoubleSpinBox(this); + 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::of(&QDoubleSpinBox::valueChanged), this, [player](double value) + { + auto& config = ::at32(g_cfg_raw_mouse.players, player)->mouse_acceleration; + config.set(std::clamp(value * 100.0, config.min, config.max)); + }); + + h_layout->addWidget(mouse_acceleration_spin_box); + gb->setLayout(h_layout); + grid_layout->addWidget(gb, grid_layout->rowCount(), 0); + + widget->setLayout(grid_layout); + tabs->addTab(widget, tr("Player %0").arg(player + 1)); + } +} + +void raw_mouse_settings_dialog::reset_config() +{ + g_cfg_raw_mouse.from_default(); + + for (usz player = 0; player < m_combos.size(); player++) + { + auto& config = ::at32(g_cfg_raw_mouse.players, player); + + for (QComboBox* combo : m_combos.at(player)) + { + if (!combo) + continue; + + const QVariant data = combo->itemData(0, button_role::button_code); + if (!data.isValid() || !data.canConvert()) + continue; + + const int cell_code = data.toInt(); + const QString def_btn_id = QString::fromStdString(config->get_button(cell_code).def); + + combo->setCurrentIndex(combo->findData(def_btn_id, button_role::button_name)); + } + } +} diff --git a/rpcs3/rpcs3qt/raw_mouse_settings_dialog.h b/rpcs3/rpcs3qt/raw_mouse_settings_dialog.h new file mode 100644 index 0000000000..1cffe60b03 --- /dev/null +++ b/rpcs3/rpcs3qt/raw_mouse_settings_dialog.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +#include + +class raw_mouse_settings_dialog : public QDialog +{ + Q_OBJECT + +public: + raw_mouse_settings_dialog(QWidget* parent = nullptr); + +private: + void add_tabs(QTabWidget* tabs); + + void reset_config(); + + std::vector> m_combos; +};