diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index 7b295e2d0e..aaccdc2860 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -114,6 +114,20 @@ void fmt_class_string::format(std::string& out, u }); } +// last 4 out of 7 ports (7,6,5,4). index starts at 1 +static u32 port_num(u32 gem_num) +{ + ensure(gem_num < CELL_GEM_MAX_NUM); + return CELL_PAD_MAX_PORT_NUM - gem_num; +} + +// last 4 out of 7 ports (6,5,4,3). index starts at 0 +static u32 pad_num(u32 gem_num) +{ + ensure(gem_num < CELL_GEM_MAX_NUM); + return (CELL_PAD_MAX_PORT_NUM - 1) - gem_num; +} + // ********************** // * HLE helper structs * // ********************** @@ -278,12 +292,38 @@ public: return; } + bool is_connected = false; + switch (g_cfg.io.move) { case move_handler::fake: + { + connected_controllers = 0; + std::lock_guard lock(pad::g_pad_mutex); + const auto handler = pad::get_current_handler(); + for (u32 i = 0; i < std::min(attribute.max_connect, CELL_GEM_MAX_NUM); i++) + { + const auto& pad = ::at32(handler->GetPads(), pad_num(i)); + if (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) + { + connected_controllers++; + + if (gem_num == i) + { + is_connected = true; + } + } + } + break; + } case move_handler::mouse: { connected_controllers = 1; + + if (gem_num == 0) + { + is_connected = true; + } break; } #ifdef HAVE_LIBEVDEV @@ -291,8 +331,13 @@ public: { gun_thread& gun = g_fxo->get(); std::scoped_lock lock(gun.handler.mutex); - connected_controllers = gun.handler.init() ? gun.handler.get_num_guns() : 0; - gun.num_devices = connected_controllers; + gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0; + connected_controllers = std::min(std::min(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices); + + if (gem_num < connected_controllers) + { + is_connected = true; + } break; } #endif @@ -306,10 +351,10 @@ public: controller.sphere_rgb = gem_color::get_default_color(gem_num); // Assign status and port number - if (gem_num < connected_controllers) + if (is_connected) { controller.status = CELL_GEM_STATUS_READY; - controller.port = CELL_PAD_MAX_PORT_NUM - gem_num; + controller.port = port_num(gem_num); } } @@ -638,12 +683,12 @@ extern bool is_input_allowed(); /** * \brief Maps Move controller data (digital buttons, and analog Trigger data) to DS3 pad input. * Unavoidably buttons conflict with DS3 mappings, which is problematic for some games. - * \param port_no DS3 port number to use + * \param gem_num gem index to use * \param digital_buttons Bitmask filled with CELL_GEM_CTRL_* values * \param analog_t Analog value of Move's Trigger. Currently mapped to R2. - * \return true on success, false if port_no controller is invalid + * \return true on success, false if controller is disconnected */ -static void ds3_input_to_pad(const u32 port_no, be_t& digital_buttons, be_t& analog_t) +static void ds3_input_to_pad(const u32 gem_num, be_t& digital_buttons, be_t& analog_t) { digital_buttons = 0; analog_t = 0; @@ -656,14 +701,14 @@ static void ds3_input_to_pad(const u32 port_no, be_t& digital_buttons, be_t std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); - const auto& pad = ::at32(handler->GetPads(), port_no); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) { return; } - const auto& cfg = ::at32(g_cfg_gem.players, port_no); + const auto& cfg = ::at32(g_cfg_gem.players, gem_num); cfg->handle_input(pad, true, [&](gem_btn btn, u16 value, bool pressed) { if (!pressed) @@ -707,12 +752,12 @@ static void ds3_input_to_pad(const u32 port_no, be_t& digital_buttons, be_t constexpr u16 ds3_max_x = 255; constexpr u16 ds3_max_y = 255; -static inline void ds3_get_stick_values(u32 port_no, const std::shared_ptr& pad, s32& x_pos, s32& y_pos) +static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr& pad, s32& x_pos, s32& y_pos) { x_pos = 0; y_pos = 0; - const auto& cfg = ::at32(g_cfg_gem.players, port_no); + const auto& cfg = ::at32(g_cfg_gem.players, gem_num); cfg->handle_input(pad, true, [&](gem_btn btn, u16 value, bool pressed) { if (!pressed) @@ -733,7 +778,7 @@ static inline void ds3_get_stick_values(u32 port_no, const std::shared_ptr& } template -static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_controller& controller, T& gem_state) +static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, T& gem_state) { if (!gem_state || !is_input_allowed()) { @@ -743,7 +788,7 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); - const auto& pad = ::at32(handler->GetPads(), port_no); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) { @@ -751,15 +796,15 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro } s32 ds3_pos_x, ds3_pos_y; - ds3_get_stick_values(port_no, pad, ds3_pos_x, ds3_pos_y); + ds3_get_stick_values(gem_num, pad, ds3_pos_x, ds3_pos_y); if constexpr (std::is_same>::value) { - pos_to_gem_state(port_no, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y); + pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y); } else if constexpr (std::is_same>::value) { - pos_to_gem_image_state(port_no, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y); + pos_to_gem_image_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y); } } @@ -767,11 +812,11 @@ static void ds3_pos_to_gem_state(const u32 port_no, const gem_config::gem_contro * \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 * libPad, so no translation is needed. - * \param port_no DS3 port number to use + * \param gem_num gem index to use * \param ext External data to modify - * \return true on success, false if port_no controller is invalid + * \return true on success, false if controller is disconnected */ -static void ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller& controller, CellGemExtPortData& ext) +static void ds3_input_to_ext(const u32 gem_num, const gem_config::gem_controller& controller, CellGemExtPortData& ext) { ext = {}; @@ -783,7 +828,7 @@ static void ds3_input_to_ext(const u32 port_no, const gem_config::gem_controller std::lock_guard lock(pad::g_pad_mutex); const auto handler = pad::get_current_handler(); - const auto& pad = ::at32(handler->GetPads(), port_no); + const auto& pad = ::at32(handler->GetPads(), pad_num(gem_num)); if (!(pad->m_port_status & CELL_PAD_STATUS_CONNECTED)) { @@ -1460,6 +1505,33 @@ error_code cellGemGetInfo(vm::ptr info) } // TODO: Support connecting PlayStation Move controllers + + if (g_cfg.io.move == move_handler::fake) + { + gem.connected_controllers = 0; + + std::lock_guard lock(pad::g_pad_mutex); + const auto handler = pad::get_current_handler(); + + for (u32 i = 0; i < CELL_GEM_MAX_NUM; i++) + { + const auto& pad = ::at32(handler->GetPads(), pad_num(i)); + const bool connected = (pad && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED) && i < gem.attribute.max_connect); + + if (connected) + { + gem.connected_controllers++; + gem.controllers[i].status = CELL_GEM_STATUS_READY; + gem.controllers[i].port = port_num(i); + } + else + { + gem.controllers[i].status = CELL_GEM_STATUS_DISCONNECTED; + gem.controllers[i].port = 0; + } + } + } + info->max_connect = gem.attribute.max_connect; info->now_connect = gem.connected_controllers; diff --git a/rpcs3/Emu/Io/gem_config.h b/rpcs3/Emu/Io/gem_config.h index 5132a678dc..2197535c4d 100644 --- a/rpcs3/Emu/Io/gem_config.h +++ b/rpcs3/Emu/Io/gem_config.h @@ -36,9 +36,9 @@ struct cfg_gem final : public emulated_pad_config cfg_pad_btn y_axis{ this, "Y-Axis", gem_btn::y_axis, pad_button::ls_y }; }; -struct cfg_gems final : public emulated_pads_config +struct cfg_gems final : public emulated_pads_config { - cfg_gems() : emulated_pads_config("gem") {}; + cfg_gems() : emulated_pads_config("gem") {}; }; extern cfg_gems g_cfg_gem;