From d47b58e9933e21583e72c7289a3a3e79f4a2d33d Mon Sep 17 00:00:00 2001 From: Megamouse Date: Wed, 14 May 2025 05:34:40 +0200 Subject: [PATCH] Implement fake ps move external devices --- rpcs3/Emu/CMakeLists.txt | 1 + rpcs3/Emu/Cell/Modules/cellGem.cpp | 414 ++++++++++++++---- rpcs3/Emu/Cell/Modules/cellGem.h | 34 ++ rpcs3/Emu/Cell/Modules/cellPad.cpp | 2 +- rpcs3/Emu/Io/gem_config.cpp | 83 ++++ rpcs3/Emu/Io/gem_config.h | 114 ++++- rpcs3/Input/ps_move_handler.cpp | 31 -- rpcs3/emucore.vcxproj | 1 + rpcs3/emucore.vcxproj.filters | 5 +- .../rpcs3qt/emulated_pad_settings_dialog.cpp | 177 ++++++-- rpcs3/rpcs3qt/emulated_pad_settings_dialog.h | 3 +- rpcs3/rpcs3qt/settings_dialog.cpp | 6 +- 12 files changed, 714 insertions(+), 157 deletions(-) create mode 100644 rpcs3/Emu/Io/gem_config.cpp diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 0164376dff..f61c23239e 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -394,6 +394,7 @@ target_sources(rpcs3_emu PRIVATE Io/Dimensions.cpp Io/evdev_gun_handler.cpp Io/GameTablet.cpp + Io/gem_config.cpp Io/GHLtar.cpp Io/GunCon3.cpp Io/Infinity.cpp diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index bfbeb416df..3e2b056855 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -27,39 +27,6 @@ LOG_CHANNEL(cellGem); -template <> -void fmt_class_string::format(std::string& out, u64 arg) -{ - format_enum(out, arg, [](gem_btn value) - { - switch (value) - { - case gem_btn::start: return "Start"; - case gem_btn::select: return "Select"; - case gem_btn::triangle: return "Triangle"; - case gem_btn::circle: return "Circle"; - case gem_btn::cross: return "Cross"; - case gem_btn::square: return "Square"; - case gem_btn::move: return "Move"; - case gem_btn::t: return "T"; - 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; - }); -} - template <> void fmt_class_string::format(std::string& out, u64 arg) { @@ -234,7 +201,7 @@ public: struct gem_controller { u32 status = CELL_GEM_STATUS_DISCONNECTED; // Connection status (CELL_GEM_STATUS_DISCONNECTED or CELL_GEM_STATUS_READY) - u32 ext_status = CELL_GEM_NO_EXTERNAL_PORT_DEVICE; // External port connection status + u32 ext_status = 0; // External port connection status u32 ext_id = 0; // External device ID (type). For example SHARP_SHOOTER_DEVICE_ID u32 port = 0; // Assigned port bool enabled_magnetometer = true; // Whether the magnetometer is enabled (probably used for additional rotational precision) @@ -1918,6 +1885,312 @@ static void ps_move_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& co } } +static const std::unordered_map ext_btn_map = +{ + { gem_btn::sharpshooter_firing_mode_1, button_flags::ss_firing_mode_1 }, + { gem_btn::sharpshooter_firing_mode_2, button_flags::ss_firing_mode_2 }, + { gem_btn::sharpshooter_firing_mode_3, button_flags::ss_firing_mode_3 }, + { gem_btn::sharpshooter_trigger, button_flags::ss_trigger }, + { gem_btn::sharpshooter_reload, button_flags::ss_reload }, + { gem_btn::racing_wheel_d_pad_up, CELL_PAD_CTRL_UP }, + { gem_btn::racing_wheel_d_pad_right, CELL_PAD_CTRL_RIGHT }, + { gem_btn::racing_wheel_d_pad_down, CELL_PAD_CTRL_DOWN }, + { gem_btn::racing_wheel_d_pad_left, CELL_PAD_CTRL_LEFT }, + { gem_btn::racing_wheel_throttle, 0 }, + { gem_btn::racing_wheel_l1, CELL_PAD_CTRL_L1 }, + { gem_btn::racing_wheel_r1, CELL_PAD_CTRL_R1 }, + { gem_btn::racing_wheel_l2, 0 }, + { gem_btn::racing_wheel_r2, 0 }, + { gem_btn::racing_wheel_paddle_l, button_flags::rw_paddle_l }, + { gem_btn::racing_wheel_paddle_r, button_flags::rw_paddle_r }, + { gem_btn::combo_sharpshooter_firing_mode_1, button_flags::ss_firing_mode_1 }, + { gem_btn::combo_sharpshooter_firing_mode_2, button_flags::ss_firing_mode_2 }, + { gem_btn::combo_sharpshooter_firing_mode_3, button_flags::ss_firing_mode_3 }, + { gem_btn::combo_sharpshooter_trigger, button_flags::ss_trigger }, + { gem_btn::combo_sharpshooter_reload, button_flags::ss_reload }, + { gem_btn::combo_racing_wheel_d_pad_up, CELL_PAD_CTRL_UP }, + { gem_btn::combo_racing_wheel_d_pad_right, CELL_PAD_CTRL_RIGHT }, + { gem_btn::combo_racing_wheel_d_pad_down, CELL_PAD_CTRL_DOWN }, + { gem_btn::combo_racing_wheel_d_pad_left, CELL_PAD_CTRL_LEFT }, + { gem_btn::combo_racing_wheel_throttle, 0 }, + { gem_btn::combo_racing_wheel_l1, CELL_PAD_CTRL_L1 }, + { gem_btn::combo_racing_wheel_r1, CELL_PAD_CTRL_R1 }, + { gem_btn::combo_racing_wheel_l2, 0 }, + { gem_btn::combo_racing_wheel_r2, 0 }, + { gem_btn::combo_racing_wheel_paddle_l, button_flags::rw_paddle_l }, + { gem_btn::combo_racing_wheel_paddle_r, button_flags::rw_paddle_r }, +}; + +static const std::unordered_map ext_btn_indices = +{ + { gem_btn::racing_wheel_throttle, 0 }, + { gem_btn::racing_wheel_l2, 1 }, + { gem_btn::racing_wheel_r2, 2 }, + { gem_btn::racing_wheel_paddle_l, 3 }, + { gem_btn::racing_wheel_paddle_r, 4 }, + { gem_btn::combo_racing_wheel_throttle, 0 }, + { gem_btn::combo_racing_wheel_l2, 1 }, + { gem_btn::combo_racing_wheel_r2, 2 }, + { gem_btn::combo_racing_wheel_paddle_l, 3 }, + { gem_btn::combo_racing_wheel_paddle_r, 4 }, +}; + +static u32 ext_device_id(gem_ext_id id) +{ + switch (id) + { + case gem_ext_id::disconnected: return 0; + case gem_ext_id::sharpshooter: return SHARP_SHOOTER_DEVICE_ID; + case gem_ext_id::racing_wheel: return RACING_WHEEL_DEVICE_ID; + } + fmt::throw_exception("Mo ID found for id = %d", static_cast(id)); +} + +template +static void input_to_ext(u32 external_device_id, CellGemExtPortData& ext, std::set& combos, gem_btn btn, pad_button pad_btn, u16 value, bool pressed) +{ + if (!pressed) + return; + + if constexpr (has_combo && is_combo) + { + if (external_device_id == SHARP_SHOOTER_DEVICE_ID) + { + switch (btn) + { + case gem_btn::combo_sharpshooter_firing_mode_1: + case gem_btn::combo_sharpshooter_firing_mode_2: + case gem_btn::combo_sharpshooter_firing_mode_3: + case gem_btn::combo_sharpshooter_trigger: + case gem_btn::combo_sharpshooter_reload: + ext.custom[0] |= ::at32(ext_btn_map, btn); + combos.insert(pad_btn); + break; + default: + break; + } + } + else if (external_device_id == RACING_WHEEL_DEVICE_ID) + { + switch (btn) + { + case gem_btn::combo_racing_wheel_throttle: + case gem_btn::combo_racing_wheel_l2: + case gem_btn::combo_racing_wheel_r2: + ext.custom[::at32(ext_btn_indices, btn)] = static_cast(value); + combos.insert(pad_btn); + break; + case gem_btn::combo_racing_wheel_paddle_l: + case gem_btn::combo_racing_wheel_paddle_r: + ext.custom[::at32(ext_btn_indices, btn)] |= ::at32(ext_btn_map, btn); + combos.insert(pad_btn); + break; + case gem_btn::combo_racing_wheel_d_pad_up: + case gem_btn::combo_racing_wheel_d_pad_right: + case gem_btn::combo_racing_wheel_d_pad_down: + case gem_btn::combo_racing_wheel_d_pad_left: + ext.digital1 |= ::at32(ext_btn_map, btn); + combos.insert(pad_btn); + break; + case gem_btn::combo_racing_wheel_l1: + case gem_btn::combo_racing_wheel_r1: + ext.digital2 |= ::at32(ext_btn_map, btn); + combos.insert(pad_btn); + break; + default: + break; + } + } + } + else + { + if constexpr (has_combo) + { + if (combos.contains(pad_btn)) + { + return; + } + } + + if (external_device_id == SHARP_SHOOTER_DEVICE_ID) + { + switch (btn) + { + case gem_btn::sharpshooter_firing_mode_1: + case gem_btn::sharpshooter_firing_mode_2: + case gem_btn::sharpshooter_firing_mode_3: + case gem_btn::sharpshooter_trigger: + case gem_btn::sharpshooter_reload: + ext.custom[0] |= ::at32(ext_btn_map, btn); + break; + default: + break; + } + } + else if (external_device_id == RACING_WHEEL_DEVICE_ID) + { + switch (btn) + { + case gem_btn::combo_racing_wheel_throttle: + case gem_btn::combo_racing_wheel_l2: + case gem_btn::combo_racing_wheel_r2: + ext.custom[::at32(ext_btn_indices, btn)] = static_cast(value); + break; + case gem_btn::combo_racing_wheel_paddle_l: + case gem_btn::combo_racing_wheel_paddle_r: + ext.custom[::at32(ext_btn_indices, btn)] |= ::at32(ext_btn_map, btn); + break; + case gem_btn::combo_racing_wheel_d_pad_up: + case gem_btn::combo_racing_wheel_d_pad_right: + case gem_btn::combo_racing_wheel_d_pad_down: + case gem_btn::combo_racing_wheel_d_pad_left: + ext.digital1 |= ::at32(ext_btn_map, btn); + break; + case gem_btn::combo_racing_wheel_l1: + case gem_btn::combo_racing_wheel_r1: + ext.digital2 |= ::at32(ext_btn_map, btn); + break; + default: + break; + } + } + } +} + +static void real_input_to_ext(u32 gem_num, gem_config::gem_controller& controller, CellGemExtPortData& ext) +{ + std::lock_guard lock(pad::g_pad_mutex); + + const auto handler = pad::get_pad_thread(); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); + + if (!pad->is_connected()) + { + controller.ext_status = 0; + controller.ext_id = 0; + return; + } + + ps_move_data& move_data = pad->move_data; + + controller.ext_status = move_data.external_device_connected ? CELL_GEM_EXT_CONNECTED : 0; // TODO: | CELL_GEM_EXT_EXT0 | CELL_GEM_EXT_EXT1 + controller.ext_id = move_data.external_device_connected ? move_data.external_device_id : 0; + + if (!move_data.external_device_connected) + { + return; + } + + // TODO: + // ext.analog_left_x + // ext.analog_left_y + // ext.analog_right_x + // ext.analog_right_y + // ext.digital1 + // ext.digital2 + + ext.status = controller.ext_status; + std::memcpy(ext.custom, move_data.external_device_data.data(), 5); +} + +static void fake_input_to_ext(u32 gem_num, gem_config::gem_controller& controller, CellGemExtPortData& ext) +{ + std::lock_guard lock(pad::g_pad_mutex); + + const auto handler = pad::get_pad_thread(); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); + + if (!pad->is_connected()) + { + controller.ext_status = 0; + controller.ext_id = 0; + return; + } + + ps_move_data& move_data = pad->move_data; + const auto& cfg = ::at32(g_cfg_gem_fake.players, gem_num); + + move_data.external_device_id = ext_device_id(cfg->external_device); + move_data.external_device_connected = move_data.external_device_id != 0; + move_data.external_device_data = {}; + + controller.ext_status = move_data.external_device_connected ? CELL_GEM_EXT_CONNECTED : 0; // TODO: | CELL_GEM_EXT_EXT0 | CELL_GEM_EXT_EXT1 + controller.ext_id = move_data.external_device_connected ? move_data.external_device_id : 0; + + if (!move_data.external_device_connected) + { + return; + } + + cfg->handle_input(pad, true, [&move_data, &ext](gem_btn btn, pad_button pad_btn, u16 value, bool pressed, bool& /*abort*/) + { + static std::set s_combos = {}; + input_to_ext(move_data.external_device_id, ext, s_combos, btn, pad_btn, value, pressed); + }); + + ext.status = controller.ext_status; + std::memcpy(ext.custom, move_data.external_device_data.data(), 5); +} + +static void mouse_input_to_ext(u32 mouse_no, gem_config::gem_controller& controller, CellGemExtPortData& ext) +{ + auto& handler = g_fxo->get(); + + std::scoped_lock lock(handler.mutex); + + // Make sure that the mouse handler is initialized + handler.Init(std::min(g_fxo->get().attribute.max_connect, CELL_GEM_MAX_NUM)); + + if (mouse_no >= handler.GetMice().size()) + { + controller.ext_status = 0; + controller.ext_id = 0; + return; + } + + const Mouse& mouse_data = ::at32(handler.GetMice(), mouse_no); + const auto& cfg = ::at32(g_cfg_gem_mouse.players, mouse_no); + + const u32 external_device_id = ext_device_id(cfg->external_device); + const bool external_device_connected = external_device_id != 0; + + controller.ext_status = external_device_connected ? CELL_GEM_EXT_CONNECTED : 0; // TODO: | CELL_GEM_EXT_EXT0 | CELL_GEM_EXT_EXT1 + controller.ext_id = external_device_connected ? external_device_id : 0; + + if (!external_device_connected) + { + return; + } + + bool combo_active = false; + std::set combos; + + // 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; + } + }); + + // Check combos + if (combo_active) + { + cfg->handle_input(mouse_data, [external_device_id, &ext, &combos](gem_btn btn, pad_button pad_btn, u16 value, bool pressed, bool& /*abort*/) + { + input_to_ext(external_device_id, ext, combos, btn, pad_btn, value, pressed); + }); + } + + // Check normal buttons + cfg->handle_input(mouse_data, [external_device_id, &ext, &combos](gem_btn btn, pad_button pad_btn, u16 value, bool pressed, bool& /*abort*/) + { + input_to_ext(external_device_id, ext, combos, btn, pad_btn, value, pressed); + }); +} + /** * \brief Maps external Move controller data to DS3 input. (This can be input from any physical pad, not just the DS3) * Implementation detail: CellGemExtPortData's digital/analog fields map the same way as @@ -1926,7 +2199,7 @@ static void ps_move_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& co * \param ext External data to modify * \return true on success, false if controller is disconnected */ -static void ds3_input_to_ext(u32 gem_num, gem_config::gem_controller& controller, CellGemExtPortData& ext) +static void get_external_device_input(u32 gem_num, gem_config::gem_controller& controller, CellGemExtPortData& ext) { ext = {}; @@ -1935,53 +2208,6 @@ static void ds3_input_to_ext(u32 gem_num, gem_config::gem_controller& controller return; } - std::lock_guard lock(pad::g_pad_mutex); - - const auto handler = pad::get_pad_thread(); - const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); - - if (!pad->is_connected()) - { - return; - } - - const auto& move_data = pad->move_data; - - controller.ext_status = move_data.external_device_connected ? CELL_GEM_EXT_CONNECTED : 0; // TODO: | CELL_GEM_EXT_EXT0 | CELL_GEM_EXT_EXT1 - controller.ext_id = move_data.external_device_connected ? move_data.external_device_id : 0; - - ext.status = controller.ext_status; - - for (const AnalogStick& stick : pad->m_sticks) - { - switch (stick.m_offset) - { - case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: ext.analog_left_x = stick.m_value; break; - case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: ext.analog_left_y = stick.m_value; break; - case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: ext.analog_right_x = stick.m_value; break; - case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: ext.analog_right_y = stick.m_value; break; - default: break; - } - } - - for (const Button& button : pad->m_buttons) - { - if (!button.m_pressed) - continue; - - switch (button.m_offset) - { - case CELL_PAD_BTN_OFFSET_DIGITAL1: ext.digital1 |= button.m_outKeyCode; break; - case CELL_PAD_BTN_OFFSET_DIGITAL2: ext.digital2 |= button.m_outKeyCode; break; - default: break; - } - } - - if (!move_data.external_device_connected) - { - return; - } - // The sharpshooter only sets the custom bytes as follows: // custom[0] (0x01): Firing mode selector is in position 1. // custom[0] (0x02): Firing mode selector is in position 2. @@ -1996,7 +2222,21 @@ static void ds3_input_to_ext(u32 gem_num, gem_config::gem_controller& controller // custom[3] (0x01): Left paddle // custom[3] (0x02): Right paddle - std::memcpy(ext.custom, move_data.external_device_data.data(), 5); + switch (g_cfg.io.move) + { + case move_handler::real: + real_input_to_ext(gem_num, controller, ext); + break; + case move_handler::fake: + fake_input_to_ext(gem_num, controller, ext); + break; + case move_handler::mouse: + case move_handler::raw_mouse: + mouse_input_to_ext(gem_num, controller, ext); + break; + default: + break; + } } /** @@ -2029,7 +2269,7 @@ static bool mouse_input_to_pad(u32 mouse_no, be_t& digital_buttons, be_t combos; @@ -2759,7 +2999,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v if (g_cfg.io.move != move_handler::null) { - ds3_input_to_ext(gem_num, gem.controllers[gem_num], inertial_state->ext); + get_external_device_input(gem_num, gem.controllers[gem_num], inertial_state->ext); inertial_state->timestamp = (get_guest_system_time() - gem.start_timestamp_us); inertial_state->counter = gem.inertial_counter++; @@ -2953,7 +3193,7 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptrext); + get_external_device_input(gem_num, controller, gem_state->ext); if (controller.enabled_tracking) { @@ -3370,7 +3610,7 @@ error_code cellGemReadExternalPortDeviceInfo(u32 gem_num, vm::ptr ext_id, v { // Get external device status CellGemExtPortData ext_port_data{}; - ds3_input_to_ext(gem_num, controller, ext_port_data); + get_external_device_input(gem_num, controller, ext_port_data); } if (!(controller.ext_status & CELL_GEM_EXT_CONNECTED)) diff --git a/rpcs3/Emu/Cell/Modules/cellGem.h b/rpcs3/Emu/Cell/Modules/cellGem.h index c70e2386ba..237425f225 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.h +++ b/rpcs3/Emu/Cell/Modules/cellGem.h @@ -278,3 +278,37 @@ struct CellGemVideoConvertAttribute ENABLE_BITWISE_SERIALIZATION; }; + +namespace +{ + enum button_flags : u16 + { + select = 0x01, + start = 0x08, + triangle = 0x10, + circle = 0x20, + cross = 0x40, + square = 0x80, + ps = 0x0001, + move = 0x4008, + t = 0x8010, + ext_dev = 0x1000, + + // Sharpshooter + ss_firing_mode_1 = 0x01, + ss_firing_mode_2 = 0x02, + ss_firing_mode_3 = 0x04, + ss_trigger = 0x40, + ss_reload = 0x80, + + // Racing Wheel + rw_d_pad_up = 0x10, + rw_d_pad_right = 0x20, + rw_d_pad_down = 0x40, + rw_d_pad_left = 0x80, + rw_l1 = 0x04, + rw_r1 = 0x08, + rw_paddle_l = 0x01, + rw_paddle_r = 0x02, + }; +} diff --git a/rpcs3/Emu/Cell/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp index 61e29805aa..dd299f0736 100644 --- a/rpcs3/Emu/Cell/Modules/cellPad.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp @@ -464,7 +464,7 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) case CELL_PAD_CTRL_DOWN: set_value(pad->m_press_down, value); break; case CELL_PAD_CTRL_RIGHT: set_value(pad->m_press_right, value); break; case CELL_PAD_CTRL_UP: set_value(pad->m_press_up, value); break; - // These arent pressure btns + // These aren't pressure btns case CELL_PAD_CTRL_R3: case CELL_PAD_CTRL_L3: case CELL_PAD_CTRL_START: diff --git a/rpcs3/Emu/Io/gem_config.cpp b/rpcs3/Emu/Io/gem_config.cpp new file mode 100644 index 0000000000..6151d1d081 --- /dev/null +++ b/rpcs3/Emu/Io/gem_config.cpp @@ -0,0 +1,83 @@ +#include "stdafx.h" +#include "gem_config.h" + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](gem_ext_id value) + { + switch (value) + { + case gem_ext_id::disconnected: return "Disconnected"; + case gem_ext_id::sharpshooter: return "Sharpshooter"; + case gem_ext_id::racing_wheel: return "Racing Wheel"; + } + + return unknown; + }); +} + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](gem_btn value) + { + switch (value) + { + case gem_btn::start: return "Start"; + case gem_btn::select: return "Select"; + case gem_btn::triangle: return "Triangle"; + case gem_btn::circle: return "Circle"; + case gem_btn::cross: return "Cross"; + case gem_btn::square: return "Square"; + case gem_btn::move: return "Move"; + case gem_btn::t: return "T"; + 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::sharpshooter_firing_mode_1: return "Firing Mode 1"; + case gem_btn::sharpshooter_firing_mode_2: return "Firing Mode 2"; + case gem_btn::sharpshooter_firing_mode_3: return "Firing Mode 3"; + case gem_btn::sharpshooter_trigger: return "Trigger"; + case gem_btn::sharpshooter_reload: return "Reload"; + case gem_btn::racing_wheel_d_pad_up: return "Up"; + case gem_btn::racing_wheel_d_pad_right: return "Right"; + case gem_btn::racing_wheel_d_pad_down: return "Down"; + case gem_btn::racing_wheel_d_pad_left: return "Left"; + case gem_btn::racing_wheel_throttle: return "Throttle"; + case gem_btn::racing_wheel_l1: return "L1"; + case gem_btn::racing_wheel_r1: return "R1"; + case gem_btn::racing_wheel_l2: return "L2"; + case gem_btn::racing_wheel_r2: return "R2"; + case gem_btn::racing_wheel_paddle_l: return "Paddle L"; + case gem_btn::racing_wheel_paddle_r: return "Paddle R"; + case gem_btn::combo_sharpshooter_firing_mode_1: return "Combo Firing Mode 1"; + case gem_btn::combo_sharpshooter_firing_mode_2: return "Combo Firing Mode 2"; + case gem_btn::combo_sharpshooter_firing_mode_3: return "Combo Firing Mode 3"; + case gem_btn::combo_sharpshooter_trigger: return "Combo Trigger"; + case gem_btn::combo_sharpshooter_reload: return "Combo Reload"; + case gem_btn::combo_racing_wheel_d_pad_up: return "Combo Up"; + case gem_btn::combo_racing_wheel_d_pad_right: return "Combo Right"; + case gem_btn::combo_racing_wheel_d_pad_down: return "Combo Down"; + case gem_btn::combo_racing_wheel_d_pad_left: return "Combo Left"; + case gem_btn::combo_racing_wheel_throttle: return "Combo Throttle"; + case gem_btn::combo_racing_wheel_l1: return "Combo L1"; + case gem_btn::combo_racing_wheel_r1: return "Combo R1"; + case gem_btn::combo_racing_wheel_l2: return "Combo L2"; + case gem_btn::combo_racing_wheel_r2: return "Combo R2"; + case gem_btn::combo_racing_wheel_paddle_l: return "Combo Paddle L"; + case gem_btn::combo_racing_wheel_paddle_r: return "Combo Paddle R"; + case gem_btn::count: return "Count"; + } + + return unknown; + }); +} diff --git a/rpcs3/Emu/Io/gem_config.h b/rpcs3/Emu/Io/gem_config.h index 9cfca88ddb..a87e98593d 100644 --- a/rpcs3/Emu/Io/gem_config.h +++ b/rpcs3/Emu/Io/gem_config.h @@ -2,6 +2,13 @@ #include "emulated_pad_config.h" +enum class gem_ext_id : u32 +{ + disconnected, + sharpshooter, + racing_wheel +}; + enum class gem_btn : u32 { start, @@ -17,7 +24,9 @@ enum class gem_btn : u32 combo_begin, combo = combo_begin, - combo_start, + + combo_buttons_begin, + combo_start = combo_buttons_begin, combo_select, combo_triangle, combo_circle, @@ -25,7 +34,52 @@ enum class gem_btn : u32 combo_square, combo_move, combo_t, - combo_end = combo_t, + combo_buttons_end = combo_t, + combo_end = combo_buttons_end, + + sharpshooter_begin, + sharpshooter_firing_mode_1 = sharpshooter_begin, + sharpshooter_firing_mode_2, + sharpshooter_firing_mode_3, + sharpshooter_trigger, + sharpshooter_reload, + sharpshooter_end = sharpshooter_reload, + + combo_sharpshooter_begin, + combo_sharpshooter_firing_mode_1 = combo_sharpshooter_begin, + combo_sharpshooter_firing_mode_2, + combo_sharpshooter_firing_mode_3, + combo_sharpshooter_trigger, + combo_sharpshooter_reload, + combo_sharpshooter_end = combo_sharpshooter_reload, + + racing_wheel_begin, + racing_wheel_d_pad_up = racing_wheel_begin, + racing_wheel_d_pad_right, + racing_wheel_d_pad_down, + racing_wheel_d_pad_left, + racing_wheel_throttle, + racing_wheel_l1, + racing_wheel_r1, + racing_wheel_l2, + racing_wheel_r2, + racing_wheel_paddle_l, + racing_wheel_paddle_r, + racing_wheel_end = racing_wheel_paddle_r, + + combo_racing_wheel_begin, + combo_racing_wheel_d_pad_up = combo_racing_wheel_begin, + combo_racing_wheel_d_pad_right, + combo_racing_wheel_d_pad_down, + combo_racing_wheel_d_pad_left, + combo_racing_wheel_throttle, + combo_racing_wheel_l1, + combo_racing_wheel_r1, + combo_racing_wheel_l2, + combo_racing_wheel_r2, + combo_racing_wheel_paddle_l, + combo_racing_wheel_paddle_r, + combo_racing_wheel_end = combo_racing_wheel_paddle_r, count }; @@ -44,6 +98,26 @@ struct cfg_fake_gem final : public emulated_pad_config cfg_pad_btn t{ this, "T", gem_btn::t, pad_button::R2 }; cfg_pad_btn x_axis{ this, "X-Axis", gem_btn::x_axis, pad_button::ls_x }; cfg_pad_btn y_axis{ this, "Y-Axis", gem_btn::y_axis, pad_button::ls_y }; + + cfg_pad_btn sharpshooter_firing_mode_1{ this, "Sharpshooter Firing Mode 1", gem_btn::sharpshooter_firing_mode_1, pad_button::dpad_left }; + cfg_pad_btn sharpshooter_firing_mode_2{ this, "Sharpshooter Firing Mode 2", gem_btn::sharpshooter_firing_mode_2, pad_button::dpad_up }; + cfg_pad_btn sharpshooter_firing_mode_3{ this, "Sharpshooter Firing Mode 3", gem_btn::sharpshooter_firing_mode_3, pad_button::dpad_right }; + cfg_pad_btn sharpshooter_trigger{ this, "Sharpshooter Trigger", gem_btn::sharpshooter_trigger, pad_button::L1 }; + cfg_pad_btn sharpshooter_reload{ this, "Sharpshooter Reload", gem_btn::sharpshooter_reload, pad_button::L2 }; + + cfg_pad_btn racing_wheel_d_pad_up{ this, "Racing Wheel D-Pad Up", gem_btn::racing_wheel_d_pad_up, pad_button::dpad_up }; + cfg_pad_btn racing_wheel_d_pad_right{ this, "Racing Wheel D-Pad Right", gem_btn::racing_wheel_d_pad_right, pad_button::dpad_right }; + cfg_pad_btn racing_wheel_d_pad_down{ this, "Racing Wheel D-Pad Down", gem_btn::racing_wheel_d_pad_down, pad_button::dpad_down }; + cfg_pad_btn racing_wheel_d_pad_left{ this, "Racing Wheel D-Pad Left", gem_btn::racing_wheel_d_pad_left, pad_button::dpad_left }; + cfg_pad_btn racing_wheel_throttle{ this, "Racing Wheel Throttle", gem_btn::racing_wheel_throttle, pad_button::rs_up }; + cfg_pad_btn racing_wheel_l1{ this, "Racing Wheel L1", gem_btn::racing_wheel_l1, pad_button::L1 }; + cfg_pad_btn racing_wheel_r1{ this, "Racing Wheel R1", gem_btn::racing_wheel_r1, pad_button::R1 }; + cfg_pad_btn racing_wheel_l2{ this, "Racing Wheel L2", gem_btn::racing_wheel_l2, pad_button::L2 }; + cfg_pad_btn racing_wheel_r2{ this, "Racing Wheel R2", gem_btn::racing_wheel_r2, pad_button::R2 }; + cfg_pad_btn racing_wheel_paddle_l{ this, "Racing Wheel Paddle L", gem_btn::racing_wheel_paddle_l, pad_button::L3 }; + cfg_pad_btn racing_wheel_paddle_r{ this, "Racing Wheel Paddle R", gem_btn::racing_wheel_paddle_r, pad_button::R3 }; + + cfg::_enum external_device{ this, "External Device", gem_ext_id::disconnected }; }; struct cfg_fake_gems final : public emulated_pads_config @@ -72,6 +146,42 @@ struct cfg_mouse_gem final : public emulated_pad_config 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 }; + + cfg_pad_btn sharpshooter_firing_mode_1{ this, "Sharpshooter Firing Mode 1", gem_btn::sharpshooter_firing_mode_1, pad_button::pad_button_max_enum }; + cfg_pad_btn sharpshooter_firing_mode_2{ this, "Sharpshooter Firing Mode 2", gem_btn::sharpshooter_firing_mode_2, pad_button::pad_button_max_enum }; + cfg_pad_btn sharpshooter_firing_mode_3{ this, "Sharpshooter Firing Mode 3", gem_btn::sharpshooter_firing_mode_3, pad_button::pad_button_max_enum }; + cfg_pad_btn sharpshooter_trigger{ this, "Sharpshooter Trigger", gem_btn::sharpshooter_trigger, pad_button::pad_button_max_enum }; + cfg_pad_btn sharpshooter_reload{ this, "Sharpshooter Reload", gem_btn::sharpshooter_reload, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_sharpshooter_firing_mode_1{ this, "Combo Sharpshooter Firing Mode 1", gem_btn::combo_sharpshooter_firing_mode_1, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_sharpshooter_firing_mode_2{ this, "Combo Sharpshooter Firing Mode 2", gem_btn::combo_sharpshooter_firing_mode_2, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_sharpshooter_firing_mode_3{ this, "Combo Sharpshooter Firing Mode 3", gem_btn::combo_sharpshooter_firing_mode_3, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_sharpshooter_trigger{ this, "Combo Sharpshooter Trigger", gem_btn::combo_sharpshooter_trigger, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_sharpshooter_reload{ this, "Combo Sharpshooter Reload", gem_btn::combo_sharpshooter_reload, pad_button::pad_button_max_enum }; + + cfg_pad_btn racing_wheel_d_pad_up{ this, "Racing Wheel D-Pad Up", gem_btn::racing_wheel_d_pad_up, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_d_pad_right{ this, "Racing Wheel D-Pad Right", gem_btn::racing_wheel_d_pad_right, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_d_pad_down{ this, "Racing Wheel D-Pad Down", gem_btn::racing_wheel_d_pad_down, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_d_pad_left{ this, "Racing Wheel D-Pad Left", gem_btn::racing_wheel_d_pad_left, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_throttle{ this, "Racing Wheel Throttle", gem_btn::racing_wheel_throttle, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_l1{ this, "Racing Wheel L1", gem_btn::racing_wheel_l1, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_r1{ this, "Racing Wheel R1", gem_btn::racing_wheel_r1, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_l2{ this, "Racing Wheel L2", gem_btn::racing_wheel_l2, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_r2{ this, "Racing Wheel R2", gem_btn::racing_wheel_r2, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_paddle_l{ this, "Racing Wheel Paddle L", gem_btn::racing_wheel_paddle_l, pad_button::pad_button_max_enum }; + cfg_pad_btn racing_wheel_paddle_r{ this, "Racing Wheel Paddle R", gem_btn::racing_wheel_paddle_r, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_d_pad_up{ this, "Combo Racing Wheel D-Pad Up", gem_btn::combo_racing_wheel_d_pad_up, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_d_pad_right{ this, "Combo Racing Wheel D-Pad Right", gem_btn::combo_racing_wheel_d_pad_right, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_d_pad_down{ this, "Combo Racing Wheel D-Pad Down", gem_btn::combo_racing_wheel_d_pad_down, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_d_pad_left{ this, "Combo Racing Wheel D-Pad Left", gem_btn::combo_racing_wheel_d_pad_left, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_throttle{ this, "Combo Racing Wheel Throttle", gem_btn::combo_racing_wheel_throttle, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_l1{ this, "Combo Racing Wheel L1", gem_btn::combo_racing_wheel_l1, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_r1{ this, "Combo Racing Wheel R1", gem_btn::combo_racing_wheel_r1, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_l2{ this, "Combo Racing Wheel L2", gem_btn::combo_racing_wheel_l2, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_r2{ this, "Combo Racing Wheel R2", gem_btn::combo_racing_wheel_r2, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_paddle_l{ this, "Combo Racing Wheel Paddle L", gem_btn::combo_racing_wheel_paddle_l, pad_button::pad_button_max_enum }; + cfg_pad_btn combo_racing_wheel_paddle_r{ this, "Combo Racing Wheel Paddle R", gem_btn::combo_racing_wheel_paddle_r, pad_button::pad_button_max_enum }; + + cfg::_enum external_device{ this, "External Device", gem_ext_id::disconnected }; }; struct cfg_mouse_gems final : public emulated_pads_config diff --git a/rpcs3/Input/ps_move_handler.cpp b/rpcs3/Input/ps_move_handler.cpp index 7eb74d3e96..7ce6dd2706 100644 --- a/rpcs3/Input/ps_move_handler.cpp +++ b/rpcs3/Input/ps_move_handler.cpp @@ -13,37 +13,6 @@ namespace constexpr id_pair MOVE_ID_ZCM1 = {0x054C, 0x03D5}; constexpr id_pair MOVE_ID_ZCM2 = {0x054C, 0x0c5e}; - enum button_flags : u16 - { - select = 0x01, - start = 0x08, - triangle = 0x10, - circle = 0x20, - cross = 0x40, - square = 0x80, - ps = 0x0001, - move = 0x4008, - t = 0x8010, - ext_dev = 0x1000, - - // Sharpshooter - ss_firing_mode_1 = 0x01, - ss_firing_mode_2 = 0x02, - ss_firing_mode_3 = 0x04, - ss_trigger = 0x40, - ss_reload = 0x80, - - // Racing Wheel - rw_d_pad_up = 0x10, - rw_d_pad_right = 0x20, - rw_d_pad_down = 0x40, - rw_d_pad_left = 0x80, - rw_l1 = 0x04, - rw_r1 = 0x08, - rw_paddle_l = 0x01, - rw_paddle_r = 0x02, - }; - enum battery_status : u8 { charge_empty = 0x00, diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 3e623663d4..4257708f84 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -86,6 +86,7 @@ true + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 94f0382bcc..5e4836860c 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -1369,6 +1369,9 @@ Emu\Io + + Emu\Io + @@ -2881,4 +2884,4 @@ Emu\GPU\RSX\Program\MSAA - + \ No newline at end of file diff --git a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp index aee4c44c77..13bdce1814 100644 --- a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.cpp @@ -13,11 +13,13 @@ #include "Emu/Io/usio_config.h" #include "util/asm.hpp" +#include #include #include #include #include #include +#include #include enum button_role @@ -123,12 +125,35 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) { ensure(!!tabs); + const bool show_mouse_legend = m_type == pad_type::mousegem; + const bool show_external_device_selection = m_type == pad_type::mousegem || m_type == pad_type::ds3gem; + + if (show_mouse_legend) + { + if (!g_cfg_mouse.load()) + { + cfg_log.notice("Could not restore mouse config. Using defaults."); + } + + if (!g_cfg_raw_mouse.load()) + { + cfg_log.notice("Could not restore raw mouse config. Using defaults."); + } + } + std::set ignored_values; const auto remove_value = [&ignored_values](int value) { ignored_values.insert(static_cast(value)); }; + const auto remove_values = [remove_value](int begin, int end) + { + for (int i = begin; i <= end; i++) + { + remove_value(i); + } + }; usz players = 0; switch (m_type) @@ -148,22 +173,22 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) case pad_type::gem: players = g_cfg_gem_real.players.size(); - // Ignore combo, x and y axis + // Ignore combo, sharpshooter, wheel, 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); - } + remove_values(static_cast(gem_btn::sharpshooter_begin), static_cast(gem_btn::sharpshooter_end)); + remove_values(static_cast(gem_btn::racing_wheel_begin), static_cast(gem_btn::racing_wheel_end)); + remove_values(static_cast(gem_btn::combo_begin), static_cast(gem_btn::combo_end)); + remove_values(static_cast(gem_btn::combo_sharpshooter_begin), static_cast(gem_btn::combo_sharpshooter_end)); + remove_values(static_cast(gem_btn::combo_racing_wheel_begin), static_cast(gem_btn::combo_racing_wheel_end)); 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); - } + remove_values(static_cast(gem_btn::combo_begin), static_cast(gem_btn::combo_end)); + remove_values(static_cast(gem_btn::combo_sharpshooter_begin), static_cast(gem_btn::combo_sharpshooter_end)); + remove_values(static_cast(gem_btn::combo_racing_wheel_begin), static_cast(gem_btn::combo_racing_wheel_end)); break; case pad_type::mousegem: players = g_cfg_gem_mouse.players.size(); @@ -185,30 +210,18 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) constexpr u32 max_items_per_column = 6; const int count = static_cast(T::count) - static_cast(ignored_values.size()); - int rows = count; + int rows = show_external_device_selection ? max_items_per_column : count; - for (u32 cols = 1; utils::aligned_div(static_cast(count), cols) > max_items_per_column;) + if (!show_external_device_selection) { - rows = utils::aligned_div(static_cast(count), ++cols); + for (u32 cols = 1; utils::aligned_div(static_cast(count), cols) > max_items_per_column;) + { + rows = utils::aligned_div(static_cast(count), ++cols); + } } m_combos.resize(players); - const bool show_mouse_legend = m_type == pad_type::mousegem; - - if (show_mouse_legend) - { - if (!g_cfg_mouse.load()) - { - cfg_log.notice("Could not restore mouse config. Using defaults."); - } - - if (!g_cfg_raw_mouse.load()) - { - cfg_log.notice("Could not restore raw mouse config. Using defaults."); - } - } - for (usz player = 0; player < players; player++) { // Create grid with all buttons @@ -228,7 +241,9 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) if constexpr (std::is_same_v) { const gem_btn btn = static_cast(i); - if (btn >= gem_btn::combo_begin && btn <= gem_btn::combo_end) + if ((btn >= gem_btn::combo_begin && btn <= gem_btn::combo_end) || + (btn >= gem_btn::combo_sharpshooter_begin && btn <= gem_btn::combo_sharpshooter_end) || + (btn >= gem_btn::combo_racing_wheel_begin && btn <= gem_btn::combo_racing_wheel_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.")); @@ -348,13 +363,19 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) } }); - if (row >= rows) + if (row >= rows || + (show_external_device_selection && + (i == static_cast(gem_btn::combo_buttons_begin) || + i == static_cast(gem_btn::sharpshooter_begin) || + i == static_cast(gem_btn::racing_wheel_begin) || + i == static_cast(gem_btn::combo_sharpshooter_begin) || + i == static_cast(gem_btn::combo_racing_wheel_begin)))) { row = 0; col++; } - ::at32(m_combos, player).push_back(combo); + ::at32(m_combos, player).push_back(std::make_pair(combo, gb)); h_layout->addWidget(combo); gb->setLayout(h_layout); grid_layout->addWidget(gb, row, col); @@ -364,6 +385,100 @@ void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs) QVBoxLayout* v_layout = new QVBoxLayout(this); + // Allow to select external devices + if (show_external_device_selection) + { + QRadioButton* rb_disconnected = new QRadioButton(tr("Disconnected"), this); + QRadioButton* rb_sharpshooter = new QRadioButton(tr("Sharpshooter"), this); + QRadioButton* rb_racing_wheel = new QRadioButton(tr("Racing Wheel"), this); + QButtonGroup* bg = new QButtonGroup(this); + bg->addButton(rb_disconnected, static_cast(gem_ext_id::disconnected)); + bg->addButton(rb_sharpshooter, static_cast(gem_ext_id::sharpshooter)); + bg->addButton(rb_racing_wheel, static_cast(gem_ext_id::racing_wheel)); + QHBoxLayout* h_layout = new QHBoxLayout(this); + h_layout->addWidget(rb_disconnected); + h_layout->addWidget(rb_sharpshooter); + h_layout->addWidget(rb_racing_wheel); + QGroupBox* gb = new QGroupBox(tr("External Device"), this); + gb->setToolTip(tr("Select an external device to emulate.")); + gb->setLayout(h_layout); + v_layout->addWidget(gb); + + const auto enable_buttons = [this, player](gem_ext_id id) + { + for (auto& [combo, gb] : m_combos.at(player)) + { + if (!combo || !gb) + continue; + + const QVariant data = combo->itemData(0, button_role::emulated_button); + if (!data.isValid() || !data.canConvert()) + continue; + + const int button = data.value(); + + switch (id) + { + case gem_ext_id::disconnected: + gb->setEnabled(!( + (button >= static_cast(gem_btn::sharpshooter_begin) && button <= static_cast(gem_btn::sharpshooter_end)) || + (button >= static_cast(gem_btn::racing_wheel_begin) && button <= static_cast(gem_btn::racing_wheel_end)) || + (button >= static_cast(gem_btn::combo_sharpshooter_begin) && button <= static_cast(gem_btn::combo_sharpshooter_end)) || + (button >= static_cast(gem_btn::combo_racing_wheel_begin) && button <= static_cast(gem_btn::combo_racing_wheel_end)))); + break; + case gem_ext_id::sharpshooter: + gb->setEnabled(!( + (button >= static_cast(gem_btn::racing_wheel_begin) && button <= static_cast(gem_btn::racing_wheel_end)) || + (button >= static_cast(gem_btn::combo_racing_wheel_begin) && button <= static_cast(gem_btn::combo_racing_wheel_end)))); + break; + case gem_ext_id::racing_wheel: + gb->setEnabled(!( + (button >= static_cast(gem_btn::sharpshooter_begin) && button <= static_cast(gem_btn::sharpshooter_end)) || + (button >= static_cast(gem_btn::combo_sharpshooter_begin) && button <= static_cast(gem_btn::combo_sharpshooter_end)))); + break; + default: + break; + } + } + }; + + gem_ext_id ext_id = gem_ext_id::disconnected; + switch (m_type) + { + case pad_type::ds3gem: + ext_id = ::at32(g_cfg_gem_fake.players, player)->external_device.get(); + break; + case pad_type::mousegem: + ext_id = ::at32(g_cfg_gem_mouse.players, player)->external_device.get(); + break; + default: + break; + } + + bg->button(static_cast(ext_id))->setChecked(true); + enable_buttons(ext_id); + + connect(bg, &QButtonGroup::idToggled, [this, player, enable_buttons](int id, bool checked) + { + if (!checked) return; + + const gem_ext_id ext_id = static_cast(id); + enable_buttons(ext_id); + + switch (m_type) + { + case pad_type::ds3gem: + ::at32(g_cfg_gem_fake.players, player)->external_device.set(ext_id); + break; + case pad_type::mousegem: + ::at32(g_cfg_gem_mouse.players, player)->external_device.set(ext_id); + break; + default: + break; + } + }); + } + // Create a legend of the current mouse settings if (show_mouse_legend) { @@ -558,7 +673,7 @@ void emulated_pad_settings_dialog::reset_config() for (usz player = 0; player < m_combos.size(); player++) { - for (QComboBox* combo : m_combos.at(player)) + for (auto& [combo, gb] : m_combos.at(player)) { if (!combo) continue; diff --git a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.h b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.h index 490dee3ae7..e157e67a64 100644 --- a/rpcs3/rpcs3qt/emulated_pad_settings_dialog.h +++ b/rpcs3/rpcs3qt/emulated_pad_settings_dialog.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -37,5 +38,5 @@ private: pad_type m_type; - std::vector> m_combos; + std::vector>> m_combos; }; diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index abea4b47bf..6da24a9c88 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -359,7 +359,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std SubscribeTooltip(ui->ppu__static, tooltips.settings.ppu__static); SubscribeTooltip(ui->ppu_llvm, tooltips.settings.ppu_llvm); - QButtonGroup *ppu_bg = new QButtonGroup(this); + QButtonGroup* ppu_bg = new QButtonGroup(this); ppu_bg->addButton(ui->ppu__static, static_cast(ppu_decoder_type::_static)); ppu_bg->addButton(ui->ppu_llvm, static_cast(ppu_decoder_type::llvm)); @@ -695,7 +695,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std SubscribeTooltip(ui->rb_async_with_shader_interpreter, tooltips.settings.async_with_shader_interpreter); SubscribeTooltip(ui->rb_shader_interpreter_only, tooltips.settings.shader_interpreter_only); - QButtonGroup *shader_mode_bg = new QButtonGroup(this); + QButtonGroup* shader_mode_bg = new QButtonGroup(this); shader_mode_bg->addButton(ui->rb_legacy_recompiler, static_cast(shader_mode::recompiler)); shader_mode_bg->addButton(ui->rb_async_recompiler, static_cast(shader_mode::async_recompiler)); shader_mode_bg->addButton(ui->rb_async_with_shader_interpreter, static_cast(shader_mode::async_with_interpreter)); @@ -1447,7 +1447,7 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std // Radio Buttons // creating this in ui file keeps scrambling the order... - QButtonGroup *enter_button_assignment_bg = new QButtonGroup(this); + QButtonGroup* enter_button_assignment_bg = new QButtonGroup(this); enter_button_assignment_bg->addButton(ui->enterButtonAssignCircle, 0); enter_button_assignment_bg->addButton(ui->enterButtonAssignCross, 1);