From a0df1e09a655f980e10a6a636b5916686b97cdcf Mon Sep 17 00:00:00 2001 From: Megamouse Date: Thu, 9 Jan 2025 21:10:28 +0100 Subject: [PATCH] ps move: allow to configure mouse move handler buttons --- rpcs3/Emu/Cell/Modules/cellGem.cpp | 134 +++++++++++++----- rpcs3/Emu/Io/Buzz.cpp | 2 +- rpcs3/Emu/Io/GHLtar.cpp | 2 +- rpcs3/Emu/Io/GunCon3.cpp | 2 +- rpcs3/Emu/Io/TopShotElite.cpp | 2 +- rpcs3/Emu/Io/TopShotFearmaster.cpp | 2 +- rpcs3/Emu/Io/Turntable.cpp | 2 +- rpcs3/Emu/Io/emulated_pad_config.h | 34 +++-- rpcs3/Emu/Io/gem_config.h | 43 +++++- rpcs3/Emu/Io/usio.cpp | 4 +- .../rpcs3qt/emulated_pad_settings_dialog.cpp | 98 +++++++++++-- rpcs3/rpcs3qt/emulated_pad_settings_dialog.h | 1 + rpcs3/rpcs3qt/main_window.cpp | 6 + rpcs3/rpcs3qt/main_window.ui | 6 + 14 files changed, 273 insertions(+), 65 deletions(-) diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index 48d609120f..22988d25e6 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -40,9 +40,18 @@ void fmt_class_string::format(std::string& out, u64 arg) case gem_btn::square: return "Square"; case gem_btn::move: return "Move"; case gem_btn::t: return "T"; - case gem_btn::count: return "Count"; case gem_btn::x_axis: return "X-Axis"; case gem_btn::y_axis: return "Y-Axis"; + case gem_btn::combo: return "Combo"; + case gem_btn::combo_start: return "Combo Start"; + case gem_btn::combo_select: return "Combo Select"; + case gem_btn::combo_triangle: return "Combo Triangle"; + case gem_btn::combo_circle: return "Combo Circle"; + case gem_btn::combo_cross: return "Combo Cross"; + case gem_btn::combo_square: return "Combo Square"; + case gem_btn::combo_move: return "Combo Move"; + case gem_btn::combo_t: return "Combo T"; + case gem_btn::count: return "Count"; } return unknown; @@ -177,6 +186,7 @@ using gun_thread = named_thread; cfg_gems g_cfg_gem_real; cfg_fake_gems g_cfg_gem_fake; +cfg_mouse_gems g_cfg_gem_mouse; struct gem_config_data { @@ -494,8 +504,14 @@ public: cellGem.notice("Could not load fake gem config. Using defaults."); } + if (!g_cfg_gem_mouse.load()) + { + cellGem.notice("Could not load mouse gem config. Using defaults."); + } + cellGem.notice("Real gem config=\n", g_cfg_gem_real.to_string()); cellGem.notice("Fake gem config=\n", g_cfg_gem_fake.to_string()); + cellGem.notice("Mouse gem config=\n", g_cfg_gem_mouse.to_string()); } }; @@ -1574,7 +1590,7 @@ static void ds3_input_to_pad(const u32 gem_num, be_t& digital_buttons, be_t return; } - const auto handle_input = [&](gem_btn btn, u16 value, bool pressed) + const auto handle_input = [&](gem_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/) { if (!pressed) return; @@ -1606,9 +1622,7 @@ static void ds3_input_to_pad(const u32 gem_num, be_t& digital_buttons, be_t digital_buttons |= CELL_GEM_CTRL_T; analog_t = std::max(analog_t, value); break; - case gem_btn::x_axis: - case gem_btn::y_axis: - case gem_btn::count: + default: break; } }; @@ -1632,7 +1646,7 @@ static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr& y_pos = 0; const auto& cfg = ::at32(g_cfg_gem_fake.players, gem_num); - cfg->handle_input(pad, true, [&](gem_btn btn, u16 value, bool pressed) + cfg->handle_input(pad, true, [&](gem_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/) { if (!pressed) return; @@ -1828,41 +1842,97 @@ static bool mouse_input_to_pad(u32 mouse_no, be_t& digital_buttons, be_t pressed_buttons; const Mouse& mouse_data = ::at32(handler.GetMice(), mouse_no); - const auto is_pressed = [&mouse_data, &pressed_buttons](MouseButtonCodes button) -> bool + auto& cfg = ::at32(g_cfg_gem_mouse.players, mouse_no); + + bool combo_active = false; + std::set combos; + + static const std::unordered_map btn_map = { - // Only allow each button to be used for one action unless it's the combo button. - return (mouse_data.buttons & button) && (button == (CELL_MOUSE_BUTTON_3 + 0u/*fix warning*/) || pressed_buttons.insert(button).second); + { gem_btn::start, CELL_GEM_CTRL_START }, + { gem_btn::select, CELL_GEM_CTRL_SELECT }, + { gem_btn::triangle, CELL_GEM_CTRL_TRIANGLE }, + { gem_btn::circle, CELL_GEM_CTRL_CIRCLE }, + { gem_btn::cross, CELL_GEM_CTRL_CROSS }, + { gem_btn::square, CELL_GEM_CTRL_SQUARE }, + { gem_btn::move, CELL_GEM_CTRL_MOVE }, + { gem_btn::t, CELL_GEM_CTRL_T }, + { gem_btn::combo_start, CELL_GEM_CTRL_START }, + { gem_btn::combo_select, CELL_GEM_CTRL_SELECT }, + { gem_btn::combo_triangle, CELL_GEM_CTRL_TRIANGLE }, + { gem_btn::combo_circle, CELL_GEM_CTRL_CIRCLE }, + { gem_btn::combo_cross, CELL_GEM_CTRL_CROSS }, + { gem_btn::combo_square, CELL_GEM_CTRL_SQUARE }, + { gem_btn::combo_move, CELL_GEM_CTRL_MOVE }, + { gem_btn::combo_t, CELL_GEM_CTRL_T }, }; - digital_buttons = 0; + // Check combo button first + cfg->handle_input(mouse_data, [&combo_active](gem_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& abort) + { + if (pressed && btn == gem_btn::combo) + { + combo_active = true; + abort = true; + } + }); - if ((is_pressed(CELL_MOUSE_BUTTON_3) && is_pressed(CELL_MOUSE_BUTTON_1)) || is_pressed(CELL_MOUSE_BUTTON_6)) - digital_buttons |= CELL_GEM_CTRL_SELECT; + // Check combos + if (combo_active) + { + cfg->handle_input(mouse_data, [&digital_buttons, &combos](gem_btn btn, pad_button pad_btn, u16 /*value*/, bool pressed, bool& /*abort*/) + { + if (!pressed) + return; - if ((is_pressed(CELL_MOUSE_BUTTON_3) && is_pressed(CELL_MOUSE_BUTTON_2)) || is_pressed(CELL_MOUSE_BUTTON_7)) - digital_buttons |= CELL_GEM_CTRL_START; + switch (btn) + { + case gem_btn::combo_start: + case gem_btn::combo_select: + case gem_btn::combo_triangle: + case gem_btn::combo_circle: + case gem_btn::combo_cross: + case gem_btn::combo_square: + case gem_btn::combo_move: + case gem_btn::combo_t: + digital_buttons |= ::at32(btn_map, btn); + combos.insert(pad_btn); + break; + default: + break; + } + }); + } - if ((is_pressed(CELL_MOUSE_BUTTON_3) && is_pressed(CELL_MOUSE_BUTTON_4)) || is_pressed(CELL_MOUSE_BUTTON_8)) - digital_buttons |= CELL_GEM_CTRL_TRIANGLE; + // Check normal buttons + cfg->handle_input(mouse_data, [&digital_buttons, &combos](gem_btn btn, pad_button pad_btn, u16 /*value*/, bool pressed, bool& /*abort*/) + { + if (!pressed) + return; - if (is_pressed(CELL_MOUSE_BUTTON_3) && is_pressed(CELL_MOUSE_BUTTON_5)) - digital_buttons |= CELL_GEM_CTRL_SQUARE; + switch (btn) + { + case gem_btn::start: + case gem_btn::select: + case gem_btn::square: + case gem_btn::cross: + case gem_btn::circle: + case gem_btn::triangle: + case gem_btn::move: + case gem_btn::t: + // Ignore this gem_btn if the same pad_button was already used in a combo + if (!combos.contains(pad_btn)) + { + digital_buttons |= ::at32(btn_map, btn); + } + break; + default: + break; + } + }); - if (is_pressed(CELL_MOUSE_BUTTON_1)) - digital_buttons |= CELL_GEM_CTRL_T; - - if (is_pressed(CELL_MOUSE_BUTTON_2)) - digital_buttons |= CELL_GEM_CTRL_MOVE; - - if (is_pressed(CELL_MOUSE_BUTTON_4)) - digital_buttons |= CELL_GEM_CTRL_CIRCLE; - - if (is_pressed(CELL_MOUSE_BUTTON_5)) - digital_buttons |= CELL_GEM_CTRL_CROSS; - - analog_t = (mouse_data.buttons & CELL_MOUSE_BUTTON_1) ? 0xFFFF : 0; + analog_t = (digital_buttons & CELL_GEM_CTRL_T) ? 0xFFFF : 0; return true; } diff --git a/rpcs3/Emu/Io/Buzz.cpp b/rpcs3/Emu/Io/Buzz.cpp index 06cdc2f064..108bdec0ab 100644 --- a/rpcs3/Emu/Io/Buzz.cpp +++ b/rpcs3/Emu/Io/Buzz.cpp @@ -161,7 +161,7 @@ void usb_device_buzz::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint*/ } const auto& cfg = g_cfg_buzz.players[i]; - cfg->handle_input(pad, true, [&buf, &index](buzz_btn btn, u16 /*value*/, bool pressed) + cfg->handle_input(pad, true, [&buf, &index](buzz_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/) { if (!pressed) return; diff --git a/rpcs3/Emu/Io/GHLtar.cpp b/rpcs3/Emu/Io/GHLtar.cpp index 140c8e3a98..d6fe87e9fc 100644 --- a/rpcs3/Emu/Io/GHLtar.cpp +++ b/rpcs3/Emu/Io/GHLtar.cpp @@ -147,7 +147,7 @@ void usb_device_ghltar::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpoint } const auto& cfg = ::at32(g_cfg_ghltar.players, m_controller_index); - cfg->handle_input(pad, true, [&buf](ghltar_btn btn, u16 value, bool pressed) + cfg->handle_input(pad, true, [&buf](ghltar_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/) { if (!pressed) return; diff --git a/rpcs3/Emu/Io/GunCon3.cpp b/rpcs3/Emu/Io/GunCon3.cpp index ee9694447c..7eef591ecc 100644 --- a/rpcs3/Emu/Io/GunCon3.cpp +++ b/rpcs3/Emu/Io/GunCon3.cpp @@ -227,7 +227,7 @@ void usb_device_guncon3::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, return; } - const auto input_callback = [&gc](guncon3_btn btn, u16 value, bool pressed) + const auto input_callback = [&gc](guncon3_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/) { if (!pressed) return; diff --git a/rpcs3/Emu/Io/TopShotElite.cpp b/rpcs3/Emu/Io/TopShotElite.cpp index 0d85cfd5fa..b170027a9f 100644 --- a/rpcs3/Emu/Io/TopShotElite.cpp +++ b/rpcs3/Emu/Io/TopShotElite.cpp @@ -280,7 +280,7 @@ void usb_device_topshotelite::interrupt_transfer(u32 buf_size, u8* buf, u32 /*en } bool up = false, right = false, down = false, left = false; - const auto input_callback = [&ts, &up, &down, &left, &right](topshotelite_btn btn, u16 value, bool pressed) + const auto input_callback = [&ts, &up, &down, &left, &right](topshotelite_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/) { if (!pressed) return; diff --git a/rpcs3/Emu/Io/TopShotFearmaster.cpp b/rpcs3/Emu/Io/TopShotFearmaster.cpp index bfae945365..aba831fa9c 100644 --- a/rpcs3/Emu/Io/TopShotFearmaster.cpp +++ b/rpcs3/Emu/Io/TopShotFearmaster.cpp @@ -308,7 +308,7 @@ void usb_device_topshotfearmaster::interrupt_transfer(u32 buf_size, u8* buf, u32 } bool up = false, right = false, down = false, left = false; - const auto input_callback = [&ts, &up, &down, &left, &right](topshotfearmaster_btn btn, u16 value, bool pressed) + const auto input_callback = [&ts, &up, &down, &left, &right](topshotfearmaster_btn btn, pad_button /*pad_button*/, u16 value, bool pressed, bool& /*abort*/) { if (!pressed) return; diff --git a/rpcs3/Emu/Io/Turntable.cpp b/rpcs3/Emu/Io/Turntable.cpp index af5648d40b..63bb815a1d 100644 --- a/rpcs3/Emu/Io/Turntable.cpp +++ b/rpcs3/Emu/Io/Turntable.cpp @@ -159,7 +159,7 @@ void usb_device_turntable::interrupt_transfer(u32 buf_size, u8* buf, u32 /*endpo return; const auto& cfg = ::at32(g_cfg_turntable.players, m_controller_index); - cfg->handle_input(pad, true, [&buf](turntable_btn btn, u16 value, bool pressed) + cfg->handle_input(pad, true, [&buf](turntable_btn btn, pad_button /*pad_btn*/, u16 value, bool pressed, bool& /*abort*/) { if (!pressed) return; diff --git a/rpcs3/Emu/Io/emulated_pad_config.h b/rpcs3/Emu/Io/emulated_pad_config.h index b6703b01dd..3b0887459c 100644 --- a/rpcs3/Emu/Io/emulated_pad_config.h +++ b/rpcs3/Emu/Io/emulated_pad_config.h @@ -88,7 +88,7 @@ public: button_map.clear(); } - void handle_input(std::shared_ptr pad, bool press_only, const std::function& func) const + void handle_input(std::shared_ptr pad, bool press_only, const std::function& func) const { if (!pad) return; @@ -97,19 +97,25 @@ public: { if (button.m_pressed || !press_only) { - handle_input(func, button.m_offset, button.m_outKeyCode, button.m_value, button.m_pressed, true); + if (handle_input(func, button.m_offset, button.m_outKeyCode, button.m_value, button.m_pressed, true)) + { + return; + } } } for (const AnalogStick& stick : pad->m_sticks) { - handle_input(func, stick.m_offset, get_axis_keycode(stick.m_offset, stick.m_value), stick.m_value, true, true); + if (handle_input(func, stick.m_offset, get_axis_keycode(stick.m_offset, stick.m_value), stick.m_value, true, true)) + { + return; + } } } - void handle_input(const Mouse& mouse, const std::function& func) const + void handle_input(const Mouse& mouse, const std::function& func) const { - for (int i = 0; i < 7; i++) + for (int i = 0; i < 8; i++) { const MouseButtonCodes cell_code = get_mouse_button_code(i); if ((mouse.buttons & cell_code)) @@ -117,7 +123,11 @@ public: const pad_button button = static_cast(static_cast(pad_button::mouse_button_1) + i); const u32 offset = pad_button_offset(button); const u32 keycode = pad_button_keycode(button); - handle_input(func, offset, keycode, 255, true, true); + + if (handle_input(func, offset, keycode, 255, true, true)) + { + return; + } } } } @@ -163,10 +173,12 @@ protected: return empty_set; } - void handle_input(const std::function& func, u32 offset, u32 keycode, u16 value, bool pressed, bool check_axis) const + bool handle_input(const std::function& func, u32 offset, u32 keycode, u16 value, bool pressed, bool check_axis) const { m_mutex.lock(); + bool abort = false; + const auto& btns = find_button(offset, keycode); if (btns.empty()) { @@ -180,24 +192,26 @@ protected: case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: - handle_input(func, offset, static_cast(axis_direction::both), value, pressed, false); + abort = handle_input(func, offset, static_cast(axis_direction::both), value, pressed, false); break; default: break; } } - return; + return abort; } for (const auto& btn : btns) { if (btn && func) { - func(btn->btn_id(), value, pressed); + func(btn->btn_id(), btn->get(), value, pressed, abort); + if (abort) break; } } m_mutex.unlock(); + return abort; } }; diff --git a/rpcs3/Emu/Io/gem_config.h b/rpcs3/Emu/Io/gem_config.h index d737928790..2be86ff3c4 100644 --- a/rpcs3/Emu/Io/gem_config.h +++ b/rpcs3/Emu/Io/gem_config.h @@ -4,7 +4,7 @@ #include -enum class gem_btn +enum class gem_btn : u32 { start, select, @@ -17,6 +17,18 @@ enum class gem_btn x_axis, y_axis, + combo_begin, + combo = combo_begin, + combo_start, + combo_select, + combo_triangle, + combo_circle, + combo_cross, + combo_square, + combo_move, + combo_t, + combo_end = combo_t, + count }; @@ -41,6 +53,34 @@ struct cfg_fake_gems final : public emulated_pads_config cfg_fake_gems() : emulated_pads_config("gem") {}; }; +struct cfg_mouse_gem final : public emulated_pad_config +{ + cfg_mouse_gem(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} + + cfg_pad_btn start{ this, "Start", gem_btn::start, pad_button::mouse_button_6 }; + cfg_pad_btn select{ this, "Select", gem_btn::select, pad_button::mouse_button_7 }; + cfg_pad_btn triangle{ this, "Triangle", gem_btn::triangle, pad_button::mouse_button_8 }; + cfg_pad_btn circle{ this, "Circle", gem_btn::circle, pad_button::mouse_button_4 }; + cfg_pad_btn cross{ this, "Cross", gem_btn::cross, pad_button::mouse_button_5 }; + cfg_pad_btn square{ this, "Square", gem_btn::square, pad_button::mouse_button_3 }; + cfg_pad_btn move{ this, "Move", gem_btn::move, pad_button::mouse_button_2 }; + cfg_pad_btn t{ this, "T", gem_btn::t, pad_button::mouse_button_1 }; + cfg_pad_btn combo{ this, "Combo", gem_btn::combo, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_start{ this, "Combo Start", gem_btn::combo_start, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_select{ this, "Combo Select", gem_btn::combo_select, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_triangle{ this, "Combo Triangle", gem_btn::combo_triangle, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_circle{ this, "Combo Circle", gem_btn::combo_circle, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_cross{ this, "Combo Cross", gem_btn::combo_cross, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_square{ this, "Combo Square", gem_btn::combo_square, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_move{ this, "Combo Move", gem_btn::combo_move, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_t{ this, "Combo T", gem_btn::combo_t, pad_button::pad_button_max_enum }; +}; + +struct cfg_mouse_gems final : public emulated_pads_config +{ + cfg_mouse_gems() : emulated_pads_config("gem_mouse") {}; +}; + struct cfg_gem final : public emulated_pad_config { cfg_gem(node* owner, const std::string& name) : emulated_pad_config(owner, name) {} @@ -62,3 +102,4 @@ struct cfg_gems final : public emulated_pads_config extern cfg_gems g_cfg_gem_real; extern cfg_fake_gems g_cfg_gem_fake; +extern cfg_mouse_gems g_cfg_gem_mouse; diff --git a/rpcs3/Emu/Io/usio.cpp b/rpcs3/Emu/Io/usio.cpp index 7dea19c8fb..faecec177d 100644 --- a/rpcs3/Emu/Io/usio.cpp +++ b/rpcs3/Emu/Io/usio.cpp @@ -203,7 +203,7 @@ void usb_device_usio::translate_input_taiko() if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed()) { const auto& cfg = ::at32(g_cfg_usio.players, pad_number); - cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed) + cfg->handle_input(pad, false, [&](usio_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/) { switch (btn) { @@ -288,7 +288,7 @@ void usb_device_usio::translate_input_tekken() if (const auto& pad = ::at32(handler->GetPads(), pad_number); (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && is_input_allowed()) { const auto& cfg = ::at32(g_cfg_usio.players, pad_number); - cfg->handle_input(pad, false, [&](usio_btn btn, u16 /*value*/, bool pressed) + cfg->handle_input(pad, false, [&](usio_btn btn, pad_button /*pad_btn*/, u16 /*value*/, bool pressed, bool& /*abort*/) { switch (btn) { diff --git a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp index 835f940797..a3fcde1e82 100644 --- a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp @@ -92,6 +92,10 @@ emulated_pad_settings_dialog::emulated_pad_settings_dialog(pad_type type, QWidge setWindowTitle(tr("Configure Emulated PS Move (Fake)")); add_tabs(tabs); break; + case emulated_pad_settings_dialog::pad_type::mousegem: + setWindowTitle(tr("Configure Emulated PS Move (Mouse)")); + add_tabs(tabs); + break; case emulated_pad_settings_dialog::pad_type::guncon3: setWindowTitle(tr("Configure Emulated GunCon 3")); add_tabs(tabs); @@ -116,8 +120,12 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) { ensure(!!tabs); - constexpr u32 max_items_per_column = 6; - int count = static_cast(T::count); + std::set ignored_values; + + const auto remove_value = [&ignored_values](int value) + { + ignored_values.insert(static_cast(value)); + }; usz players = 0; switch (m_type) @@ -137,13 +145,29 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) case pad_type::gem: players = g_cfg_gem_real.players.size(); - // Ignore x and y axis - static_assert(static_cast(gem_btn::y_axis) == static_cast(gem_btn::count) - 1); - static_assert(static_cast(gem_btn::x_axis) == static_cast(gem_btn::count) - 2); - count -= 2; + // Ignore combo, x and y axis + remove_value(static_cast(gem_btn::x_axis)); + remove_value(static_cast(gem_btn::y_axis)); + for (int i = static_cast(gem_btn::combo_begin); i <= static_cast(gem_btn::combo_end); i++) + { + remove_value(i); + } break; case pad_type::ds3gem: players = g_cfg_gem_fake.players.size(); + + // Ignore combo + for (int i = static_cast(gem_btn::combo_begin); i <= static_cast(gem_btn::combo_end); i++) + { + remove_value(i); + } + break; + case pad_type::mousegem: + players = g_cfg_gem_mouse.players.size(); + + // Ignore x and y axis + remove_value(static_cast(gem_btn::x_axis)); + remove_value(static_cast(gem_btn::y_axis)); break; case pad_type::guncon3: players = g_cfg_guncon3.players.size(); @@ -156,6 +180,8 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) break; } + constexpr u32 max_items_per_column = 6; + const int count = static_cast(T::count) - static_cast(ignored_values.size()); int rows = count; for (u32 cols = 1; utils::aligned_div(static_cast(count), cols) > max_items_per_column;) @@ -170,8 +196,10 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) QWidget* widget = new QWidget(this); QGridLayout* grid_layout = new QGridLayout(this); - for (int i = 0, row = 0, col = 0; i < count; i++, row++) + for (int i = 0, row = 0, col = 0; i < static_cast(T::count); i++) { + if (ignored_values.contains(i)) continue; + const T id = static_cast(i); const QString name = QString::fromStdString(fmt::format("%s", id)); @@ -179,16 +207,35 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) QGroupBox* gb = new QGroupBox(name, this); QComboBox* combo = new QComboBox; - for (int p = 0; p < static_cast(pad_button::pad_button_max_enum); p++) + if constexpr (std::is_same_v) { - const QString translated = localized_emu::translated_pad_button(static_cast(p)); - combo->addItem(translated); - const int index = combo->findText(translated); - combo->setItemData(index, p, button_role::button); - combo->setItemData(index, i, button_role::emulated_button); + const gem_btn btn = static_cast(i); + if (btn >= gem_btn::combo_begin && btn <= gem_btn::combo_end) + { + gb->setToolTip(tr("Press the \"Combo\" button in combination with any of the other combo buttons to trigger their related PS Move button.\n" + "This can be useful if your device does not have enough regular buttons.")); + } } - if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) + // Add empty value + combo->addItem(""); + const int index = combo->findText(""); + combo->setItemData(index, static_cast(pad_button::pad_button_max_enum), button_role::button); + combo->setItemData(index, i, button_role::emulated_button); + + if (m_type != pad_type::mousegem) + { + for (int p = 0; p < static_cast(pad_button::pad_button_max_enum); p++) + { + const QString translated = localized_emu::translated_pad_button(static_cast(p)); + combo->addItem(translated); + const int index = combo->findText(translated); + combo->setItemData(index, p, button_role::button); + combo->setItemData(index, i, button_role::emulated_button); + } + } + + if (std::is_same_v || std::is_same_v || std::is_same_v || m_type == pad_type::mousegem) { for (int p = static_cast(pad_button::mouse_button_1); p <= static_cast(pad_button::mouse_button_8); p++) { @@ -221,6 +268,9 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) case pad_type::ds3gem: saved_btn_id = ::at32(g_cfg_gem_fake.players, player)->get_pad_button(static_cast(id)); break; + case pad_type::mousegem: + saved_btn_id = ::at32(g_cfg_gem_mouse.players, player)->get_pad_button(static_cast(id)); + break; case pad_type::guncon3: saved_btn_id = ::at32(g_cfg_guncon3.players, player)->get_pad_button(static_cast(id)); break; @@ -265,6 +315,9 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) case pad_type::ds3gem: ::at32(g_cfg_gem_fake.players, player)->set_button(static_cast(id), btn_id); break; + case pad_type::mousegem: + ::at32(g_cfg_gem_mouse.players, player)->set_button(static_cast(id), btn_id); + break; case pad_type::guncon3: ::at32(g_cfg_guncon3.players, player)->set_button(static_cast(id), btn_id); break; @@ -287,6 +340,8 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) h_layout->addWidget(combo); gb->setLayout(h_layout); grid_layout->addWidget(gb, row, col); + + row++; } widget->setLayout(grid_layout); @@ -334,6 +389,12 @@ void emulated_pad_settings_dialog::load_config() cfg_log.notice("Could not load fake gem config. Using defaults."); } break; + case emulated_pad_settings_dialog::pad_type::mousegem: + if (!g_cfg_gem_mouse.load()) + { + cfg_log.notice("Could not load mouse gem config. Using defaults."); + } + break; case emulated_pad_settings_dialog::pad_type::guncon3: if (!g_cfg_guncon3.load()) { @@ -377,6 +438,9 @@ void emulated_pad_settings_dialog::save_config() case emulated_pad_settings_dialog::pad_type::ds3gem: g_cfg_gem_fake.save(); break; + case emulated_pad_settings_dialog::pad_type::mousegem: + g_cfg_gem_mouse.save(); + break; case emulated_pad_settings_dialog::pad_type::guncon3: g_cfg_guncon3.save(); break; @@ -411,6 +475,9 @@ void emulated_pad_settings_dialog::reset_config() case emulated_pad_settings_dialog::pad_type::ds3gem: g_cfg_gem_fake.from_default(); break; + case emulated_pad_settings_dialog::pad_type::mousegem: + g_cfg_gem_mouse.from_default(); + break; case emulated_pad_settings_dialog::pad_type::guncon3: g_cfg_guncon3.from_default(); break; @@ -454,6 +521,9 @@ void emulated_pad_settings_dialog::reset_config() case pad_type::ds3gem: def_btn_id = ::at32(g_cfg_gem_fake.players, player)->default_pad_button(static_cast(data.toInt())); break; + case pad_type::mousegem: + def_btn_id = ::at32(g_cfg_gem_mouse.players, player)->default_pad_button(static_cast(data.toInt())); + break; case pad_type::guncon3: def_btn_id = ::at32(g_cfg_guncon3.players, player)->default_pad_button(static_cast(data.toInt())); break; diff --git a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.h b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.h index 772f467182..ad1b863d7e 100644 --- a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.h @@ -21,6 +21,7 @@ public: usio, gem, ds3gem, + mousegem, guncon3, topshotelite, topshotfearmaster, diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 46e056e43a..b4bc2af5d6 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -2911,6 +2911,12 @@ void main_window::CreateConnects() dlg->show(); }); + connect(ui->confPSMoveMouseAct, &QAction::triggered, this, [this] + { + emulated_pad_settings_dialog* dlg = new emulated_pad_settings_dialog(emulated_pad_settings_dialog::pad_type::mousegem, this); + dlg->show(); + }); + connect(ui->confPSMoveDS3Act, &QAction::triggered, this, [this] { emulated_pad_settings_dialog* dlg = new emulated_pad_settings_dialog(emulated_pad_settings_dialog::pad_type::ds3gem, this); diff --git a/rpcs3/rpcs3qt/main_window.ui b/rpcs3/rpcs3qt/main_window.ui index ba29696974..adb66d8bcf 100644 --- a/rpcs3/rpcs3qt/main_window.ui +++ b/rpcs3/rpcs3qt/main_window.ui @@ -244,6 +244,7 @@ + @@ -1333,6 +1334,11 @@ PS Move (Fake) + + + PS Move (Mouse) + + GunCon 3